谷歌百度以图搜图 "感知哈希算法" C#简单实现

来源:互联网 发布:晾衣架图片价格淘宝 编辑:程序博客网 时间:2024/06/05 05:59
/// <summary>/// 感知哈希算法/// </summary>public class ImageComparer{/// <summary>/// 获取图片的Hashcode/// </summary>/// <param name="imageName"></param>/// <returns></returns>public static string GetImageHashCode(string imageName){int width = 8;int height = 8;//第一步//将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,//只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。Bitmap bmp = new Bitmap(Thumb(imageName));int[] pixels = new int[width * height];//第二步//将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。for (int i = 0; i < width; i++){for (int j = 0; j < height; j++){Color color = bmp.GetPixel(i, j);pixels[i * height + j] = RGBToGray(color.ToArgb());}}//第三步//计算所有64个像素的灰度平均值。int avgPixel = Average(pixels);//第四步//将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。int[] comps = new int[width * height];for (int i = 0; i < comps.Length; i++){if (pixels[i] >= avgPixel){comps[i] = 1;}else{comps[i] = 0;}}//第五步//将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。StringBuilder hashCode = new StringBuilder();for (int i = 0; i < comps.Length; i += 4){int result = comps[i] * (int)Math.Pow(2, 3) + comps[i + 1] * (int)Math.Pow(2, 2) + comps[i + 2] * (int)Math.Pow(2, 1) + comps[i + 2];hashCode.Append(BinaryToHex(result));}bmp.Dispose();return hashCode.ToString();}/// <summary>/// 计算"汉明距离"(Hamming distance)。/// 如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。/// </summary>/// <param name="sourceHashCode"></param>/// <param name="hashCode"></param>/// <returns></returns>public static int HammingDistance(String sourceHashCode, String hashCode){int difference = 0;int len = sourceHashCode.Length;for (int i = 0; i < len; i++){if (sourceHashCode[i] != hashCode[i]){difference++;}}return difference;}/// <summary>/// 缩放图片/// </summary>/// <param name="imageName"></param>/// <returns></returns>private static Image Thumb(string imageName){return Image.FromFile(imageName).GetThumbnailImage(8, 8, () => { return false; }, IntPtr.Zero);}/// <summary>/// 转为64级灰度/// </summary>/// <param name="pixels"></param>/// <returns></returns>private static int RGBToGray(int pixels){int _red = (pixels >> 16) & 0xFF;int _green = (pixels >> 8) & 0xFF;int _blue = (pixels) & 0xFF;return (int)(0.3 * _red + 0.59 * _green + 0.11 * _blue);}/// <summary>/// 计算平均值/// </summary>/// <param name="pixels"></param>/// <returns></returns>private static int Average(int[] pixels){float m = 0;for (int i = 0; i < pixels.Length; ++i){m += pixels[i];}m = m / pixels.Length;return (int)m;}private static char BinaryToHex(int binary){char ch = ' ';switch (binary){case 0:ch = '0';break;case 1:ch = '1';break;case 2:ch = '2';break;case 3:ch = '3';break;case 4:ch = '4';break;case 5:ch = '5';break;case 6:ch = '6';break;case 7:ch = '7';break;case 8:ch = '8';break;case 9:ch = '9';break;case 10:ch = 'a';break;case 11:ch = 'b';break;case 12:ch = 'c';break;case 13:ch = 'd';break;case 14:ch = 'e';break;case 15:ch = 'f';break;default:ch = ' ';break;}return ch;}}

原创粉丝点击