差值哈希(DHash)

上一篇講了四種哈希算法的概述和每種算法的基本步驟,這篇詳細討論下 DHash:

  1. 縮小尺寸,建議 9*8(col = row + 1)
  2. 灰度化
  3. 計算灰度差值(做差變爲 8*8 的矩陣)
  4. 計算哈希值

縮小尺寸

這一步用 Android 的系統方法就簡單了:

Bitmap bitmap = ThumbnailUtils.extractThumbnail(bitmap, destW, destH);

但爲了能和服務端(Java)兼容,找到了一個純數據結構的算法:

雙線性插值法,參加:https://blog.csdn.net/u012679980/article/details/49449647。

修改了部分代碼,計算效率有很大的提升。

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
通過上面的算法進行圖片縮小,不管是 Android 端還是服務端,得到的結果都是相同的。

這裏先說一下數組存放圖片信息的方式:

  1. 二維:二維比較容易理解,圖片是 x、y 兩個方向的像素點組成,對應到一個二維數組即可。
  2. 一維:二維轉一維,以一個方向爲基準,一般是 x 方向,存完第一行存第二行,就將二維數組轉化爲一維了,比如 9*9 的二維數組,變爲一維數組,第 10 個元素對應的是二維數組第二行的第一個元素。
  3. 三維:像素點是有三種顏色組成的,因此三維的 z 方向就是存儲的 ARGB,透明度、紅、綠、藍。

上面代碼的思路還是很好理解的:

假設 x 軸有 800 個像素點,但我們要縮小到 9 個,那個距離就是 100,即每隔 100 個像素點取出一個。取出的 9 個像素點就是樁子。y 方向同理。

但實際操作沒有這麼簡單,會出現從 700 個像素點中取 9 個的現象,間隔不是整數,因此會通過取整後的目標像素點周圍相鄰的四個點,按權重來計算出取出的像素點的具體值。大家可以參見上面給出的博客地址具體看下思路。

其中第三步驟 convertToOneDim 中的 ABGR --> ARGB 也與文章不同,但不增加算法複雜度,只是將色值的表達方式轉換成比較常用的形式。

灰度化

在這裏插入圖片描述
灰度化就是將彩色圖片轉化成 64 階黑白圖片,當然紅綠藍是按一定的係數縮小。

這個地方就體現到 縮小尺寸 裏講到的 ABGR --> ARGB 的好處了,通用方法的順序都是按 R、G、B 排列的。

計算灰度差值

在這裏插入圖片描述
這一步是 DHash 的核心步驟,所有 hash 算法一般最終都是採樣 64 個點,但 DHash 之所以採樣 9*8 個像素點是基於其比較差值的邏輯。

DHash 是將每一行後一個元素和前一個元素做差,差值大於等於 0 則記 1,小於 0 則記 0。

假設 9*8 的數組是:a1a9、b1b9、c1~c9 ······ h1~h9

即 a2-a1 記錄,a3-a2 記錄,a4-a3 記錄 ······ a9-a8 記錄;b、c ······ 以此類推,一共記錄 64 個01 值。

得到的這個 64 位的二進制值就是這張圖片的指紋。

計算哈希值

將這個 64 位的二進制值轉爲 16 位的十六進制值就是這張圖片的 DHash 值。

本文原創發佈於公衆號 習習立 ,關注公衆號回覆 hash 獲取源碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章