OpenCV入门(15):图像处理之阈值处理
在图像处理中,阈值处理是一种常用的技术,用于将图像转换为二值图像(即黑白图像)。通过设定一个阈值,可以将图像中的像素分为两类:高于阈值的像素和低于阈值的像素。
OpenCV 提供了多种阈值处理方法,本文将详细介绍三种常见的阈值处理技术:简单阈值处理、自适应阈值处理以及 Otsu's 二值化。
一、简单阈值处理
简单阈值处理是最基础的阈值处理方法。它通过设定一个固定的阈值,将图像中的像素分为两类。OpenCV 提供了 cv::threshold() 函数来实现这一功能。
1.1 函数说明
函数原型
double cv::threshold ( InputArray src,
OutputArray dst,
double thresh,
double maxval,
int type )
参数说明
src:输入图像,通常为灰度图像。thresh:设定的阈值。maxval:当像素值超过(或小于,根据类型)阈值时,赋予的新值。type:阈值处理的类型。下面详细介绍。
返回值
retval: 实际使用的阈值(在某些情况下可能与设定的阈值不同)。dst: 处理后的图像。
1.2 基本阈值处理类型
(1)阈值二值化(binary)
cv::THRESH_BINARY:如果像素值>指定的阈值,则设置为最大值(通常是 255);否则设置为 0。用于将图像分割成黑白两部分,即将前景和背景分离。

(2)阈值反二值化(binary_inv)
cv::THRESH_BINARY_INV:THRESH_BINARY 的反向版本。如果像素值大于阈值,则设置为 0;否则设置为最大值。用于需要反转前景和背景的场景。

(3)截断(truncate)
cv::THRESH_TRUNC:当像素值>指定的阈值时,将其设置为阈值;否则保持原来的像素值。这种方法将高于阈值的部分截断,常用于限制图像中的最大亮度。

(4)阈值取零(threshold to zero)
cv::THRESH_TOZERO:如果像素值>阈值,则保持原像素值;否则设置为 0。这种方法可以用于只保留图像中高于某一亮度的部分,其余部分设置为背景。

(5)阈值反取零(threshold to zero inverted)
cv::THRESH_TOZERO_INV:THRESH_TOZERO 的反向版本。如果像素值>阈值,则设置为 0;否则保持原来的像素值。适用于需要反转高亮和低亮部分的场景。

1.3 实例
所有阈值处理的实例代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
//载入图像
Mat img = imread("./lena.jpg");
if (img.empty())
{
cout << "Error: Could not load image" << endl;
return 0;
}
// 多种阈值处理
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY); // 先转为灰度图
Mat dst1,dst2,dst3,dst4,dst5;
threshold(gray, dst1, 127, 255, THRESH_BINARY); // 二值化阈值处理
threshold(gray, dst2, 127, 255, THRESH_BINARY_INV); // 反二值化阈值处理
threshold(gray, dst3, 127, 255, THRESH_TRUNC); // 截断阈值化处理
threshold(gray, dst4, 127, 255, THRESH_TOZERO_INV); // 超阈值零处理
threshold(gray, dst5, 127, 255, THRESH_TOZERO); // 低阈值零处理
// 显示图像
imshow("gray_image", gray);
imshow("THRESH_BINARY", dst1);
imshow("THRESH_BINARY_INV", dst2);
imshow("THRESH_TRUNC", dst3);
imshow("THRESH_TOZERO_INV", dst4);
imshow("THRESH_TOZERO", dst5);
// 等待用户按键后退出
waitKey(0);
destroyAllWindows();
return 0;
}
各类型的对比效果图如下所示。
二值化阈值处理:

反二值化阈值处理:

截断阈值化处理:

超阈值零处理:

低阈值零处理:

二、自适应阈值处理(Adaptive Thresholding)
自适应阈值(Adaptive Thresholding)的工作原理是根据图像局部区域的特征来动态调整阈值,从而处理光照不均或对比度不够的图像。它的主要思想是对于图像中的每一个像素,根据其周围邻域的像素值来确定一个局部阈值。这样可以避免全局阈值方法可能带来的效果不佳的问题,尤其是在图像的不同区域光照差异较大的情况下。
2.1 函数说明
使用的函数原型为:
void adaptiveThreshold( InputArray src, OutputArray dst,
double maxValue, int adaptiveMethod,
int thresholdType, int blockSize, double C );
src: 输入图像,通常为灰度图像。maxValue: 当像素值超过(或小于,根据类型)阈值时,赋予的新值。adaptiveMethod: 自适应阈值计算方法,常见的类型有:cv2.ADAPTIVE_THRESH_MEAN_C: 阈值是邻域的平均值减去常数C。cv2.ADAPTIVE_THRESH_GAUSSIAN_C: 阈值是邻域的加权平均值减去常数C,权重由高斯函数确定。
thresholdType: 阈值处理的类型,通常为cv2.THRESH_BINARY或cv2.THRESH_BINARY_INV。blockSize: 计算阈值时使用的邻域大小,必须为奇数。C: 从平均值或加权平均值中减去的常数。dst: 返回值,即处理后的图像。
2.2 适用场景
- 图像光照不均匀或有明显的阴影。
- 需要在复杂背景下进行分割。
2.3 优缺点
自适应阈值的优点:
- 适应光照变化: 能够处理光照不均匀的图像,避免全局阈值方法对不同区域处理不一致的问题。
- 局部处理: 通过局部窗口计算阈值,可以更好地处理细节和复杂背景。
自适应阈值的缺点:
- 计算复杂度较高: 由于需要对每个像素计算局部阈值,处理时间相对较长。
- 参数选择: 自适应阈值方法中的参数(如窗口大小和常量)需要根据具体图像调整,以获得最佳效果。
2.4 实例
实例如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
// 载入图像
Mat img = imread("./lena.jpg");
if (img.empty())
{
cout << "Error: Could not load image" << endl;
return 0;
}
// 自适应阈值处理
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY); // 先转为灰度图
Mat dst;
adaptiveThreshold(gray, dst, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 7, 10);
// 创建窗口,WINDOW_NORMAL使窗口可以自由调节大小
namedWindow("gray_image",WINDOW_NORMAL);
namedWindow("adaptiveThreshold", WINDOW_NORMAL);
// 显示图像
imshow("gray_image", gray);
imshow("adaptiveThreshold", dst);
// 等待用户按键后退出
waitKey(0);
destroyAllWindows();
return 0;
}
效果图如下所示:

三、Otsu's 阈值处理
Otsu’s 阈值法是一种自动选择阈值的全局方法。它通过分析图像的灰度直方图,找到能够最大化类间方差(前景和背景)的阈值。Otsu’s 方法适用于双峰分布的图像(即前景和背景的灰度值分布相对独立且存在两个峰值)
最大化类间方差(Between-Class Variance)是 Otsu’s 阈值法的核心概念,旨在选择一个最佳阈值,使得图像的前景和背景之间的差异最大化。这种方法通过分析图像的灰度直方图,找到一个阈值,使得图像被分割成前景和背景后,它们之间的类间方差最大。
Otsu’s 方法遍历所有可能的阈值,并计算每个阈值对应的类间方差,选择使类间方差最大的阈值作为最终的阈值。
示例图像直方图如下所示:

3.1 函数说明
使用的函数原型为:
double threshold( InputArray src, OutputArray dst,
double thresh, double maxval, int type );
src: 输入图像,通常为灰度图像。thresh: 由于 Otsu's 方法会自动确定阈值,因此该参数通常设置为0。maxval: 当像素值超过(或小于,根据类型)阈值时,赋予的新值。type: 阈值处理的类型,通常为cv2.THRESH_BINARY或cv2.THRESH_BINARY_INV,并加上cv2.THRESH_OTSU。
3.2 适用场景
- 图像的灰度直方图呈现双峰分布。
- 需要自动选择最优阈值。
3.3 优缺点
- 优点: 自动选择阈值,适用于双峰图像的分割。
- 缺点: 对多峰分布的图像效果不佳,计算量相对较大。
3.4 实例
实例如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
//载入图像
Mat img = imread("./lena.png"); // ./dog_Otsu.png
if (img.empty())
{
cout << "Error: Could not load image" << endl;
return 0;
}
// Otsu's阈值处理
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY); // 先转为灰度图
Mat dst;
threshold(gray, dst, 0, 255, THRESH_OTSU); // OTSU
//显示图像
imshow("gray_image", gray);
imshow("THRESH_OTSU", dst);
waitKey(0);
return 0;
}
效果图如下所示:

四、阈值处理的应用场景
- 文档图像的二值化:用于将扫描的文档图像转换为黑白图像,以便进一步的 OCR(光学字符识别)处理。
- 物体检测:在自动化检测系统中,阈值处理可以用于分割目标物体,以便进行形状分析或特征提取。
- 医学图像处理:用于分割细胞、器官或其他生物结构。
阈值处理是图像预处理中常用的步骤,尤其适合对噪声较少、对比度较高的图像进行处理。根据具体应用的需要,可以选择合适的阈值处理方法。
五、总结
- 全局阈值适合简单、光照均匀的图像,计算速度快但对复杂场景效果不好。
- 自适应阈值适合光照不均的复杂图像,能更好地处理细节,但计算复杂度较高。
- Otsu’s 阈值法是一种自动选择阈值的全局方法,适合灰度直方图呈双峰分布的图像。

浙公网安备 33010602011771号