1. 二值化:从“黑白分明”说起
大家好,我是老张,在图像处理这行摸爬滚打十来年了。今天咱们聊一个听起来很专业,但实际应用无处不在的技术——图像二值化。简单来说,二值化就是把一张彩色的或者灰度的图片,变成只有纯黑和纯白两种颜色的图片。这个过程,就像是把一张复杂的素描画,用最粗的马克笔重新描一遍,只留下最核心的轮廓和形状。
你可能会问,好好的图片为什么要变成黑白两色?这用处可太大了。比如,你手机上的扫描软件,能把一张纸质发票拍下来,自动识别上面的文字和数字,背后很可能就用到了二值化技术,先把背景和文字分离开。再比如,工厂里用摄像头检查产品上有没有划痕或瑕疵,第一步往往也是把图像二值化,让缺陷在黑白背景下变得一目了然。还有我们熟悉的二维码识别,第一步也是把图像变成黑白分明的样子,方便机器“阅读”。
在OpenCV这个强大的计算机视觉库中,实现二值化最核心的函数就是 cv2.threshold()。别看它只是一个函数,里面却藏着好几种不同的玩法,从最简单的“一刀切”全局阈值,到聪明的“因地制宜”自适应阈值,再到能自己找最佳分割点的Otsu算法。接下来,我就带你深入浅出地走一遍,结合大量我实际项目中踩过的坑和总结的经验,让你不仅能看懂代码,更能知道在什么情况下该用什么方法。
2. 全局阈值:简单粗暴的“一刀切”
2.1 核心函数与五种“刀法”
全局阈值,顾名思义,就是给整张图片设定一个固定的门槛值。OpenCV的 cv2.threshold() 函数就是这个“执刀人”。它的基本语法是这样的:
retval, dst = cv2.threshold(src, thresh, maxval, type)
我习惯把参数拆开揉碎了理解:
src:待处理的源图像。这里有个关键点:虽然函数说明里说可以是多通道,但为了稳妥起见,我强烈建议你先用cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)转换成灰度图再处理,避免色彩通道带来的意外。thresh:你设定的那个“门槛”,比如经典的127。maxval:当像素值超过(或低于)门槛时,要被赋予的新值,通常是255(白色)。type:这是“刀法”的选择器,决定了怎么砍这一刀。它直接决定了二值化的效果。retval:函数返回的实际使用的阈值,在普通全局阈值里,它就是你设定的thresh;但在Otsu算法里,它会变成算法找到的最佳阈值。dst:处理后的结果图像。
这个 type 参数有五种主要“刀法”,我用一个简单的灰度渐变图来给你直观展示一下区别。假设我们有一幅从纯黑(0)到纯白(255)均匀渐变的图像,设定阈值 thresh=127,maxval=255。
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 创建一个简单的水平渐变灰度图(0到255)
gradient = np.tile(np.linspace(0, 255, 256, dtype=np.uint8), (100, 1))
ret, thresh_binary = cv2.threshold(gradient, 127, 255, cv2.THRESH_BINARY)
ret, thresh_binary_inv = cv2.threshold(gradient, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh_trunc = cv2.threshold(gradient, 127, 255, cv2.THRESH_TRUNC)
ret, thresh_tozero = cv2.threshold(gradient, 127, 255, cv2.THRESH_TOZERO)
ret, thresh_tozero_inv = cv2.threshold(gradient, 127, 255, cv2.THRESH_TOZERO_INV)
titles = ['Original Gradient', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [gradient, thresh_binary, thresh_binary_inv, thresh_trunc, thresh_tozero, thresh_tozero_inv]
plt.figure(figsize=(12, 6))
for i in range(6):
plt.subplot(2, 3, i+1)
plt.imshow(images[i], cmap='gray', vmin=0, vmax=255)
plt.title(titles[i])
plt.axis('off')
plt.tight_layout()
plt.show()
运行这段代码,你会看到六张小图,效果差异一目了然。下面我结合这个渐变图,用大白话解释每种“刀法”:
cv2.THRESH_BINARY(二值化):这是最经典的。像素值 > 127的,全变成255(白);像素值 <= 127的,全变成0(黑)。结果就是渐变图中间被一刀切开,左边全黑,右边全白。
cv2.THRESH_BINARY_INV(反二值化):跟上面正好反过来。像素值 > 127的,变黑(0);像素值 <= 127的,变白(255)。相当于把黑白区域对调了。
cv2.THRESH_TRUNC(截断):这个比较有意思,它不产生纯二值图。像素值 > 127的


1964

被折叠的 条评论
为什么被折叠?



