OpenCV二值化处理
1.1. 为什么需要二值化操作
二值化操作将灰度图像转换为黑白图像,即将图像中的像素值分为两类:前景(通常为白色,值为 255)和背景(通常为黑色,值为 0)。二值化的主要目的是简化图像,突出目标物体,便于后续的图像分析和处理,如特征提取、目标检测、图像分割等。
1.2. 二值化操作的原理
二值化操作通过设定一个阈值,将图像中的像素值与该阈值进行比较:
- 如果像素值大于或等于阈值,则将其设为最大值(通常是 255)。
- 如果像素值小于阈值,则将其设为最小值(通常是 0)。
OpenCV 中常用的二值化方法包括:
- 全局阈值法:使用一个固定的阈值对整个图像进行二值化。
- 自动阈值法(OTSU):适用于双峰直方图的图像,该方法会自动计算一个阈值,使得前景和背景的类间方差最大,从而实现最佳的二值化效果。
- 自适应阈值法:根据图像的局部区域动态计算阈值,适用于光照不均匀的图像。
1.3. OpenCV 中如何实现二值化操作
1.3.1. 全局阈值法
使用 cv2.threshold()
函数实现全局阈值二值化:
import cv2
# 读取图像并转换为灰度图像
img = cv2.imread('example.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 全局阈值二值化
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 显示结果
cv2.imshow('Binary Image', binary)
cv2.waitKey(0)
cv2.destroyAllWindows()
参数说明:
src
:输入的灰度图像。thresh
:阈值。maxval
:最大值,通常为 255。type
:二值化类型,如cv2.THRESH_BINARY
。
1.3.2. Otsu 阈值法
使用 cv2.threshold
函数实现 Otsu 阈值法:
Python复制
ret, binary = cv2.threshold(src, thresh, maxval, type)
src
:输入的灰度图像。thresh
:初始阈值(通常设置为 0,因为 Otsu 方法会自动计算最佳阈值)。maxval
:阈值化后的最大值,通常是 255。type
:阈值化类型,使用cv2.THRESH_BINARY + cv2.THRESH_OTSU
表示使用 Otsu 方法。ret
:自动计算的阈值。binary
:二值化后的图像。
# 读取图像并转换为灰度图像
img = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 使用 Otsu 方法自动计算阈值
ret, binary_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 自适应阈值二值化
binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
# 显示结果
cv2.imshow('Adaptive Binary Image', binary)
cv2.waitKey(0)
cv2.destroyAllWindows()
参数说明:
src
:输入的灰度图像。maxValue
:最大值,通常为 255。adaptiveMethod
:自适应方法,如cv2.ADAPTIVE_THRESH_MEAN_C
。thresholdType
:二值化类型,如cv2.THRESH_BINARY
。blockSize
:局部窗口大小,必须是奇数。C
:常数偏移值。
1.4. 使用注意事项
- 图像预处理:在进行二值化之前,通常需要对图像进行预处理,如去噪、灰度转换等。
- 阈值选择:阈值的选择对二值化结果影响很大,需要根据图像的灰度分布和处理需求来选择合适的阈值。
- 自适应阈值:对于光照不均匀的图像,自适应阈值法通常比全局阈值法效果更好。
- 二值化类型:根据具体需求选择合适的二值化类型,如
cv2.THRESH_BINARY
、cv2.THRESH_BINARY_INV
等。
1.5. 例子
我们用一个物体表面的裂缝为例子实验:
def TestThreshold():
# 读取图像并转换为灰度图像
image_path = 'Carck.png'
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
raise FileNotFoundError(f"图像文件未找到:{image_path}")
# 方法1:全局阈值法
# 使用固定阈值进行二值化
_, binary_global = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 方法2:OTSU 自动阈值法
# 自动计算阈值
_, binary_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 方法3:自适应阈值法
# 根据局部区域动态计算阈值
binary_adaptive = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
# 显示结果
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1)
plt.imshow(img, cmap='gray')
plt.title('Original Image')
plt.axis('off')
plt.subplot(2, 2, 2)
plt.imshow(binary_global, cmap='gray')
plt.title('Global Thresholding')
plt.axis('off')
plt.subplot(2, 2, 3)
plt.imshow(binary_otsu, cmap='gray')
plt.title('OTSU Thresholding')
plt.axis('off')
plt.subplot(2, 2, 4)
plt.imshow(binary_adaptive, cmap='gray')
plt.title('Adaptive Thresholding')
plt.axis('off')
plt.tight_layout()
plt.show()
可以看到全局阈值发和OTSU自动化阈值法效果还可以,自适应阈值法提取效果没有那么好
可以观察到OTSU检查出来的划痕更完整,大家可以修改全局阈值法的值127减少和增大分别会发生什么
# 方法1:全局阈值法
# 使用固定阈值进行二值化
_, binary_global = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY) #增大阈值
_, binary_global = cv2.threshold(img, 120, 255, cv2.THRESH_BINARY) #减少阈值