近期研究了一下以圖搜圖這個炫酷的東西。百度和谷歌都有提供以圖搜圖的功能,有興趣可以找一下。當然,不是很深入。深入的話,得運用到深度學習這貨。Python深度學習當然不在話下。
這個功能最核心的東西就是怎么讓電腦識別圖片。
這個問題也是困擾了我,在偶然的機會,看到哈希感知算法。這個分兩種,一種是基本的均值哈希感知算法(dHash),一種是余弦變換哈希感知算法(pHash)。dHash是我自己命名的,為了和pHash區分。這里兩種方法,我都用Python實現了^_^
哈希感知算法基本原理如下:
1、把圖片轉成一個可識別的字符串,這個字符串也叫哈希值
2、和其他圖片匹配字符串
算法不是耍耍嘴皮子就行了,重點是怎么把圖片變成一個可識別的字符串。(鄙視網上那些抄來抄去的文章,連字都一模一樣)拿一張圖片舉例。
首先,把這個圖片縮小到8x8大小,並改成灰度模式。這樣是為了模糊化處理圖片,並減少計算量。
8x8的圖片太小了,放大圖片給大家看一下。
8x8大小的圖片就是有64個像素值。計算這64個像素的平均值,進一步降噪處理。
像素值=[
247, 245, 250, 253, 251, 244, 240, 240,
247, 253, 228, 208, 213, 243, 247, 241,
252, 226, 97, 80, 88, 116, 231, 247,
255, 172, 79, 65, 51, 58, 191, 255,
255, 168, 71, 60, 53, 69, 205, 255,
255, 211, 65, 58, 56, 104, 244, 252,
248, 253, 119, 42, 53, 181, 252, 243,
244, 240, 218, 175, 185, 230, 242, 244]
平均值=185.359375
得到這個平均值之后,再和每個像素對比。像素值大於平均值的標記成1,小於或等於平均值的標記成0。組成64個數字的字符串(看起來也是一串二進制的)。
降噪結果=[
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 1, 1,
1, 0, 0, 0, 0, 0, 1, 1,
1, 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 0, 1, 1,
1, 1, 1, 0, 0, 1, 1, 1]
64位字符串 = '1111111111111111110000111000001110000011110000111100001111100111'
由於64位太長,比較起來也麻煩。每4個字符為1組,由2進制轉成16進制。這樣就剩下一個長度為16的字符串。這個字符串也就是這個圖片可識別的哈希值。
哈希值 = 'ffffc38383c3c3e7'
Python代碼如下:
#coding:utf-8 #!usr/bin/python2.7 """ author:Haddy Yang (楊仕航) data:2016-04-01(代碼是4月1號寫的,中間太忙了,現在才發布出來) description:get image's hash value environ: python2.7 and python2.6 """ #yum install python-imaging (安裝PIL圖像庫,python2.6) #PIL官方提供的Python2.6可以使用,2.7不行。 #Python2.7可以用pillow庫 #import Image #python2.6 PIL from PIL import Image #python2.7 pillow import sys def get_hash(image_path): """get image hash string""" im = Image.open(image_path) #antialias 抗鋸齒 #convert 轉換 L 代表灰度 im = im.resize((8, 8), Image.ANTIALIAS).convert('L') #avg:像素的平均值 avg=sum(list(im.getdata()))/64.0 #avg和每個像素比較,得到長度64的字符串 str=''.join(map(lambda i: '0' if i<avg else '1', im.getdata())) #str切割,每4個字符一組,轉成16進制字符 return ''.join(map(lambda x:'%x' % int(str[x:x+4],2), range(0,64,4))) if __name__ == '__main__': if len(sys.argv)!=2: print '#sample: python imghash.py filename' else: print get_hash(sys.argv[1])
看看其他圖片的哈希值:
b.jpg :fff3fbe1e181c3ff
c.jpg :ffffdf818080d9f9
d.jpg :ffffcfc7c7c3c7ef
這3張圖片的哈希值分別和a.jpg(舉例的那張圖片)的哈希值對比。對比方法用漢明距離:相同位置上的字符不同的個數。例如a.jpg和b.jpg對比
有11個位置的字符不一樣,則漢明距離是11。漢明距離越小就說明圖片越相識。超過10就說明圖片很不一樣。
a.jpg和c.jpg的漢明距離是8;
a.jpg和d.jpg的漢明距離是7。
說明在這3張圖片中,d.jpg和a.jpg最相似。
大致算法就是這樣,漢明距離的代碼我沒給出,這個比較簡單。一般都是在數據庫里面進行計算,得到比較小的那些圖片感知哈希值。
當然,實際應用中很少用這種算法,因為這種算法比較敏感。同一張圖片旋轉一定角度或者變形一下,那個哈希值差別就很大。不過,它的計算速度是最快的,通常可以用於查找縮略圖。
下篇博文講一下,余弦哈希感知算法的Python實現。這種算法在實際運用中會比較多。 《以圖搜圖(二):Python實現pHash算法》
(原創博文,轉載請注明來自 yshblog.com)