最近发现网上关于 estimateRigidTransform 的详细说明很少,因此这里做一个详细的解释。希望对大家有用。
一、函数定义如下:
Mat estimateRigidTransform(InputArraysrc,InputArraydst,boolfullAffine)
前两个参数,可以是 :src=srcImage (变换之前的图片Mat) dst=transImage(变换之后的图片Mat)
也可以: src=array(变换之前的关键点Array) dst=array(变换之后的关键点Array)
第三个参数: 1(全仿射变换,包括:rotation, translation, scaling,shearing,reflection)
0(带有约束的仿射变换)
默认参数1:全仿射变换。
fullAffine 与 partialAaffine 主要区别是:变换矩阵中后者可以是刚体变换。(不是必须,体会可以的含义)
也就可以后者没有尺度缩放。
二、直观感受:
paritcalAffine 的变换矩阵必须是如下类型:
旋转矩阵对角线元素的 绝对值 肯定相等。
假设我们的矩阵
|a11|=|a22| 同时|a21|=|a22|.真是基本条件。
fullAffine 的rotate矩阵可以是:
旋转矩阵可以没有任何数值上的约束。aii之间无数值上的约束。
三、fullAffine原理及变换公式
如果我们有一个点变换之前是[x,y,1],变换后是[x',y',1] 则fullAffine表示如下:
展开后表示
如果我们想求这【a-f】 6个变量需要有6个方程,也就是3组点。但是比三个点多呢?
比如:20个点。那就是用最小方差。
四、partial affine的原理及变换公式
1.尺度变换
2.旋转矩阵
1、2结合后
注意:这里的tx 指的是x方向的transpose (平移),ty同理。
解这个T需要四个方程:也就是两组点。同样,点多的情况下用最小方差原理。计算最优变换。
1 #ifndef _HEAD_H_ 2 #define _HEAD_H_ 3 4 #include 5 6 /* definitions of Macros */ 7 8 #define PI 3.141592 9 #define MAX_COUNT 30 10 cv::Mat preTransGray, curTransGray; 11 cv::Mat preRotaGray , curRotaGray; 12 std::vector transPoints[2], rotaPoints[2],knowPoint[2]; std::vector status; std::vectorerr; 13 14 void testOpticalFlowEstimation() 15 { 16 std::cout << "optical flow methon for estimating the transform form reference scan " << "to reference scan ..." << std::endl; double refPose_x = 250, refPose_y = 250; // Init rectangle center 17 cv::Mat trans_src_image = cv::imread("./testImage/squareRef.png"); // resolution: 500*500 and the rectangle center is (250,250) 18 cv::Mat trans_dst_image = cv::imread("./testImage/squareCur.png"); // resolution: 500*500 and the rectangle center is (260,240) 19 cv::Mat rota_src_image = cv::imread("./testImage/rotateRectRef.png"); 20 cv::Mat rota_dst_image = cv::imread("./testImage/rotateRectCur.png"); 21 cv::Mat contra_image = cv::imread("./testImage/contrastRef_Rotate.png"); 22 cvtColor(trans_src_image,preTransGray, cv::COLOR_BGR2GRAY); 23 cvtColor(trans_dst_image,curTransGray, cv::COLOR_BGR2GRAY); 24 cvtColor(rota_src_image,preRotaGray, cv::COLOR_BGR2GRAY); 25 cvtColor(rota_dst_image,curRotaGray, cv::COLOR_BGR2GRAY); 26 cv::TermCriteria termcrit(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 20 ,0.01); 27 cv::Size subPixWinSize(10,10), winSize(31,31); 28 goodFeaturesToTrack(preTransGray,transPoints[0],MAX_COUNT,0.01,10); // 29 find corners goodFeaturesToTrack(preRotaGray,rotaPoints[0],MAX_COUNT,0.01,10); // find corners /*subpiexl detection*/ // 30 cornerSubPix(curGray,points[0],subPixWinSize,cv::Size(-1,-1),termcrit); 31 cornerSubPix(preTransGray,transPoints[0],subPixWinSize,cv::Size(-1,-1),termcrit); 32 cornerSubPix(preRotaGray,rotaPoints[0],subPixWinSize,cv::Size(-1,-1),termcrit); /*PryLK method calculate optical flow*/ // 33 calcOpticalFlowPyrLK(preGray,curGray,points[0],points[1],status,err,winSize,5,termcrit,0,0.01); 34 calcOpticalFlowPyrLK(preTransGray,curTransGray,transPoints[0],transPoints[1],status,err,winSize,3,termcrit,0,0.01); 35 calcOpticalFlowPyrLK(preRotaGray,curRotaGray,rotaPoints[0],rotaPoints[1],status,err,winSize,3,termcrit,0,0.01); // Notice the last para in estimateRigidTransform func 36 37 // if you choose 0 : partAffine , indicate you will perform a rigid transform // choose 1 : fullAffine , indicate you will perform a non-rigid transfrom 38 cv::Mat transEstimate = estimateRigidTransform(transPoints[0],transPoints[1],0); 39 cv::Mat rotaEstimate = estimateRigidTransform(rotaPoints[0],rotaPoints[1],0); 40 #if 0 41 This program silce tests some points rigid transform Note :that we already know the Points position before & after transform 42 #endif 43 cv::Point2f a(230,220),b(270,220),c(270,280),d(230,280); 44 cv::Point2f Ta(220,270),Tb(220,230),Tc(280,230),Td(280,270); 45 knowPoint[0].push_back(a), knowPoint[1].push_back(Ta); 46 knowPoint[0].push_back(b), knowPoint[1].push_back(Tb); 47 knowPoint[0].push_back(c), knowPoint[1].push_back(Tc); 48 knowPoint[0].push_back(d), knowPoint[1].push_back(Td); 49 cv::Mat pointEstimate = estimateRigidTransform(knowPoint[0],knowPoint[1],0); 50 std::cout << "pointEstimate : \n" << pointEstimate << std::endl; std::cout << "transEstimate : \n" << transEstimate << std::endl; std::cout << 51 "rotaEstimate : \n" << rotaEstimate << std::endl; std::cout << "Test: before transform the center is " << refPose_x <<" "<< refPose_y << std::endl; refPose_x = transEstimate.at 52 (0)* refPose_x + transEstimate.at 53 (1)* refPose_y + transEstimate.at 54 (2); refPose_y = transEstimate.at 55 (3)* refPose_x + transEstimate.at 56 (4)* refPose_y + transEstimate.at 57 (5); 58 bool displayKeypoints = false; 59 if(displayKeypoints) 60 { 61 for(auto c:transPoints[0]) 62 { 63 std::cout << c << std::endl; circle(preTransGray,c,2,cv::Scalar(0,15,255),-1); 64 } 65 std::cout << "========================== " << std::endl; 66 for(auto c:transPoints[1]) 67 { 68 std::cout << c << std::endl; circle(curTransGray,c,2,cv::Scalar(0,97,25),-1); 69 } 70 } 71 cv::imshow("preGray",preTransGray); 72 cv::waitKey(0); 73 cv::imshow("vertGray",curTransGray); 74 cv::waitKey(0); 75 std::cout << "Test after transform the center is " << refPose_x << " "<< refPose_y << std::endl; 76 } 77 78 #endif