操作图像

输入/输出

图像

从文件中读入一副图像:

Mat img = imread(filename)

如果你读入一个jpg文件,缺省情况下将创建一个3通道图像。如果你需要灰度(单通道)图像,使用如下语句:

Mat img = imread(filename, 0);

将图像保存到一个文件:

Mat img = imwrite(filename);

XML/YAML

TBD

基本图像操作

获取像素的亮度值

要获取像素的亮度值,你必须知道图像的类型和通道的数目。如下例子展示了获取单通道灰度图(类型 8UC1)的(x, y)位置处的像素值:

Scalar intensity = img.at<uchar>(x, y);

intensity.val[0] 中保存从0到255的值。现在我们看一下3通道图像如何获取像素值,颜色顺序为 BGRimread 返回的缺省顺序):

Vec3b intensity = img.at<Vec3b>(x, y);
uchar blue = intensity.val[0];
uchar green = intensity.val[1];
uchar red = intensity.val[2];

你可以使用同样的方法处理浮点图像(例如通对一个3通道图像进行Sobel运算得到的浮点图像):

Vec3f intensity = img.at<Vec3f>(x, y);
float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];

同样的方法也可用于像素值的修改:

img.at<uchar>(x, y) = 128;

一些OpenCV函数,例如calib3d模块中的 projectPoints 函数,需要以 Mat 的格式输入二维或者三维的点。这样的矩阵必须有且仅有一列,这样每行对应一个点,矩阵类型需要是32FC2或者32FC3。这样的矩阵可以很容易的从 std::vector 转换而来:

vector<Point2f> points;
//... fill the array
Mat pointsMat = Mat(points);

您也可以通过 Mat::at 方法来读写矩阵中的一个元素:

Point2f point = pointsMat.at<Point2f>(i, 0);

内存管理和参考计数(reference counting)

Mat 内存储了矩阵/图像的属性(行数,列数,数据类型等)以及一个指向数据的指针。因此几个 Mat 实例可以指向同一个数据。 Mat 中还记录了参考计数(reference count),这样在 Mat 被释放时就知道是否需要释放数据。这儿是一个不需复制数据就创建两个矩阵的例子:

std::vector<Point3f> points;
// .. fill the array
Mat pointsMat = Mat(points).reshape(1);

这样我们得到了一个3列的32FC1矩阵,而不是1列的32FC3矩阵。 pointsMat 使用 points 的数据,且当它释放时不会是否数据。在这个例子中,开发者需要知道 points 的生命比 pointsMat 长。如果我们需要复制数据,那么请使用 Mat::copyToMat::clone

Mat img = imread("image.jpg");
Mat img1 = img.clone();

在C API中,开发者必须实现创建输出图像然后再调用函数。与之相比不同的是C++ API支持空的 Mat 类型的输出参数。C++ API会调用 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, 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() 会进入一个消息循环,来等待 image 窗口上的按键动作。 类型为 32F 的图像需要转为 8U 类型。如下:

Mat img = imread("image.jpg");
Mat grey;
cvtColor(img, grey, CV_BGR2GREY);

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);

namedWindow("image", CV_WINDOW_AUTOSIZE);
imshow("image", draw);
waitKey();

翻译

于仕琪 http://www.opencv.org.cn

Table Of Contents

Previous topic

OpenCV用户指南

Next topic

Features2d

This Page