圖像的二值化,就是講圖像變成黑或者白兩種顏色。在很多場(chǎng)合,對(duì)圖像進(jìn)行二值化,可以忽略圖像的顏色信息,背景信息,保留更加重要的形態(tài)信息。并且圖像二值化處理之后,圖像的信息量大為減少,處理起來(lái)也更加方便。
最簡(jiǎn)單的圖像二值化的方法。就是先將圖像轉(zhuǎn)化為灰度圖,然后再設(shè)置一個(gè)閾值。小于這個(gè)閾值的像素點(diǎn)調(diào)整成0,而大于這個(gè)閾值的像素點(diǎn)調(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
當(dāng)然,使用的時(shí)候,圖像首先要轉(zhuǎn)成灰度圖
im = Image.open('1.png').convert('L')
這里的默認(rèn)閾值是200。這樣對(duì)處理已經(jīng)基本是黑白的情況(例如黑白的電子書(shū))效果比較好。但是如果要處理自帶底色的(例如火車票)等,直接使用默認(rèn)閾值就可能使得整張圖幾乎變成黑色或者白色。例如下圖,圖一的閾值取在160左右效果比較好,而如果取200,則圖像會(huì)變成純黑色。如果我們要處理更多種類的情況,默認(rèn)閾值法根本不適用。

我們看到,文字圖片和背景通常會(huì)出現(xiàn)兩個(gè)駝峰。因此,我們需要有一個(gè)算法找到這兩個(gè)駝峰中間的最佳的閾值。otsu法(最大類間方差法,有時(shí)也稱之為大津算法)就是目前比較好的確定閾值的算法。
otsu算法的原理非常簡(jiǎn)單。首先,我們把圖像分成大于閾值和小于閾值的兩個(gè)部分,也就是前景與背景兩個(gè)部分。我們可以計(jì)算這兩個(gè)部分的類間方差。類間方差越大,就說(shuō)明兩個(gè)部分直接的灰度差距越大。將0~255這256個(gè)閾值都試用一遍,找到類間方差最大的值,通常就是我們要找的最佳閾值了。
代碼如下:
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索引的像素值個(gè)數(shù)列表
s_max = (0, -10)
for threshold in range(256):
# 遍歷所有閾值,根據(jù)公式挑選出最好的
# 更新
w_0 = sum(pixel_counts[:threshold]) # 得到閾值以下像素個(gè)數(shù)
w_1 = sum(pixel_counts[threshold:]) # 得到閾值以上像素個(gè)數(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)
# 類間方差等價(jià)公式
# 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]
效果還是不錯(cuò)的。(把個(gè)人信息刪去了)
