1. 程式人生 > >在Python中用小波分析影象的雜湊值

在Python中用小波分析影象的雜湊值

本文為數盟原創譯文,轉載請註明出處為數盟社群。

作者:DMITRY PETROV

過去的幾個週末,Kaggle的這個專案讓我玩得樂此不疲Avito Duplicate Ads Detection problem。這個機器學習的問題,除了結構化的資料集之外,還包括超過1000萬個影象。在這個專案的競爭中,許多玩家使用影象的雜湊值而不是優化模型建立過程中的實際影象。

我發現有趣的是 – 最形象雜湊的實施採用了標準的離散餘弦變換(CDT)。我曾經從事過多年的影象工作,我記得離散小波變換(DWT)可能會提供更好的結果的影象。我無法找到任何Python實現DWT基於影象的雜湊,所以我實現了一個並上傳到imagehash庫。這種變化在GitHub上的和新版本的包中實現。在本文中,我將簡明扼要的介紹它是如何工作的。

1. Imagehash Python庫

我發現的最簡單有效的庫是來自於約翰內斯布赫爾的imagehash庫。可以在庫中實現多種影象雜湊:aHash,pHash,dHash。所有三種方法的縮放影象轉換成灰度級8×8的影象首位。然後該庫執行用於每個64畫素的一些計算並分配一個二進位制的1或0的值。這些64bit值形成演算法的輸出。該bit計算方法是不同的:

aHash – 平均雜湊,對於每個畫素輸出1,如果該畫素是大於或等於平均值,否則為0。

pHash – 感知雜湊,不同於aHash,但首先它確實是離散餘弦變換和頻域的作品。

dHash – 梯度雜湊,計算每個畫素的差值,並與平均差異的差異進行比較。

* wHash – 小波雜湊,幾天前我把它新增到庫裡。它的工作原理在頻域中作為pHash但它使用DWT代替DCT變換。

您可以檢視本文的雜湊值的更詳細的說明。

下面這串程式碼展示瞭如何使用這個庫

import PIL

from PIL import Image

import imagehash

hash1 = imagehash.phash(Image.open(‘test1.jpg’))

print(hash1)

> d879f8f89b1bbf

hash2 = imagehash.phash(Image.open(‘test2.jpg’))

print(hash2)

> 99636ab4aecc4569

hash1 == hash2

> False

hash1 – hash2

42

從示例程式碼中的看出兩個影象絕對不是相同的。64個bit中有42個是不同的。類似的影象差異將達到6-8bit。

2.計算影象的雜湊值

對於普通的照片,基於頻率一樣pHash方法通常給出更好的結果,因為在頻域對影象變換像更穩定:

JPG壓縮

色彩模式更改或應用影象過濾器

大小縮放

甚至一些細微的影象編輯:裁剪影象的一部分,標誌著由水印影象,新增修改影象的文字。

例如,讓我們來看一看影象和相同影象的轉換版本。這將是一個非常受歡迎的Lenna影象。許多影象處理研究使用這張圖片。我還記得自我的學生時代起這幅畫非常有名,約10年以前,當我做一些影象研究的時候。

lenna

Lenna.png. Original image. Size 512×512.

讓我們在影象上的一些基本的轉換和比較雜湊值。首先,我們將推出尺寸變化從512×512到400×400畫素。然後我們將改變顏色的模式,然後壓縮為JPEG,作為最終步驟。

lenna1

Lenna1.jpg. Color schema and image size were changed. JPG compressed. Size 400×400

import PIL

from PIL import Image

import imagehash

lenna = PIL.Image.open(‘lenna.png’)

lenna1 = PIL.Image.open(‘lenna1.jpg’)

h = imagehash.phash(lenna)

h1 = imagehash.phash(lenna1)

h-h1

> 0

哈…不錯!即使經過壓縮,調整大小和顏色變化的影象中沒有差異雜湊值。

讓我們將更多的轉換到lenna1.jpg影象(不是原單):

僅取畫面的中央部

新增文字

再壓縮

lenna2

Lenna2.jpg. More image transformations. Size 317×360

我分享所有的三張圖片:

lenna.png,lenna1.JPG,lenna2.jpg。

lenna2 = PIL.Image.open(‘lenna2.jpg’)

h2 = imagehash.phash(lenna2)

h – h2

> 20

(h – h2)/len(h.hash)**2

> 0.3125

好吧。現在我們可以看到散差為20,即每雜湊位31.2%。第二個指標是要好得多,因為雜湊大小的變化不同的雜湊值。

aHash帶來不同的結果。即使lenna1.jpg的簡單改造顯示1.6%的雜湊差異。更明顯的lenna2.jpg給出29.7%的差異。

a = imagehash.average_hash(lenna)

a1 = imagehash.average_hash(lenna1)

a2 = imagehash.average_hash(lenna2)

a – a1

(a – a1)/len(a.hash)**2

> 0.015625

(a – a2)/len(a.hash)**2

> 0.296875

3.小波雜湊

離散小波變換(DWT)是頻表示的另一種形式。流行的DCT和傅立葉變換使用餘弦函式作為基礎的一組罪過\:罪(x)時,罪(2×),罪(3倍),等等。與此相反,DWT使用一個單一的功能作為基礎,但在不同的形式:縮放和移動。基礎功能是可以改變的,這就是為什麼我們可以有Haar小波,Daubechie-4小波等,這尺度效應給我們很大“時頻表示”的時候,低頻部分類似於原始訊號。

這裡有一個極好的為小波而備Python庫 – pywt。我用這個庫來實現的imagehash庫whash()方法。預設情況下whash()計算用哈爾變換8×8的雜湊值。另外,該方法刪除最低哈爾頻率LL(最大)。最低頻率由來自僅一個數據點/畫素,這點代表了影象的對比度,而不是對雜湊如此有用。

wHash Python程式碼如下:

w = imagehash.whash(lenna)

w1 = imagehash.whash(lenna1)

w2 = imagehash.whash(lenna2)

(w – w1)/len(w.hash)**2

> 0.03125

(w – w2)/len(w.hash)**2

> 0.28125

4.驗證

為了使結果更清晰,讓我們將影象與原始影象進行比較。預期雜湊差應為50%。這裡是另一種比較標準影象 – barbara.jpg。讓我們來計算使用所有雜湊萊娜圖和芭芭拉之間的雜湊差異。程式碼如下:

barbara

Barbara.jpg

barb = PIL.Image.open(‘barbara.jpg’)

w_b = imagehash.whash(barb)

h_b = imagehash.phash(barb)

a_b = imagehash.average_hash(barb)

(a – a_b)/len(a.hash)**2

> 0.5

(h – h_b)/len(w.hash)**2

> 0.53125

(w – w_b)/len(w.hash)**2

> 0.4375

所有結果的列表:

aHash pHash wHash
lenna vs. lenna1 1.6% 0% 3.1%
lenna vs. lenna2 29.7% 31.3% 28.1%
lenna vs.barbara 50% 53.1% 43.8%

5.已知問題

當處理較大數目的小影象時我發現一個問題。pywt似乎有記憶體洩漏。這個問題已經github上提出了。我會盡力與pywt創作者聯絡有關問題。

通過與50K〜影象目錄緩解這個問題我剛才分割影象的每個並重新執行處理為每個目錄分別。

結論

很難說哪一種方法提供了更好的結果。這取決於你的應用程式,你應該專注於般精準\召回或AUC您的應用程式或機器學習模型度量。對於我Kaggle得分whash()+帶來了0.04%的AUC指標,除了我目前的〜92.9%的結果。

它看起來並不是一種巨大的差異。但是,我們應該記住,在建模程式碼中,我們通過一個字母的變化來自phash()來實現這whash()。我很高興能有更多的先進的分析工具,我希望這種方法將是一個很好的補充您的分析工具箱。此外,我認為,wHash具有由方法引數進行調優的巨大潛力。

請分享你在使用本庫的經驗、任何意見、建議、程式碼改進和修正,當然還有讚賞。

原文連結:https://fullstackml.com/2016/07/02/wavelet-image-hash-in-python/