OpenCV 图像阈值处理
OpenCV 图像阈值处理 教程(中文)重点讲解 OpenCV 中用于图像阈值处理的核心功能,主要基于 imgproc 模块的 threshold 和 adaptiveThreshold 函数。阈值处理是图像分割的基础,用于将图像转换为二值图像或突出特定像素范围,广泛应用于目标检测、边缘提取等场景。本教程提供清晰的 Python 代码示例、解释和注意事项,适合初学者快速上手。假设你已安装 OpenCV(opencv-python)。
一、图像阈值处理概述
- 阈值处理:根据像素值与阈值的比较,将像素值设置为特定值(如 0 或 255),用于图像分割或增强。
- 应用场景:
- 二值化:将图像分为前景和背景。
- 预处理:为边缘检测、轮廓提取做准备。
- 特征提取:突出特定灰度范围。
- 关键函数:
cv2.threshold:全局阈值处理。cv2.adaptiveThreshold:自适应阈值处理,基于局部像素。- 输入要求:通常为灰度图像(单通道,
uint8类型)。
二、核心阈值处理功能与代码示例
以下按阈值处理类型分类,逐一讲解并提供 Python 示例代码。
2.1 全局阈值处理 (cv2.threshold)
全局阈值处理对整个图像应用单一阈值,适合光照均匀的图像。
支持的阈值类型:
cv2.THRESH_BINARY:大于阈值设为最大值,小于等于设为 0。cv2.THRESH_BINARY_INV:反向二值化。cv2.THRESH_TRUNC:大于阈值设为阈值,小于不变。cv2.THRESH_TOZERO:小于阈值设为 0,大于不变。cv2.THRESH_TOZERO_INV:大于阈值设为 0,小于不变。
示例:全局阈值处理
import cv2
import numpy as np
# 读取灰度图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
print("错误:无法加载图像")
exit()
# 应用不同阈值类型
thresh_value = 127
max_value = 255
# 二值化
_, thresh_binary = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_BINARY)
_, thresh_binary_inv = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_BINARY_INV)
_, thresh_trunc = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_TRUNC)
_, thresh_tozero = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_TOZERO)
_, thresh_tozero_inv = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_TOZERO_INV)
# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('THRESH_BINARY', thresh_binary)
cv2.imshow('THRESH_BINARY_INV', thresh_binary_inv)
cv2.imshow('THRESH_TRUNC', thresh_trunc)
cv2.imshow('THRESH_TOZERO', thresh_tozero)
cv2.imshow('THRESH_TOZERO_INV', thresh_tozero_inv)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存结果
cv2.imwrite('thresh_binary.jpg', thresh_binary)
cv2.imwrite('thresh_binary_inv.jpg', thresh_binary_inv)
cv2.imwrite('thresh_trunc.jpg', thresh_trunc)
cv2.imwrite('thresh_tozero.jpg', thresh_tozero)
cv2.imwrite('thresh_tozero_inv.jpg', thresh_tozero_inv)
说明:
threshold返回两个值:阈值(通常为输入阈值)和处理后的图像。thresh_value:阈值,范围 0-255,需根据图像调整。max_value:通常设为 255(白色)。
2.2 自适应阈值处理 (cv2.adaptiveThreshold)
自适应阈值根据局部像素邻域动态计算阈值,适合光照不均的图像。
支持的自适应方法:
cv2.ADAPTIVE_THRESH_MEAN_C:邻域均值作为阈值。cv2.ADAPTIVE_THRESH_GAUSSIAN_C:邻域高斯加权均值作为阈值。
示例:自适应阈值处理
import cv2
# 读取灰度图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
print("错误:无法加载图像")
exit()
# 自适应阈值
block_size = 11 # 邻域大小(奇数)
C = 2 # 常数偏移
# 均值自适应
thresh_mean = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, block_size, C)
# 高斯自适应
thresh_gaussian = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, block_size, C)
# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('均值自适应', thresh_mean)
cv2.imshow('高斯自适应', thresh_gaussian)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存结果
cv2.imwrite('thresh_mean.jpg', thresh_mean)
cv2.imwrite('thresh_gaussian.jpg', thresh_gaussian)
说明:
block_size:邻域大小(奇数,如 11),影响局部阈值计算。C:从计算的阈值中减去的常数,调整分割效果。- 高斯方法通常对复杂背景更有效。
2.3 自动阈值(Otsu 方法)
Otsu 方法自动选择最佳阈值,最大化类间方差,适合双峰直方图图像。
示例:Otsu 阈值处理
import cv2
# 读取灰度图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
print("错误:无法加载图像")
exit()
# Otsu 阈值
_, thresh_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('Otsu 阈值', thresh_otsu)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存结果
cv2.imwrite('thresh_otsu.jpg', thresh_otsu)
说明:
THRESH_OTSU:自动计算阈值,忽略手动指定的阈值(设为 0)。- 常与
THRESH_BINARY组合使用。
三、综合示例:阈值处理流水线
结合全局阈值、自适应阈值和 Otsu 方法:
import cv2
import numpy as np
def threshold_pipeline(image_path):
"""阈值处理流水线"""
# 读取灰度图像
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
print("错误:无法加载图像")
return
# 1. 全局二值化
_, thresh_binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 2. 自适应阈值(高斯)
thresh_adaptive = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
# 3. Otsu 阈值
_, thresh_otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('全局二值化', thresh_binary)
cv2.imshow('自适应阈值', thresh_adaptive)
cv2.imshow('Otsu 阈值', thresh_otsu)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存结果
cv2.imwrite('thresh_binary.jpg', thresh_binary)
cv2.imwrite('thresh_adaptive.jpg', thresh_adaptive)
cv2.imwrite('thresh_otsu.jpg', thresh_otsu)
# 使用示例
threshold_pipeline('lena.jpg') # 替换为你的图像路径
四、阈值处理应用:轮廓检测预处理
阈值处理常用于轮廓检测的预处理:
import cv2
import numpy as np
# 读取灰度图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
if img is None:
print("错误:无法加载图像")
exit()
# 自适应阈值
thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
# 查找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
img_color = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.drawContours(img_color, contours, -1, (0, 255, 0), 2)
# 显示结果
cv2.imshow('原始灰度图像', img)
cv2.imshow('阈值图像', thresh)
cv2.imshow('轮廓', img_color)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存结果
cv2.imwrite('contours.jpg', img_color)
说明:
- 阈值处理生成二值图像,适合
findContours提取轮廓。 - 自适应阈值对复杂背景效果更好。
五、注意事项
- 输入图像:
- 阈值处理通常需要灰度图像(单通道)。
- 确保图像为
uint8类型。
- 参数调整:
- 全局阈值的
thresh_value需根据图像灰度分布调整。 - 自适应阈值的
block_size应为奇数,过大或过小影响效果。
- 性能优化:
- 预处理(如高斯模糊)可减少噪声,提高阈值效果。
- 使用 ROI 减少计算量。
- 错误处理:
- 检查
imread返回值,防止图像加载失败。 - 确保
block_size和C参数合理。
- 选择方法:
- 全局阈值适合光照均匀的图像。
- 自适应阈值适合光照不均或复杂背景。
- Otsu 方法适合双峰直方图图像。
六、资源
- 官方文档:https://docs.opencv.org/master/d7/d4d/tutorial_py_thresholding.html
- imgproc 模块:https://docs.opencv.org/master/d7/d1d/tutorial_how_to_use_IPP.html
- 社区:在 X 平台搜索
#opencv获取最新讨论。
如果你需要更深入的阈值处理示例(如多阈值组合、动态调整阈值)或 C++ 实现代码,请告诉我,我可以提供详细的解决方案或针对特定任务的优化!