SIFT and Image Stitching
图像处理课期中要写一个图像拼接程序.
这方面的技术当然已经很成熟了, 开源界最著名的当属 hugin, 拼全景图效果非常好. 在学术界也已经不是难题了, Lowe 在 IJCV2007 的一篇 Automatic Panoramic Image Stitching using Invariant Features 是一个完整的流程介绍. MSRA 的 Szeliski 有过一本几十页的 Image Alignment and Stitching: A Tutorial, 也详细的介绍了图像拼接的众多方法. 我基本就照着 Lowe, Szeliski 的一堆论文的方法在搞.
首先是要找 Feature. Image Stitching 对 Feature 的要求不是特别高, 一些简单的 Feature 似乎就可以. 但根据老师的建议我还是写了一个 SIFT. SIFT 的一个比较全面的介绍应该是 Lowe 在 IJCV2004 的一篇 Distinctive Image Features from Scale-Invariant Keypoints, 至今已有近 2 万引用 orz.SIFT 的大致步骤如下:
-
Scale-Space and DOG-Space
Scale-Space 是个早已在用的技术. 简单来说就是对于一张图片, 把它 resize 成
种尺寸, 加 种不同尺度的 Gaussion Blur, 得到的 张图就叫 Scale-Space, 把它们再两两做差就得到 DOG-Space. 不过之前看到过一本厚厚的书就叫什么 CV 中的 Scale Space 方法, 所以这应该只是一个粗浅的理解, 好像还有更高端的东西. -
Keypoint
这时候, Lowe 说, DOG-Space 里的极值点基本上就是关键点了, 只要再做些小处理. 处理包括在局部计算一些偏移, 舍去一些不太好的点 (对比度低, 在边缘上).
-
Orientation
SIFT 是 Rotation Invariant 的. 实现这一点其实也比较直观, 就是在每个关键点处找一个主方向出来, 用相对角度作为 Feature Descriptor. 最终的 Descriptor 就是在关键点周围找 16 个点, 每个点周围八个相对方向的梯度值. 是一个 128-d 的 double vector.
-
Matching
Lowe 也给了 Matching 的方法, 说用欧式距离是最好的. 另外还说如果最好与次好相差太小就不要了.
在两幅图的 Feature 匹配上之后, 要算一个转移矩阵出来, 大家都说用一个 RANSAC 算法. 名字听上去好 NB 啊: Random Sample Consensus, 其实很 SB.. 大致就是: 先随机取些匹配点, 把矩阵解出来, 看这个矩阵 Match 了多少个点. 嗯, 这没问题, 然后.. 再随机取些点, 再解出来, 再随机取点, 再解出来.. 最后用最好的那个..... 给这算法跪了.
但是只是这样做的话有一个问题: 如果摄像机是旋转拍摄, 变换矩阵是 8 参数的 Homography, 图片一多, 就会拼成这样:

地上那条白线本来是一个圆的, 理想情况在全景图中它应该被拉直, 可是我们真的快要把它拼成了一个圆.. 这当然是不行的, 再加上一两张图, 图片就会超大了 = =.
这个地方纠结了好久, 最后的解决方法是, 在全景图拼接时, 把原图先 warping 到一个柱面上. 一开始还有点想不通, 后来我看到了 Stanford CS178 的这个页面. 一个很直观的 applet.

然后就可以拼全景图出来了, 只是拼出来的整个曲线会扭曲. 这个根本原因应该是照相时具体参数不知道, 所以比例, 角度什么的全是错的, warp 到了错误的圆柱上. paper 里的 Bundle Adjustment 不会搞, 就自己 yy 了一个二分寻找最佳倾斜角的方法, 以把图片拉长为优化目标, 最后还真把图片给拉直了.
拉直了之后再做一些后处理, 在边界处做一些插值, 然后切成矩形, 图就拼好了~

后来开哥带我去拍了个外景:

把拼的图变换到极坐标上

源代码及一个正式一点的报告在 github
另外, 崔鹏老师的图像处理课十分不错, 上课内容不像很多课一样随随便便能在书里翻到. 而且讲的也都是挺精华挺注重理解的东西.
就像是 Andrew Ng 的机器学习给我的感觉一样, 想想并没有真的教特别多的知识, 但最精华的思想全部都包括了, 整个领域的 big picture 也有了.