一、什么是阈值处理
阈值处理是指剔除图像内的像素值高于一定值或者低于一定值的像素点。按照上述阈值处理方式,可以将一幅灰度图像处理为一幅二至图像,很好地将前景和背景区分开。
我们可以在终端中使用 pip 安装 OpenCV 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载。
pip install opencv-python -i https://mirrors.aliyun.com/pypi/simple
国内常用的 pip 下载源列表:
- 阿里云 https://mirrors.aliyun.com/pypi/simple
- 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple
- 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple
- 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple
在 OpenCV 中,提供了 cv2.threshold() 函数用于实现阈值处理。
cv2.threshold(src: cv2.typing.MatLike, thresh: float, maxval: float, type: int, dst: cv2.typing.MatLike | None = ...) -> tuple[float, cv2.typing.MatLike]: ...
其中,参数 src 是 原始图像,推荐使用 灰度图。参数 thresh 是 要设置的阈值。参数 maxval 表示当 type 参数为 cv2.THRESH_BINARY 或者 cv2.THRESH_BINARY_INV 类型时,需要设定的最大值。参数 type 是 阈值分割的类型。参数 dst 是 边缘检测后的图像。
参数 type 是 阈值分割的类型,它的取值如下:
cv2.THRESH_BINARY # 二值化阈值处理
cv2.THRESH_BINARY_INV # 反二值化阈值处理
cv2.THRESH_TRUNC # 截断阈值处理
cv2.THRESH_TOZERO # 低阈值零处理
cv2.THRESH_TOZERO_INV # 超阈值零处理
cv2.THRESH_MASK # 掩码阈值处理
cv2.THRESH_OTSU # Otsu阈值处理
cv2.THRESH_TRIANGLE # 三角形阈值处理
【1】、二值化阈值处理
二值阈值处理会将原始图像处理为仅有两个值的二值图像,其针对像素点的处理方式如下:
- 对于灰度值大于阈值 thresh 的像素点,将其灰度值设定为最大值。
- 对于灰度值小于或等于阈值 thresh 的像素点,将其灰度值设置为 0。

import cv2
import numpy as npif __name__ == '__main__':src = np.random.randint(0, 256, (5, 5), dtype=np.uint8)# 二值化阈值处理threshold_value, dst = cv2.threshold(src, 128, 255, cv2.THRESH_BINARY)print("src: \n", src)print("threshold value: ", threshold_value)print("dst: \n", dst)
【2】、反二值化阈值处理
反二值阈值处理的结果也是仅有两个值的二值图像,与二值化阈值处理的区别在于,两者对像素值的处理方式不同。反二值化阈值处理针对像素点的处理方式为:
- 对于灰度值大于阈值的像素点,将其值设置为 0。
- 对于灰度值小于或等于阈值的像素点,将其值设置为 255。

import cv2
import numpy as npif __name__ == '__main__':src = np.random.randint(0, 256, (5, 5), dtype=np.uint8)# 反二值化阈值处理threshold_value, dst = cv2.threshold(src, 128, 255, cv2.THRESH_BINARY_INV)print("src: \n", src)print("threshold value: ", threshold_value)print("dst: \n", dst)
【3】、截断阈值处理
截断阈值化处理会将图像中大于阈值的像素值的值设置为阈值,小于或等于该阈值的像素点的值保持不变。

import cv2
import numpy as npif __name__ == '__main__':src = np.random.randint(0, 256, (5, 5), dtype=np.uint8)# 截断阈值处理threshold_value, dst = cv2.threshold(src, 128, 255, cv2.THRESH_TRUNC)print("src: \n", src)print("threshold value: ", threshold_value)print("dst: \n", dst)
【4】、低阈值零处理
低阈值零处理会将图像中小于或等于阈值的像素点的值处理为 0,大于阈值的像素点的值保持不变,即先选定一个阈值,然后对图像做如下处理:
- 对于像素值大于阈值的像素点,其值将保持不变。
- 对于像素值小于或等于阈值的像素点,其值将被处理为 0。

import cv2
import numpy as npif __name__ == '__main__':src = np.random.randint(0, 256, (5, 5), dtype=np.uint8)# 低阈值零处理threshold_value, dst = cv2.threshold(src, 128, 255, cv2.THRESH_TOZERO)print("src: \n", src)print("threshold value: ", threshold_value)print("dst: \n", dst)
【5】、超阈值零处理
超阈值零处理会将图像中大于阈值的像素点的值处理为 0,小于或等于该阈值的像素点的值保持不变,即先选定一个阈值,然后对图像做如下处理:
- 对于像素值大于阈值的像素点,其像素点将被处理为 0。
- 对于像素点小于或等于阈值的像素点,其像素点将保持不变。

import cv2
import numpy as npif __name__ == '__main__':src = np.random.randint(0, 256, (5, 5), dtype=np.uint8)# 超阈值零处理threshold_value, dst = cv2.threshold(src, 128, 255, cv2.THRESH_TOZERO_INV)print("src: \n", src)print("threshold value: ", threshold_value)print("dst: \n", dst)
【6】、Otsu 阈值处理
在使用 cv2.threshold() 函数进行阈值处理时,需要自定义一个阈值,并以此阈值作为图像阈值处理的依据。通常情况下处理的图像都是色彩均衡的,这时直接将阈值设为 127 是比较合适的。但是,有些图像灰度值的分布是不均衡的,如果此时还将阈值设置为 127,那么阈值的结果就是失败的。
Otsu 方法能够根据当前图像给出最佳的类间分割阈值。简而言之,Otsu 方法会遍历所有可能阈值,从而找到最佳的阈值。Otst 方法,也被称为最大类间方差法。该方法使用的是聚类的思想,它把图像中所有像素点的像素值按灰度分成两组,确保:
- 两组之间,灰度值差异最大。
- 两组之内,灰度值差异最小。
Otsu 方法通过方差的计算,来寻找最佳的灰度级作为分组依据。它的计算简单方便,同时它不容易受到图像亮度和对比度的影响。因此,Otsu 算法是对复杂图像进行阈值分割时,计算阈值的一种非常有效的方法。
在 OpenCV 中,通过在 cv2.shreshold() 函数中对 type 参数多传入一个 cv2.THRESH_OTSU 值,即可以实现 Otsu 方式的阈值分割。在使用 Otsu 方法时,需要把阈值设置为 0。此时,cv2.threshold() 函数会自动寻找最有阈值,并将该阈值返回。
import cv2
import numpy as npif __name__ == '__main__':src = np.random.randint(0, 256, (5, 5), dtype=np.uint8)# Otsu阈值处理threshold_value, dst = cv2.threshold(src, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)print("src: \n", src)print("threshold value: ", threshold_value)print("dst: \n", dst)
二、自适应阈值处理
对于色彩均衡的图像,直接使用一个阈值就能够完成对图像的阈值化处理。但是,有时图像的色彩是不均衡的,此时如果只使用一个阈值,就无法得到清晰有效的阈值分割结果图像。有一种改进的阈值处理技术,其使用变化的阈值完成对图像的阈值处理,这种技术被称为自适应阈值处理。
在进行阈值处理时,自适应阈值处理的方式通过计算每个图像点周围邻近区域的加权平均值获得阈值,并使用该阈值对当前像素点进行处理。与普通的阈值处理方法相比,自适应阈值能力能够更好地处理明暗差异过大的图像。
在 OpenCV 中,提供了 cv2.adaptiveThreshold() 函数用于实现自适应阈值处理。
cv2.adaptiveThreshold(src: cv2.typing.MatLike, maxValue: float, adaptiveMethod: int, thresholdType: int, blockSize: int, C: float, dst: cv2.typing.MatLike | None = ...) -> cv2.typing.MatLike: ...
其中,参数 src 是 原始图像,该图像必须是 8 位单通道的图像。参数 maxValue 是 最大值。参数 adaptiveMethod 是 自适应方法。参数 thresholdType 是 阈值处理方式,该值必须是 cv2.THRESH_BINARY 或者 cv2.THRESH_BINARY_INV 中的一个。参数 blockSize 是 块大小,表示一个像素在计算其阈值时所使用的邻域尺寸。参数 c 是 常量。参数 dst 是 边缘检测后的图像。
cv2.adaptiveThreshold() 函数根据参数 adaptiveMethod 来确定自适应阈值的计算方法。它包含cv2.ADAPTIVE_THRESH_MEAN_C 和 cv2.ADAPTIVE_THRESH_GAUSSIAN_C 两种不同的方法。这两种方法都是逐个像素的计算自适应阈值的,自适应阈值等于每个像素由 blockSize 参数所指定邻域的加权平均值减去常量 c。两种不同的方法在计算邻域的加权平均值是所采用的方式不同:
cv2.ADAPTIVE_THRESH_MEAN_C # 邻域所有像素点的权重值是一致的
cv2.ADAPTIVE_THRESH_GAUSSIAN_C # 邻域所有像素点的权重值是根据高斯分布计算的
import sys
import cv2if __name__ == '__main__':src = cv2.imread("assets/images/sudoku.png")if src is None:print("加载图片失败")sys.exit(0)gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) # 转换为灰度图像# 自适应阈值dst = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 7, 0)cv2.imshow("dst", dst)cv2.waitKey(0)cv2.destroyAllWindows()sys.exit(0)
