這種以圖搜圖可以用感知哈希算法,
第壹步 縮小圖片尺寸
將圖片縮小到8x8的尺寸, 總***64個像素. 這壹步的作用是去除各種圖片尺寸和圖片比例的差異, 只保留結構、明暗等基本信息.
第二步 轉為灰度圖片
將縮小後的圖片, 轉為64級灰度圖片.
第三步 計算灰度平均值
計算圖片中所有像素的灰度平均值
第四步 比較像素的灰度
將每個像素的灰度與平均值進行比較, 如果大於或等於平均值記為1, 小於平均值記為0.
第五步 計算哈希值
將上壹步的比較結果, 組合在壹起, 就構成了壹個64位的二進制整數, 這就是這張圖片的指紋.
第六步 對比圖片指紋
得到圖片的指紋後, 就可以對比不同的圖片的指紋, 計算出64位中有多少位是不壹樣的. 如果不相同的數據位數不超過5, 就說明兩張圖片很相似, 如果大於10, 說明它們是兩張不同的圖片.
具體的c#代碼可以看
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;
}
}
}