人工智能笔记 / 图像二值化
常用颜色格式:RGB
为了在进行机器学习等任务时减少数据量,加快处理速度,我们需要对图像类的数据进行二值化。
特征提取是一个不可逆,阶段性的过程,所以在提取中要尽可能的保留真正有用的部分。
二值化原理
人为设置阈值法
由于二值化的图像只有两种颜色:黑和白。则我们可以设置一个阈值:当大于这个阈值时,将像素视为黑色,否则则视为白色。
但这种方法也有缺点:对于一张整体偏亮的颜色,像素点的RGB值可能会都低于阈值,导致出现大面积纯白的图像,对于整体偏暗的图像也同理。
人为设置阈值法优化:平均值法
为了优化人为设置阈值法中的缺点,我们可以对整张图片的RGB值取平均值作为阈值。
但这种方法也有缺点,例如局部颜色过暗或过亮。
自适应阈值法
自适应阈值法的具体实现是:将一个大图片分割为多个小区域,再对每个小区域分别求平均值或中值作为阈值进行二值化。
缺点是如果分割的时候正好分割到了物体,可能会导致物体颜色不均匀。
Otsu's 方法
Otsu's是更为复杂的一种二值化取阈值方法。
首先对于一张图片,计算其灰度直方图,图像通常成双峰图像,且双峰间有一些距离。
归一化
接下来对颜色进行归一化,将255或更大的数值全部缩小到[0,1]的范围
计算公式:
x' = \frac{x - min(x)}{max(x) - min(x)}
其中x是原始数据,max(x)和min(x)分别是所有数据中的最大和最小值,x'是归一化后的数据。
类间方差
接下来对于每一个可能的阈值,计算类间方差。
类间方差是指二值化后的两个类(即阈值以上和以下的像素)的平均值之间的方差。
给定一个灰度图像,记为 h(r_k), k=0,1,2,...,L-1,其中 r_k为像素值, L-1为灰度级别,(对于8位图像, L=256),设阈值为 t,则像素值小于阈值的类记为 C_0,像素值大于阈值的类记为 C_1
首先计算两个类的概率 p_0(t)和 p_1(t):
p_0(t) = \sum\limits^{t-1}_{i=0}h(r_i)
p_1(t) = \sum\limits^{L-1}_{i=t}h(r_i)
然后计算两个类的平均灰度 \mu_0(t)和 \mu_1(t):
\mu_0(t) = \sum\limits^{t-1}_{i=0}\frac{i\cdot h(r_i)}{p_0(t)}
\mu_1(t) = \sum\limits^{L-1}_{i=t}\frac{i\cdot h(r_i)}{p_1(t)}
计算总平均灰度 \mu_{T}:
\mu_{T} = \sum\limits^{L-1}_{i=0}i \cdot h(r_i)
类间方差 \sigma^{2}_{B}(t)定义为:
\sigma^{2}_{B}(t) = p_0(t) \cdot (\mu_0(t) - \mu_{T})^{2} + p_1(t) \cdot (\mu_1(t) - \mu_{T})^{2}
Otsu's的目标就是找到一个阈值 t,使得类间方差 \sigma^{2}_{B}(t)最大(代表黑白分化最明显)
缺点:对于高分辨率的图像计算量过大。
代码实现
使用Python
import numpy as np
image = XXX // 这里的image是一个np array,存的是RGB的图像
先声明最好的类间均值 \sigma^{2}_{B}和阈值 t:
best_sigma_B = 0
best_threshold = 0
计算灰度直方图:
histogram = np.bincount(image.ravel(), minlength=256)
bincount
方法的功能是统计array内从0直到最大数字出现的个数,minlength代表颜色范围自少是 [0,255]
ravel
是将多维数组平铺成一维数组(有点类似扁平化),这里是为了把每个像素的RGB值数组拆开
histogram = histogram / np.sum(histogram)
将灰度直方图的值域控制在 [0,1]
计算总平均灰度 \mu_T:
mu_T = np.sum([i * histogram[i] for i in range(256)])
接下来在[0,256)内遍历阈值 t,阈值为整数(for的代码略)
计算概率 p_0和 p_1:
p_0 = np.sum(histogram[:t])
p_1 = np.sum(histogram[t:])
计算两个类的平均灰度 \mu_0和 \mu_1:
mu_0 = np.sum([i * histogram[i] for i in range(t)])
mu_1 = np.sum([i * histogram[i] for i in range(t, 256)])
计算类间方差 \sigma^{2}_{B}:
sigma_B = p_0 * (mu_0 - mu_T) ** 2 + p_1 * (mu_1 - mu_T) ** 2
如果类间方差为最大,更新最好类间方差和阈值
if sigma_B > best_sigma_B:
best_sigma_B = sigma_B
best_threshold = t
循环结束后即可找到最好的阈值。
图像示例
原图
处理后