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

/// <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;
		}
	}

    原文作者:哈希算法
    原文地址: https://blog.csdn.net/love_beibei/article/details/7568398
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞