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。用于将图像分割成黑白两部分,即将前景和背景分离。

Blog_OpenCV_Learnl_47.png


(2)阈值反二值化(binary_inv)

cv::THRESH_BINARY_INVTHRESH_BINARY 的反向版本。如果像素值大于阈值,则设置为 0;否则设置为最大值。用于需要反转前景和背景的场景。

Blog_OpenCV_Learnl_48.png


(3)截断(truncate)

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

Blog_OpenCV_Learnl_49.png


(4)阈值取零(threshold to zero)

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

Blog_OpenCV_Learnl_50.png


(5)阈值反取零(threshold to zero inverted)

cv::THRESH_TOZERO_INVTHRESH_TOZERO 的反向版本。如果像素值>阈值,则设置为 0;否则保持原来的像素值。适用于需要反转高亮和低亮部分的场景。

Blog_OpenCV_Learnl_51.png


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;
}

各类型的对比效果图如下所示。

二值化阈值处理:

Blog_OpenCV_Learnl_41.png


反二值化阈值处理:

Blog_OpenCV_Learnl_42.png


截断阈值化处理:

Blog_OpenCV_Learnl_43.png


超阈值零处理:

Blog_OpenCV_Learnl_44.png


低阈值零处理:

Blog_OpenCV_Learnl_45.png


二、自适应阈值处理(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_BINARYcv2.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;
}

效果图如下所示:

Blog_OpenCV_Learnl_52.png


三、Otsu's 阈值处理

Otsu’s 阈值法是一种自动选择阈值的全局方法。它通过分析图像的灰度直方图,找到能够最大化类间方差(前景和背景)的阈值。Otsu’s 方法适用于双峰分布的图像(即前景和背景的灰度值分布相对独立且存在两个峰值)

最大化类间方差(Between-Class Variance)Otsu’s 阈值法的核心概念,旨在选择一个最佳阈值,使得图像的前景和背景之间的差异最大化。这种方法通过分析图像的灰度直方图,找到一个阈值,使得图像被分割成前景和背景后,它们之间的类间方差最大。

Otsu’s 方法遍历所有可能的阈值,并计算每个阈值对应的类间方差,选择使类间方差最大的阈值作为最终的阈值。

示例图像直方图如下所示:

Blog_OpenCV_Learnl_53.png


3.1 函数说明

使用的函数原型为:

double threshold( InputArray src, OutputArray dst,
                 double thresh, double maxval, int type );
  • src: 输入图像,通常为灰度图像。
  • thresh: 由于 Otsu's 方法会自动确定阈值,因此该参数通常设置为 0
  • maxval: 当像素值超过(或小于,根据类型)阈值时,赋予的新值。
  • type: 阈值处理的类型,通常为 cv2.THRESH_BINARYcv2.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;
}

效果图如下所示:

Blog_OpenCV_Learnl_55.png


四、阈值处理的应用场景

  • 文档图像的二值化:用于将扫描的文档图像转换为黑白图像,以便进一步的 OCR(光学字符识别)处理。
  • 物体检测:在自动化检测系统中,阈值处理可以用于分割目标物体,以便进行形状分析或特征提取。
  • 医学图像处理:用于分割细胞、器官或其他生物结构。

阈值处理是图像预处理中常用的步骤,尤其适合对噪声较少、对比度较高的图像进行处理。根据具体应用的需要,可以选择合适的阈值处理方法。

五、总结

  • 全局阈值适合简单、光照均匀的图像,计算速度快但对复杂场景效果不好。
  • 自适应阈值适合光照不均的复杂图像,能更好地处理细节,但计算复杂度较高。
  • Otsu’s 阈值法是一种自动选择阈值的全局方法,适合灰度直方图呈双峰分布的图像。

posted @ 2025-08-11 17:26  fengMisaka  阅读(240)  评论(0)    收藏  举报