在要求输入邮箱的文本域,请填写真实的邮件地址。非真实邮件地址,将收不到回复信息。

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

C# 清风 594℃ 0评论

在谷歌百度以图搜索中, 用户可以上传一张图片, 谷歌百度显示因特网中与此图片相同或者相似的图片.

第一步:将图片缩小到8×8的尺寸,总共64个像素。这一步的作用是去除图片的细节, 只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。

第二步:将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。

第三步:计算所有64个像素的灰度平均值。

第四步:将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

第五步:将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序。

第六步:计算”汉明距离”(Hamming distance),如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。


using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace GlobalImageUpload 
{
	internal class ImageSimilarity 
	{
		/// <summary>
		/// 读取图片
		/// </summary>
		/// <param name="filename"></param>
		/// <returns></returns>
		private  Image readImage(String filename) 
		{
			try 
			{
				Image sourceImage = null;
				sourceImage=Image.FromFile(filename);
				return sourceImage;
			}
			catch 
			{
			}
			return null;
		}
		/// <summary>
		/// 灰度值计算
		/// </summary>
		/// <param name="posClr"></param>
		/// <returns></returns>
		private  int rgbToGray(Color posClr) 
		{
			return (posClr.R + posClr.G + posClr.B + posClr.A) / 4;
			//return (posClr.R * 19595 + posClr.G * 38469 + posClr.B * 7472) >> 16;
		}
		/// <summary>
		/// 计算平均值
		/// </summary>
		/// <param name="pixels"></param>
		/// <returns></returns>
		private  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;
		}
		/// <summary>
		/// 计算汉明距离
		/// </summary>
		/// <param name="sourceHashCode">源hashCode</param>
		/// <param name="hashCode">与之比较的hashCode</param>
		/// <returns></returns>
		public  int hammingDistance(string sourceHashCode, string hashCode) 
		{
			int difference = 0;
			int len = sourceHashCode.Length;
			for (int i = 0; i < len; i++) 
			{
				if (sourceHashCode.ToCharArray()[i] != hashCode.ToCharArray()[i]) 
				{
					difference++;
				}
			}
			return difference;
		}
		public  string produceFinger(string filename) 
		{
			string result = " ";
			System.Drawing.Image source = null;
			try 
			{
				source = readImage(filename);
				result = produceFinger(source);
			}
			catch(Exception ex) 
			{
			}
			finally 
			{
				if (source != null) 
				{
					source.Dispose();
				}
			}
			return result;
		}
		/// <summary>
		/// 形成图像指纹
		/// </summary>
		/// <param name="file"></param>
		/// <returns></returns>
		public  string produceFinger(System.Drawing.Image file) 
		{
			System.Drawing.Image source = (System.Drawing.Image)file.Clone();
			// 读取文件
			int width = 8;
			int height = 8;
			// 第一步,缩小尺寸。
			// 将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。
			Bitmap b = new Bitmap(source, 8, 8);
			System.Drawing.Image thumb = b;
			// 第二步,简化色彩。
			// 将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。
			int[] pixels = new int[width * height];
			for (int i = 0; i < width; i++) 
			{
				for (int j = 0; j < height; j++) 
				{
					pixels[i * height + j] = rgbToGray(((Bitmap)thumb).GetPixel(i, j));
				}
			}
			// 第三步,计算平均值。
			// 计算所有64个像素的灰度平均值。
			int avgPixel = average(pixels);
			// 第四步,比较像素的灰度。
			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;
				}
			}
			// 第五步,计算哈希值。
			string hashCode = "";
			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 += (binaryToHex(result));
			}
			if (source != null) 
			{
				source.Dispose();
			}
			return hashCode;
		}
		/// <summary>
		/// 返回对应编码
		/// </summary>
		/// <param name="binary"></param>
		/// <returns></returns>
		private  string binaryToHex(int binary) 
		{
			string[] bintoHex = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
			if (binary >= 0 && binary <= 15) 
			{
				return bintoHex[binary];
			}
			return " ";
		}
	}
}

调用方法如下:


static void Main(string[] args) 
{
	GlobalImageUpload.ImageSimilarity similarity = new GlobalImageUpload.ImageSimilarity();
	string hash1 = similarity.produceFinger(@"H:\1.jpg");
	string hash2 = similarity.produceFinger(@"H:\2.jpg");
	int diff=similarity.hammingDistance(hash1,hash2);
	if (diff < 5) { Console.WriteLine("两张图很相似"); } if (diff >= 5 && diff <= 10) { Console.WriteLine("两张图有点相似"); } if (diff >10) 
	{
		Console.WriteLine("两张图不相同");
	}
	Console.Read();
}

 

转载请注明:清风博客 » 谷歌百度以图搜图感知哈希算法之C#简单实现

喜欢 (2)or分享 (0)
支付宝扫码打赏 微信打赏
发表我的评论
取消评论

CAPTCHA Image
Reload Image
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址