> 技术文档 > OpenCV学习探秘之二 :数字图像的矩阵原理,OpenCV图像类与常用函数接口说明,及其常见操作核心技术详解

OpenCV学习探秘之二 :数字图像的矩阵原理,OpenCV图像类与常用函数接口说明,及其常见操作核心技术详解


一、图像处理基础概念​

1.1数字图像的矩阵

如下图,这是我们看到的 Lena 的头像,但是计算机看来,这副图像只是一堆亮度各异的点。一副尺寸为 M × N 的图像可以用一个 M × N 的矩阵来表示,矩阵元素的值表示这个位置上的像素的亮度,一般来说像素值越大表示该点越亮。
OpenCV学习探秘之二 :数字图像的矩阵原理,OpenCV图像类与常用函数接口说明,及其常见操作核心技术详解
一般来说,灰度图用 2 维矩阵表示;彩色(多通道)图像用 3 维矩阵(M × N × 3)表示。对于图像显示来说,目前大部分设备都是用无符号 8 位整数(类型为 CV_8U)表示像素亮度。

1.2数字图像的本质​

图像在计算机中本质是多维矩阵​:

  • 彩色图像:三维矩阵(高度×宽度×3),通道顺序为BGR(非RGB)
  • 灰度图像:二维矩阵(高度×宽度),像素值范围0-255(0黑→255白)
  • ​像素关系​:相邻像素通过4-邻域、8-邻域空间连接,构成连通域

1.3​图像处理的意义​

​ - 降噪增强​:提升图像质量(如医疗影像去噪)

  • ​特征提取​:识别关键信息(如边缘、角点)
  • ​数据压缩​:减少存储与计算量(如灰度化降75%内存);

二、OpenCV图像类

2.1 Mat类结构

Mat类是 OpenCV 用于存储和操作图像 / 矩阵数据的核心结构,其设计兼顾了内存效率与操作灵活性。从结构上看,Mat由头部(Header) 和数据块(Data Block) 两部分组成。
OpenCV学习探秘之二 :数字图像的矩阵原理,OpenCV图像类与常用函数接口说明,及其常见操作核心技术详解

2.2 Mat类构造

opencv最核心的Mat类,Mat 是一个非常优秀的图像类,它同时也是一个通用的矩阵类,可以用来创建和操作多维矩阵。有多种方法创建一个 Mat 对象。常用的构造函数有:

  • Mat::Mat()
    无参数构造方法;
  • Mat::Mat(int rows, int cols, int type)
    创建行数为 rows,列数为 col,类型为 type 的图像;
  • Mat::Mat(Size size, int type)
    创建大小为 size,类型为 type 的图像;
  • Mat::Mat(int rows, int cols, int type, const Scalar& s)
    创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初始化为值 s;
  • Mat::Mat(Size size, int type, const Scalar& s)
    创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s;
  • Mat::Mat(const Mat& m)
    将 m 赋值给新创建的对象,此处不会对图像数据进行复制,m 和新对象共用图像数据;
  • Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
    创建行数为 rows,列数为 col,类型为 type 的图像,此构造函数不创建图像数据所需内存,而是直接使用 data 所指内存,图像的行步长由 step指定。
  • Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)
    创建大小为 size,类型为 type 的图像,此构造函数不创建图像数据所需内存,而是直接使用 data 所指内存,图像的行步长由 step 指定。
  • Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
    创建的新图像为 m 的一部分,具体的范围由 rowRange 和 colRange 指定,此构造函数也不进行图像数据的复制操作,新图像与 m 共用图像数据;
  • Mat::Mat(const Mat& m, const Rect& roi)
    创建的新图像为 m 的一部分,具体的范围 roi 指定,此构造函数也不进行图像数据的复制操作,新图像与 m 共用图像数据。
    这些构造函数中,很多都涉及到类型type。type可以是CV_8UC1,CV_16SC1,…,CV_64FC4 等。里面的 8U 表示 8 位无符号整数,16S 表示 16 位有符号整数,64F表示 64 位浮点数(即 double 类型);C 后面的数表示通道数,例如 C1 表示一个通道的图像,C4 表示 4 个通道的图像,以此类推。

三 常用接口函数

3.1 图像读写与显示

3.1.1 读取图像
  • imread(const string& filename, int flags=IMREAD_COLOR)
    读取图像文件,flags可选:
    IMREAD_COLOR:加载彩色图(默认);
    IMREAD_GRAYSCALE:加载灰度图;
    IMREAD_UNCHANGED:加载包含 Alpha 通道的图像;
3.1.2 保存图像
  • imwrite(const string& filename, InputArray img)
    保存图像到文件,支持格式:JPEG、PNG、BMP 等。
3.1.3 显示图像
  • namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE)
    创建窗口,flags可选:
    WINDOW_AUTOSIZE:窗口大小自适应图像;
    WINDOW_NORMAL:窗口可调整大小;
  • imshow(const string& winname, InputArray mat)
    在指定窗口显示图像。搭配waitKey(int delay=0)等待按键事件,delay为毫秒数,0 表示无限等待。

3.2 图像操作颜色空间转换

3.2.1 颜色空间转换
  • cvtColor(InputArray src, OutputArray dst, int code)
    转换颜色空间。
3.2.2 图像缩放
  • resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR)
    调整图像大小,interpolation可选:
    INTER_LINEAR:双线性插值(默认);
    INTER_NEAREST:最近邻插值;
    INTER_CUBIC:双三次插值(放大更清晰);
3.2.3 图像翻转与旋转
  • flip(InputArray src, OutputArray dst, int flipCode)
    翻转图像,flipCode:
    0:上下翻转
    1:左右翻转
    -1:上下 + 左右翻转
  • rotate(InputArray src, OutputArray dst, int rotateCode)
    旋转图像,rotateCode:
    ROTATE_90_CLOCKWISE:顺时针 90 度;
    ROTATE_180:180 度;
    ROTATE_90_COUNTERCLOCKWISE:逆时针 90 度;

3.3 图像滤波与增强

3.3.1 平滑滤波
  • blur(InputArray src, OutputArray dst, Size ksize)
    均值滤波,ksize为核大小(如(3, 3))。
  • GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0)
    高斯滤波,sigmaX为 X 方向标准差。
  • medianBlur(InputArray src, OutputArray dst, int ksize)
    中值滤波,ksize为核大小(奇数)。
3.3.2 边缘检测
  • Canny(InputArray image, OutputArray edges, double threshold1, double threshold2)
    Canny 边缘检测,threshold1和threshold2为双阈值。
3.3.3 直方图均衡化
  • equalizeHist(InputArray src, OutputArray dst)
    增强图像对比度(仅适用于灰度图)。

3.4 形态学操作

  • erode(InputArray src, OutputArray dst, InputArray kernel)
    腐蚀操作,缩小前景物体。
  • dilate(InputArray src, OutputArray dst, InputArray kernel)
    膨胀操作,扩大前景物体。
  • morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel)
    形态学高级操作,op可选:
    MORPH_OPEN:开运算(先腐蚀后膨胀)
    MORPH_CLOSE:闭运算(先膨胀后腐蚀)
    MORPH_GRADIENT:形态学梯度(膨胀 - 腐蚀)

3.5 图像算术与逻辑运算

  • add(InputArray src1, InputArray src2, OutputArray dst)
    图像加法(支持带权重的加法)。
  • subtract(InputArray src1, InputArray src2, OutputArray dst)
    图像减法。
  • bitwise_and(InputArray src1, InputArray src2, OutputArray dst)
    按位与(用于掩码操作)。
  • bitwise_or(InputArray src1, InputArray src2, OutputArray dst)
    按位或。
  • bitwise_not(InputArray src, OutputArray dst)
    按位取反。

3.6 几何变换

3.6.1 仿射变换
  • warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize)
    应用仿射变换,M为 2×3 变换矩阵。
  • getRotationMatrix2D(Point2f center, double angle, double scale)
    获取旋转矩阵(用于warpAffine)。
3.6.2 透视变换
  • warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize)
    应用透视变换,M为 3×3 变换矩阵。
  • getPerspectiveTransform(const Point2f src[], const Point2f dst[])
    计算透视变换矩阵。

3.7 特征提取

  • findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method)
    查找图像轮廓,mode为轮廓检索模式,method为轮廓近似方法。
  • HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold)
    Hough 直线检测。
  • HoughCircles(InputArray image, OutputArray circles, int method, double dp, double minDist)
    Hough 圆检测。

3.8 其他常用操作

  • split(const Mat& src, Mat* mvbegin)
    将多通道图像分割为单通道(例如 BGR→B、G、R)。
  • merge(const Mat* mv, size_t count, OutputArray dst)
    将多个单通道图像合并为多通道。
  • copyTo(InputArray src, OutputArray dst, InputArray mask)
    带掩码的图像复制。
  • setTo(InputOutputArray dst, const Scalar& value, InputArray mask=noArray())
    将图像或 ROI 设置为指定值。

四 常见操作原理说明

4.1 灰度处理原理与效果

在计算机视觉中,灰度图像是指每个像素仅由一个数值表示其亮度的图像,数值范围通常为 0(黑色)到 255(白色)。将彩色图像转换为灰度图像的过程称为灰度处理,其核心是通过加权平均或特定算法将 RGB 三个通道的信息合并为单通道。

4.1.1 灰度处理原理

常见的灰度转换的数学原理算法有以下几种:

平均值法

将 RGB 三个通道的数值取平均:

Gray = (R + G + B) / 3
加权平均法(更符合人眼感知)

人眼对绿色更敏感,因此绿色通道权重更高:

Gray = 0.299*R + 0.587*G + 0.114*B

这也是 OpenCV 默认的转换公式(CV_BGR2GRAY)

最大值法

使用 RGB 中的最大值作为灰度值:

Gray = max(R, G, B)
4.1.2 灰度处理的效果与场景
效果
  • 减少数据量:从三通道变为单通道,内存占用减少 1/3。
  • 突出形状特征:消除颜色干扰,更专注于纹理、边缘等结构信息。
常见应用
  • 人脸识别:预处理阶段常将图像转为灰度,降低计算复杂度。
  • 边缘检测:灰度图像更适合 Canny、Sobel 等算子提取边缘。
  • 模板匹配:灰度处理可提高匹配准确性。
  • 图像压缩:灰度图像可使用更高效的压缩算法。
4.1.2 代码示例
#include #include using namespace cv;using namespace std;int main() { // 读取彩色图像 Mat colorImage = imread(\"input.jpg\", IMREAD_COLOR); if (colorImage.empty()) { cout << \"无法读取图像!\" << endl; return -1; } // 创建用于存储灰度图像的Mat对象 Mat grayImage; // 方法1: 使用OpenCV内置函数进行灰度转换 cvtColor(colorImage, grayImage, COLOR_BGR2GRAY); // 方法2: 手动实现加权平均法 Mat manualGray = Mat::zeros(colorImage.size(), CV_8UC1); for (int i = 0; i < colorImage.rows; i++) { for (int j = 0; j < colorImage.cols; j++) { Vec3b pixel = colorImage.at<Vec3b>(i, j); // 注意: OpenCV中颜色顺序为BGR而非RGB uchar gray = 0.299 * pixel[2] + 0.587 * pixel[1] + 0.114 * pixel[0]; manualGray.at<uchar>(i, j) = gray; } } // 显示原图和灰度图 imshow(\"彩色图像\", colorImage); imshow(\"OpenCV灰度转换\", grayImage); imshow(\"手动灰度转换\", manualGray); // 保存灰度图像 imwrite(\"output_gray.jpg\", grayImage); // 等待按键退出 waitKey(0); return 0;}

4.2 颜色空间转换

颜色空间是描述颜色的数学模型,不同场景下需选择合适的颜色空间(如 RGB 适合显示,HSV 适合颜色分割)。OpenCV 通过cvtColor函数实现颜色空间转换,核心是基于数学公式的通道数值映射。

4.2.1 核心原理

颜色空间转换的本质是 通道数值的数学变换:通过预设公式将原颜色空间的通道值(如 RGB 的 R、G、B)转换为目标空间的通道值(如 HSV 的 H、S、V)。
OpenCV 支持很多种转换(通过ColorConversionCodes枚举指定),以下是常用类型及效果:

转换类型 适用场景 效果特点 COLOR_BGR2RGB 图像显示(OpenCV 默认 BGR 存储) 交换 R 和 B 通道,解决 OpenCV 与其他库(如 Qt)的显示颜色偏差。 COLOR_BGR2GRAY 预处理(减少计算量) 转为单通道灰度图,保留亮度信息,消除颜色干扰。 COLOR_BGR2HSV 颜色分割(如目标检测) H 通道单独表示颜色,可通过阈值快速提取特定颜色(如红色物体)。 COLOR_BGR2YCrCb 肤色检测 Y 通道为亮度,Cr、Cb 通道对肤色敏感,适合提取人脸区域。 COLOR_BGR2Lab 光照不变性场景 Lab 空间对光照变化不敏感,适合光照不均时的颜色分析。
4.2.2 常见颜色转换示例:
#include #include using namespace cv;using namespace std;int main() { // 1. 读取图像(OpenCV默认以BGR格式加载) Mat bgr_img = imread(\"test.jpg\"); if (bgr_img.empty()) { cout << \"无法读取图像!\" << endl; return -1; } // 2. 定义目标图像 Mat rgb_img, gray_img, hsv_img, ycrcb_img; // 3. 颜色空间转换(核心函数:cvtColor) cvtColor(bgr_img, rgb_img, COLOR_BGR2RGB); // BGR→RGB(用于正确显示) cvtColor(bgr_img, gray_img, COLOR_BGR2GRAY); // BGR→灰度 cvtColor(bgr_img, hsv_img, COLOR_BGR2HSV); // BGR→HSV cvtColor(bgr_img, ycrcb_img, COLOR_BGR2YCrCb); // BGR→YCrCb // 4. 显示结果 imshow(\"原图(BGR)\", bgr_img); imshow(\"RGB(用于显示校正)\", rgb_img); imshow(\"灰度图(减少干扰)\", gray_img); imshow(\"HSV(颜色分割友好)\", hsv_img); imshow(\"YCrCb(肤色检测)\", ycrcb_img); // 5. 保存结果 imwrite(\"hsv_result.jpg\", hsv_img); imwrite(\"gray_result.jpg\", gray_img); // 等待按键退出 waitKey(0); destroyAllWindows(); return 0;}

4.3 图像滤波与增强

4.3.1 图像滤波

图像滤波与增强是计算机视觉中,用于改善图像质量、突出特征或抑制噪声。OpenCV 提供了丰富的滤波与增强函数,核心是通过卷积操作或像素值映射实现。滤波是通过 卷积核(Kernel) 对图像进行邻域操作的过程。

  • 线性滤波:输出像素是邻域像素的加权和(如均值滤波、高斯滤波)。
  • 非线性滤波:输出像素由邻域像素的排序或统计值决定(如中值滤波、双边滤波)。

数学表达:输出像素值 = 卷积核 × 邻域像素矩阵(逐元素相乘后求和)。

常见滤波方法及效果

滤波类型 原理 效果与应用场景 均值滤波 用邻域平均值替代中心像素 模糊图像、降噪,但会丢失细节 高斯滤波 用高斯函数加权邻域像素 平滑图像,保留更多细节,常用于预处理 中值滤波 用邻域像素的中值替代中心像素 有效去除椒盐噪声,保留边缘 双边滤波 同时考虑空间距离和像素值差异 平滑图像的同时保留边缘,适合美颜等场景
4.3.2 图像增强原理

增强是通过像素值映射函数调整图像对比度或亮度:

  • 线性增强:直接缩放像素值范围(如直方图均衡化)。
  • 非线性增强:通过对数、指数等函数调整(如伽马校正)。
增强类型 原理 效果与场景 直方图均衡化 拉伸像素值分布,使直方图更均匀 增强整体对比度,适合低对比度图像 伽马校正 通过幂函数调整亮度(γ>1 变暗,γ<1 变亮) 局部细节增强,适合调整过曝或过暗图像

代码示例

#include #include using namespace cv;using namespace std;int main() { // 1. 读取图像(可替换为带噪声的图像) Mat src = imread(\"test.jpg\", IMREAD_COLOR); if (src.empty()) { cout << \"无法读取图像!\" << endl; return -1; } // 2. 定义输出图像 Mat blur_img, gaussian_img, median_img, bilateral_img; Mat equalized_img, gamma_corrected_img; // 3. 图像滤波 blur(src, blur_img, Size(5, 5));  // 均值滤波(5×5核) GaussianBlur(src, gaussian_img, Size(5, 5), 0); // 高斯滤波 medianBlur(src, median_img, 5);  // 中值滤波(核大小必须为奇数) bilateralFilter(src, bilateral_img, 9, 75, 75); // 双边滤波 // 4. 图像增强 // 4.1 直方图均衡化(需先转为灰度图) Mat gray, equalized_gray; cvtColor(src, gray, COLOR_BGR2GRAY); equalizeHist(gray, equalized_gray); cvtColor(equalized_gray, equalized_img, COLOR_GRAY2BGR); // 4.2 伽马校正 Mat src_f; src.convertTo(src_f, CV_32F, 1.0/255.0); // 归一化到[0,1] pow(src_f, 0.5, gamma_corrected_img); // γ=0.5(变亮) gamma_corrected_img.convertTo(gamma_corrected_img, CV_8U, 255.0); // 5. 显示结果 imshow(\"原图\", src); imshow(\"均值滤波\", blur_img); imshow(\"高斯滤波\", gaussian_img); imshow(\"中值滤波\", median_img); imshow(\"双边滤波\", bilateral_img); imshow(\"直方图均衡化\", equalized_img); imshow(\"伽马校正(γ=0.5)\", gamma_corrected_img); // 6. 保存结果 imwrite(\"gaussian_result.jpg\", gaussian_img); imwrite(\"equalized_result.jpg\", equalized_img); waitKey(0); return 0;}

4.4 边缘检测

边缘检测是计算机视觉中,用于识别图像中亮度突变的区域(即边缘),广泛应用于目标分割、特征提取和场景理解。OpenCV 提供了多种边缘检测算法,核心是基于一阶或二阶导数计算像素值的变化率。
图像边缘在对应像素值的梯度突变,数学上通过卷积核计算一阶导数(如 Sobel、Prewitt 算子)或二阶导数(如 Laplacian 算子)来检测这种变化。

4.4.1 常见边缘检测算法对比:
算法 原理 效果 适用场景 Sobel 一阶导数算子 计算水平和垂直梯度 边缘较粗,定位精度中等快速检测、预处理 Canny 多阶段优化(非极大值抑制 + 双阈值) 边缘细、定位准、假边缘少 高精度场景(如工业检测) Laplacian 二阶导数算子,检测梯度的零交叉点 对边缘方向不敏感,可能产生双边缘 简单场景、快速原型 Prewitt 类似 Sobel,但权重均匀 计算简单,对噪声敏感 教学或低计算资源场景
4.4.2 代码示例
#include #include using namespace cv;using namespace std;int main() { // 1. 读取图像并转为灰度图 Mat src = imread(\"test.jpg\", IMREAD_COLOR); if (src.empty()) { cout << \"无法读取图像!\" << endl; return -1; } Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); // 2. 高斯平滑(减少噪声) Mat blurred; GaussianBlur(gray, blurred, Size(3, 3), 0); // 3. 定义输出图像 Mat sobelx, sobely, sobel_edges; Mat laplacian_edges; Mat canny_edges; Mat prewitt_edges; // 4. Sobel边缘检测 Sobel(blurred, sobelx, CV_64F, 1, 0, 3); // x方向梯度 Sobel(blurred, sobely, CV_64F, 0, 1, 3); // y方向梯度 convertScaleAbs(sobelx, sobelx);  // 转换为8位无符号整数 convertScaleAbs(sobely, sobely); addWeighted(sobelx, 0.5, sobely, 0.5, 0, sobel_edges); // 合并梯度 // 5. Laplacian边缘检测 Laplacian(blurred, laplacian_edges, CV_8U, 3); // 6. Canny边缘检测(关键参数:阈值1和阈值2) Canny(blurred, canny_edges, 50, 150); // 7. Prewitt边缘检测(手动实现) Mat prewitt_x = (Mat_<int>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1); Mat prewitt_y = (Mat_<int>(3, 3) << -1, -1, -1, 0, 0, 0, 1, 1, 1); Mat grad_x, grad_y; filter2D(blurred, grad_x, CV_16S, prewitt_x); filter2D(blurred, grad_y, CV_16S, prewitt_y); convertScaleAbs(grad_x, grad_x); convertScaleAbs(grad_y, grad_y); addWeighted(grad_x, 0.5, grad_y, 0.5, 0, prewitt_edges); // 8. 显示结果 imshow(\"原图\", src); imshow(\"Sobel边缘\", sobel_edges); imshow(\"Laplacian边缘\", laplacian_edges); imshow(\"Canny边缘\", canny_edges); imshow(\"Prewitt边缘\", prewitt_edges); // 9. 保存结果 imwrite(\"canny_result.jpg\", canny_edges); waitKey(0); return 0;}

4.5 腐蚀与膨胀

腐蚀(Erosion)与膨胀(Dilation)是形态学图像处理的操作中,用于改变图像中物体的形状和大小。它们通过 结构元素(Structuring Element)对图像进行逐像素扫描,实现对前景物体的收缩或扩张。腐蚀和膨胀本质上是对图像中 “前景像素(通常为白色)” 的操作。

4.5.1 腐蚀(Erosion)

原理:结构元素在图像上滑动,若结构元素完全包含于前景区域,则保留中心像素,否则删除。
效果:前景物体收缩,孔洞扩大,细小连接被断开。

4.5.2 膨胀(Dilation)

原理:结构元素在图像上滑动,若结构元素与前景区域有交集,则中心像素被设为前景。
效果:前景物体扩张,孔洞缩小,断裂部分被连接。

4.5.3 应用对比
操作 典型应用 腐蚀 去除小噪声点;分离相连物体;细化轮廓; 膨胀 连接断裂部分;增强轮廓
4.5.4 代码示例:
#include #include using namespace cv;using namespace std;int main() { // 1. 读取图像并转为二值图(简化演示) Mat src = imread(\"test.jpg\", IMREAD_GRAYSCALE); if (src.empty()) { cout << \"无法读取图像!\" << endl; return -1; } // 二值化处理(阈值操作) Mat binary; threshold(src, binary, 127, 255, THRESH_BINARY); // 2. 定义结构元素(可使用矩形、椭圆或十字形) Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5)); // 3. 腐蚀和膨胀操作 Mat eroded, dilated; erode(binary, eroded, kernel); // 腐蚀 dilate(binary, dilated, kernel); // 膨胀 // 4. 高级形态学操作(开运算和闭运算) Mat opened, closed; morphologyEx(binary, opened, MORPH_OPEN, kernel); // 开运算 = 腐蚀+膨胀 morphologyEx(binary, closed, MORPH_CLOSE, kernel); // 闭运算 = 膨胀+腐蚀 // 5. 显示结果 imshow(\"原图\", src); imshow(\"二值图\", binary); imshow(\"腐蚀\", eroded); imshow(\"膨胀\", dilated); imshow(\"开运算\", opened); imshow(\"闭运算\", closed); // 6. 保存结果 imwrite(\"eroded.jpg\", eroded); imwrite(\"dilated.jpg\", dilated); waitKey(0); return 0;}