图像预处理-二值化

二值化,使得图像呈现明显的黑白效果,二值化一方面减少了数据维度,另一方面通过排除原图中噪声带来的干扰,可以凸显有效区域的轮廓结构。

目前,二值化的方法主要分为以下几种:

  • 全局阈值法(global binarization)
    • 固定阈值法
    • otsu法
  • 局部阈值法(local binarization)
  • 基于深度学习方法

全局阈值法

1.固定阈值方法

对于输入图形中的所有像素点统一使用一个固定阈值

g ( x , y ) = { 255 , if f(x, y) ≥ T 0 , else  g(x,y) = \begin{cases} 255, & \text{if } \text{f(x, y)} \geq \text{T}\\ 0, & \text{else } \end{cases} g(x,y)={255,0,if f(x, y)Telse 

T是超参数值,自己指定。

面临的一个问题是,很难为不同的输入图像确定最佳阈值

#!/bin/python
# fileUsing: use threshold value T to binary image

import cv2
from matplotlib import pyplot as plt

image = cv2.imread("img/2-1.png")
# 将输入图像转为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 绘制灰度图
plt.subplot(121), plt.imshow(gray, "gray")
plt.title("input image"), plt.xticks([]), plt.yticks([])

# 对灰度图使用 全局阈值 算法
h, w = gray.shape

T = 100  # set threshold value
for y in range(w):
    for x in range(h):
        if gray[x][y] < T:
            gray[x][y] = 0
        else:
            gray[x][y] = 255

# 绘制阈值图
plt.subplot(122), plt.imshow(gray, "gray")
plt.title("thread image"), plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

Otsu算法

Otsu算法也称为最大类间方差,是一种自适应的阈值确定方法。

基本思想如下:

将图像的像素分布图画出来,那么图像上应该有两个比较明显的波峰,即对应前景和背景。在这两个波峰之间肯定有一个谷,那么可以将分割阈值设在这里,从而对图像达到一个良好的分割效果。Ostu算法就是基于这样的思想去进行分割的,它是求出用这个阈值分割后的两个图像的类间方差,尽可能的让类间方差最大的那个像素值,即为分割阈值。

具体而言,将输入图像0-255分为L个灰度等级,n_i 表示灰度级为i的元素个数,像素总数N为N=n1+n2+n3+…+nL,。

  • 对于每个灰度等级,都去统计整个像素值中有多少属于等级的元素个数,比如将灰度值分为0-m个等级,对于0-m的每一个灰度值t,将它作为阈值将图像分割为灰度值为0t以及t+1m这两部分
  • 计算每一部分的所占比例w1,w2 ,每一部分的平均灰度值u1,u2 ,以及总的平均灰度值u
  • 计算他们的类间方差δ2=w1(u1−u)^2+w2(u2−u)^2=w1w2(u1−u2)^2
  • 取出类间方差最大时对应的阈值t,这就可以作为我们最终所取的阈值。

实现:

import cv2
import sys
from matplotlib import pyplot as plt

image = cv2.imread("img/2-1.png")
# 将输入图像转为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 绘制灰度图
plt.subplot(311), plt.imshow(gray, "gray")
plt.title("input image"), plt.xticks([]), plt.yticks([])
# 对灰度图使用 Ostu 算法
ret1, th1 = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)  # 有实现
cv2.imwrite('th1.jpg', th1)
# 绘制灰度直方图
plt.subplot(312), plt.hist(gray.ravel(), 256)
# 标注 Ostu 阈值所在直线
plt.axvline(x=ret1, color='red', label='otsu')
plt.legend(loc='upper right')
plt.title("Histogram"), plt.xticks([]), plt.yticks([])
# 绘制二值化图像
plt.subplot(313), plt.imshow(th1, "gray")
plt.title("output image"), plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

参考

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐