二值化(Binarization)是一种图像处理操作,它的目的是将一幅灰度图像转换为仅包含两种像素值(通常为 0 和 255,分别代表黑色和白色)的二值图像。通过设定一个合适的阈值(Threshold),根据像素点的灰度值与该阈值的比较结果来确定其最终是被置为 0 还是 255,以此来突出图像中的目标物体,简化后续的图像分析、目标检测、特征提取等操作。
图像二值化就是把一幅图像上的颜色或者灰度值变成只有两种情况,就像给图像穿了一件只有黑白两种颜色的“衣服”。需要注意的是二值化只能针对灰度图像,也就是说对于一张彩色图片要进行二值化处理,必须先转换为灰度图。
比如,你有一张照片,照片里有各种各样的颜色和灰度。经过二值化处理后,照片上只有黑色和白色两种颜色了。这种处理方式在很多场景下很有用,像在识别文字或者一些简单的物体轮廓时,把复杂的颜色信息简化成黑白两种情况,能让后续的处理更简单、更高效。
阈值法二值化是一种常见的图像二值化处理方法,对于给定的灰度图像中的每个像素点,将其灰度值与一个预先设定的固定阈值进行比较。如果像素的灰度值大于等于这个阈值,就将其赋值为一个较高的值(比如 255,表示白色);如果像素的灰度值小于阈值,就将其赋值为一个较低的值(比如 0,表示黑色)。
以下是一个使用Python和OpenCV实现阈值法二值化的简单代码示例。
import cv2
# 读取灰度图像
img_gray = cv2.imread('./images/png/test01.png', 0)
# 设定全局阈值并进行二值化处理
_, img_binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 显示结果
cv2.imshow('Binary Image', img_binary)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imread 的参数解释如下:
flag = -1, 8位深度,原通道
flag = 0, 8位深度,1通道
flag = 1, 8位深度,3通道
flag = 2, 原深度, 1通道
flag = 3, 原深度, 3通道
flag = 4, 8位深度,3通道
在OpenCV中,反阈值二值化(Inverse Binary Thresholding)是一种常见的阈值处理方法。这种方法与常规的二值化相反,其具体操作是:如果像素值大于设定的阈值,则该像素值被设置为最小值(通常是黑色,即0);如果像素值小于或等于阈值,则该像素值被设置为最大值(通常是白色,即255)。
以下是一个使用Python和OpenCV实现反阈值法二值化的简单代码示例。
import cv2
# 读取灰度图像
img_gray = cv2.imread('./images/png/test01.png', 0)
# 设定全局阈值并进行反阈值二值化处理
_, img_binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
# 显示结果
cv2.imshow('Binary Image', img_binary)
cv2.waitKey(0)
cv2.destroyAllWindows()

截断阈值二值法通过设定一个固定的阈值,将图像中的像素值分为两类。对于每个像素,如果其灰度值大于阈值,则将其设置为该阈值;如果灰度值小于或等于阈值,则保持原值不变。这种方法在OpenCV中通过cv2.THRESH_TRUNC实现。截断阈值二值法适用于需要保留原图像某些特征,同时对超出阈值的像素进行限制的情况。例如,在某些图像增强或特征提取任务中,可以避免像素值的极端变化,从而更好地突出图像的某些部分。
需要注意的是灰度值越大颜色越白,灰度值越小颜色越黑。
在图像处理中,灰度值通常用来表示像素的亮度。一般来说,灰度值的范围是0到255: - 灰度值0表示黑色。 - 灰度值255表示白色。 - 中间的数值表示不同的灰色,例如,灰度值127表示一种中等的灰色。
所以,灰度值越大,颜色越接近白色;灰度值越小,颜色越接近黑色。例如,在一张灰度图像中,一个像素点的灰度值为200,那么它会比另一个灰度值为50的像素点更亮、更白。
以下是一个使用Python和OpenCV实现截断阈值法二值化的简单代码示例。
import cv2
# 读取灰度图像
image = cv2.imread('./images/png/test01.png', 0)
# 设置阈值
threshold_value = 127
# 应用截断阈值二值化
_, binary_image = cv2.threshold(image, threshold_value, 255, cv2.THRESH_TRUNC)
# 显示结果
cv2.imshow("Original Image", image)
cv2.imshow("Truncated Binary Image", binary_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

OTSU+阈值法二值化是一种基于Otsu算法的自动阈值选择方法,常用于图像分割和预处理。
原理: OTSU算法(大津法)通过计算图像的直方图,自动寻找一个阈值,使得图像中前景和背景的类间方差最大。类间方差越大,说明两类之间的差异越明显,分割效果越好。
实现步骤: - 读取图像:将图像读取为灰度图像。 - 计算直方图:统计每个灰度级出现的像素数量。 - 遍历所有可能的阈值:计算每个阈值对应的前景和背景的均值以及类间方差。 - 选择类间方差最大的阈值:该阈值即为最佳分割阈值。 - 使用计算得到的阈值进行二值化:将图像中的像素值分为0或255。
以下是一个使用Python和OpenCV实现OTSU+阈值法二值化的简单代码示例。
import cv2
import numpy as np
def otsu_threshold(img):
"""
计算Otsu阈值并进行二值化
参数:
img:输入的灰度图像
返回:
阈值,二值化后的图像
"""
# 计算图像直方图
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_norm = hist.ravel() / hist.sum()
# 初始化变量
max_var = 0
threshold = 0
# 遍历所有可能的阈值
for i in range(1, 256):
# 计算前景和背景像素占比
omega0 = np.sum(hist_norm[:i])
omega1 = np.sum(hist_norm[i:])
# 计算前景和背景像素均值
mu0 = np.sum(hist_norm[:i] * np.arange(i)) / omega0 if omega0 > 0 else 0
mu1 = np.sum(hist_norm[i:] * np.arange(i, 256)) / omega1 if omega1 > 0 else 0
# 计算类间方差
var = omega0 * omega1 * (mu0 - mu1)**2
# 更新最大类间方差和对应的阈值
if var > max_var:
max_var = var
threshold = i
# 使用计算得到的阈值进行二值化
_, binary_img = cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY)
return threshold, binary_img
# 读取图像并转换为灰度图
img = cv2.imread('./images/png/test01.png', cv2.IMREAD_GRAYSCALE)
# 计算Otsu阈值并进行二值化
threshold, binary_img = otsu_threshold(img)
# 显示结果
print(f'Otsu阈值:{threshold}')
cv2.imshow('Original Image', img)
cv2.imshow('Binary Image', binary_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
也可以直接使用OpenCV的cv2.threshold函数实现OTSU二值化,设置cv2.THRESH_OTSU标志位即可,代码实现如下:
import cv2
# 读取灰度图像
img = cv2.imread('./images/jpg/bird01.jpg', 0)
# 使用OTSU二值化
ret, otsu_img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print("best_threshold:", ret)
# 显示结果
cv2.imshow("Original Image", img)
cv2.imshow("OTSU Binary Image", otsu_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
