OpenCV 图像操作基础:读写、像素访问与内存管理
OpenCV 中图像操作的核心技术,包括从文件加载和保存图像的方法、不同通道类型下的像素访问方式(C++ 与 Python)、Mat 类的内存管理与引用计数机制。内容涵盖了基本的矩阵运算、感兴趣区域(ROI)提取、颜色空间转换以及图像可视化的具体实现。此外,还补充了位运算、阈值处理等常用图像处理技巧,并提供了常见的错误排查建议,帮助开发者建立扎实的 OpenCV 基础。

OpenCV 中图像操作的核心技术,包括从文件加载和保存图像的方法、不同通道类型下的像素访问方式(C++ 与 Python)、Mat 类的内存管理与引用计数机制。内容涵盖了基本的矩阵运算、感兴趣区域(ROI)提取、颜色空间转换以及图像可视化的具体实现。此外,还补充了位运算、阈值处理等常用图像处理技巧,并提供了常见的错误排查建议,帮助开发者建立扎实的 OpenCV 基础。

使用 imread 函数从文件加载图像。在 C++ 中,返回类型为 cv::Mat。
#include <opencv2/opencv.hpp>
using namespace cv;
int main() {
// 默认创建 3 通道 BGR 图像
Mat img = imread("image.jpg");
// 如果读取 jpg 文件,默认创建一个 3 通道图像
// 如果需要灰度图像,请指定 IMREAD_GRAYSCALE 标志
Mat grayImg = imread("image.jpg", IMREAD_GRAYSCALE);
if (img.empty()) {
std::cerr << "无法加载图像" << std::endl;
return -1;
}
return 0;
}
注意: 文件的格式由其内容(前几个字节)决定,但保存时通常由扩展名决定。
使用 imwrite 函数将图像写入文件。
// 将图像保存到文件
imwrite("output.png", img);
注意: 文件的格式由其扩展名决定(如 .jpg, .png, .bmp)。
OpenCV 提供了从内存缓冲区而不是文件读取和写入图像的功能,常用于网络传输或处理流数据。
为了获得像素强度值,您必须知道图像的类型和通道数。以下是单通道灰度图像(类型 8UC1)和像素坐标 x 和 y 的示例:
// 获取像素值
unsigned char intensity = img.at<unsigned char>(y, x);
仅限 C++ 版本: intensity 包含从 0 到 255 的值。注意 x 和 y 的顺序。由于在 OpenCV 中,图像由与矩阵相同的结构表示,因此我们对这两种情况使用相同的约定 - 从 0 开始的行索引(或 y 坐标)排在最前面,从 0 开始的列索引(或 x 坐标)紧随其后。
或者,您可以使用以下表示法(仅限 C++):
intensity = img.at<unsigned char>(Point(x, y));
现在让我们考虑一个带有 BGR 颜色排序的 3 通道图像(imread 返回的默认格式):
C++ 代码
Vec3b intensity = img.at<Vec3b>(y, x);
uchar blue = intensity[0];
uchar green = intensity[1];
uchar red = intensity[2];
Python 代码
blue = img[y, x, 0]
green = img[y, x, 1]
red = img[y, x, 2]
您可以对浮点图像使用相同的方法(例如,您可以通过在 3 通道图像上运行 Sobel 来获取此类图像):
Vec3f intensity = img.at<Vec3f>(y, x);
float blue = intensity[0];
float green = intensity[1];
float red = intensity[2];
可以使用相同的方法来更改像素强度:
img.at<unsigned char>(y, x) = 128;
Mat 是一种结构,用于保留矩阵/图像特征(行和列数、数据类型等)和指向数据的指针。因此,没有什么能阻止我们拥有对应于相同数据的多个 Mat 实例。Mat 保留一个引用计数,该计数指示在销毁特定 Mat 实例时是否必须释放数据。
下面是在不复制数据的情况下创建两个矩阵的示例:
std::vector<Point> points;
// ... 填充数组
Mat pointsMat = Mat(points).reshape(1, 1);
As a result, we get a 32FC1 matrix with 3 columns instead of 32FC3 matrix with 1 column. pointsMat uses data from points and will not deallocate the memory when destroyed. In this particular instance, however, developer has to make sure that lifetime of points is longer than of pointsMat.
If we need to copy the data, this is done using clone() or copyTo():
Mat img = imread("image.jpg");
Mat img1 = img.clone();
An empty output Mat can be supplied to each function. Each implementation calls Mat::create for a destination matrix. This method allocates data for a matrix if it is empty. If it is not empty and has the correct size and type, the method does nothing. If however, size or type are different from the input arguments, the data is deallocated (and lost) and a new data is allocated.
Mat img = imread("image.jpg");
Mat sobelx;
cv::Sobel(img, sobelx, CV_32F, 1, 0);
矩阵上定义了许多方便的运算符。例如,以下是我们如何从现有的灰度图像中制作黑色图像:
img = Scalar(0);
选择感兴趣的区域(ROI):
Rect r(10, 10, 100, 100);
Mat smallImg = img(r);
从彩色到灰度的转换:
Mat img = imread("image.jpg"); // 加载 8UC3 镜像
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
将图像类型从 8UC1 更改为 32FC1:
src.convertTo(dst, CV_32F);
在开发过程中查看算法的中间结果非常有用。OpenCV 提供了一种可视化图像的便捷方式。可以使用以下方式显示 8U 图像:
Mat img = imread("image.jpg");
imshow("Image", img);
waitKey(0);
destroyAllWindows();
对 imshow 的调用会启动一个消息传递周期,该周期在'Image'窗口中等待击键。32F 图像需要转换为 8U 型。
Mat img = imread("image.jpg");
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
Mat sobelx;
Sobel(gray, sobelx, CV_32F, 1, 0);
double minVal, maxVal;
minMaxLoc(sobelx, &minVal, &maxVal); // 最小和最大强度
Mat draw;
sobelx.convertTo(draw, CV_8U, 255.0 / (maxVal - minVal), -minVal * 255.0 / (maxVal - minVal));
imshow("Sobel", draw);
waitKey(0);
destroyAllWindows();
位运算是图像处理中的基础操作,常用于掩膜处理。
Mat src1 = imread("source1.png");
Mat src2 = imread("source2.png");
Mat dst;
bitwise_and(src1, src2, dst);
将图像二值化是许多预处理步骤的关键。
Mat src = imread("image.jpg", IMREAD_GRAYSCALE);
Mat dst;
threshold(src, dst, 127, 255, THRESH_BINARY);
imread 返回值是否为空,防止后续操作崩溃。Mat 有引用计数,但在复杂循环中手动管理资源仍是好习惯。掌握 OpenCV 的图像读写、像素访问及内存管理机制是进行计算机视觉开发的基础。通过合理使用 Mat 类及其相关函数,可以高效地处理各种图像任务。在实际项目中,建议结合具体的业务需求,选择合适的算法模块(如 calib3d, features2d 等)进行扩展。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online