天天看點

[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結

《聖經》記載,當時人類聯合起來興建希望能通往天堂的高塔;為了阻止人類的計劃,上帝讓人類說不同的語言,使人類互相之間不能溝通,計劃是以失敗。

像“Homography”這樣的術語經常提醒我,我們仍然在與溝通鬥争。Homography(單應性)是一個簡單的概念,卻有一個奇怪的名字!

1 介紹

1.1 什麼是Homography

考慮圖1所示的同一個平面(比如書皮)的兩幅圖像。紅點表示兩幅圖像中相同的實體坐标點。在計算機視覺術語中,我們稱之為對應點。

[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結

Homography就是将一張圖像上的點映射到另一張圖像上對應點的3x3變換矩陣。是以該矩陣我們可以表示為:

[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結

讓我們考慮一組對應點,

[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結

位于第一張圖像和

[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結

位于第二張圖像中。然後,Homography以下列方式映射它們:

[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結

1.2 使用Homography進行圖像對齊

隻要它們位于現實世界中的同一平面上,上述等式對于所有對應點都是正确的。換句話說,您可以将單應性應用于第一張圖像,第一張圖像中的書籍将與第二張圖像中的書籍對齊!見下圖。那麼對于不在此平面上的點呢?這時再應用 Homography 就無法再對齊到對應點了。比如下圖的桌子,地闆。對于這種圖像中有多個平面的情況,我們就需要針對每一個平面使用單獨的Homography進行對齊。

[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結

1.3 Homography的應用-全景拼接

在上一節中,我們了解到如果已知兩個圖像之間的Homography,我們可以将一個圖像映射到另一個圖像上。但是,有一個很大的問題。圖像必須位于同一個平面(書的頂部),并且隻有該平面部分才會正确對齊。事實證明,如果您拍攝任何不包括一個平面的場景,然後通過旋轉相機拍攝第二張照片,這兩張圖檔就可以通過Homography相關聯!您剛剛拍攝的完全随意的3D場景的兩個圖像可以用Homography相關聯。這兩個圖像将共享一些可以對齊和拼接的公共區域,并且可以獲得兩個圖像的全景圖。然而這隻是很粗糙的全景拼接,但基本原則是使用Homography和智能拼接。

2 Homography的計算

要計算兩個圖像之間的單應性,您需要知道兩個圖像之間至少有4個點對應關系。如果你有超過4個對應點,那就更好了。原因在于對于 H 矩陣,一般設 H22 為 1, 是以 H 有 8 個未知參數。至少需要8 個等式才能求解。而一組對應點可以提供 2 個等式,是以,至少需要 4 組對應點(任意三點不共線)來求得 H。OpenCV将穩健地估計最适合所有對應點的單應性。通常,這些點對應是通過比對圖像之間的SIFT或SURF等特征自動找到的,但在這篇文章中我們隻是提前設定特征點。代碼如下:

C++代碼:

// OpenCV_Homography.cpp : 此檔案包含 "main" 函數。程式執行将在此處開始并結束。
//

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    // Read source image 原圖
    Mat im_src = imread("./image/book2.jpg");
    // Four corners of the book in source image 4個角點
    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("./image/book1.jpg");

    // Four corners of the book in destination image. 4個對應點
    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 計算Homography需要至少4組對應點.
    // pts_src : 源圖像點坐标,pts_dst : 結果圖像坐标
    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);
    return 0;
}
           

python代碼:

#!/usr/bin/env python

import cv2
import numpy as np

if __name__ == '__main__' :

    # Read source image.
    im_src = cv2.imread('./image/book2.jpg')
    # Four corners of the book in source image
    pts_src = np.array([[141, 131], [480, 159], [493, 630],[64, 601]])

    # Read destination image.
    im_dst = cv2.imread('./image/book1.jpg')
    # Four corners of the book in destination image.
    pts_dst = np.array([[318, 256],[534, 372],[316, 670],[73, 473]])

    # Calculate Homography
    h, status = cv2.findHomography(pts_src, pts_dst)

    # Warp source image to destination based on homography
    im_out = cv2.warpPerspective(im_src, h, (im_dst.shape[1],im_dst.shape[0]))

    # Display images
    cv2.imshow("Source Image", im_src)
    cv2.imshow("Destination Image", im_dst)
    cv2.imshow("Warped Source Image", im_out)

    cv2.waitKey(0)

           

3 總結

舉個例子,例如虛拟廣告牌,把下圖1替換下圖2的廣告,得到下圖3

[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結
[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結
[OpenCV實戰]18 Opencv中的單應性矩陣Homography1 介紹2 Homography的計算3 總結

實際步驟很簡單

1 用選擇上圖2時代廣場上廣告屏的 4 個頂點,作為 pts_dst;

2 選取欲嵌入的圖像的 4 個頂點,假設圖像尺寸 W x H, 那麼 四個頂點就是 (0,0), (0, W-1), (H - 1, 0), (H - 1, W - 1)。作為pts_src 類似下面代碼,這樣pts_src 和pts_dst就是一組對應點;

// Create a vector of points.
    vector<Point2f> pts_src;
    pts_src.push_back(Point2f(0,0));
    pts_src.push_back(Point2f(size.width - 1, 0));
    pts_src.push_back(Point2f(size.width - 1, size.height -1));
    pts_src.push_back(Point2f(0, size.height - 1 ));
           
// Calculate Homography 計算Homography需要至少4組對應點.
    // pts_src : 源圖像點坐标,pts_dst : 結果圖像坐标
    Mat h = findHomography(pts_src, pts_dst);
           
// Warp source image
    warpPerspective(im_src, im_temp, h, im_temp.size());