图像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仅适用于背景不变,前景部分变化的场景比较。