最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

用Python實現(xiàn)通過哈希算法檢測圖片重復的教程

 更新時間:2015年04月02日 10:17:44   作者:Silviu Tantos  
這篇文章主要介紹了用Python實現(xiàn)通過哈希算法檢測圖片重復的教程,這個方法被Iconfinder用作防盜版技術,需要的朋友可以參考下

Iconfinder 是一個圖標搜索引擎,為設計師、開發(fā)者和其他創(chuàng)意工作者提供精美圖標,目前托管超過 34 萬枚圖標,是全球最大的付費圖標庫。用戶也可以在 Iconfinder 的交易板塊上傳出售原創(chuàng)作品。每個月都有成千上萬的圖標上傳到Iconfinder,同時也伴隨而來大量的盜版圖。Iconfinder 工程師 Silviu Tantos 在本文中提出一個新穎巧妙的圖像查重技術,以杜絕盜版。

我們將在未來幾周之內推出一個檢測上傳圖標是否重復的功能。例如,如果用戶下載了一個圖標然后又試圖通過上傳它來獲利(曾發(fā)生過類似案例),那么通過我們的方法,就可以檢測出該圖標是否已存在,并且標記該賬戶欺詐。在大量文件中檢測某文件是否已經存在的一個常用方法是,通過計算數據集中每一個文件的哈希值,并將該哈希值存儲在數組庫中。當想要查找某特定文件時,首先計算該文件哈希值,然后在數據庫中查找該哈希值。
選擇一個哈希算法

加密哈希算法是一個常用的哈希算法。類似MD5,SHA1,SHA256這種在任何一種語言都可以找到可調用的標準庫,它們對于簡單的用例非常有效。

例如,在Python中先導入hashlib模塊,然后調用函數就可以生成某一個字符串或者文件的哈希值。
 

>>> import hashlib
 
# Calculating the hash value of a string.
>>> hashlib.md5('The quick brown fox jumps over the lazy dog').hexdigest()
'9e107d9d372bb6826bd81d3542a419d6'
 
# Loading an image file into memory and calculating it's hash value.
>>> image_file = open('data/cat_grumpy_orig.png').read()
>>> hashlib.md5(image_file).hexdigest()
'3e1f6e9f2689d59b9ed28bcdab73455f'

這個算法對于未被篡改的上傳文件非常有效,如果輸入數據有細微變化,加密哈希算法都會導致雪崩效應,從而造成新文件的哈希值完全不同于原始文件哈希值。

比如下面這個例子,它在句子的結尾多加了一個句號。
 

# Original text.
>>> hashlib.md5('The quick brown fox jumps over the lazy dog').hexdigest()
'9e107d9d372bb6826bd81d3542a419d6'
 
# Slight modification of the text.
>>> hashlib.md5('The quick brown fox jumps over the lazy dog.').hexdigest()
'e4d909c290d0fb1ca068ffaddf22cbd0'

如果圖像背景色被改變,圖像被裁剪,旋轉或者某一個像素被修改,那么都無法在圖像哈希庫中匹配。可見傳統(tǒng)哈希算法并不具有實用性。正如你在上面例子中看到的,哈希值9 e107d9d372bb6826bd81d3542a419d6 和e4d909c290d0fb1ca068ffaddf22cbd0幾乎是不同的(除了幾個字符)。

例如,修改圖像中貓咪鼻子的顏色后,圖像的哈希值將改變。

 201542101201416.jpg (649×318)

# Load the original image into memory and calculate it's hash value.
>>> image_file = open('data/cat_grumpy_orig.png').read()
>>> hashlib.md5(image_file).hexdigest()
'3e1f6e9f2689d59b9ed28bcdab73455f'
 
# Load the modified image into memory and calculate it's hash value.
>>> image_file_modified = open('data/cat_grumpy_modif.png').read()
>>> hashlib.md5(image_file_modified).hexdigest()
'12d1b9409c3e8e0361c24beaee9c0ab1'

目前已有許多感知哈希算法,本文將要提出一個新的dhash(差異哈希)算法,該算法計算相鄰像素之間的亮度差異并確定相對梯度。對于以上的用例,感知哈希算法將非常有效。感知哈希算法從文件內容的各種特征中獲得一個能夠靈活分辨不同文件微小區(qū)別的多媒體文件指紋。

 
dHash

深入學習dHash算法前,先介紹一些基礎知識。一個彩色圖像是由RGB三原色組成,可以看成一個紅綠藍三原色的顏色集。比如利用用Python圖像庫(PIL)加載一個圖像,并打印像素值。

201542101238378.jpg (717×717)

Test image

>>> from PIL import Image
>>> test_image = Image.open('data/test_image.jpg')
 
# The image is an RGB image with a size of 8x8 pixels.
>>> print 'Image Mode: %s' % test_image.mode
Image Mode: RGB
>>> print 'Width: %s px, Height: %s px' % (test_image.size[0], test_image.size[1])
Width: 4 px, Height: 4 px
 
# Get the pixel values from the image and print them into rows based on
# the image's width.
>>> width, height = test_image.size
>>> pixels = list(test_image.getdata())
>>> for col in xrange(width):
...  print pixels[col:col+width]
...
[(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255)]
[(0, 0, 0), (212, 45, 45), (51, 92, 154), (130, 183, 47)]
[(206, 210, 198), (131, 78, 8), (131, 156, 180), (117, 155, 201)]
[(104, 133, 170), (215, 130, 20), (153, 155, 155), (104, 142, 191)]

現(xiàn)在我們回到dHash算法,該算法有四個步驟,本文詳細說明每一步并驗證它在原始圖像和修改后圖像的效果。前三個像素的紅綠藍顏色強度值分別為255,其余兩個顏色強度值分別為0,純黑色像素三原色為0,純白色像素三原色為255。其它顏色像素則是由不同強度三原色值組成的。

 
1.圖像灰度化

通過灰度化圖像,將像素值減少到一個發(fā)光強度值。例如,白色像素(255、255、255)成為255而黑色像素(0,0,0)強度值將成為0。

201542101324348.jpg (628×336)

2.將圖像縮小到一個常見大小

將圖像縮減到一個常見基礎尺寸,比如寬度大高度一個像素值的9*8像素大?。ǖ降谌侥憔湍苊靼诪槭裁词沁@個尺寸)。通過這個方法將圖像中的高頻和細節(jié)部分移除,從而獲得一個有72個強度值的樣本。由于調整或者拉伸圖像并不會改變它的哈希值,所以將所有圖像歸一化到該大小。

201542101403771.jpg (595×259)

3.比較鄰域像素

前兩步實現(xiàn)后得到一個強度值列表,比較該二進制值數組的每一行的相鄰像素。
 

>>> from PIL import Image
>>> img = Image.open('data/cat_grumpy_orig_after_step_2.png')
>>> width, height = img.size
>>> pixels = list(img.getdata())
>>> for col in xrange(width):
...  print pixels[col:col+width]
...
[254, 254, 255, 253, 248, 254, 255, 254, 255]
[254, 255, 253, 248, 254, 255, 254, 255, 255]
[253, 248, 254, 255, 254, 255, 255, 255, 222]
[248, 254, 255, 254, 255, 255, 255, 222, 184]
[254, 255, 254, 255, 255, 255, 222, 184, 177]
[255, 254, 255, 255, 255, 222, 184, 177, 184]
[254, 255, 255, 255, 222, 184, 177, 184, 225]
[255, 255, 255, 222, 184, 177, 184, 225, 255]

第一個值254和第二個254做比較,第二個值和第三個值比,以此類推,從而每行得到8個布爾值。
 

>>> difference = []
>>> for row in xrange(height):
...  for col in xrange(width):
...   if col != width:
...    difference.append(pixels[col+row] > pixels[(col+row)+1])
...
>>> for col in xrange(width-1):
...  print difference[col:col+(width-1)]
...
[False, False, True, True, False, False, True, False]
[False, True, True, False, False, True, False, False]
[True, True, False, False, True, False, False, False]
[True, False, False, True, False, False, False, True]
[False, False, True, False, False, False, True, True]
[False, True, False, False, False, True, True, False]
[True, False, False, False, True, True, False, False]
[False, False, False, True, True, False, False, True]

4.轉換為二值

為了方便哈希值存儲和使用,將8個布爾值轉換為16進制字符串。Ture變成1,而False變成0。
Python實現(xiàn)

下面是完整Python實現(xiàn)的完成算法:
 

def dhash(image, hash_size = 8):
  # Grayscale and shrink the image in one step.
  image = image.convert('L').resize(
    (hash_size + 1, hash_size),
    Image.ANTIALIAS,
  )
 
  pixels = list(image.getdata())
 
  # Compare adjacent pixels.
  difference = []
  for row in xrange(hash_size):
    for col in xrange(hash_size):
      pixel_left = image.getpixel((col, row))
      pixel_right = image.getpixel((col + 1, row))
      difference.append(pixel_left > pixel_right)
 
  # Convert the binary array to a hexadecimal string.
  decimal_value = 0
  hex_string = []
  for index, value in enumerate(difference):
    if value:
      decimal_value += 2**(index % 8)
    if (index % 8) == 7:
      hex_string.append(hex(decimal_value)[2:].rjust(2, '0'))
      decimal_value = 0
 
  return ''.join(hex_string)

最常見情況,圖片稍有不同,哈希值很可能是相同的,所以我們可以直接比較。
 

>>> from PIL import Image
>>> from utility import dhash, hamming_distance
>>> orig = Image.open('data/cat_grumpy_orig.png')
>>> modif = Image.open('data/cat_grumpy_modif.png')
>>> dhash(orig)
'4c8e3366c275650f'
>>> dhash(modif)
'4c8e3366c275650f'
>>> dhash(orig) == dhash(modif)
True

如果有一

個保存哈希值的SQL數據庫, 可以這樣簡單判斷哈希值“4 c8e3366c275650f ”是否存在:
 

SELECT pk, hash, file_path FROM image_hashes
  WHERE hash = '4c8e3366c275650f';

現(xiàn)在,對于一些有較大差別的圖像,它們的哈希值可能是不相同的,那么需要計算由一個字符串變成另一個字符串所需替換的最少字符數,即漢明距離。
維基百科上有一些計算兩個字符串之間的漢明距離的Python示例代碼。但是也可以直接基于MySQL數據庫上的計算和查詢來實現(xiàn)。
 

SELECT pk, hash, BIT_COUNT(
  CONV(hash, 16, 10) ^ CONV('4c8e3366c275650f', 16, 10)
) as hamming_distance
  FROM image_hashes
  HAVING hamming_distance < 4
  ORDER BY hamming_distance ASC;

對所查詢的值與數據庫中的哈希值進行異或操作,計數不同位數。由于BIT_COUNT只能操作整數,所以要將所有十六進制的哈希值轉成十進制。

 
結束語

本文使用Python實現(xiàn)了所介紹的算法,當然了讀者可以使用任何編程語言實現(xiàn)算法。

在簡介中提過,本文算法將應用到Iconfinder上去防止重復提交圖標,可以預想,感知哈希算法還有更多實際應用。因為有相似特征的圖像的哈希值也是相似的,所以它可以幫助圖像推薦系統(tǒng)尋找相似圖像。

相關文章

  • python做接口測試的必要性

    python做接口測試的必要性

    在本篇文章里小編給大家整理的是關于python做接口測試的必要性以及相關知識點,有興趣的朋友們學習下。
    2019-11-11
  • 一行Python3代碼實現(xiàn)解析地址信息

    一行Python3代碼實現(xiàn)解析地址信息

    在日常數據處理的過程中,有時候拿到手的是完整的地址信息,如果需要從地址信息中解析出相應的各級行政單元名稱,方式有很多,而今天要介紹的方式只需要一行代碼即可快速實現(xiàn),快跟隨小編一起學習一下吧
    2022-05-05
  • Python之inspect模塊實現(xiàn)獲取加載模塊路徑的方法

    Python之inspect模塊實現(xiàn)獲取加載模塊路徑的方法

    今天小編就為大家分享一篇Python之inspect模塊實現(xiàn)獲取加載模塊路徑的方法,具有很好的價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • python?lambda?表達式形式分析

    python?lambda?表達式形式分析

    這篇文章主要介紹了python?lambda?表達式形式分析,?lambda??表達式會創(chuàng)建一個函數對象,可以對其賦值并如同普通函數一樣使用,下面通過定義了一個求平方的?lambda?表達式展開主題內容,需要的朋友可以參考一下
    2022-04-04
  • python實現(xiàn)將list拼接為一個字符串

    python實現(xiàn)將list拼接為一個字符串

    這篇文章主要介紹了python實現(xiàn)將list拼接為一個字符串方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • argparse?模塊簡介

    argparse?模塊簡介

    argparse是一個用來解析命令行參數的 Python 庫,它是 Python 標準庫的一部分,基于 python 2.7 的stdlib 代碼,這篇文章主要介紹了argparse?模塊詳解,需要的朋友可以參考下
    2023-02-02
  • Python實現(xiàn)網站表單提交和模板

    Python實現(xiàn)網站表單提交和模板

    今天小編就為大家分享一篇關于Python實現(xiàn)網站表單提交和模板,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Python如何實現(xiàn)MySQL實例初始化詳解

    Python如何實現(xiàn)MySQL實例初始化詳解

    這篇文章主要給大家介紹了關于Python如何實現(xiàn)MySQL實例初始化的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-11-11
  • Python字符串逐字符或逐詞反轉方法

    Python字符串逐字符或逐詞反轉方法

    這篇文章主要介紹了Python字符串逐字符或逐詞反轉方法,本文對逐字符或逐詞分別給出兩種方法,需要的朋友可以參考下
    2015-05-05
  • Python字符串拼接、截取及替換方法總結分析

    Python字符串拼接、截取及替換方法總結分析

    這篇文章主要介紹了Python字符串拼接、截取及替換方法,結合實例形式總結分析了Python針對字符串的拼接、截取與替換的原理與常見使用技巧,需要的朋友可以參考下
    2016-04-04

最新評論

清河县| 绥德县| 玉林市| 澜沧| 内乡县| 健康| 兴城市| 汶川县| 昌都县| 旅游| 晋州市| 望江县| 文登市| 景德镇市| 武鸣县| 独山县| 枝江市| 界首市| 普陀区| 南汇区| 通榆县| 汶川县| 遂川县| 闽侯县| 星子县| 故城县| 青川县| 宁都县| 高阳县| 绥江县| 东阿县| 民勤县| 伊川县| 泰兴市| 台北市| 海南省| 修水县| 达日县| 海门市| 双牌县| 农安县|