• 谷歌百度以图搜图 "感知哈希算法" 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;
    		}
    	}
    

      

  • 相关阅读:
    用归并排序或树状数组求逆序对数量 poj2299
    UVA10600 次小生成树
    最小生成树求最大比率 UVALive
    求树的重心 poj 1655
    求树的直径+并查集(bfs,dfs都可以)hdu4514
    树形DP+RMQ+尺取法 hdu4123
    区间dp 51nod1021
    LCS poj1080
    最长公共子序列hdu1503
    python No handlers could be found for logger错误的解决
  • 原文地址:https://www.cnblogs.com/waw/p/3727888.html
Copyright © 2020-2023  润新知