第一步 縮小圖片尺寸
將圖片縮小到8x8的尺寸, 總共64個像素. 這一步的作用是去除各種圖片尺寸和圖片比例的差異, 只保留結構、明暗等基本信息.
第二步 轉為灰度圖片
將縮小后的圖片, 轉為64級灰度圖片.
第三步 計算灰度平均值
計算圖片中所有像素的灰度平均值
第四步 比較像素的灰度
將每個像素的灰度與平均值進行比較, 如果大於或等於平均值記為1, 小於平均值記為0.
第五步 計算哈希值
將上一步的比較結果, 組合在一起, 就構成了一個64位的二進制整數, 這就是這張圖片的指紋.
第六步 對比圖片指紋
得到圖片的指紋后, 就可以對比不同的圖片的指紋, 計算出64位中有多少位是不一樣的. 如果不相同的數據位數不超過5, 就說明兩張圖片很相似, 如果大於10, 說明它們是兩張不同的圖片.
using
System;
using
System.IO;
using
System.Drawing;
namespace
SimilarPhoto
{
class
SimilarPhoto
{
Image SourceImg;
public
SimilarPhoto(
string
filePath)
{
SourceImg = Image.FromFile(filePath);
}
public
SimilarPhoto(Stream stream)
{
SourceImg = Image.FromStream(stream);
}
public
String GetHash()
{
Image image = ReduceSize();
Byte[] grayValues = ReduceColor(image);
Byte average = CalcAverage(grayValues);
String reslut = ComputeBits(grayValues, average);
return
reslut;
}
// Step 1 : Reduce size to 8*8
private
Image ReduceSize(
int
width = 8,
int
height = 8)
{
Image image = SourceImg.GetThumbnailImage(width, height, () => {
return
false
; }, IntPtr.Zero);
return
image;
}
// Step 2 : Reduce Color
private
Byte[] ReduceColor(Image image)
{
Bitmap bitMap =
new
Bitmap(image);
Byte[] grayValues =
new
Byte[image.Width * image.Height];
for
(
int
x = 0; x<image.Width; x++)
for
(
int
y = 0; y < image.Height; y++)
{
Color color = bitMap.GetPixel(x, y);
byte
grayValue = (
byte
)((color.R * 30 + color.G * 59 + color.B * 11) / 100);
grayValues[x * image.Width + y] = grayValue;
}
return
grayValues;
}
// Step 3 : Average the colors
private
Byte CalcAverage(
byte
[] values)
{
int
sum = 0;
for
(
int
i = 0; i < values.Length; i++)
sum += (
int
)values[i];
return
Convert.ToByte(sum / values.Length);
}
// Step 4 : Compute the bits
private
String ComputeBits(
byte
[] values,
byte
averageValue)
{
char
[] result =
new
char
[values.Length];
for
(
int
i = 0; i < values.Length; i++)
{
if
(values[i] < averageValue)
result[i] =
'0'
;
else
result[i] =
'1'
;
}
return
new
String(result);
}
// Compare hash
public
static
Int32 CalcSimilarDegree(
string
a,
string
b)
{
if
(a.Length != b.Length)
throw
new
ArgumentException();
int
count = 0;
for
(
int
i = 0; i < a.Length; i++)
{
if
(a[i] != b[i])
count++;
}
return
count;
}
}
}