OpenCV图像操作
输入/输出
图片
从文件加载图像:
Mat img = imread(filename)
如果您读取jpg文件,则默认情况下会创建3通道映像。如果需要灰度图像,请使用:
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来获取此类图像):
(y,x); 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);
因此,我们得到一个32FC1矩阵与3列而不是32FC3矩阵与1列。pointsMat使用点数据,销毁时不会释放内存。然而,在这种特殊情况下,开发人员必须确保点的生命周期比pointMat长。如果我们需要复制数据,可以使用例如cv :: Mat :: copyTo或cv :: Mat :: clone:
Mat img = imread(“image.jpg”);
Mat img1 = img.clone();
相反,使用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型。例如:
Mat img = imread("image.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();