OpenCV 基本阈值操作详解
目标
在本教程中,您将学习如何使用 OpenCV 函数执行基本的阈值操作。阈值处理是图像分割中最基础且重要的技术之一,广泛应用于文档扫描、字符识别、物体检测等场景。
OpenCV 中的基本阈值操作,包括阈值二值化、反转、截断、归零等五种类型及其数学公式。通过 C++ 代码示例演示了如何使用 cv::threshold 函数配合滑动条实时调整阈值参数。文章还涵盖了图像预处理、噪声处理、Otsu 自动阈值法以及实际应用中的注意事项,旨在帮助开发者掌握图像分割的基础技术。

在本教程中,您将学习如何使用 OpenCV 函数执行基本的阈值操作。阈值处理是图像分割中最基础且重要的技术之一,广泛应用于文档扫描、字符识别、物体检测等场景。
阈值(Thresholding)是最简单的图像分割方法。其核心思想是将图像中的像素根据强度值与设定的阈值进行比较,从而将感兴趣的区域与背景分离开来。这种分离通常基于对象像素和背景像素之间的灰度差异。
为了区分我们感兴趣的像素与其他像素,我们对每个像素的强度值与一个确定的阈值(thresh)进行比较。一旦确定了哪些像素属于感兴趣区域,就可以将它们设置为特定的值(如 0 表示黑色,255 表示白色),以便后续处理。
OpenCV 提供了 cv::threshold 函数来执行多种类型的阈值操作。主要包含以下五种类型:
如果源像素值大于阈值,则将其设置为最大值(通常为 255),否则设置为 0。
公式: $$\text{dst}(x, y) = \begin{cases} \text{maxVal} & \text{if } \text{src}(x, y) > \text{thresh} \ 0 & \text{otherwise} \end{cases}$$
应用场景:适用于前景比背景亮的情况,例如黑底白字的文档扫描。
如果源像素值大于阈值,则将其设置为 0,否则设置为最大值。
公式: $$\text{dst}(x, y) = \begin{cases} 0 & \text{if } \text{src}(x, y) > \text{thresh} \ \text{maxVal} & \text{otherwise} \end{cases}$$
应用场景:适用于前景比背景暗的情况,例如白底黑字的文本提取。
如果源像素值大于阈值,则将其值限制为阈值;否则保持不变。
公式: $$\text{dst}(x, y) = \begin{cases} \text{thresh} & \text{if } \text{src}(x, y) > \text{thresh} \ \text{src}(x, y) & \text{otherwise} \end{cases}$$
应用场景:用于平滑图像或去除过亮的噪声点,保留原始灰度信息但不超过特定亮度。
如果源像素值大于阈值,则保持原值;否则设置为 0。
公式: $$\text{dst}(x, y) = \begin{cases} \text{src}(x, y) & \text{if } \text{src}(x, y) > \text{thresh} \ 0 & \text{otherwise} \end{cases}$$
应用场景:用于提取图像中较亮的部分,抑制暗部噪声。
如果源像素值大于阈值,则设置为 0;否则保持原值。
公式: $$\text{dst}(x, y) = \begin{cases} 0 & \text{if } \text{src}(x, y) > \text{thresh} \ \text{src}(x, y) & \text{otherwise} \end{cases}$$
应用场景:用于提取图像中较暗的部分,抑制亮部干扰。
以下是一个完整的 C++ 示例程序,展示了如何加载图像、转换为灰度图,并使用滑动条实时调整阈值类型和阈值大小。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int threshold_value = 0;
int threshold_type = 3;
const int max_value = 255;
const int max_type = 4;
const int max_binary_value = 255;
Mat src, src_gray, dst;
const char* window_name = "阈值演示";
const char* trackbar_type = "类型:\n0: 二进制\n1: 二进制反转\n2: 截断\n3: 归零\n4: 归零反转";
const char* trackbar_value = "值";
// 回调函数:当滑动条变化时调用
static void Threshold_Demo(int, void*) {
// 0: 二进制
// 1: 二进制反转
// 2: 阈值被截断
// 3: 阈值为零
// 4: 零点反转阈值
threshold(src_gray, dst, threshold_value, max_binary_value, threshold_type);
imshow(window_name, dst);
}
int main(int argc, char** argv) {
string imageName = "image.jpg"; // 默认图片名
if (argc > 1) {
imageName = argv[1];
}
// 加载图片
src = imread(imageName, IMREAD_COLOR);
if (src.empty()) {
cout << "无法读取图像:" << imageName << endl;
return -1;
}
// 图片转换为灰色
cvtColor(src, src_gray, COLOR_BGR2GRAY);
// 创建显示结果的窗口
namedWindow(window_name, WINDOW_AUTOSIZE);
// 创建 Trackbar 以选择阈值类型
createTrackbar(trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);
// 创建 Trackbar 以选择阈值
createTrackbar(trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);
// 初始化调用一次
Threshold_Demo(0, 0);
waitKey(0);
return 0;
}
让我们详细检查程序的结构和关键步骤:
首先,程序尝试从命令行参数获取图像路径,若未提供则使用默认文件名。使用 imread 加载图像后,必须检查是否成功(empty() 返回 true 表示失败)。
由于阈值操作通常在灰度图上效果最佳,因此使用 cvtColor 将 BGR 彩色图像转换为灰度图。
trackbar_type: 允许用户切换 5 种不同的阈值算法类型。trackbar_value: 允许用户动态调整阈值的具体数值(0-255)。Threshold_Demo 函数作为回调函数,每当滑动条的值发生变化时自动触发。
src_gray (输入灰度图), dst (输出图), threshold_value (当前阈值), max_binary_value (最大值), threshold_type (算法类型)。cv::threshold 执行实际的像素变换。imshow 更新窗口内容。waitKey(0) 使程序等待键盘输入,确保窗口保持打开状态,直到用户按键退出。
编译并运行程序后,您可以观察不同设置下的图像变化。
当选择'二进制反转'模式时,原本比阈值更亮的像素会变暗(变为 0),而较暗的像素变亮(变为 255)。这常用于提取深色文字或物体。
当选择'归零'模式时,低于阈值的像素变为黑色(0),高于阈值的像素保持原样。这有助于突出图像中的高亮区域,同时保留细节。
全局阈值(Global Thresholding)假设整个图像的亮度分布相对均匀。对于光照不均的图像,建议使用自适应阈值(Adaptive Thresholding)。
在进行阈值操作前,建议先对图像进行高斯模糊(Gaussian Blur)或中值滤波(Median Blur),以减少噪声点对阈值分割的影响。
Mat blurred;
gaussianBlur(src_gray, blurred, Size(5, 5), 0);
threshold(blurred, dst, threshold_value, max_binary_value, threshold_type);
OpenCV 还支持 Otsu 算法自动寻找最佳阈值。只需将 threshold_value 设为 0 并添加 THRESH_OTSU 标志即可。
double otsu_thresh = threshold(src_gray, dst, 0, 255, THRESH_BINARY + THRESH_OTSU);
cout << "Otsu threshold value: " << otsu_thresh << endl;
对于实时视频流处理,避免在循环中频繁创建窗口或重分配内存。尽量复用 Mat 对象,并确保图像处理流水线高效。
本教程详细介绍了 OpenCV 中的基本阈值操作。通过理解五种主要的阈值类型及其数学原理,结合 C++ 代码实践,您可以灵活地应用于各种图像分割任务。掌握阈值处理是进入计算机视觉领域的重要一步,建议结合实际项目多加练习,探索其在 OCR、医疗影像及工业检测中的应用潜力。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 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