1. 程式人生 > 程式設計 >影象處理庫 pillow應用-驗證碼去噪

影象處理庫 pillow應用-驗證碼去噪

前面我們學習了 Python 的影象處理庫 PIL,學會了一些相關的影象處理方法,好多人心裡會問:有什麼用呢?這一節我們就拿實際的例子來回答大家。

識別驗證碼的原理

現在大多數網站登入不再是簡單地輸入使用者名稱密碼了,一般都伴隨著此二者之外的驗證手段,目的是阻止一些居心不良的行為。而圖片驗證碼是其中一種比較常用的手段。所謂道高一尺魔高一丈,在 IT 行業中,對於這種安全防守,肯定會有針對性地破解勢力。對於圖片驗證碼的識別破解,目前已經有了很多成熟的方法。我想大概是從自動搶火車票興起之後快速發展而來的吧。

首先我們來看一張未處理的驗證碼圖片:

image-vc.png

想要識別驗證碼,我們需要有一套圖片識別演演算法(這個目前已經有成熟的應用,大家可以自行搜尋),然後拿到足夠多的樣本去餵養它,讓它不斷地自我學習,不斷提升識別準確率。在餵養演演算法之前,我們首先要做的就是對原始圖片進行處理,一般包括的步驟是:

  • 將彩色圖片轉換成灰度圖
  • 將灰度圖二值化處理
  • 去除圖片噪點

經過這三步處理之後,一般圖片的驗證碼數字或者字母會比較明顯好辨別了。

下面我們以上面那張簡單的驗證碼圖片為例,來運用 Python 的 PIL 庫的方法對圖片進行去噪處理。

1. 彩色圖片轉換成灰度圖

什麼事灰度圖呢?灰度圖,也可以認為是黑白圖。我們知道彩色圖片是有不同的顏色的畫素組合到一起的,灰度圖可以類似的認為是由不同灰度值的畫素組合在一起後呈現出來的。

任何顏色都有紅、綠、藍三原色組成,假如原來某點的顏色為 RGB(R,G,B),那麼,我們可以通過下面幾種方法,將其轉換為灰度:

  • 1.浮點演演算法
Gray=R*0.3+G*0.59+B*0.11
複製程式碼
  • 2.整數方法
Gray=(R*30+G*59+B*11)/100
複製程式碼
  • 3.移位方法
Gray =(R*76+G*151+B*28)>>8
複製程式碼
  • 4.平均值法
Gray=(R+G+B)/3
複製程式碼
  • 5.僅取綠色
Gray=G
複製程式碼

通過上述任一種方法求得Gray後,將原來的RGB(R,G,B)中的R,B統一用Gray替換,形成新的顏色RGB(Gray,Gray,Gray),用它替換原來的RGB(R,B)就是灰度圖了。

我們用程式碼實現非常簡單:

from PIL import Image

# 開啟原始圖片
im = Image.open('vc.png'
) # 展示原始圖片 im.show() # 將原始圖片灰度化 grey_im = im.convert('L') # 展示灰度化圖片 grey_im.show() # 儲存灰度化圖片 grey_im.save('grey.png') 複製程式碼

執行上面程式碼後,我們可以看到轉換後的灰度圖了,如下所示:

image-grey.png

2. 將灰度圖片二值化

我們已經得到了灰度圖,接下來就是將灰度圖二值化。所謂二值化就是將灰度影象轉換成由黑白二色組成的影象。思路就是確定一個閾值,大於閾值的畫素表示為白色,小於閾值的畫素表示為黑色,以此將圖片的畫素(灰度值)劃分為兩部分:0和1,例如0代表黑色,1代表白色,然後我們就可以用一串0和1組成的數字來表示一張圖片。

from PIL import Image

# 二值處理
# 設定閾值threshold,畫素值小於閾值,取值0,畫素值大於閾值,取值1
# 閾值具體多少需要多次嘗試,不同閾值效果不一樣
def get_table(threshold=115):
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    return table

# 開啟灰度化圖片並進行二值處理
binary_im = Image.open('grey.png').point(get_table(120),"1")
# 展示二值化圖片
binary_im.show()
# 儲存二值化圖片
binary_im.save('binary.png')
複製程式碼

我們首先定義了一個二值處理的方法,該方法就是根據傳入的一個閾值,將0到256之間的數進行分類,大於這個閾值取1,小於閾值取0。然後我們使用 Image 的 point 方法,該方法針對傳入的函式對每一個畫素點進行操作。我們傳入二值處理方法,對每個畫素點進行二值化處理,將圖片轉換成二值圖片。

這裡的閾值是需要大家嘗試之後才能確定的,不同的圖片,在閾值不同時會出現不同的處理效果,大家需要用不同的閾值去處理,檢視處理之後的效果圖,找到比較合理的閾值。本例中使用的是120。

經過二值化處理之後,我們的圖片變成了下面這樣:

image-binary.png

3. 對圖片進行降噪處理

我們看二值化後的圖片,可以看到還有一些幹擾線,這些線條也會影響演演算法的識別準確率,所以我們需要想辦法去掉這些幹擾線。

降噪的方法有很多,主要難點是判斷哪些點是噪點。由於我們這張驗證碼圖片上的數字和字母的線條比干擾線的線條粗,因此我們認為字母和數字線條上的點周圍8個點範圍內黑色點的個數應該比干擾線上的點要多。因此我們這裡採用的思路是:

根據一個點 A 的 RGB 值,與周圍的8個點的 RBG 值比較,設定一個值 N(0 <N <8),當 A 的 RGB 值與周圍8個點的 RGB 相等數小於 N 時,此點為噪點。

對應的程式程式碼為:

from PIL import Image,ImageDraw


# 判斷噪點,如果確認是噪點,用該點的上面一個點的灰度進行替換
# 根據一個點A的RGB值,與周圍的8個點的RBG值比較,設定一個值 N(0 <N <8),當A的RGB值與周圍8個點的RGB相等數小於N時,此點為噪點
# x,y: 畫素點座標
# G: 影象二值化閥值
# N: 降噪率 0 < N <8
def get_pixel(image,x,y,N):
    # 獲取畫素值
    L = image.getpixel((x,y))

    # 與閾值比較
    if L > G:
        L = True
    else:
        L = False

    nearDots = 0

    if L == (image.getpixel((x - 1,y - 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x - 1,y)) > G):
        nearDots += 1
    if L == (image.getpixel((x - 1,y + 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x,y - 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x,y + 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x + 1,y - 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x + 1,y)) > G):
        nearDots += 1
    if L == (image.getpixel((x + 1,y + 1)) > G):
        nearDots += 1

    if nearDots < N:
        return image.getpixel((x,y - 1))
    else:
        return None


# 降噪
# Z: 降噪次數
def clear_noise(image,N,Z):
    draw = ImageDraw.Draw(image)

    for i in range(0,Z):
        for x in range(1,image.size[0] - 1):
            for y in range(1,image.size[1] - 1):
                color = get_pixel(image,N)
                if color is not None:
                    draw.point((x,y),color)

# 開啟二值化圖片
b_im = Image.open('binary.png')
# 將二值化圖片降噪
clear_noise(b_im,50,4,4)
# 展示降噪後的圖片
b_im.show()
# 儲存降噪後的圖片
b_im.save('result.png')
複製程式碼

在本例中,我們設定的二值化閾值為50,降噪率為4,降噪次數為4.這幾個引數也是不同的圖片會有不同的值,大家需要根據不同的圖片自行設定。

降噪後的圖片效果如下:

image-result.png

我們可以看到,經過上面的處理之後,圖片上的字母和數字已經很清晰了,再使用圖片識別演演算法,準確率應該會很高。

除了上面的步驟,我們還可以通過 PIL 庫的 ImageEnhance 和 ImageFilter 對圖片做其他處理,例如增加對比度、亮度、銳化等,最終的目的都是去除圖片的噪點,是圖片更容易辨別。大家如果感興趣的話可以試試看。

總結

本節我們通過使用 PIL 庫的一些簡單方法,對驗證碼圖片進行一系列的處理,從而達到降噪的目標。通過本節的學習,大家應該要學會學以致用,運用我們學習的一些理論知識去解決工作或生活中遇到的實際問題。 PIL 庫還有很多其他的方法都可以用來對圖片進行不同的處理,大家可以自己去探索。

參考

www.osgeo.cn/pillow/refe…