参考:
1、https://docs.opencv.org/3.2.0/
2、https://github.com/opencv/opencv/
Operations with images
Input/Output
Images
从文件加载图像:
Mat img = imread(filename)
//或
Mat img = imread(filename,IMREAD_COLOR)
如果您读取一个jpg文件,默认情况下会创建一个3通道图像。 如果您需要灰度图像,请使用:
Mat img = imread(filename, 0);
//或
Mat img = imread(filename,IMREAD_GRAYSCALE)
注:
文件格式由其内容决定(前几个字节)将图像保存到文件中:
imwrite(filename, img);
该文件的格式是由其扩展名决定的。
使用imdecode和imencode从内存中读/写图像而不是文件。
基本操作与图像
访问像素强度值
为了获得像素强度值,您必须知道图像的类型和通道的数量。 以下是单通道灰度图像(类型8UC1)和像素坐标x和y的示例:
Scalar intensity = img.at<uchar>(y, x);
intensity.val [0]包含从0到255的值。请注意x和y的排序。 因为在OpenCV中,图像由与矩阵相同的结构表示,所以我们在两种情况下都使用相同的约定 - 基于0的行索引(或y坐标)首先出现,然后是基于0的列索引(或x坐标) 它。 或者,您可以使用以下表示法:
Scalar intensity = img.at<uchar>(Point(x, y));
现在让我们考虑一个BGR颜色排序的3通道图像(imread返回的默认格式):
Vec3b intensity = img.at<Vec3b>(y, x);
uchar blue = intensity.val[0];
uchar green = intensity.val[1];
uchar red = intensity.val[2];
您可以对浮点图像使用相同的方法(例如,可以通过在3通道图像上运行Sobel来获得这样的图像):
Vec3f intensity = img.at<Vec3f>(y, x);
float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];
可以使用相同的方法来改变像素强度:
img.at<uchar>(y, x) = 128;
在OpenCV中有函数,特别是来自calib3d模块的函数,比如projectPoints,它们以Mat的形式获取一个2D或3D点的数组。 矩阵应该只包含一列,每一行对应一个点,矩阵类型应相应为32FC2或32FC3。 这样的矩阵可以很容易地从std :: vector构造出来:
vector<Point2f> points;
//... fill the array
Mat pointsMat = Mat(points);
可以使用相同的方法在这个矩阵中访问一个点Mat :: at:
Point2f point = pointsMat.at<Point2f>(i, 0);
内存管理和引用计数
Mat是一种保持矩阵/图像特征(行和列号,数据类型等)和指向数据的指针的结构。 所以没有任何东西阻止我们有几个Mat实例对应于相同的数据。 一个Mat保留一个引用计数,告诉数据是否在Mat的特定实例被销毁时被释放。 以下是创建两个矩阵而不复制数据的示例:
std::vector<Point3f> points;
// .. fill the array
Mat pointsMat = Mat(points).reshape(1);
结果,我们得到了3列32FC1矩阵,而不是1列32FC3矩阵。 pointsMat使用来自点的数据,并且在销毁时不会释放内存。 然而,在这个特定的例子中,开发者必须确保点的寿命比点的长。 如果我们需要复制数据,则使用例如cv :: Mat :: copyTo或cv :: Mat :: clone:
Mat img = imread("image.jpg");
Mat img1 = img.clone();
Mat img2;img.copyTo(img2);
相反,如果C API需要由开发人员创建输出图像,则可以为每个函数提供一个空输出Mat。 每个实现调用目标矩阵的Mat :: create。 如果该方法为空,则该方法为矩阵分配数据。 如果它不是空的并且具有正确的大小和类型,则该方法不做任何事情。 但是,如果大小或类型与输入参数不同,则会释放(并丢失)数据,并分配新数据。 例如:
Mat img = imread("image.jpg");
Mat sobelx;
Sobel(img, sobelx, CV_32F, 1, 0);
原始的操作
在矩阵上定义了许多方便的操作符。 例如,下面是我们如何从现有的灰度图像“img”制作黑色图像:
img = Scalar(0);
选择一个感兴趣的区域:
Rect r(10, 10, 100, 100);
Mat smallImg = img(r);
从Mat到C API数据结构的转换:
Mat img = imread("image.jpg");
IplImage img1 = img;
CvMat m = img;
注意,这里没有数据复制。
从彩色转换到灰度:
Mat img = imread("image.jpg"); // loading a 8UC3 image
Mat grey;
cvtColor(img, grey, COLOR_BGR2GRAY);
将图像类型从8UC1更改为32FC1:
src.convertTo(dst, CV_32F);
可视化图像
在开发过程中查看算法的中间结果是非常有用的。 OpenCV提供了一种可视化图像的便捷方式。 一个8U图像可以显示使用:
Mat img = imread("image.jpg");
namedWindow("image", WINDOW_AUTOSIZE);
imshow("image", img);
waitKey();
对waitKey()的调用会启动一个消息传递循环,等待“图像”窗口中的关键笔划。 32F图像需要转换为8U类型。 例如:
#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat img = imread("messi5.jpg");
Mat grey;
cvtColor(img, grey, COLOR_BGR2GRAY);
Mat sobelx;
Sobel(grey, sobelx, CV_32F, 1, 0);
double minVal, maxVal;
minMaxLoc(sobelx, &minVal, &maxVal); //find minimum and maximum intensities
Mat draw;
sobelx.convertTo(draw, CV_8U, 255.0 / (maxVal - minVal), -minVal * 255.0 / (maxVal - minVal));
namedWindow("image", WINDOW_AUTOSIZE);
imshow("image", draw);
waitKey();
return 0;
}