Homography 笔记(附 OpenCV 代码)

翻译自 https://www.learnopencv.com/homography-examples-using-opencv-python-c/
依个人口味略作修改,侵权删。

据圣经神话的记载,巴别塔(The Tower of Babel)是人类的第一个工程灾难。这个项目具备了所有的条件,但是仍然失败了。因为上帝混淆了人类的语言,从而使得他们无法再有效的沟通协作,进而导致了通天塔的崩溃和人类的混乱。

在我看来,像 Homography 这样的术语在时刻提醒我们,我们仍在为语言构成的沟通鸿沟而挣扎。Homography 就是一个很简单的概念却起了一个很唬人的名字。

什么是 Homography?

考虑 同一个平面(比如书皮)的两张图片,红点表示同一个物理坐标点在两张图片上的各自位置。在 CV 术语中,我们称之为对应点。

Corresponding points

Homography 就是将一张图像上的点映射到另一张图像上对应点的3x3变换矩阵.
A Homography is a transformation ( a 3×3 matrix ) that maps the points in one image to the corresponding points in the other image.

因为 Homography 是一个 3x3 的 矩阵,所以我们可以把它写成

Homography

对于图中的一对儿对应点,位于图一的 (x1, y1) 和 位于图二的 (x2, y2). H 把二者映射关系建立起来

H

使用 Homography 进行图像对齐(Image Alignment)

对于所有的对应点,只要它们都位于同一个物理平面上,上述 Homography 就是成立的。换句话说,就是可以把图一中书皮上的所有点都映射到图二的书皮上,也就是看起来,图一中的书皮和图二中的书皮对齐了!如下图:

Image Alignment

那么对于不在此平面上的点呢?这时再应用 Homography 就无法再对齐到对应点了。比如 上图中的 桌面,地面,橱柜面。对于这种图像中有多个平面的情况,我们就需要针对每一个平面使用其对应的Homography了。

全景拼接:Homography 的一个重要应用

在前面的例子中,我们知道,如果已知 两个图像的 Homography,那么我们可以把一张图像 warp 到 另外一张图像内去。但是,这里有一个很严重的bug:两张图像必须包含同一个平面,并且仅有这个平面上的点是准确对齐的。事实上,可以证明,如果你用相机拍摄一张任意风景的照片(不仅仅是一个平面)然后旋转相机再任意拍摄一张,这两张照片可以用一个 Homography 联系起来! 刚才拍摄的两张任意3D场景的图片可以用 Homography 联系起来,而两张图像会有一些共同的区域,这些区域又可以用来对齐和拼接,bingo,这样你就可以得到这两张图像的全景拼接图了。当然,这还是很粗糙的全景拼接,还需要很多精细的细节操作,但是基本原理是这样的,用Homography 把共同的部分对齐,然后巧妙的拼接,从而看不到拼缝。全景拼接,大功告成。

如何计算 Homography?

对于 H 矩阵,一般设 H22 为 1, 所以 H 有 8 个未知参数。至少需要8 个等式才能求解。而一组对应点可以提供 2 个等式,所以,至少需要 4 组对应点(任意三点不共线)来求得 H。 如果有更多组对应点,效果更佳。 OpenCV 可以鲁棒地计算出一个最好地拟合所有对应点的 Homography。通常,图像间的这些对应点通过 SIFT 或者 SURF 这样算法进行自动特征提取和匹配。当然,对于简单的demo,手动选取对应点就足够了。

OpenCV C++

//pts_src : 源图像点坐标
//pts_dst : 结果图像坐标
// 数据类型都是 vector<Point2f>.
// 需要至少4组对应点.
Mat h = findHomography(pts_src, pts_dst);

//im_src : 源图像
// im_dst : 结果图像
// h: 上一步计算得到的 Homography
// size : im_dst 的 大小(宽度,高度)
// 将 im_src 通过 h warp 到 im_dst 上去
warpPerspective(im_src, im_dst, h, size);

下面是一个例子

#include "opencv2/opencv.hpp" 

using namespace cv;
using namespace std;

int main( int argc, char** argv)
{
    // Read source image.
    Mat im_src = imread("book2.jpg");
    // Four corners of the book in source image
    vector<Point2f> pts_src;
    pts_src.push_back(Point2f(141, 131));
    pts_src.push_back(Point2f(480, 159));
    pts_src.push_back(Point2f(493, 630));
    pts_src.push_back(Point2f(64, 601));


    // Read destination image.
    Mat im_dst = imread("book1.jpg");
    // Four corners of the book in destination image.
    vector<Point2f> pts_dst;
    pts_dst.push_back(Point2f(318, 256));
    pts_dst.push_back(Point2f(534, 372));
    pts_dst.push_back(Point2f(316, 670));
    pts_dst.push_back(Point2f(73, 473));

    // Calculate Homography
    Mat h = findHomography(pts_src, pts_dst);

    // Output image
    Mat im_out;
    // Warp source image to destination based on homography
    warpPerspective(im_src, im_out, h, im_dst.size());

    // Display images
    imshow("Source Image", im_src);
    imshow("Destination Image", im_dst);
    imshow("Warped Source Image", im_out);

    waitKey(0);
}

Homography 应用

虚拟广告牌

在很多直播体育赛事中,广告是动态插入到直播视频流中去的,从而根据观众的个人喜好,地域习俗等展示个性化的广告。

以下是第一张上传到互联网的图片

the first image uploaded to the internet

下图是 时代广场的 图片

The Times Square, NY

好了,我们想把 第一张图嵌入到 时代广场的 广告屏上去,4 步搞定

  1. 选择时代广场上广告屏的 4 个顶点,作为 pts_dst
  2. 选取欲嵌入的图像的 4 个顶点,假设图像尺寸 W x H, 那么 四个顶点就是 (0,0), (0, W-1), (H - 1, 0), (H - 1, W - 1)
  3. 使用 pts_dst 和 pts_src 计算 Homography
  4. 对 源图像应用计算得到的 Homography 从而 混合到 目标图像上。得到下图

Warped Image

猜你喜欢

转载自blog.csdn.net/baishuo8/article/details/80777995