一. 输入/输出
① 从一个文件中加载一个图像
Mat img = imread(filename);
如果你想读取一个jpg
图像,默认会创建一个3通道的图像.如果你需要一个灰度图像,使用:
Mat img = imread(filename,IMREAD_GRAYSCALE);
注意:
文件的格式由其内容(前几个字节)决定. 将图像保存到文件.
② 写入图像到一个文件中
imwrite(filename,img);
注意:
文件的格式由其扩展名决定.使用cv::imdecode
和cv::imencode
从内存中读取和写入图像,而不是文件.
二. 图像的基本操作
① 访问像素强度值
为了得到像素的强度值,你必须知道图像的类型和通道的数量.下面是一个单通道灰度图像(类型 8UC1)和像素坐标x和y的示例:
Scalar intensity = img.at<uchar>(Point(x,y));
现在让我们考虑一个BGR颜色排序的3通道图像(imread返回的默认格式):
Vec3b intesity = img.at<Vec3b>(y,x);
uchar blue = intesity.val[0];
uchar green = intesity.val[1];
uchar red = intesity.val[2];
你可以对浮点类型的图像使用相同的方法(例如,可以通过3通道图像上运行Soble
来获得这样的图像)(仅限C++):
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
模块的函数,比如cv::projectPoints
,以Mat
的形式获取二维或者三维点的数组.矩阵应该恰好包含一列,每一行对应一个点,对应的矩阵类型应该是32FC2
或者32FC3
.这样的矩阵可以很容易地从std::vector
中构造(仅限C++):
vector<Point2f> points;
// ... fill the array
Mat pointsMat = Mat(points);
你可以使用相同的方法访问这个矩阵中的一个点Mat::at
(仅限C++):
Point2f point = pointsMat.at<Point2f>(i,0);
三. 内存管理和引用计数
Mat是这样一中结构体,它保存了矩阵/图像特征(行数和列数,数据类型等)和一个指向数据的指针.因此,没有什么可以阻止我们拥有多个对应相同数据的Mat实例.Mat保持了一个引用计数,当特定的Mat实例被销毁的时候,它告诉数据是否必须被释放.下面是一个在不复制数据的情况下创建两个矩阵的示例(仅限C++):
std::vector<Point3f> points;
// .. fill the array
Mat pointsMat = Mat(points).reshape(1);
结果,我们得到一个三列的32FC1
矩阵,而不是1列的32FC3
矩阵.pointsMat使用来自points的数据,销毁时不会释放内存.但是,在这个特殊的例子中,开发人员必须确保points的声明周期比pointsMat长.我们如果需要复制数据,可以使用cv::Mat::copyTo
或者cv::Mat::clone()
来完成.
Mat img = imread("image.jgp");
Mat img1 = img.clone();
可以为每个函数提供空的输出Mat.每个市县对目标矩阵调用Mat::create.如果矩阵为空,则此方法为其分配数据.如果它不是空的,并且具有正确的大小和类型,则该方法不执行任何操作.但是,如果大小或者类型与输入参数不同,则释放(或丢失)数据,并分配新数据.例如:
Mat img = imread("image.jgp");
Mat sobelx;
Sobel(img,sobelx,CV_32F,1,0);
四. 原始操作
矩阵上定了许多方便的运算符.例如,下面展示了我们如何从现有的灰度图像
img
中生成黑色图像
img = Scalar(0);
选择感应区的区域
Rect r(10,10,100,100);
Mat smallImg = img(r);
将图像从彩色图像转换为灰度图像
Mat img = imread("image.jpg"); // loading a 8UC3 image
Mat gray;
cvtColor(img,gray,COLOR_BGR2GRAY);
将图像的数据类型从
8UC1
转换为32FC1
:
src.convertTo(dst,CV_32F);
五. 可视化图像
在开发的过程中查看算法的中间结果是非常有用的.Opencv提供了一种方便的可视化图像的方法.一个8U的图像可以显示使用:
Mat img = imread("image.jpg");
nameWindow("image",WINDOW_AUTOSIZE);
imshow("image",img);
waitKey();
通过调用
waitKey()
启动一个循环接收消息,等待图像串口的点击键盘.一个32F
的图像需要转换为8U
的类型,例如:
Mat img = imread("image.jgp");
Mat gray;
cvtColor(img,gray,COLOR_BGR2GRAY);
Mat sobelX;
Sobel(gray,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));
nameWindow("image" WINDOW_AUTOSIZE);
imshow("image",draw);
waitKey();
注意:
这里的cv::nameWindow
不是必要的,因为它后面紧跟着cv::imshow
,它可以用于更该窗口属性或者使用cv::createTrackbar
时的时候使用.