基于numpy和opencv的数字图像处理(二):图像二值化

数字图像处理


Author:louwill

Machine Learning Lab

     本系列重点理一下区别于目前深度学习之外的传统数字图像处理基础。主要参考教材为冈萨雷斯的《数字图像处理》第四版和yoyo的Gasyori100knock仓库。以案例和代码实现为主,主要实现工具为Python的numpy和opencv库。numpy用来作为原理实现,opencv作为应用实现。

     本节主要讲一下图像二值化主要原理和大津法,对基于大津法的图像阈值分割做一个简单了解。

二值化

     在机器学习特征处理中,我们经常会用到二值化方法。顾名思义,图像二值化就是将图像仅使用黑和白两种颜色来进行表示的方法。我们来看具体的图像二值化例子。基于numpy的处理方法如下:

     原始图像:

img = cv2.imread('./harden.png')

基于numpy和opencv的数字图像处理(二):图像二值化_第1张图片

     灰度化和二值化处理:

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);

基于numpy和opencv的数字图像处理(二):图像二值化_第2张图片

     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);

基于numpy和opencv的数字图像处理(二):图像二值化_第3张图片

     由于基于阈值的图像二值化方法较为直观、实现简单且计算速度快,所以阈值化方法在传统的图像分割中占有重要地位。

大津法

     基于阈值的图像二值化方法的一个关键在于如何选定阈值,这可以视作为一个全局寻优问题。大津法也即otsu法,是由日本学者大津展之于1979年提出的一种图像阈值分割方法。该方法将阈值划分视作是一个统计决策问题,其目的在于将像素分配给两组或多组的过程中使得引入的平均误差最小。大津法给出的方案是使得两组之间的类间方差最大时的阈值为最优阈值。所以大津法也叫最大类间方差法。

     先来看一下大津法的基本原理。假设划分阈值为t,小于阈值t的像素区域为0,大于阈值t的像素区域为1。w0和w1分别为被阈值t分开的两类像素占总像素的比值。M0和M1分别为这两个类像素均值,{S_0}^2和{S_1}^2分别为这两个类中像素值的方差。

     类内方差和类间方差为:

基于numpy和opencv的数字图像处理(二):图像二值化_第4张图片

     图像整体方差为:

基于numpy和opencv的数字图像处理(二):图像二值化_第5张图片

     图像分离度可定义为:

基于numpy和opencv的数字图像处理(二):图像二值化_第6张图片

     最大化图像分离度即最大化{S_b}^2。所以使得:

基于numpy和opencv的数字图像处理(二):图像二值化_第7张图片

最大化即可。

     来看具体实例,利用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

基于numpy和opencv的数字图像处理(二):图像二值化_第8张图片

     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);

     效果如下:

基于numpy和opencv的数字图像处理(二):图像二值化_第9张图片

     大津法作为一种寻找最佳全局阈值处理的方法,是基于阈值化的图像分割的代表算法。其优点就是快速高效,当目标物体和背景像素灰度分布差异较为明显时,大津法可作为一种较好的图像分割方法。但其缺点也很明显,大津法只能针对单一目标进行二值化分割。

参考资料:

冈萨雷斯 数字图像处理 第四版

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的数字图像处理(一):通道替换与灰度化


一个算法工程师的成长之路

长按二维码.关注机器学习实验室

你可能感兴趣的:(基于numpy和opencv的数字图像处理(二):图像二值化)