输入/输出
图像
从文件加载图像
Mat img = imread(filename)
如果你加载的是 JPG 文件,将会默认创建一个 3 通道的图像,如果你需要灰度图,可以用:
Mat img = imread(filename, 0);
注意
文件的根据市根据文件内容自动识别的(一般是前几个字节的内容)
将突破保存到文件:
imwrite(filename, img);
注意
文件的格式是通过其扩展名进行识别.
注意
请使用 imdecode 和 imencode 来读写内存中的图片,而不是文件中的图片。
XML/YAML
待处理
基本的图像操作
访问像素强度值
为了获得像素强度值,你需要知道图片的类型已经包含多少个通道。这里是一个单通道灰度图的例子(8UC1 类型), 其像素坐标为 x 和 y:
Scalar intensity = img.at<uchar>(y, x);
intensity.val[0] 包含了值范围从 0 到 255。请注意 x 和 y 参数的顺序。因为 OpenCV 的图像是使用和阵列相同结构的方式存储,我们使用相同的约定来处理两种方式:基于 0 的行索引(或者称为纵坐标)作为首个参数以及基于 0 的列索引(横坐标)跟进其后。你也可以使用下面的方式来代替:
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];
你可以对浮点图像使用相同的方法(例如通过运行 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);
上述结果返回一个 32FC1 的矩阵,包含 3 列数据,而不是 32FC3 的 1 列数据。pointsMat 使用这些点数据,在销毁的时候不会释放内存。在这个特定的情况下,开发者必须确保点阵的生命周期比 pointsMat 要长才行。如果我们需要复制数据,可以使用 Mat::copyTo 或者 Mat::clone:
Mat img = imread("image.jpg");
Mat img1 = img.clone();
与开发人员所创建的输出图像的相反,一个空的输出 Mat 可以提供给每个函数。该方法为一个空的矩阵分配数据。如果矩阵的数据和类型都无误,则该方法什么都不做。如果输入参数的大小和类型不一致,该数据就会被释放(并丢失)然后分配新的数据,例如:
Mat img = imread("image.jpg");
Mat sobelx;
Sobel(img, sobelx, CV_32F, 1, 0);
基本操作
一个阵列有很多的基本操作。例如我们可以从一个已有的灰度图总生成一个黑色图像::
img = Scalar(0);
Selecting a region of interest:
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, CV_BGR2GRAY);
将图片类型从 8UC1 改为 32FC1:
src.convertTo(dst, CV_32F);
图像显示
在开发过程中看到通过你算法出来的图片是很爽的。OpenCV 提供了一个便捷的方式来显示图像。一个8U图像可以使用如下代码显示:
Mat img = imread("image.jpg");
namedWindow("image", CV_WINDOW_AUTOSIZE);
imshow("image", img);
waitKey();
waitKey() 方法调用开始一个消息的传递循环,等待用户在图像窗口中按键。32F 的图像需要转成 8U 才可以显示,例如:
Mat img = imread("image.jpg");
Mat grey;
cvtColor(img, grey, CV_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", CV_WINDOW_AUTOSIZE);
imshow("image", draw);
waitKey();