2009年8月13日星期四

简单有效的图像去雾技术

标签:微软亚洲研究院 图像去雾 cvpr 最佳论文 研究心得 论文背后故事  分类:技术

                                                                                  作者:何恺明

 那是2009年4月24日的早上,我收到了一封不同寻常的email。发信人是CVPR 2009的主席们,他们说我的文章获得了CVPR 2009的最佳论文奖(Best Paper Award)。我反复阅读这封邮件以确认我没有理解错误。这真是一件令人难以置信的事情。 

北京灰霾照片的去雾结果

 

CVPR的中文名是计算机视觉与模式识别会议,是计算机视觉领域最顶尖 的国际会议之一。今年的CVPR共收到约1450篇投稿,其中393篇文章被接收,接收率为26%。只有一篇文章被选为今年的最佳论文。这是CVPR创立 25年以来首次由中国人获得这个奖项。这篇文章是我在微软亚洲研究院形象计算组实习的时候完成的,也是我个人真正意义上写的第一篇论文。

  

简单有效的图像去雾技术

 

这篇论文研究的问题是图像的去雾技术,它可 以还原图像的颜色和能见度,同时也能利用雾的浓度来估计物体的距离,这些在计算机视觉上都有重要应用(例如三维重建,物体识别)。但是之前人们还没找到简 单有效的方法来达到这个目的。在这篇论文里,我们找到了一个非常简单的,甚至说令人惊讶统计规律,并提出了有效的去雾方法。

   

与之前的方法不同,我们把注意力放到了无雾图像的统计特征上。我们发现,在无雾图像中,每一个局部区域都很有可能会有阴影,或者是纯颜色的东西,又或者是黑色的东西。因此,每一个局部区域都很有可能有至少一个颜色通道会有很低的值。我们把这个统计规律叫做Dark Channel Prior。直观来说,Dark Channel Prior认为每一个局部区域都总有一些很暗的东西。这个规律很简单,但在我们研究的去雾问题上却是本质的基本规律。

 

由于雾总是灰白色的,因此一旦图像受到雾的影响,那么这些本来应该很暗的东西就会变得灰白。不仅如此,根据物理上雾的形成公式,我们还能根据这些东西的灰白程度来判断雾的浓度。因此,我们提出的Dark Channel Prior能很有效地去除雾的影响,同时利用物的浓度来估算物体的距离。

 

电脑游戏带来的灵感

 

这个想法的产生来自于两个偶然的观察。

 

第一个观察来自一个3D游戏。这个游戏有很多带有雾的场景,但这些场景 都是虚构的不实在的东西。计算机生成的3D图像会与自然图像的统计规律有很大区别,但人的视觉系统却仍然能感觉到虚拟图像中存在的雾。这让我相信,人的视 觉系统一定有一种有效的机制来感知有雾的图像,而且这种机制一定与现存的去雾方法不一样。前人提出的去雾方法都把重点放在图像的对比度上,但虚拟场景和现 实场景在对比度上的统计规律会很不一样。人的视觉系统仍然能够感知虚拟场景中的雾,说明除了对比度以外,人眼一定还在利用别的东西来感知雾。所以我觉得, 这个问题里一定有人们未曾发现的更接近本质的东西。

 

第二个观察来自对前人的去雾方法的研究。之前最有效的去雾方法是Fattal在2008年的Siggraph文章《Single Image Dehazing》中提出来的,这篇文章是我们首要超越的目标。这篇文章里给出的比较结果中,我发现一种叫做Dark Object Subtraction的方法有时候会有更好的效果。这种方法利用了全图最暗的点来去除全局均匀的雾。如果雾的确是均匀的,这种方法就会更有效。其缺点在于它无法处理不均匀的雾,而这却正是去雾问题中的难点。因此自然的想法就是局部利用Dark Object Subtraction处理图像。而恰巧这样做并不需要利用对比度,说明它与之前的方法有了本质的区别。让人吃惊的是,在大量的实验中,我发现这么简单的想法,其效果却非常好。 

  

但我们论文中最重要的观点却形成在我动笔写文章之后。在文章的前几稿 中,我在形象计算组的mentor孙剑一直追问我,我们的方法能成功的本质原因是什么,背后有什么我们没有充分理解透彻的“真知灼见”。尽管我们有很简单 的方法,也有很漂亮的实验结果,但我们却无法让人对这种方法的有效性感到信服。这是因为我们还讲不出个道理来。带着这个问题,我又回到了实验和观察之中。 我发现,既然大量实验结果证实局部做Dark Object Subtraction的做法是成功的,那么就说明去雾之后的图像的每个局部的确是有暗的物体存在的。也就是说,在这个方法成功的背后,其实有一个关于无 雾图像的统计规律。我的mentor孙剑让我去先去研究一个无雾图像的数据库。通过大量的实验,我们发现这个统计规律是客观存在的。这就是我们所提出的 Dark Channel Prior。

        

这是我写的第一篇论文

 

2007年,我从清华大学基础科学班本科毕业,之后就读于香港中文大 学。在基础科学班的主修课程是数学和物理,因此在本科阶段,我并没有系统地学习过计算机方面的相关知识。出于兴趣,我选修了计算机图形和图像方面的一些相 关课程。但是在进入微软亚洲研究院实习的初期,这些基础课程远远不足以应付我面对的研究工作。背景知识的缺乏使我在入门的路上举步维艰。在阅读文章的时 候,我常常都不知道哪些是大家都在用的方法,哪些才是作者的贡献。对我来说,我看见的每一样东西都是新的。

 

在面试的时候,我的导师汤晓鸥就跟我说过,他并不在意我没有相关的背景 知识,因为所有相关的东西都是可以学的。在进入微软亚洲研究院实习的头一年里,我在mentor孙剑的指导下做过几个不同的课题,虽然都没有成功,但从中 学习了不少知识。其中我花了大量时间研究的image matting问题 (半透明物体边界提取),就对这次的文章有很大帮助。在刚开始研究去雾的时候,我就发现雾的方程和matting的方程非常相似,而我之前所研究的 matting框架可以给去雾带来帮助。利用这个框架,我只需要寻找一个能局部估算雾的浓度的方法就行了。这个框架使得我能专心的寻找这样的方法并且最后 提出了Dark Channel Prior。 

纽约、北京灰霾照片的去雾结果

 

即使有了想法和实验结果,第一次写文章也使我觉得非常困难。我经常陷入 自己和自己吵架的角色当中。在每一段话写好之后,我常常会质问自己事情到底是不是这样的,这其中有没有漏洞。我也会问自己,如果我是评委,或者是读者,那 么我能看懂这篇文章吗,我怎么写才能让思路更加流畅。就在这样的挣扎中,一稿通常要写好几天。而即使是这样,起初的几稿也远没能让孙剑满意。一开始,他只 在文章的结构、思路和观点的提出上给我建议,而不去具体修改我的文章。于是我又回去继续和自己吵架。但每当我把自己说服了,孙剑还是总能提出新的质疑。就 在这样的循环中,终于有一天孙剑说文章已经写得不错了,他才开始具体的修改。正是这样的苛刻要求,才会有后来高质量的文章。

 

大道之行在于简

 

我们这篇文章的三个审稿人都给出了最高的评分。他们认为我们的方法简单 而有效。其中一位评委说,Dark Channel Prior的想法听起来很不可思议,但我们却证明了其真实性。另一位评委认为很少有文章能够用如此简单的方法使实验结果获得如此大的提升。还有一位评委甚 至亲自实现了我们的方法并确认其可行。孙剑说阅读这样的评审结果是一件让人快乐的事情。而汤老师认为,这篇文章的成功在于三个方面。第一,方法非常简单; 第二,对于一个很困难的问题,给出了很好的结果;第三,发现了一个基本的自然规律并且应用在实际的问题中。在迈阿密的演讲结束后,观众也给予了很高的评 价。他们跟我说,这是这次CVPR上最有趣的一个演讲。

 

一位与会的研究员说,最好的idea,往往就是那些看起来很简单,但说 出来大家都会觉得怎么没有人想到过的idea。而我们的idea正好就符合了这一点。我们论文摘要的第一句话是这么说的,“我们提出了一个简单而有效的方 法”。或许,这就是对我们这次工作最好的概括——简单的,就是美的。

 

作者介绍

何恺明:微软亚洲研究院视觉计算组实习生,现就读于香港中文大学讯息工程多媒体实验室,本科毕业于清华大学基础科学班。他是2006年微软小学者奖获得者,2003年广东省高考状元

2009年8月12日星期三

广东:卡口系统年内启用可快速识别套牌车

http://news.QQ.com  2009年08月10日13:38   金羊网-羊城晚报   

  本报讯记者崔朝阳报道:广东省公安厅近日在对省人大代表的建议答复中表示,可快速发现、识别和截查套牌车的卡口系统有望年内在广东全省范围投入使用,为加大对套牌车的打击力度,公安厅还拟提请省人大常委会修订《广东省道路交通安全条例》,加大对查处套牌车的处罚力度。

       今年初的省“两会”期间,陈进德等6名省人大代表提交建议指出,套牌车难发现、难查处、轻处罚,全省交警系统没有形成有效的联动措施,是套牌车层出不穷的重要原因。

  省公安厅表示,针对目前对套牌车处罚过轻,公安厅目前正会同省政府法制办开展调研,拟在年内提请省人大常委会修改道路交通安全条例,增加限制违法行为人人身自由(拘留)、加大罚款额度、没收违法车辆、追究刑事责任等条款,增加违法人违法成本。

  此外,对套牌车,广东已建立全省范围的套牌车黑名单库,将套牌车号码都录入库中,部署全省警力查询。具有号牌识别功能、一旦发现盗抢机动车或假号牌车自动报警的卡口系统,预计年内可投入使用。

  代表在建议中还提出,应增加车牌科技含量,让真牌不易被仿造,假牌更易被识别。对此,公安厅表示,该厅还在研发电子车牌,未来的电子车牌中将置入电子芯片,建立车牌电子身份认证系统,确保车辆唯一性,从源头上根除套牌车。

  记者今晨从省公安厅交管局了解到,由于车牌制作涉及国家统一标准问题,公安厅已就此上报国家相关部门,目前还在等待批复。

2009年8月10日星期一

利用OpenCV进行图像连接

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>

/* プロトタイプ宣言 */
IplImage *combine_image (int num, IplImage ** tmp);

/* メイン関数 */
int
main (int argc, char **argv)
{
  int i, img_num;
  IplImage **img;
  IplImage *combined_img;

  // (1)コマンド引数で指定された画像を全て読み込む
  if (argc < 2) {
    return 1;
  }
  else {
    img_num = argc - 1;
    img = (IplImage **) cvAlloc (sizeof (IplImage *) * img_num);
    for (i = 0; i < img_num; i++) {
      img[i] = cvLoadImage (argv[i + 1], CV_LOAD_IMAGE_COLOR);
      if (img[i] == 0)
        return -1;
    }
  }

  // (2)画像を連結する
  combined_img = combine_image (img_num, img);

  cvNamedWindow ("Image", CV_WINDOW_AUTOSIZE);
  cvShowImage ("Image", combined_img);
  cvWaitKey (0);

  cvDestroyWindow ("Image");
  cvReleaseImage (&combined_img);
  for (i = 0; i < img_num; i++) {
    cvReleaseImage (&img[i]);
  }
  cvFree (&img);

  return 0;
}

/* 画像を連結する関数 */
IplImage *
combine_image (int num, IplImage ** tmp)
{
  int i;
  int width = 0, height = 0;
  IplImage *cimg;
  CvRect roi = cvRect (0, 0, 0, 0);

  // (3)与えられた各画像から,連結後の幅と高さを求める
  for (i = 0; i < num; i++) {
    width += tmp[i]->width;
    height = height < tmp[i]->height ? tmp[i]->height : height;
  }
  cimg = cvCreateImage (cvSize (width, height), IPL_DEPTH_8U, 3);
  cvZero (cimg);

  // (4)ROIを利用して各画像をコピーする
  for (i = 0; i < num; i++) {
    roi.width = tmp[i]->width;
    roi.height = tmp[i]->height;
    cvSetImageROI (cimg, roi);
    cvCopy (tmp[i], cimg);
    roi.x += roi.width;
  }
  cvResetImageROI (cimg);

  return cimg;
}

// (1)コマンド引数で指定された画像を全て読み込む
コマンド引数で指定された画像を全て,カラー画像として読み込む.そのなかに1つでも読み込めない画像がある場合には終了する.

// (2)画像を連結する
あらかめ定義した関数combined_img()を呼び出して,画像を横方向に連結する.この例では単純に画像の上辺を揃えて横方向に連結を行うだけであるが,画像を折り返して連結したり,さらにいわゆる「矩形パッキング問題」をの解を求めることで無駄な領域が小さくなるように連結することもできる.また,このサンプルでは連結する関数combined_image()に画像のポインタの配列を渡しているが,可変引数を利用(stdarg.h)して,combine_image()を次のように定義する方法もある.

IplImage*
combine_image(int num, ...)
{
  va_list list;
  int i;
  int width = 0, height = 0;
  IplImage *tmp[num];
  IplImage *cimg;
  CvRect roi = cvRect(0, 0, 0, 0);
        
  va_start(list, num);
  for(i=0; iwidth;
    height = height < tmp[i]->height ? tmp[i]->height : height;
  }
  va_end(list);
  cimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
  cvZero(cimg);

  for(i=0; iwidth;
    roi.height = tmp[i]->height;
    cvSetImageROI(cimg, roi);
    cvCopy(tmp[i], cimg);
    roi.x += roi.width;
  }
  cvResetImageROI(cimg);
  
  return cimg;
}
欢迎访问、交流!对本博客有何建议,请
来信告知!
本博内容来源于网络,如有不当或侵犯权益,请来信告知,将及时撤除!
如引用博客内容、论文,请注明原作者!

Google一下本博客