1. 程式人生 > >Homography 筆記(附 OpenCV 程式碼)

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