机器视觉学习-day03-灰度化实验-二值化和自适应二值化
1 二值化
二值化就是将某张图片的像素改成只有两种值(最常见的是纯黑和纯白),二值化操作的图像必须是灰度图,二值化的过程实际上是将一张灰度图上的像素根据某种规则修改为两种数值(0和maxval),使图像呈现出更为强烈的黑白效果,可以帮助后续处理图像轮廓或边缘等特征。
代码步骤:图片输入→灰度化→二值化→图片输出
1.1 阈值法(THRESH_BINARY)
阈值法就是通过设定一个阈值thresh,将灰度图的每一个像素与该阈值进行比较,小于等于阈值的像素被设置为0(黑),大于阈值的像素被设置为maxval(255-白)。
图片名为:1.png
import cv2
import numpy as np# 程序主入口
if __name__ == '__main__':# 1. 读取图像并转换为灰度图image = cv2.imread('image.jpg') # 读取原始彩色图像gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换为灰度图:加权平均法"""详细解释:cv2.imread():从指定路径读取图像,返回一个NumPy数组cv2.cvtColor(..., cv2.COLOR_BGR2GRAY): 将BGR彩色图像转换为灰度图像"""# 2. 设置阈值threshold_value = 128 # 中间值(0-255之间)"""阈值选择:- 128是0-255的中间值- 可以根据具体图像调整此值(范围0-255)"""# 3. 创建结果图像threshold_image = np.zeros_like(gray_image) # 创建与灰度图相同大小的全黑图像"""np.zeros_like() - 创建一个与输入数组形状和类型相同的全零数组这里用于存储阈值处理后的结果"""# 4.图片矫正. 获取图像尺寸height, width = gray_image.shape# 5. 应用阈值法for i in range(height):for j in range(width):# 获取当前像素值pixel_value = gray_image[i, j]# 阈值法判断if pixel_value >= threshold_value:threshold_image[i, j] = 255 # 设为白色else:threshold_image[i, j] = 0 # 设为黑色# 如果像素灰度值 > 127:设为255(纯白)# 如果像素灰度值 ≤ 127:设为0(纯黑)"""阈值法逻辑:- 遍历图像的每个像素- 如果像素值 >= 阈值,设为白色(255)- 如果像素值 < 阈值,设为黑色(0)"""# 6. 显示结果cv2.imshow('Original Gray Image', gray_image) # 原始灰度图cv2.imshow('Thresholding (T={})'.format(threshold_value), threshold_image) # 阈值法结果# 7. 等待按键关闭窗口cv2.waitKey(0)cv2.destroyAllWindows()# 8. 保存结果cv2.imwrite('threshold_result.png', threshold_image)"""结果说明:- 原始灰度图:连续色调的灰度图像- 阈值法结果:二值图像(只有黑白两种颜色)- 明亮区域(>=阈值)变为白色- 暗区域(<阈值)变为黑色"""
1.2 反阈值法(THRESH_BINARY_INY)
反阈值法与阈值法相反,当灰度图的像素值大于阈值时,像素值会被设置为0;当灰度图的像素值小于等于阈值时,像素值会被设置为最大值。
# 反阈值法(THRESH_BINARY_INV)import cv2if __name__ == '__main__':# 1. 图片输入path = '1.jpg' # 指定图片文件路径image_np = cv2.imread(path) # 读取图片到NumPy数组,格式为BGR三通道# 2. 灰度化(调用接口)image_np_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY) # BGR→灰度# 将彩色图像转为单通道灰度图像,因为二值化需要单通道输入"""详细解释:cv2.imread(path): 从指定路径读取图像cv2.cvtColor(..., cv2.COLOR_BGR2GRAY): 将BGR彩色图像转换为灰度图像"""# 3. 二值化thresh = 127 # 阈值maxval = 255 # 最大值# 二值化# 返回值1:阈值(thresh的值,部分算法是自动计算的,本例没用)# 返回值2:二值化之后的图片ret, image_np_gray = cv2.threshold(image_np_gray, # 输入的灰度图像thresh, # 阈值maxval, # 最大值cv2.THRESH_BINARY_INV # 二值化类型,反阈值即反向二值化)# 4.图片矫正. 图片输出cv2.imshow('image_np_gray', image_np_gray)cv2.waitKey(0)cv2.imwrite('INV.png', image_np_gray)
1.3 其他阈值法(了解即可)
1.3.1 截断阈值法(THRESH_TRUNC)
截断阈值法是将灰度图中所有像素值与阈值比较,当像素值大于阈值时被修改为为阈值,小于等于阈值的部分不变。
1.3.2 低阈值零处理(THRESH_TOZERO)
低阈值零处理表示像素值小于等于阈值的部分被设置为0,大于阈值的部分不变。
1.3.3 超阈值零处理(THRESH_TOZERO_INV)
超阈值零处理表示像素值大于阈值的部分被设置为0,小于等于阈值的部分不变。
1.4 OTSU阈值法
以上的二值化方法都需要手动设置阈值,但是在不同的环境下,摄像头拍摄的图像可能存在差异,导致手动设置的阈值并不适用于所有图像,这可能会使二值化的效果不理想。因此需要一种自动计算图片阈值的二值化方法,可以提高图像处理的准确性和鲁棒性。
使用 OTSU 阈值法可以找到一张图片的阈值,需要注意的是,这种方法仅用于找到阈值,并不能二值化,是在二值化之前增加的算法。OTSU算法就是通过一个值把图片分为前景色和背景色,通过统计学的方法来验证该值的合理性:最大类间方差。
通过OTSU算法得到阈值T之后,就可以结合之前的任意一种二值化方法进行操作,在虚拟仿真实验中只提供了两种二值化与OTSU结合的方式:
1. THRESH_BINARY + THRESH_OTSU :阈值法+OTSU
2. THRESH_BINARY_INT + THRESH_OTSU :反阈值法+OTSU
import cv2if __name__ == '__main__':# 1. 图片输入path = '1.jpg' # 读取原始彩色图像image_np = cv2.imread(path)# 2. 灰度化image_np_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY) # BGR→灰度"""详细解释:- cv2.imread() 读取图像,返回NumPy数组- cv2.cvtColor() 将BGR图像转换为灰度图像"""# 3. 二值化thresh = 145 # 阈值maxval = 255 # 最大值# 二值化# 返回值1:OTSU计算的阈值# 返回值2:二值化之后的图片ret, image_np_gray = cv2.threshold(image_np_gray, # 灰度图thresh, # 阈值maxval, # 最大值cv2.THRESH_BINARY + cv2.THRESH_OTSU # OTSU+二值化)"""cv2.threshold()参数说明:image_np_gray: 输入灰度图像在这个函数里thresh==0: 因为使用OTSU,这里设为0(会被忽略)maxval/255: 最大值(白色)cv2.THRESH_BINARY + cv2.THRESH_OTSU: 阈值法 + OTSU算法返回值:ret,: OTSU算法计算出的最佳阈值image_np_gray : 阈值处理后的图像(这里不需要,因为我们后面会自己处理)OTSU 算法原理:1. 计算图像灰度2. 遍历所有可能的阈值(0-254)3. 对每个阈值,将像素分为两类(前景和背景)4.图片矫正. 计算两类之间的方差(类间方差)5. 选择使类间方差最大的阈值作为最佳阈值"""print(f"OTSU算法计算的最佳阈值: {ret}")# OTSU算法计算的最佳阈值: 123.0# 4.图片矫正. 图片输出cv2.imshow('image_np_gray', image_np_gray)cv2.waitKey(0)cv2.imwrite('OTSU.png', image_np_gray)
2 自适应二值化
自适应二值化更加适合明暗分布不均匀的图片。自适应二值化会对图像的所有像素点单独计算阈值,这样更好的针对每个像素点判断是前景还是背景。自适应二值化可以更好的保留图片的信息。
代码运行步骤:图片输入→灰度化→自适应二值化→图片输出
代码参数:
参数:
maxval:最大值,通常为255
adaptiveMethod:小区域阈值的计算方式
ADAPTIVE_THRESH_MEAN_C:小区域内取均值
ADAPTIVE_THRESH_GAUSSIAN_C:小区域内加权求和,权重是个高斯核
thresholdType:二值化方法
THRESH_BINARY 阈值法
THRESH_BINARY_INV 反阈值法
blockSize:小区域的面积,通常取奇数,例如7表示7*7,后期称之为核(各种滤波和卷积等都用的到),计算的方式为滑动(从左到右,从上到下)计算
c:最终阈值等于计算的阈值减去此值
1 取均值 ADAPTIVE_THRESH_MEAN_C
import cv2if __name__ == '__main__':# 1. 图片输入path = '1.jpg'image_np = cv2.imread(path) # 读取原始彩色图像# 2. 灰度化(为了手搓二值化,暂时手搓灰度化)image_np_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY) # BGR→灰度# 将彩色图像转为单通道灰度图像,因为二值化需要单通道输入# 3. 自适应二值化maxval = 255 # 二值化后的最大值(白色)# 自适应二值化# 返回值:自适应二值化之后的图像image_np_adaptive = cv2.adaptiveThreshold(image_np_gray, # 要处理的灰度化图像maxval, # 当像素值超过阈值时赋予的值(255=白色)cv2.ADAPTIVE_THRESH_MEAN_C, # 自适应方法:使用邻域均值计算阈值# 另一种选项是 cv2.ADAPTIVE_THRESH_GAUSSIAN_C,使用高斯加权平均值cv2.THRESH_BINARY_INV, # 阈值法还是反阈值法# 二值化模式:反向二值化(大于阈值变0/黑,小于变255/白)11, # 核大小(邻域窗口尺寸)10, # C值(从均值中减去的常数))# 4.图片矫正. 图片输出cv2.imshow('image_np_adaptive', image_np_adaptive) # 显示二值化结果cv2.waitKey(0) # 等待按键后关闭窗口cv2.imwrite('zishiying.png',image_np_adaptive)