前面我們學(xué)習(xí)了 Python 的圖像處理庫(kù) PIL,學(xué)會(huì)了一些相關(guān)的圖像處理方法,好多人心里會(huì)問(wèn):有什么用呢?這一節(jié)我們就拿實(shí)際的例子來(lái)回答大家。 識(shí)別驗(yàn)證碼的原理現(xiàn)在大多數(shù)網(wǎng)站登錄不再是簡(jiǎn)單地輸入用戶名密碼了,一般都伴隨著此二者之外的驗(yàn)證手段,目的是阻止一些居心不良的行為。而圖片驗(yàn)證碼是其中一種比較常用的手段。所謂道高一尺魔高一丈,在 IT 行業(yè)中,對(duì)于這種安全防守,肯定會(huì)有針對(duì)性地破解勢(shì)力。對(duì)于圖片驗(yàn)證碼的識(shí)別破解,目前已經(jīng)有了很多成熟的方法。我想大概是從自動(dòng)搶火車票興起之后快速發(fā)展而來(lái)的吧。 首先我們來(lái)看一張未處理的驗(yàn)證碼圖片: 想要識(shí)別驗(yàn)證碼,我們需要有一套圖片識(shí)別算法(這個(gè)目前已經(jīng)有成熟的應(yīng)用,大家可以自行搜索),然后拿到足夠多的樣本去喂養(yǎng)它,讓它不斷地自我學(xué)習(xí),不斷提升識(shí)別準(zhǔn)確率。在喂養(yǎng)算法之前,我們首先要做的就是對(duì)原始圖片進(jìn)行處理,一般包括的步驟是:
經(jīng)過(guò)這三步處理之后,一般圖片的驗(yàn)證碼數(shù)字或者字母會(huì)比較明顯好辨別了。 下面我們以上面那張簡(jiǎn)單的驗(yàn)證碼圖片為例,來(lái)運(yùn)用 Python 的 PIL 庫(kù)的方法對(duì)圖片進(jìn)行去噪處理。 1. 彩色圖片轉(zhuǎn)換成灰度圖什么事灰度圖呢?灰度圖,也可以認(rèn)為是黑白圖。我們知道彩色圖片是有不同的顏色的像素組合到一起的,灰度圖可以類似的認(rèn)為是由不同灰度值的像素組合在一起后呈現(xiàn)出來(lái)的。 任何顏色都有紅、綠、藍(lán)三原色組成,假如原來(lái)某點(diǎn)的顏色為 RGB(R,G,B),那么,我們可以通過(guò)下面幾種方法,將其轉(zhuǎn)換為灰度:
Gray=R*0.3+G*0.59+B*0.11
Gray=(R*30+G*59+B*11)/100
Gray =(R*76+G*151+B*28)>>8
Gray=(R+G+B)/3
Gray=G 通過(guò)上述任一種方法求得Gray后,將原來(lái)的RGB(R,G,B)中的R,G,B統(tǒng)一用Gray替換,形成新的顏色RGB(Gray,Gray,Gray),用它替換原來(lái)的RGB(R,G,B)就是灰度圖了。 我們用代碼實(shí)現(xiàn)非常簡(jiǎn)單: from PIL import Image
# 打開(kāi)原始圖片 im = Image.open('vc.png') # 展示原始圖片 im.show()
# 將原始圖片灰度化 grey_im = im.convert('L') # 展示灰度化圖片 grey_im.show() # 保存灰度化圖片 grey_im.save('grey.png') 運(yùn)行上面代碼后,我們可以看到轉(zhuǎn)換后的灰度圖了,如下所示: 2. 將灰度圖片二值化我們已經(jīng)得到了灰度圖,接下來(lái)就是將灰度圖二值化。所謂二值化就是將灰度圖像轉(zhuǎn)換成由黑白二色組成的圖像。思路就是確定一個(gè)閾值,大于閾值的像素表示為白色,小于閾值的像素表示為黑色,以此將圖片的像素(灰度值)劃分為兩部分:0和1,例如0代表黑色,1代表白色,然后我們就可以用一串0和1組成的數(shù)字來(lái)表示一張圖片。 from PIL import Image
# 二值處理 # 設(shè)定閾值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
# 打開(kāi)灰度化圖片并進(jìn)行二值處理 binary_im = Image.open('grey.png').point(get_table(120), "1") # 展示二值化圖片 binary_im.show() # 保存二值化圖片 binary_im.save('binary.png') 我們首先定義了一個(gè)二值處理的方法,該方法就是根據(jù)傳入的一個(gè)閾值,將0到256之間的數(shù)進(jìn)行分類,大于這個(gè)閾值取1,小于閾值取0。然后我們使用 Image 的 point 方法,該方法針對(duì)傳入的函數(shù)對(duì)每一個(gè)像素點(diǎn)進(jìn)行操作。我們傳入二值處理方法,對(duì)每個(gè)像素點(diǎn)進(jìn)行二值化處理,將圖片轉(zhuǎn)換成二值圖片。 這里的閾值是需要大家嘗試之后才能確定的,不同的圖片,在閾值不同時(shí)會(huì)出現(xiàn)不同的處理效果,大家需要用不同的閾值去處理,查看處理之后的效果圖,找到比較合理的閾值。本例中使用的是120。 經(jīng)過(guò)二值化處理之后,我們的圖片變成了下面這樣: 3. 對(duì)圖片進(jìn)行降噪處理我們看二值化后的圖片,可以看到還有一些干擾線,這些線條也會(huì)影響算法的識(shí)別準(zhǔn)確率,所以我們需要想辦法去掉這些干擾線。 降噪的方法有很多,主要難點(diǎn)是判斷哪些點(diǎn)是噪點(diǎn)。由于我們這張驗(yàn)證碼圖片上的數(shù)字和字母的線條比干擾線的線條粗,因此我們認(rèn)為字母和數(shù)字線條上的點(diǎn)周圍8個(gè)點(diǎn)范圍內(nèi)黑色點(diǎn)的個(gè)數(shù)應(yīng)該比干擾線上的點(diǎn)要多。因此我們這里采用的思路是:
對(duì)應(yīng)的程序代碼為: from PIL import Image, ImageDraw
# 判斷噪點(diǎn),如果確認(rèn)是噪點(diǎn),用該點(diǎn)的上面一個(gè)點(diǎn)的灰度進(jìn)行替換 # 根據(jù)一個(gè)點(diǎn)A的RGB值,與周圍的8個(gè)點(diǎn)的RBG值比較,設(shè)定一個(gè)值 N(0 <N <8),當(dāng)A的RGB值與周圍8個(gè)點(diǎn)的RGB相等數(shù)小于N時(shí),此點(diǎn)為噪點(diǎn) # x, y: 像素點(diǎn)坐標(biāo) # G: 圖像二值化閥值 # N: 降噪率 0 < N <8 def get_pixel(image, x, y, G, 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: 降噪次數(shù) def clear_noise(image, G, 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, x, y, G, N) if color is not None: draw.point((x, y), color)
# 打開(kāi)二值化圖片 b_im = Image.open('binary.png') # 將二值化圖片降噪 clear_noise(b_im, 50, 4, 4) # 展示降噪后的圖片 b_im.show() # 保存降噪后的圖片 b_im.save('result.png') 在本例中,我們?cè)O(shè)置的二值化閾值為50,降噪率為4,降噪次數(shù)為4.這幾個(gè)參數(shù)也是不同的圖片會(huì)有不同的值,大家需要根據(jù)不同的圖片自行設(shè)定。 降噪后的圖片效果如下: 我們可以看到,經(jīng)過(guò)上面的處理之后,圖片上的字母和數(shù)字已經(jīng)很清晰了,再使用圖片識(shí)別算法,準(zhǔn)確率應(yīng)該會(huì)很高。 除了上面的步驟,我們還可以通過(guò) PIL 庫(kù)的 ImageEnhance 和 ImageFilter 對(duì)圖片做其他處理,例如增加對(duì)比度、亮度、銳化等,最終的目的都是去除圖片的噪點(diǎn),是圖片更容易辨別。大家如果感興趣的話可以試試看。 總結(jié)本節(jié)我們通過(guò)使用 PIL 庫(kù)的一些簡(jiǎn)單方法,對(duì)驗(yàn)證碼圖片進(jìn)行一系列的處理,從而達(dá)到降噪的目標(biāo)。通過(guò)本節(jié)的學(xué)習(xí),大家應(yīng)該要學(xué)會(huì)學(xué)以致用,運(yùn)用我們學(xué)習(xí)的一些理論知識(shí)去解決工作或生活中遇到的實(shí)際問(wèn)題。PIL 庫(kù)還有很多其他的方法都可以用來(lái)對(duì)圖片進(jìn)行不同的處理,大家可以自己去探索。
參考https://www./pillow/reference/ 系列文章 |
|
來(lái)自: Python技術(shù) > 《待分類》