圖像Hash算法,有PHash,DHash,AHash,以下記錄平均值哈希AHash的Delphi算法代碼
var
bmp: TBitmap = nil;
//gb: TBitmap;
//算法原理:將圖像縮放成8x8的灰度圖,統計出像素平均值
//再遍歷每個像素,值大於平均值記爲二進制的1,否則記爲0,最終得到一個64位的整數
function GetAHash(SrcBmp: TBitmap): Int64;
var
I, J: Integer;
P24, P8: PByte;
AG, SG: Integer;
AVG: Single;
CT: array[0..7, 0..7] of Byte;
begin
Result := 0;
if bmp = nil then
begin
bmp := TBitmap.Create;
bmp.Width := 8;
bmp.Height := 8;
bmp.PixelFormat := TPixelFormat.pf24bit;
end;
// if gb = nil then
// begin
// gb := TBitmap.Create;
// gb.Width := 8;
// gb.Height := 8;
// gb.PixelFormat := TPixelFormat.pf24bit;
// end;
//TODO 可以高斯模糊一下,能去除雜點的影響
SetStretchBltMode(bmp.Canvas.Handle, COLORONCOLOR); //設置指位圖拉伸模式
StretchBlt(bmp.Canvas.Handle, 0, 0, bmp.Width, bmp.Height, SrcBmp.Canvas.Handle, 0, 0, SrcBmp.Width, SrcBmp.Height, SRCCOPY); //從源矩形中複製一個位圖到目標
AG := 0;
for I := 0 to 7 do
begin
P24 := bmp.ScanLine[I];
// P8 := gb.ScanLine[I];
for J := 0 to 7 do
begin
SG := Round(P24[0] * 0.11 + P24[1] * 0.59 + P24[2] * 0.3);
CT[I, J] := SG;
// P8[0] := CT[I, J];
// P8[1] := CT[I, J];
// P8[2] := CT[I, J];
Inc(P8, 3);
AG := AG + SG;
Inc(P24, 3);
end;
end;
// bmp.SaveToFile('D:\_rgb.bmp');
// gb.SaveToFile('D:\_gray.bmp');
AVG := AG / 64;
Result := 0;
for I := 0 to 7 do
for J := 0 to 7 do
Result := Result shl 1 or Ord(CT[I, J] > AVG);
end;
兩個Hash值比較相似度,比較兩個數有多少個不同的二進制位,即:海明距離
function Hamming(Hash1, Hash2: Int64): Integer;
var
I: Integer;
A: Int64;
begin
Result := 0;
//使用一個神奇的表達式 n&=(n-1)
//參考:https://blog.csdn.net/u013243347/article/details/52220551
A := Hash1 xor Hash2;
while A <> 0 do
begin
A := A and (A -1);
Inc(Result);
end;
end;
最後,平均Hash僅適用於背景不變,前景部分變化的場景比較。