文档结构  
可译网翻译有奖活动正在进行中,查看详情 现在前往 注册?
原作者:未知    来源:docs.opencv.org [英文]
coyee    计算机    2016-06-15    1评/941阅
翻译进度:已翻译   参与翻译: CY2 (4), coyee (3)

输入/输出

图像

从文件加载图像

Mat img = imread(filename)

如果你加载的是 JPG 文件,将会默认创建一个 3 通道的图像,如果你需要灰度图,可以用:

Mat img = imread(filename, 0);

注意

文件的格式是根据文件内容自动识别的(一般是前几个字节的内容)

将图像保存到文件:

imwrite(filename, img);

注意

文件的格式是通过其扩展名进行识别.

注意

请使用 imdecode 和 imencode 来读写内存中的图片,而不是文件中的图片。

XML/YAML

待处理

基本的图像操作

访问像素强度值

为了获得像素强度值,你需要知道图片的类型以及包含多少个通道。这里是一个单通道灰度图的例子(8UC1 类型), 其像素坐标为 x 和 y:

第 1 段(可获 2 积分)
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));

现在让我们考虑一个 3 通道的BGR 色彩图像的分类(通过 imread 返回默认的格式):

Vec3b intensity = img.at<Vec3b>(y, x);
uchar blue = intensity.val[0];
uchar green = intensity.val[1];
uchar red = intensity.val[2];
第 2 段(可获 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 来构建一个矩阵:

第 3 段(可获 2 积分)
vector<Point2f> points;
//... fill the array
Mat pointsMat = Mat(points);

你可以使用 Mat::at 方法来访问阵列中的点:

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

内存管理与引用计数

Mat 是一个用来保存阵列/图像特征的数据结构(包含行列编号、数据类型等),同时包含了指向数据的指针。因此同一个数据我们可以有多个 Mat 实例。一个 Mat 实例保存了一个数据的引用计数,当 Mat 实例被销毁时引用计数会减一。下面是一个无需拷贝数据的情况下创建两个矩阵的示例代码:

第 4 段(可获 2 积分)
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 可以提供给每个函数。该方法为一个空的矩阵分配数据。如果矩阵的数据和类型都无误,则该方法什么都不做。如果输入参数的大小和类型不一致,该数据就会被释放(并丢失)然后分配新的数据,例如:

第 5 段(可获 2 积分)
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);
第 6 段(可获 2 积分)

将图片类型从 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();
第 7 段(可获 2 积分)

文章评论

coyee
很强大