OpenCV入门学习-图像处理(一)
环境:
- win11 x64
- OpenCV 4.9.0
- VS 2022 (v143)
- C++ (ISO C++ 14 标准)
1. 绘图基础
本文介绍如何使用OpenCV进行基础图 形绘制,包括直线、椭圆、矩形、圆形和填充多边形的实现方法。所有代码均使用C++语法,并明确标注命名空间。
1.1. 核心数据结构
1.1.1. cv::Point
表示二维坐标系中的点,可通过以下两种方式定义:
1 | cv::Point pt1; |
1.1.2. cv::Scalar
表示四维向量,常用于表示 BGR 颜色值(仅使用前三个参数):
1 | cv::Scalar(blue, green, red); // BGR 颜色模型示例 |
1.2. 基础绘图函数实现
1.2.1. 创建画布
初始化 400x400 的黑色背景图像:
1 | cv::Mat atom_image = cv::Mat::zeros(w, w, CV_8UC3); // 原子结构画布 |
1.2.2. 绘制直线
通过 cv::line
实现直线绘制:
1 | void MyLine(cv::Mat img, cv::Point start, cv::Point end) { |
1.2.3. 绘制椭圆
使用 cv::ellipse
绘制旋转椭圆:
1 | void MyEllipse(cv::Mat img, double angle) { |
1.2.4. 绘制实心圆
通过 cv::circle
实现填充圆形:
1 | void MyFilledCircle(cv::Mat img, cv::Point center) { |
1.2.5. 绘制多边形
使用 cv::fillPoly
绘制自定义多边形:
1 | void MyPolygon(cv::Mat img) { |
1.2.6. 绘制矩形
直接调用 cv::rectangle
函数:
1 | cv::rectangle(rook_image, |
1.2.7. 添加文本
文字标注需指定字体类型和左下角起点:
1 | cv::putText(img, |
- 字体优化:
cv::LINE_AA
抗锯齿模式可提升文字显示质量
1.2.8. 仿射变换
数学描述 cv::getAffineTransform
和
cv::warpAffine
可实现图像的平移、旋转等操作
1.3. 示例代码
1 | #include <opencv2/core.hpp> |
运行代码将生成两个窗口:

2. 随机数生成与文本绘制
将通过OpenCV的随机数生成器 cv::RNG
和文本绘制功能,演示如何动态生成随机几何图形与文字效果
2.1. 随机数生成器
OpenCV提供 cv::RNG
类生成伪随机数。初始化时需指定种子值,例如:
1 | cv::RNG rng(0xFFFFFFFF); // 使用十六进制种子初始化 |
通过 uniform(a, b)
方法生成区间
1 | int random_value = rng.uniform(0, 100); // 随机数范围 [0, 100) |
若需要浮点数,可显式指定类型:
1 | double random_float = rng.uniform(0.0, 1.0); // 生成 0.0 到 1.0 之间的浮点数 |
2.2. 绘制随机几何图形
以下示例演示如何生成随机线条:
1 | int Drawing_Random_Lines(cv::Mat image, const std::string& window_name, cv::RNG rng) { |
类似方法可扩展至其他图形(矩形、椭圆、多边形等),只需调整参数生成逻辑。
2.3. 动态文本绘制
使用 cv::putText
在图像上添加随机文字:
1 | int Displaying_Random_Text(cv::Mat image, const std::string& window_name, cv::RNG rng) { |
2.4. 动态渐变文字效果
以下代码实现文字颜色渐变与图像亮度变化的动画效果:
1 | int Displaying_Big_End(cv::Mat image, const std::string& window_name) { |
2.5. 示例代码
1 | #include <iostream> |
3. 图像平滑
3.1. 目标
使用 OpenCV
实现图像平滑处理,涵盖四种常用线性滤波器:均值滤波、高斯滤波、中值滤波和双边滤波。掌握
cv::blur()
、 cv::GaussianBlur()
、
cv::medianBlur()
和 cv::bilateralFilter()
等函数的使用方法。
3.2. 理论基础
3.2.1. 均值滤波(Normalized Box Filter)
公式:
参数说明:
和 :
表示滤波核的宽度和高度。通常选取奇数(如 3×3、5×5 等),以便确定一个明确的中心像素。归一化因子
:
保证滤波核内所有元素的权重之和为 1,从而在平滑图像时不改变整体亮度。
作用:
- 均值滤波通过计算邻域内所有像素值的平均值来减少图像噪声,具有简单高效的特点。
- 但由于对所有邻域像素赋予相同的权重,它在平滑的同时可能会使边缘和细节变得模糊。
3.2.2. 高斯滤波(Gaussian Filter)
公式:
参数说明:
:
归一化常数,用于确保整个滤波核的所有权重之和为1。 和 :
分别为高斯函数在 和 方向的均值。通常选取核的中心点,即 (若坐标以核中心为原点),或者直接设置为核的中心像素坐标。 和 :
分别为高斯函数在 和 方向的标准差,决定了权重分布的宽度。- 较大的
值使得核内权重分布更加平缓,平滑效果更强;
- 较小的
值使得权重更多集中在中心像素附近,从而在平滑的同时更好地保留局部细节。
- 当要求各向同性平滑时,可以令
。
- 较大的
作用:
- 高斯滤波器能较好地平滑图像,同时在一定程度上保留边缘信息,相比于简单的均值滤波,它更能适应图像的局部特性。
- 由于权重随距离呈指数衰减,高斯滤波在邻域中心像素附近具有更高的权重,减少了远处像素对结果的影响。
3.2.3. 中值滤波(Median Filter)
公式:
其中,
参数说明:
- 窗口大小:
定义了计算中值时考虑的邻域范围。窗口越大,能够去除的噪声范围就越广,但也可能导致细节损失;窗口较小则保留更多细节,但可能对较大范围的噪声不够鲁棒。
作用:
- 中值滤波特别适用于去除“椒盐噪声”,因为中值运算能有效抑制孤立的异常值(极大或极小的噪声像素),而不受这些异常值的极端影响。
- 与均值滤波不同,中值滤波不会产生模糊边缘的现象,能够较好地保留边缘和细节信息。
3.2.4. 双边滤波(Bilateral Filter)
公式:
参数说明:
:
空间权重,通常采用高斯函数定义,用于衡量当前像素与邻域像素之间的空间距离影响。- 一般形式为:
- 其中,
决定了空间距离的衰减速度,较大的 意味着更广的空间范围内的像素会有较高的权重。
- 一般形式为:
:
颜色(或灰度)权重,用于衡量中心像素与邻域像素在像素值(颜色或亮度)上的相似程度。- 常用形式为:
- 参数
(也称为 )控制了对像素值差异的敏感程度。较小的 会使得仅有非常相近像素值的邻域才被赋予较大权重,从而有效保护边缘信息。
- 常用形式为:
- 窗口大小:
决定了在空间上参与滤波的邻域范围。通常与 相匹配,确保窗口足够大以包含主要的贡献区域。
作用:
- 双边滤波在平滑图像噪声的同时,通过结合空间和颜色信息,有效避免了跨边缘的像素混合,从而更好地保留图像的边缘和细节。
- 适用于需要在降噪的同时保持清晰边缘的图像处理场景,如人像美化和细节增强。
参数说明:
src
:输入图像dst
:输出图像Size(w, h)
:核大小(需为奇数)Point(-1, -1)
:锚点位置(默认中心)
3.3. 代码实现
3.3.1. 均值滤波示例
1 | Mat src = imread("lena.jpg", cv::IMREAD_COLOR); |
参数说明:
src
:输入图像dst
:输出图像Size(w, h)
:核大小(需为奇数)Point(-1, -1)
:锚点位置(默认中心)
3.3.2. 高斯滤波示例
1 | cv::GaussianBlur(src, dst, Size(5, 5), 0, 0); |
参数 0
表示自动计算标准差。
3.3.3. 中值滤波示例
1 | cv::medianBlur(src, dst, 5); |
核大小必须为奇数。
3.3.4. 双边滤波示例
1 | cv::bilateralFilter(src, dst, 9, 75, 75); |
参数说明:
9
:邻域直径75
:颜色空间和坐标空间的标准差
3.4. 示例代码
通过循环逐步增大核尺寸,可观察不同滤波器的平滑效果:
1 | #include <iostream> |
3.5. 总结
- 均值滤波:简单易实现,但容易模糊边缘。适用于噪声较低且对边缘要求不高的场景。
- 高斯滤波:通过空间加权实现更自然的平滑效果,对细节保留较好。常用于预处理步骤中去除高频噪声。
- 中值滤波:特别适合去除椒盐噪声,因其中值运算对异常值不敏感,能较好地保护边缘信息。
- 双边滤波:结合空间和像素值信息,在降噪的同时能较好地保留边缘,适用于高质量图像处理。
实际应用中需根据噪声类型和图像特点选择合适的滤波方法。通过调整核大小和参数,可灵活平衡平滑效果与细节保留。
4. 形态学操作 (morphological operation)
4.1. 腐蚀与膨胀 (erosion and dilation)
形态学操作通过
结构元素(Kernel)对图像进行形状处理,常用于去噪、分离或连接图像元素。
形态学中两种基础操作——腐蚀 (Erosion) 与 膨胀
(Dilation)。
- 腐蚀:缩小图像中的亮区域,扩大暗区域。
- 膨胀:扩大图像中的亮区域,缩小暗区域。
数学表达式如下:
- 膨胀:
- 腐蚀:
膨胀和腐蚀和神经网络中的池化操作在操作上有相似之处。
4.1.1. 示例代码
OpenCV提供cv::erode
和cv::dilate
函数实现腐蚀与膨胀。以下代码演示如何通过滑动条动态调整结构元素类型和大小:
1 | #include <iostream> |
相关函数解释
1. cv::getStructuringElement
功能:生成指定形状和大小的结构元素(Kernel),用于形态学操作。
函数原型:
1 | cv::Mat cv::getStructuringElement(int shape, cv::Size ksize, cv::Point anchor = cv::Point(-1,-1)); |
参数说明:
shape
:结构元素的形状,可选值:cv::MORPH_RECT
:矩形
cv::MORPH_CROSS
:十字形
cv::MORPH_ELLIPSE
:椭圆形
ksize
:结构元素的大小,通常为奇数(如Size(3, 3)
)。
anchor
:锚点位置,默认为中心点(-1, -1)
。
示例:
1 | cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5)); |
2. cv::erode
功能:对图像进行腐蚀操作,缩小亮区域,扩大暗区域。
函数原型:
1 | void cv::erode(cv::InputArray src, cv::OutputArray dst, cv::InputArray kernel, |
参数说明:
src
:输入图像。
dst
:输出图像。
kernel
:结构元素,可通过cv::getStructuringElement
生成。
anchor
:锚点位置,默认为中心点。
iterations
:腐蚀操作的迭代次数。
borderType
:边界填充类型。
borderValue
:边界填充值。
示例:
1 | cv::Mat eroded; |
3. cv::dilate
功能:对图像进行膨胀操作,扩大亮区域,缩小暗区域。
函数原型:
1 | void cv::dilate(cv::InputArray src, cv::OutputArray dst, cv::InputArray kernel, |
参数说明:
- 参数与
cv::erode
相同。
示例:
1 | cv::Mat dilated; |
4. 总结
cv::getStructuringElement
:生成结构元素,决定腐蚀或膨胀的形状和大小。
cv::erode
:腐蚀操作,缩小亮区域。
cv::dilate
:膨胀操作,扩大亮区域。
通过组合这些函数,可以实现图像去噪、边缘检测等形态学操作。
4.2. 高级形态学操作
4.2.1. 开运算 (Opening)
- 定义:先对图像进行腐蚀,再进行膨胀。
- 公式:
- 用途:用于消除图像中较小的亮区域(噪点),同时保留目标的整体形状。
4.2.2. 闭运算 (Closing)
- 定义:先对图像进行膨胀,再进行腐蚀。
- 公式:
- 用途:可填补目标区域内部的小孔洞或暗区域,使整体形态更完整。
4.2.3. 形态学梯度 (Morphological Gradient)
- 定义:计算膨胀图像与腐蚀图像之间的差值。
- 公式:
- 用途:突出显示图像中物体的边缘信息,有助于轮廓提取。
4.2.4. 顶帽 (Top Hat)
- 定义:原始图像与其开运算结果之间的差值。
- 公式:
- 用途:用于提取图像中比周围背景亮的小区域或细节特征。
4.2.5. 黑帽 (Black Hat)
- 定义:闭运算结果与原始图像之间的差值。
- 公式:
- 用途:可检测出图像中比背景暗的小区域或细微结构。
4.2.6. 击中-不击中 (Hit-or-Miss)
定义:用于在二值图像(
CV_8UC1
)中定位特定像素模式。其核心是通过两个结构元素(Structuring Elements)分别匹配前景和背景的邻域特征,最终通过逻辑与运算确定目标位置。
公式:
其中:
: 腐蚀操作 :定义前景像素必须匹配的模式
:定义背景像素必须匹配的模式
:输入图像 的补集
操作步骤:
- 使用
对原图 进行腐蚀操作
- 使用
对补集 进行腐蚀操作
- 将两次腐蚀结果进行逻辑与(AND)
- 使用
用途
- 形状检测:查找符合特定结构的图案,例如角点、交叉点、细线等。
- 模式匹配:用于特定形状目标的存在性检测。
- 噪声去除:过滤掉与目标形状不匹配的部分,仅保留符合模板的结构。
4.2.7. 形态学操作对比总结
操作名称 | 计算方式 | 主要作用 |
---|---|---|
开运算(Opening) | 先腐蚀再膨胀 | 去除小亮噪点 |
闭运算(Closing) | 先膨胀再腐蚀 | 填充暗区域小孔洞 |
梯度(Gradient) | 膨胀 - 腐蚀 | 提取物体边缘 |
顶帽(Top Hat) | 原图 - 开运算 | 亮细节增强 |
黑帽(Black Hat) | 闭运算 - 原图 | 暗细节增强 |
击中-不击中(Hit-or-Miss) | 形态学模式匹配 | 目标形状检测 |
4.2.8. 示例代码
4.2.8.1. 开运算、闭运算、梯度、顶帽、黑帽
下面的 C++ 示例代码演示了如何利用 OpenCV 实现上述形态学操作:
1 | #include <iostream> |
4.2.8.2. hit-miss
1 | #include <opencv2/opencv.hpp> |
5. 形态学操作提取水平与垂直线条
在图像处理中,形态学操作是提取特定形状的重要工具。
这里通过从乐谱图像中分离水平线(五线谱)和垂直线(音符符干)并优化边缘效果的例子,对 OpenCV 形态学操作中的膨胀、腐蚀、结构元素等进一步深入了解。
5.1. 代码示例
1 | #include <opencv2/core.hpp> |
结果:

结果分析
- 水平线提取:五线谱的横线被完整保留,音符等小物体被移除;
- 垂直线提取:音符符干和乐谱小节线被分离,经优化后边缘更平滑;
- 应用场景:此方法可用于乐谱数字化、表格检测等需要分离规则结构的任务。
5.2. 相关补充
5.2.1.
cv::adaptiveThreshold
函数原型:
1 | void cv::adaptiveThreshold( |
参数解释
- src:输入图像,要求是灰度图(8位单通道)。
- dst:输出图像,二值化后的图像,大小和输入图像相同。
- maxValue:当像素满足阈值条件时赋予的值,通常设置为255。
- adaptiveMethod:
ADAPTIVE_THRESH_MEAN_C
:使用邻域内像素的均值作为阈值。ADAPTIVE_THRESH_GAUSSIAN_C
:使用邻域内像素的高斯加权和作为阈值,这样会使得靠近中心的像素权重更大。
- thresholdType:
THRESH_BINARY
:如果像素值大于局部阈值则赋值为maxValue
,否则赋值为0。THRESH_BINARY_INV
:与 THRESH_BINARY 相反,即小于局部阈值赋值为maxValue
,大于则赋值为0。
- blockSize:定义计算局部阈值时所考虑的邻域区域的尺寸(宽度和高度相同),必须为奇数(例如3、5、7...)。
- C:一个常数,会从计算出的局部阈值中减去,用于调整阈值的效果。正值会使阈值更低,负值则相反。
5.2.2. cv::Mat::copyTo
在 OpenCV 中,cv::Mat::copyTo
有多个重载版本,其中一个带有掩码(mask)的版本,其函数原型如下:
1 | void cv::Mat::copyTo(OutputArray dst, InputArray mask) const; |
- 参数:
- OutputArray dst:目标矩阵,用来存放复制后的结果。
- InputArray mask:掩码矩阵,通常是一个 8 位单通道(CV_8UC1)的图像。掩码中非零值的位置表示对应源图像中的像素会被复制到目标图像中;零值位置则不会发生复制操作。
6. 图像金字塔
图像金字塔是计算机视觉中用于多尺度分析的重要工具,其核心思想是通过 下采样 与 上采样 生成不同分辨率的图像序列。OpenCV提供了高斯金字塔(Gaussian Pyramid)和拉普拉斯金字塔(Laplacian Pyramid)两种实现方式。
6.1. 高斯金字塔
下采样(Downsampling)
i. 对图像进行高斯卷积核滤波,核矩阵为:
ii. 去除偶数行和偶数列,得到尺寸为原图1/4的新图像。
iii. 重复上述步骤生成金字塔各层。
上采样(Upsampling)
i. 将图像尺寸扩大两倍,新增行列填充零。
ii. 使用相同的高斯核(乘以4)进行卷积,近似补全缺失像素值。
6.1.1. 示例代码
1 | #include <iostream> |
效果
- 下采样示例:对 512×512 图像连续两次下采样,得到
128×128 图像,细节信息逐步丢失。
- 上采样示例:对下采样后的图像上采样,分辨率恢复但清晰度下降,体现金字塔重建的局限性。
6.2. 拉普拉斯金字塔
拉普拉斯金字塔(Laplacian Pyramid)是高斯金字塔的补充,用于保存图像在不同尺度下的细节信息,从而实现高精度的图像重建。其核心思想是:通过高斯金字塔的下采样与上采样过程,计算相邻层之间的差异,从而捕捉高频细节。
6.2.1. 与高斯金字塔的对应关系
- 生成方式
- 高斯金字塔:通过逐层下采样生成低分辨率图像序列。
- 拉普拉斯金字塔:通过以下步骤生成:
- 对高斯金字塔的某一层
进行上采样(使用cv::pyrUp
),得到近似的高分辨率图像 。
- 计算高斯金字塔原层
与上采样后的近似层 的差值: 即为拉普拉斯金字塔的当前层,保存了下采样过程中丢失的高频细节。
- 对高斯金字塔的某一层
- 高斯金字塔:通过逐层下采样生成低分辨率图像序列。
- 数学意义
- 拉普拉斯金字塔的每一层
记录了高斯金字塔相邻层之间的残差信息。
- 通过拉普拉斯金字塔,可以从最低分辨率的高斯层
逐步向上恢复原始图像: . - 这一特性在图像融合、压缩和超分辨率重建中至关重要。
- 拉普拉斯金字塔的每一层
图中拉普拉斯金字塔中的图像实际上对比度很低,所以这里通过 Gamma 校正 使得对比度提高了一些,看的时候方便一些。
6.2.2. 示例代码
以下代码展示了上图的产生过程:
1 | #include <opencv2/opencv.hpp> |
高斯下采样:使用 cv::pyrDown
对原始图像下采样,得到低分辨率的高斯层。
高斯上采样:对下采样后的高斯层使用
cv::pyrUp
上采样至原图尺寸。
残差计算:将上采样后的图像与原图相减,得到拉普拉斯金字塔层。
结果分析:拉普拉斯层中亮区域表示高频细节(如边缘、纹理),暗区域表示低频信息已被高斯金字塔保留。
6.2.3. 应用场景
- 图像融合
- 在融合不同曝光的图像时,拉普拉斯金字塔可分别保留各层细节,融合后重建出高质量图像。
- 例如:将两张图像的拉普拉斯金字塔逐层融合,再通过逆过程重建结果。
- 在融合不同曝光的图像时,拉普拉斯金字塔可分别保留各层细节,融合后重建出高质量图像。
- 图像压缩
- 存储拉普拉斯金字塔的残差信息(稀疏矩阵)比直接存储原图更高效。
- 结合量化技术,可实现高压缩率且保留关键细节。
- 存储拉普拉斯金字塔的残差信息(稀疏矩阵)比直接存储原图更高效。
- 图像增强
- 通过增强拉普拉斯层的高频分量(如边缘锐化),再重建图像以提升清晰度。
6.3. 总结
拉普拉斯金字塔与高斯金字塔共同构成了多尺度图像分析的基础。前者通过残差捕捉细节,后者通过下采样简化结构。在
OpenCV 中,虽然未直接提供拉普拉斯金字塔的函数,但通过组合
cv::pyrUp
、cv::pyrDown
和矩阵运算即可实现其功能。理解二者的协同作用,将为图像处理任务(如超分辨率、图像融合)提供重要的技术支撑。
7. 基本阈值操作
7.1. 阈值处理基础
阈值处理是图像分割中最简单的方法之一,其核心思想是通过比较像素强度与阈值来区分目标区域与背景。OpenCV
提供的 cv::threshold
s函数支持五种阈值操作类型,可将图像转换为二值化或特定处理后的形式。
7.2. 基本阈值操作类型
7.2.1. 二值化阈值(Binary Threshold)
7.2.2. 反向二值化阈值(Binary Inverted)
7.2.3. 截断阈值(Truncate)
7.2.4. 零阈值(Threshold to Zero)
7.2.5. 反向零阈值(Threshold to Zero Inverted)
7.3. 代码实现与解析
以下是一个完整的阈值处理示例代码,支持通过滑动条动态调整参数:
1 | #include "opencv2/highgui.hpp" |
7.4. 总结
阈值处理是OpenCV中基础的图像分割技术,适用于目标检测、背景分离等场景。通过灵活选择阈值类型和参数,开发者可以快速实现不同需求的分割效果。
8. HSV 通道的阈值操作
8.1. 理论基础
与传统的cv::threshold
函数不同,cv::inRange
允许通过设定像素值的上下限范围来提取目标区域。HSV(Hue,
Saturation,
Value)颜色空间因其色相(Hue)通道能独立表示颜色类型,常用于基于颜色的图像分割任务:
- Hue(色相):表示颜色类型,范围为0-180(OpenCV中常将0-360度映射到此范围)。
- Saturation(饱和度):从灰度(低饱和度)到纯色(高饱和度)。
- Value(明度):表示颜色亮度。
颜色空间转换公式(RGB 到 HSV)可通过 cv::cvtColor
实现,具体计算遵循标准转换规则:
8.2. 代码实现
以下示例演示如何通过实时视频流进行阈值分割:
1 | #include "opencv2/highgui.hpp" |
8.2.1. 1. 低H(Low H)
- 作用:设置 色相(Hue) 的 最低阈值。
- 范围:0-180(OpenCV中Hue范围为0-180,而非0-360)。
- 功能:
通过滑动条调整,选择目标颜色的起始色相值。例如,若要检测红色(Hue约0-10或160-180),可将Low H
设为0或160。
8.2.2. 2. 高H(High H)
- 作用:设置 色相(Hue) 的 最高阈值。
- 范围:0-180。
- 功能:
定义目标颜色的终止色相值。例如,检测红色时,若Low H=160
,则High H=180
可覆盖红色的色相范围。
8.2.3. 3. 低S(Low S)
- 作用:设置 饱和度(Saturation) 的 最低阈值。
- 范围:0-255。
- 功能:
饱和度表示颜色的纯度。低饱和度接近灰色,高饱和度接近纯色。
通过提高Low S
,可过滤掉灰度区域(如阴影或白色背景)。
8.2.4. 4. 高S(High S)
- 作用:设置 饱和度(Saturation) 的 最高阈值。
- 范围:0-255。
- 功能:
限制颜色的最大饱和度。通常保持High S=255
,表示允许所有高饱和度颜色参与检测。
8.2.5. 5. 低V(Low V)
- 作用:设置 明度(Value) 的 最低阈值。
- 范围:0-255。
- 功能:
明度表示颜色亮度。通过调整Low V
,可过滤掉过暗区域。例如,Low V=50
会排除亮度低于50的像素。
8.2.6. 6. 高V(High V)
- 作用:设置 明度(Value) 的 最高阈值。
- 范围:0-255。
- 功能:
限制颜色的最大亮度。通常保持High V=255
,允许所有亮度区域参与检测。
8.3. 运行结果
程序运行后,两个窗口分别显示原始视频和阈值处理后的二值图像。通过调节滑动条可实时观察不同阈值范围对检测效果的影响,适用于动态环境下的颜色目标跟踪。
9. 参考资料
[1] OpenCV 官方文档