OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
无匹配项
图像操作

上一教程: 矩阵掩码操作
下一教程: 使用 OpenCV 添加(混合)两张图像

兼容性OpenCV >= 3.0

输入/输出

图像

从文件加载图像

如果读取 jpg 文件,默认情况下会创建 3 通道图像。如果需要灰度图像,请使用

注意
文件格式由其内容(前几个字节)决定。要将图像保存到文件,请使用
注意
文件格式由其扩展名决定。
使用 cv::imdecodecv::imencode 从内存读取和写入图像,而不是从文件读取和写入图像。

图像基本操作

访问像素强度值

为了获取像素强度值,您必须知道图像的类型和通道数。这是一个单通道灰度图像(类型 8UC1)和像素坐标 x 和 y 的示例

仅限 C++ 版本:intensity.val[0] 包含 0 到 255 之间的值。请注意 x 和 y 的顺序。由于在 OpenCV 中,图像由与矩阵相同的结构表示,因此我们对这两种情况都使用相同的约定——基于 0 的行索引(或 y 坐标)放在前面,基于 0 的列索引(或 x 坐标)放在后面。或者,您可以使用以下表示法(**仅限 C++**)

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

现在让我们考虑一个具有 BGR 颜色顺序的 3 通道图像(imread 返回的默认格式)

C++ 代码

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

Python Python

_blue = img[y,x,0]
_green = img[y,x,1]
_red = img[y,x,2]

您可以对浮点图像使用相同的方法(例如,您可以通过对 3 通道图像运行 Sobel 来获得此类图像)(**仅限 C++**)

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

可以使用相同的方法更改像素强度

OpenCV 中有一些函数,特别是来自 calib3d 模块的函数,例如 cv::projectPoints,它采用 Mat 形式的 2D 或 3D 点数组。矩阵应恰好包含一列,每一行对应一个点,矩阵类型应分别为 32FC2 或 32FC3。可以很容易地从 std::vector 构造这样的矩阵(**仅限 C++**)

vector<Point2f> points;
//... 填充数组
Mat pointsMat = Mat(points).reshape(1);

可以使用相同的方法 Mat::at 访问此矩阵中的点(**仅限 C++**)

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

内存管理和引用计数

Mat 是一种结构,它保存矩阵/图像特性(行数和列数、数据类型等)以及指向数据的指针。因此,没有什么可以阻止我们拥有多个对应于相同数据的 Mat 实例。Mat 保持一个引用计数,该计数告诉当特定 Mat 实例被销毁时是否必须释放数据。这是一个创建两个矩阵而不复制数据的示例(**仅限 C++**)

std::vector<Point3f> points;
// .. 填充数组
Mat pointsMat = Mat(points).reshape(1);

结果,我们得到一个3列的32FC1矩阵,而不是1列的32FC3矩阵。pointsMat使用points中的数据,并在销毁时不会释放内存。但是,在这个特定实例中,开发者必须确保points的生命周期长于pointsMat。如果我们需要复制数据,可以使用例如cv::Mat::copyTocv::Mat::clone

可以向每个函数提供一个空的输出Mat。每个实现都为目标矩阵调用Mat::create方法。此方法如果矩阵为空,则为矩阵分配数据。如果它不为空并且具有正确的尺寸和类型,则该方法不执行任何操作。但是,如果尺寸或类型与输入参数不同,则数据将被释放(并丢失),并分配新的数据。例如

基本操作

矩阵上定义了许多方便的操作符。例如,以下是我们如何从现有的灰度图像img创建黑色图像的方法:

选择感兴趣区域

从彩色图像转换为灰度图像

将图像类型从 8UC1 更改为 32FC1

可视化图像

在开发过程中查看算法的中间结果非常有用。OpenCV 提供了一种方便的可视化图像的方法。可以使用以下方法显示 8U 图像:

调用waitKey()启动消息传递循环,该循环等待“image”窗口中的按键。需要将32F图像转换为8U类型。例如

注意
这里cv::namedWindow不是必需的,因为它紧跟在cv::imshow之后。但是,当使用cv::createTrackbar或需要更改窗口属性时,可以使用它。