http://yueyue1105.blog.163.com/blog/static/43111768201011160563445/
一个多星期,我几乎把全部的心思都放在如何做好图像去雾上,这中间遇到了很多困难,每解决一个问题都让我有所收获,多少次似乎快要成功,但得到的数据却不尽如人意,多少次将要放弃,却又让我找到新的线索继续尝试下去。我觉得很有必要把这一个多星期发生的事记录下来:
11月29日,数字图像处理课让我们选择大作业题目,题目共分3等,最后一等的几个题目都附带了论文,老师说这些题目比较难所以可以两个人合作,于是我随手点开了一个题目“图像去雾”,看了下论文《Single Image Haze Removal Using Dark Channel Prior》中的图片,感觉效果挺不错的,又发现是CUHK的,心想人家CUHK的人都能做,为什么我不能做,就果断叫儿子和我一起选了这个题目。后来才发现人家是博士,还是高考状元。
12月2日,读了下论文原文,发觉算法很清晰,掌握了大致流程。
12月6日,动手写代码,完成了除soft matting之外的步骤,当时以为快要完工了。。http://yueyue1105.blog.163.com/blog/static/4311176820101169534756/
12月7日,我看了Levin的论文《A Closed Form Solution to Natural Image Matting》中关于matting Laplacian matrix的描述,理解了部分推导,虽然最后一步怎么推出矩阵元素的通项不是很理解,但对我程序的实现没有影响,同时充分意识到线性代数的重要性,如果我以后搞科研,一定要重学线性代数。在我准备开始敲代码时,猛然发现L矩阵非常大,一来我存不下,二来我所知道的解线性方程组的方法只有高斯消元,复杂度更是不能接受。
12月9、10日,我看到论文最后用了预处理共轭梯度法(PCG)求解线性方程,于是借了书开始研究,但仍未解决矩阵存储问题。
12月11日,和老师约了时间讨论,老师基本上是带我过了下论文,最后他又给我看下了PCG的算法,一句“这里面只有矩阵的乘法”,一下点拨了我,因为L(i, j)有通项公式,所以不需要把L矩阵存下来,当时我的想法是用时间换空间,每次要用L的哪个元素,就算一遍。
12月12日,我和儿子合作写soft matting的代码,我让他帮我写矩阵求逆。我开始求解L(i, j),但发觉图像是h * w的,而L矩阵是(h * w)^2的,这之间的映射关系又让我感到困惑,于是我们的工作又停滞了。
12月13日,凌晨1点,我反复研究Levin的论文,终于想到了该如何映射,并且终于理解为什么L矩阵是稀疏的对称矩阵了。数字图像课,我把想法告诉了儿子,他不太同意我的想法,但是我相信这是对的,上机课时敲完了代码,却遇到了莫名其妙的栈溢出问题,整个白天我都在反复调试,还是没找到原因。晚上在ACM校队群里请教了几位神牛,才知道我在重载运算符时没有用引用返回,这样会开辟一个临时的栈空间,但我的矩阵又是非常大的,所以造成了栈溢出。
12月14日,解决了传值的问题后,我以为该结束了,但是结果却是错的。光用肉眼根本找不出代码哪有错,而且因为我并没有完全掌握L矩阵和PCG算法的特性,所有的代码都让我无法肯定正确性。最后想到将代码分成几部分测试,当我单独测试PCG算法得到正确结果时,我几乎可以肯定我的L矩阵是错的了。反复检查算L矩阵的代码,都没发现明显的错误,最后想到当时老师还给了Levin论文中附带的matlab源码,只好最后从中寻找希望了。
12月15日,前一天临睡看完了matlab源码中getLaplacian的部分,可以肯定我的L矩阵的映射方式是对的,除了发现我没有做归一化以外,没有找到代码的错误,另外,Levin的论文中一句“Note that the elements in each row of L sum to zero”又给我增加了一个检验L矩阵正确性的判断条件。上操作系统课的时候,我无聊地画着求解L(i, j)的窗口,无意中发现自己少计算了一些窗口的位置,而且想到我不用每次计算L矩阵的元素,只需用一个map存在非0元素就可以了。一下课我就回了寝室,当L矩阵的每一行之和输出0.00000,0.00000,... 时,我终于完成了整个算法的实现。下午的信息检索课,我在儿子的本上运行了一些小图,看到了所设想的结果。但是速度非常慢。我当时的想法是我们又不是真正搞研究的,能得到正确的结果就行了。但是当我看到在大图上连L矩阵的预处理都不能在1个小时内做完,我觉得这个程序就像是个摆设一样,没有一点实际的价值,但以我的知识,对于我的程序已经没有办法进行大的优化了。我想起在Levin的matlab程序中,并没有什么时空的优化,但程序就是跑得那么快,而且那么大的L矩阵,她就直接用matlab存了下来,看来matlab真的很强大。抱着试一试的心态我开始把C++程序改成matlab的,以前在数学建模课上学过一点matlab,但我那时根本不相信老师说的matlab做矩阵运算很快之类的话,因为我幼稚地以为matlab也是用程序语言编的,怎么可能比直接用C\C++写来得快呢。等我第一次开了这么大的矩阵后,才地发现matlab竟然存下了这些数据,而且运算速度快得惊人。(现在回过头来看,这段对matlab的赞美有些言过其实,还是有人能把C写得比matlab快的)
12月16日,因为已经写了一遍正确的C++程序,再写matlab就熟练了很多,有点怀疑怎么会花费这么多天在这样短短的一个程序里,简短的matlab代码用了几分钟的时间跑完了我一直想要C++跑的那张图,虽然结果和何博士的还有些许差距,不过之后也就是一些参数的调整了。
这是我有史以来最认真做的一次作业,对其中的原理我还不是完全理解,但照着论文做下来的这个过程我还是学到了很多,犯了无数菜鸟的错误。我的体会是,如果要编写的程序不是很有把握,例如用了书上解线性方程组的PCG算法,应该对它进行独立的测试,测试数据也是很重要的。做ACM的人习惯什么东西都自己来写,于是我的C++代码重载了各种矩阵运算,但是对于搞研究的人而言,研究的对象才是重点,应该尽可能避免代码上的实现问题,使用matlab这类强大的数学工具可以帮助研究者更好得着眼于研究的问题。当遇到无法解决的问题时,应该通过其它的方法来验证当前做法的正确性或者去寻找另一条路。
继续上一次的贴图:
![图像去雾成果 - Angus - To be completed](http://img764.ph.126.net/ZQpYrVQlQ2j3rYAvL-vPrA==/84442493014426909.bmp)
![图像去雾成果 - Angus - To be completed](http://img616.ph.126.net/tfQwoqSFNqGGsAYs-UnjNw==/1708553108635530290.bmp)
![图像去雾成果 - Angus - To be completed](http://img233.ph.126.net/glk43ocpyoMPCvukWS97kQ==/1368812811745794641.bmp)
![图像去雾成果 - Angus - To be completed](http://img688.ph.126.net/KyndFuckfqoYir-6TKW8zw==/2877518686914263725.bmp)
soft matting后的transmission
![图像去雾成果 - Angus - To be completed](http://img847.ph.126.net/rxDMFf1IrwZHW9OE0fRczQ==/762515711911231618.bmp)
下一步是调整参数(比如PCG的精度或者是与估计的tranmission的相关系数lamda)以及测试别的图,介于我的破本做多一些运算就会因CPU过热而重启(做这个作业已重启不下十次),明早去可视化上机课用电子楼的机器来跑。