2.5 二值化与阈值
总目录:1.1 OpenCV介绍与学习路线 | 第二章:基础图像处理 | 编号:2.5
← 上一节:2.4 滤波与降噪 | 下一节:2.6 形态学处理 →
2.5 二值化与阈值
二值化做的事情非常朴素:给每个像素安排一次“站队”,最后只留下前景与背景。轮廓算法不想面对五颜六色的世界,它更喜欢一张边界明确的黑白图。
一、阈值是在做像素分类
以最常见的二值阈值为例:
像素值 > 阈值 → 255(白)
否则 → 0(黑)
阈值不是天然真理。光照、曝光、材质变了,同一个数可能就不合适了。
二、固定阈值 threshold
used_threshold, binary = cv2.threshold(
gray,
127,
255,
cv2.THRESH_BINARY,
)
参数:
| 参数 | 含义 |
|---|---|
gray |
输入图,常见情况是单通道灰度图 |
127 |
分类阈值 |
255 |
满足条件时写入的最大值 |
THRESH_BINARY |
阈值规则 |
返回两个值:真正使用的阈值和结果图。普通固定阈值里第一个返回值通常就是传入的 127;使用 Otsu 时它才尤其有用。
五种基础规则
| 类型 | 规则概念 |
|---|---|
THRESH_BINARY |
高于阈值变白,其余变黑 |
THRESH_BINARY_INV |
高于阈值变黑,其余变白 |
THRESH_TRUNC |
高于阈值的部分压到阈值 |
THRESH_TOZERO |
低于阈值的部分归零 |
THRESH_TOZERO_INV |
高于阈值的部分归零 |
做轮廓时最常用前两种。因为 findContours 主要把白色区域当作前景,所以黑色目标落在白背景上时,经常需要 THRESH_BINARY_INV。
三、自适应阈值 adaptiveThreshold
一张纸左边亮、右边暗时,一个全局阈值可能怎么选都难受。自适应阈值会根据每个像素附近的小区域算局部阈值:
binary = cv2.adaptiveThreshold(
gray,
255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
blockSize=11,
C=2,
)
blockSize:邻域大小,必须是大于 1 的奇数;C:从局部均值或加权均值里减去的常数;MEAN_C:普通邻域均值;GAUSSIAN_C:按高斯权重计算邻域均值。
自适应不等于自动完美。块太小会追着纹理跑,块太大又接近全局阈值。
四、Otsu:自动寻找全局阈值
Otsu 会根据灰度直方图选择一个全局阈值,适合前景和背景大致形成两个峰的图像:
used_threshold, binary = cv2.threshold(
gray,
0,
255,
cv2.THRESH_BINARY + cv2.THRESH_OTSU,
)
print("Otsu threshold:", used_threshold)

噪声会搅乱直方图,常先轻度高斯滤波:
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
_, binary = cv2.threshold(
blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU
)
五、三种方法怎样选
光照稳定、速度优先 → 固定阈值
同一画面有明显明暗不均 → 自适应阈值
直方图双峰、想自动全局选 → Otsu
按颜色而不是亮度分割 → [HSV + inRange](/notes/OpenCV%E5%85%A5%E9%97%A8/2.7%20HSV%E9%A2%9C%E8%89%B2%E6%A3%80%E6%B5%8B)
调参时别只看最终框
同时显示:
cv2.imshow("Gray", gray)
cv2.imshow("Binary", binary)
若目标在二值图里已经断了、粘了或前景背景反了,后面的轮廓参数救不了它。先把这一层做好,再去调面积阈值。
留言区
不收集任何个人信息;昵称只绑定浏览器里的随机 Cookie。