数字图像处理
Author:louwill
Machine Learning Lab
本系列重点理一下区别于目前深度学习之外的传统数字图像处理基础。主要参考教材为冈萨雷斯的《数字图像处理》第四版和yoyo的Gasyori100knock仓库。以案例和代码实现为主,主要实现工具为Python的numpy和opencv库。numpy用来作为原理实现,opencv作为应用实现。
本节主要讲一下图像二值化主要原理和大津法,对基于大津法的图像阈值分割做一个简单了解。
二值化
在机器学习特征处理中,我们经常会用到二值化方法。顾名思义,图像二值化就是将图像仅使用黑和白两种颜色来进行表示的方法。我们来看具体的图像二值化例子。基于numpy的处理方法如下:
原始图像:
img = cv2.imread('./harden.png')
灰度化和二值化处理:
img = cv2.imread('./harden.png')
# 灰度化
y = 0.2126*img[:,:,2] + 0.7152*img[:,:,1] + 0.0722*img[:,:,0]
img[:,:,0] = y
img[:,:,1] = y
img[:,:,2] = y
# 以128为阈值进行二值化
y[y>=128] = 255
y[y<128] = 0
img[:,:,0] = y
img[:,:,1] = y
img[:,:,2] = y
plt.imshow(img);
opencv也提供了各类阈值化方法的调用函数。基于全局阈值的实现方式如下:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('harden.png', 0)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
ret, thresh1 = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)
plt.imshow(thresh1);
由于基于阈值的图像二值化方法较为直观、实现简单且计算速度快,所以阈值化方法在传统的图像分割中占有重要地位。
大津法
基于阈值的图像二值化方法的一个关键在于如何选定阈值,这可以视作为一个全局寻优问题。大津法也即otsu法,是由日本学者大津展之于1979年提出的一种图像阈值分割方法。该方法将阈值划分视作是一个统计决策问题,其目的在于将像素分配给两组或多组的过程中使得引入的平均误差最小。大津法给出的方案是使得两组之间的类间方差最大时的阈值为最优阈值。所以大津法也叫最大类间方差法。
先来看一下大津法的基本原理。假设划分阈值为t,小于阈值t的像素区域为0,大于阈值t的像素区域为1。w0和w1分别为被阈值t分开的两类像素占总像素的比值。M0和M1分别为这两个类像素均值,{S_0}^2和{S_1}^2分别为这两个类中像素值的方差。
类内方差和类间方差为:
图像整体方差为:
图像分离度可定义为:
最大化图像分离度即最大化{S_b}^2。所以使得:
最大化即可。
来看具体实例,利用numpy编写大津算法来进行阈值寻优。
img = cv2.imread('./harden.png')
img = img.astype(np.float)
H, W, C = img.shape
# 灰度化
out = 0.2126*img[:,:,2] + 0.7152*img[:,:,1] + 0.0722*img[:,:,0]
out = out.astype(np.uint8)
# 初始化类间方差和最佳阈值
max_sigma = 0
max_t = 0
# 遍历迭代
for _t in range(1, 255):
# 小于阈值t的类v0
v0 = out[np.where(out<_t)]
# 计算v0均值
M0 = np.mean(v0) if len(v0) > 0 else 0.
# v0类像素占比
w0 = len(v0)/(H*W)
# 大于阈值t的类v1
v1 = out[np.where(out>=_t)]
# 计算v1均值
M1 = np.mean(v1) if len(v1) > 0 else 0.
# v1类像素占比
w1 = len(v1)/(H*W)
# 类间方差
Sb2 = w0*w1*((M0-M1)**2)
# 寻优
if Sb2 > max_sigma:
max_sigma = Sb2
max_t = _t
# 打印最佳阈值
print(max_t)
通过大津法寻优可知示例图片的最佳划分阈值为97。然后以97为阈值进行二值化。效果如下所示。
out[out>=max_t] = 255
out[out
opencv中直接提供了大津法的实现函数:
img = cv2.imread('./harden.png')
# 灰度化
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 大津法阈值化处理
ret, th = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
plt.imshow(th);
效果如下:
大津法作为一种寻找最佳全局阈值处理的方法,是基于阈值化的图像分割的代表算法。其优点就是快速高效,当目标物体和背景像素灰度分布差异较为明显时,大津法可作为一种较好的图像分割方法。但其缺点也很明显,大津法只能针对单一目标进行二值化分割。
参考资料:
冈萨雷斯 数字图像处理 第四版
https://github.com/yoyoyo-yo/Gasyori100knock
https://zh.wikipedia.org/wiki/%E5%A4%A7%E6%B4%A5%E7%AE%97%E6%B3%95
往期精彩:
2019,算法工程师第一年
基于numpy和opencv的数字图像处理(一):通道替换与灰度化
一个算法工程师的成长之路
长按二维码.关注机器学习实验室