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

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

兼容性OpenCV >= 3.0

输入/输出

图像

从文件加载图像

如果读取 JPG 文件,默认会创建一个三通道图像。如果需要灰度图像,请使用

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

图像基本操作

访问像素强度值

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

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

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

现在让我们考虑一个具有 BGR 颜色顺序的三通道图像(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

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

对于浮点图像(例如,通过对三通道图像运行 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);

可以使用相同的 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);

结果,我们得到一个三列的 `32FC1` 矩阵,而不是一列的 `32FC3` 矩阵。pointsMat 使用来自 `points` 的数据,并且在销毁时不会释放内存。然而,在这种特定情况下,开发人员必须确保 `points` 的生命周期长于 `pointsMat`。如果我们需要复制数据,可以通过例如 `cv::Mat::copyTo``cv::Mat::clone` 来完成。

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

基本操作

矩阵上定义了许多方便的运算符。例如,下面是如何从现有的灰度图像 img 创建一个黑色图像:

选择感兴趣区域

从彩色到灰度的转换

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

图像可视化

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

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

注意
这里不需要 `cv::namedWindow`,因为它紧接着 `cv::imshow`。然而,它可以用于更改窗口属性或在使用 `cv::createTrackbar` 时。