现在的位置: 首页.NET技术 > 正文
在C#中快速比对图片的新方法
关键词:无 ┊ 来源: 原创收藏

MSDN的一位技术人员告诉大家一个在C#中进行图像一致性比较的简易算法。一般的情况下,人们习惯的轮询图像中的每一个像素进行比对,如果出现一个像素点的不同则判断两张照片不一致。但这样做的缺点是显而易见的:大量的查询会显著拖慢系统速度,如果要比较的图像很多则可能导致系统挂掉。新的思路是把图像文件的数据流转化成一串Base64字串,然后只要比较这些字串就可以了。作者测试了256*256以下大小的一些图片,结果完全正确而且速度明显加快。来看他是如何实现的吧。

传统的像素比对方法:

   1: private bool ImageCompareArray(Bitmap firstImage, Bitmap secondImage)
   2: {
   3:     bool flag = true;
   4:     string firstPixel;
   5:     string secondPixel;
   6: 
   7:     if (firstImage.Width == secondImage.Width
   8:         && firstImage.Height == secondImage.Height)
   9:     {
  10:         for (int i = 0; i < firstImage.Width; i++)
  11:         {
  12:             for (int j = 0; j < firstImage.Height; j++)
  13:             {
  14:                 firstPixel = firstImage.GetPixel(i, j).ToString();
  15:                 secondPixel = secondImage.GetPixel(i, j).ToString();
  16:                 if (firstPixel != secondPixel)
  17:                 {
  18:                     flag = false;
  19:                     break;
  20:                 }
  21:             }
  22:         }
  23: 
  24:         if (flag == false)
  25:         {
  26:             return false;
  27:         }
  28:         else
  29:         {
  30:             return true;
  31:         }
  32:     }
  33:     else
  34:     {
  35:         return false;
  36:     }
  37: }


改良后的代码:

   1: public static bool ImageCompareString(Bitmap firstImage, Bitmap secondImage)
   2: {
   3:     MemoryStream ms = new MemoryStream();
   4:     firstImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
   5:     String firstBitmap = Convert.ToBase64String(ms.ToArray());
   6:     ms.Position = 0;
   7: 
   8:     secondImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
   9:     String secondBitmap = Convert.ToBase64String(ms.ToArray());
  10: 
  11:     if (firstBitmap.Equals(secondBitmap))
  12:     {
  13:         return true;
  14:     }
  15:     else
  16:     {
  17:         return false;
  18:     }
  19: }

作者测试了大量图片,只要改动一个像素点,新方法都可以检测出不同。不过目前为止还没有对500*600分辨率以上的图像进行测试。
下面两个图像经测试返回true(图像完全一致)(不通过判断文件名):
dom1
dom2
相比之下两张明显不同的图片则判断为false(图片不同)。
dom1
dom3
运行大量测试以后,Base64方法的平均测试速度为每对照片0.1s。但是,使用传统的数组方法快慢则随图片而有明显差别。如果是完全一致的图片需要平均每对1.8s,检测出不同则只需要平均每对0.05s。综合看来新方法在速度上具有优势。
作者欢迎网友留言就此方法进行探讨。

cnBeta编译自MSDN

相关文章
    暂无相关文章
本文由 jack 发布于 3239天 23小时 14分钟前,目前已有 8742 人浏览
欢迎大家转载分享,请注明来源及链接;商业媒体转载请获得授权,谢谢合作!
 
zhangyufeng: 1楼3239天 19小时 7分钟前
两个完全相同的图片,md5值也相同;
两个不一样的图片,md5值也不同;
(我做的简单实验结论,可能不对哦。为什么不用md5来判断呢)

我试了一下,用md5判断的话,判断1000次才用2.7秒。
平均每次0.0027秒……
zhangyufeng: 2楼3239天 19小时 6分钟前
对了,PHP的代码:
$time_start = microtime(true);

for($i=0; $i <=10000; $i++){
$file_1_md5 = md5_file('1.jpg');
$file_2_md5 = md5_file('2.jpg');
}
$time_end = microtime(true);
echo $time_end - $time_start , "\n";
print $file_1_md5 . "\n";
print $file_2_md5 . "\n";
匿名网友: 3楼3228天 19小时 41分钟前
[quote=zhangyufeng]两个完全相同的图片,md5值也相同;两个不一样的图片,md5值也不同;(我做的简单实验结论,可能不对...[/quote]
MD5确实快,但是这个精度有点过于的大了,没有必要,而且同一张图用软件(比如ps)转存之后MD5值就已经改变了,但是图像却没有变化,至少凭肉眼观察不到,这也脱离了图片对比的范畴,MD5用作文件完整性对比还是不错的。
以上是不完全实验得出的结论,或许是错的,错了还请指正吧[emote]blink[/emote]
疯蜂: 4楼3225天 23小时 39分钟前
有点意思,试了一下,小图片还行,稍微大一点的循环比较像素会慢死,甚至会卡死。Base64还行,快多了,MD5更快[emote]biggrin[/emote]
jack: 5楼3225天 23小时 19分钟前
[quote=疯蜂]有点意思,试了一下,小图片还行,稍微大一点的循环比较像素会慢死,甚至会卡死。Base64还行,快多了...[/quote]
其实可以这么理解,MD5相同的应该就相同,当然这么说也不一定,根据王小云教授的论文,MD5其实可以碰撞,但是这个基本不会让咱们碰见。
但是MD5不同的 图片也可能相同,是吧?不同意见的可以反驳我啊
疯蜂: 6楼3225天 23小时 15分钟前
[quote=jack]引用:疯蜂 发表的主题 有点意思,试了一下,小图片还行,稍微大一点的循环比较像素会慢死,甚至会卡死。...[/quote]
MD5判断文件完整性还不赖,图片的话有点大材小用了,试想用铡刀杀鸡会杀成什么样。而且很有可能出现MD5不同图片相同的结果[emote]ph34r[/emote]
疯蜂: 7楼3225天 23小时 8分钟前
//网上摘的,还没试能不能用

//关于两个幅图片进行比较并得出变化区域的主要代码
//效率较逐像素比较高上几百倍..
//转载请注明此贴出自[url]www.cnntec.com[/url]
//注: bmp格式编码头内容
//===============================
//地址 长度 内容
//00 2 bm标识
//02 4 图像大小
//06 4 0
//0A 4 图像信息开始位置
//0E 4 信息头大小
//12 4 ImageWidth
//16 4 imageHeight
//1A 2 1
//1C 4 图像位深

//获取需要比较的两副图
byte[] bm1 = System.IO.File.ReadAllBytes("e:\\bm1.bmp");
byte[] bm2 = System.IO.File.ReadAllBytes("e:\\bm2.bmp");

//读取bm1图像的头信息
if (bm1[0] != 'B' || bm1[1] != 'M')
{
MessageBox.Show("图像不是bmp格式!可将图片先转换为bmp格式.");
return;
}
//创建显示比较结果的图
byte[] bm3 = new byte[bm1.Length];
//获取图像信息开始位置
int startIndex = bm1[10] + bm1[11] * 256 + bm1[12] * 65536 + bm1[13] * 16777216;
//获取图像色位深度
int bit = bm1[28];
//检查两幅图的头信息是否相同
for (int i = 0; i < startIndex; i++)
{
if (bm1[i] != bm2[i])
{
MessageBox.Show("图像编码格式或分辨率不同!");
return;
}
bm3[i] = bm1[i];
}
int step = bit / 8;
bool isDiffer = false;
//比较两幅图片并将区别区域写入第三幅图。
for (int i = startIndex; i < bm1.Length; i += step)
{
//对bm1 和 bm2 进行比较
for (int j = 0; j < step; j++)
{
if (bm1[i + j] != bm2[i + j])
{
isDiffer = true;
break;
}
}
if (isDiffer)
{
//将这个区别点写入bm3.
for (int j = 0; j < step - 1; j++)
{
bm3[i + j] = 200;
}
isDiffer = false;
}
}
//得到区域图像
Image img = Image.FromStream(new System.IO.MemoryStream(bm3));
匿名网友: 8楼3222天 18小时 25分钟前
同一张图用软件(比如ps)转存之后MD5值不会改变[emote]ph34r[/emote]
匿名网友: 9楼1143天 22小时 55分钟前
留言是种美德,写点什么...
匿名网友: 10楼1143天 22小时 53分钟前
留言是种美德,写点什么...

添加评论