圖像的二值化,就是講圖像變成黑或者白兩種顏色。在很多場合,對圖像進行二值化,可以忽略圖像的顏色信息,背景信息,保留更加重要的形態(tài)信息。并且圖像二值化處理之后,圖像的信息量大為減少,處理起來也更加方便。
最簡單的圖像二值化的方法。就是先將圖像轉化為灰度圖,然后再設置一個閾值。小于這個閾值的像素點調(diào)整成0,而大于這個閾值的像素點調(diào)整成255。
在Python3下,用PIL做圖像處理,代碼如下:
from PIL import Image
def binarizing(image, threshold=200):
pixdata = image.load()
w, h = image.size
for y in range(h):
for x in range(w):
if pixdata[x, y] < threshold:
pixdata[x, y] = 0
else:
pixdata[x, y] = 255
return image
當然,使用的時候,圖像首先要轉成灰度圖
im = Image.open('1.png').convert('L')
這里的默認閾值是200。這樣對處理已經(jīng)基本是黑白的情況(例如黑白的電子書)效果比較好。但是如果要處理自帶底色的(例如火車票)等,直接使用默認閾值就可能使得整張圖幾乎變成黑色或者白色。例如下圖,圖一的閾值取在160左右效果比較好,而如果取200,則圖像會變成純黑色。如果我們要處理更多種類的情況,默認閾值法根本不適用。

不同圖的灰度直方圖
我們看到,文字圖片和背景通常會出現(xiàn)兩個駝峰。因此,我們需要有一個算法找到這兩個駝峰中間的最佳的閾值。otsu法(最大類間方差法,有時也稱之為大津算法)就是目前比較好的確定閾值的算法。
otsu算法的原理非常簡單。首先,我們把圖像分成大于閾值和小于閾值的兩個部分,也就是前景與背景兩個部分。我們可以計算這兩個部分的類間方差。類間方差越大,就說明兩個部分直接的灰度差距越大。將0~255這256個閾值都試用一遍,找到類間方差最大的值,通常就是我們要找的最佳閾值了。
代碼如下:
import numpy as np
def otsu_threshold(im):
width, height = im.size
pixel_counts = np.zeros(256)
for x in range(width):
for y in range(height):
pixel = im.getpixel((x, y))
pixel_counts[pixel] = pixel_counts[pixel] + 1
# 得到圖片的以0-255索引的像素值個數(shù)列表
s_max = (0, -10)
for threshold in range(256):
# 遍歷所有閾值,根據(jù)公式挑選出最好的
# 更新
w_0 = sum(pixel_counts[:threshold]) # 得到閾值以下像素個數(shù)
w_1 = sum(pixel_counts[threshold:]) # 得到閾值以上像素個數(shù)
# 得到閾值下所有像素的平均灰度
u_0 = sum([i * pixel_counts[i] for i in range(0, threshold)]) / w_0 if w_0 > 0 else 0
# 得到閾值上所有像素的平均灰度
u_1 = sum([i * pixel_counts[i] for i in range(threshold, 256)]) / w_1 if w_1 > 0 else 0
# 總平均灰度
u = w_0 * u_0 + w_1 * u_1
# 類間方差
g = w_0 * (u_0 - u) * (u_0 - u) + w_1 * (u_1 - u) * (u_1 - u)
# 類間方差等價公式
# g = w_0 * w_1 * (u_0 * u_1) * (u_0 * u_1)
# 取最大的
if g > s_max[1]:
s_max = (threshold, g)
return s_max[0]
效果還是不錯的。(把個人信息刪去了)

火車票二值化