人工智能笔记 / 图像二值化

人工智能笔记 / 图像二值化

二值化 + Otsu代码实现

人工智能笔记 / 图像二值化

常用颜色格式: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_0p_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

循环结束后即可找到最好的阈值。

图像示例

原图

处理后

LICENSED UNDER CC BY-NC-SA 4.0
Comment