OpenCV仿射變換

2018-09-15 10:19 更新

目標(biāo)

在本教程中,您將學(xué)習(xí)如何:

理論

什么是仿射變換(Affine Transformations)?

  • 可以以矩陣乘法(線(xiàn)性變換)的形式表示的轉(zhuǎn)換,后跟向量加法(轉(zhuǎn)換)。
  • 從上面我們可以使用仿射變換表達(dá):
  1. 旋轉(zhuǎn)(線(xiàn)性變換)
  2. 翻譯(矢量添加)
  3. 縮放操作(線(xiàn)性變換)

您可以看到,實(shí)質(zhì)上,仿射變換表示兩個(gè)圖像之間的關(guān)系。

  • 代表仿射變換的通常方法是使用2×3矩陣。

OpenCV仿射變換

考慮到我們要使用A和B來(lái)轉(zhuǎn)換2D矢量,我們可以這樣做:

OpenCV仿射變換

我們?nèi)绾潍@得仿射變換?

  • 我們提到仿射變換基本上是兩個(gè)圖像之間的關(guān)系。關(guān)于這種關(guān)系的信息大概可以通過(guò)兩種方式來(lái)實(shí)現(xiàn):
  1. 我們知道X和T,我們也知道它們是相關(guān)的。那么我們的任務(wù)就是找M
  2. 我們知道M和X。為了獲得T,我們只需要計(jì)算T= M? X。其中M的是確定的(i.e.即具有2乘3矩陣),或者它可以作為點(diǎn)之間的幾何關(guān)系。
  • 讓我們以更好的方式來(lái)解釋?zhuān)╞)。由于M和下面圖像2有關(guān),因此我們可以分析兩個(gè)圖像中三個(gè)點(diǎn)相關(guān)的最簡(jiǎn)單的情況??聪聢D:

OpenCV仿射變換

點(diǎn)1,2和3(在圖像1中形成三角形)被映射到圖像2中,仍然形成三角形,但是現(xiàn)在它們已經(jīng)變得眾所周知。如果我們發(fā)現(xiàn)這3個(gè)點(diǎn)的仿射變換(你可以根據(jù)需要選擇它們),那么我們可以將這個(gè)發(fā)現(xiàn)的關(guān)系應(yīng)用于圖像中的所有像素。

Code

  1. 這個(gè)程序是做什么的?加載圖像對(duì)圖像應(yīng)用仿射變換。該變換是從三點(diǎn)之間的關(guān)系得到的。為此,我們使用函數(shù)cv :: warpAffine。轉(zhuǎn)換后對(duì)圖像進(jìn)行旋轉(zhuǎn)。該旋轉(zhuǎn)相對(duì)于圖像中心等待用戶(hù)退出程序
  2. 本教程的代碼如下所示。您也可以在這里下載

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
const char* source_window = "Source image";
const char* warp_window = "Warp";
const char* warp_rotate_window = "Warp + Rotate";
int main( int, char** argv )
{
  Point2f srcTri[3];
  Point2f dstTri[3];
  Mat rot_mat( 2, 3, CV_32FC1 );
  Mat warp_mat( 2, 3, CV_32FC1 );
  Mat src, warp_dst, warp_rotate_dst;
  src = imread( argv[1], IMREAD_COLOR );
  warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
  srcTri[0] = Point2f( 0,0 );
  srcTri[1] = Point2f( src.cols - 1.f, 0 );
  srcTri[2] = Point2f( 0, src.rows - 1.f );
  dstTri[0] = Point2f( src.cols*0.0f, src.rows*0.33f );
  dstTri[1] = Point2f( src.cols*0.85f, src.rows*0.25f );
  dstTri[2] = Point2f( src.cols*0.15f, src.rows*0.7f );
  warp_mat = getAffineTransform( srcTri, dstTri );
  warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
  Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
  double angle = -50.0;
  double scale = 0.6;
  rot_mat = getRotationMatrix2D( center, angle, scale );
  warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
  namedWindow( source_window, WINDOW_AUTOSIZE );
  imshow( source_window, src );
  namedWindow( warp_window, WINDOW_AUTOSIZE );
  imshow( warp_window, warp_dst );
  namedWindow( warp_rotate_window, WINDOW_AUTOSIZE );
  imshow( warp_rotate_window, warp_rotate_dst );
  waitKey(0);
  return 0;
}

說(shuō)明

  • 聲明我們將使用的一些變量,例如存儲(chǔ)我們的結(jié)果的矩陣和2個(gè)點(diǎn)數(shù)組,以存儲(chǔ)定義我們的Affine變換的2D點(diǎn)。
Point2f srcTri [3];
Point2f dstTri [3];
Mat rot_mat(2,3,CV_32FC1);
Mat warp_mat(2,3,CV_32FC1);
Mat src,warp_dst,warp_rotate_dst;
  • 加載圖片:
src = imread(argv [1],1);
  • 將目標(biāo)圖像初始化為具有與源相同的大小和類(lèi)型:
warp_dst = Mat :: zeros(src.rows,src.cols,src.type());
  • 仿射變換:如上所述,我們需要兩組3點(diǎn)來(lái)推導(dǎo)仿射變換關(guān)系。看一看:
srcTri [0] = Point2f(0,0);
srcTri [1] = Point2f(src.cols  -  1,0);
srcTri [2] = Point2f(0,src.rows  -  1);
dstTri [0] = Point2f(src.cols * 0.0,src.rows * 0.33);
dstTri [1] = Point2f(src.cols * 0.85,src.rows * 0.25);
dstTri [2] = Point2f(src.cols * 0.15,src.rows * 0.7);

您可能想要繪制這些要點(diǎn),以便更好地了解其變化。它們的位置與示例圖中所示的位置大致相同(在理論部分)。您可能會(huì)注意到由3點(diǎn)定義的三角形的大小和方向改變。

warp_mat = getAffineTransform(srcTri,dstTri);

我們得到一個(gè)2×3矩陣作為輸出(在這種情況下為warp_mat

  • 然后我們將剛剛發(fā)現(xiàn)的仿射變換應(yīng)用到src圖像
warpAffine(src,warp_dst,warp_mat,warp_dst.size());

具有以下參數(shù):

  1. src:輸入圖像
  2. warp_dst:輸出圖像
  3. warp_mat:仿射變換
  4. warp_dst.size():輸出圖像所需的大小

我們剛剛得到了我們的第一個(gè)轉(zhuǎn)換的形象 我們會(huì)顯示一下。在此之前,我們也想旋轉(zhuǎn)它...

  • 旋轉(zhuǎn):要旋轉(zhuǎn)圖像,我們需要知道兩件事情:

  1. 相對(duì)于圖像將旋轉(zhuǎn)的中心
  2. 要旋轉(zhuǎn)的角度。在OpenCV中,正角度是逆時(shí)針?lè)较?/li>
  3. 可選:比例因子

我們使用以下代碼片段定義這些參數(shù):

Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
double angle = -50.0;
double scale = 0.6;

  • 我們用OpenCV函數(shù)cv :: getRotationMatrix2D生成旋轉(zhuǎn)矩陣,它返回一個(gè)2×3矩陣(在這種情況下為rot_mat

rot_mat = getRotationMatrix2D( center, angle, scale );

  • 我們現(xiàn)在將找到的旋轉(zhuǎn)應(yīng)用到我們以前的轉(zhuǎn)換的輸出。

warpAffine(warp_dst,warp_rotate_dst,rot_mat,warp_dst.size());

  • 最后,我們?cè)趦蓚€(gè)窗口中顯示我們的結(jié)果,加上原始圖像的良好度量:

namedWindow(source_window,WINDOW_AUTOSIZE);
imshow(source_window,src);
namedWindow(warp_window,WINDOW_AUTOSIZE);
imshow(warp_window,warp_dst);
namedWindow(warp_rotate_window,WINDOW_AUTOSIZE);
imshow(warp_rotate_window,warp_rotate_dst);

  • 我們只需要等到用戶(hù)退出程序

waitKey(0);

結(jié)果

在編譯上面的代碼之后,我們可以給它一個(gè)圖像的路徑作為參數(shù)。例如,對(duì)于像:

OpenCV仿射變換

在應(yīng)用第一個(gè)仿射變換后,我們得到:

OpenCV仿射變換

最后,在應(yīng)用負(fù)旋轉(zhuǎn)(記住負(fù)方向順時(shí)針)和比例因子后,我們得到:

OpenCV仿射變換

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)