我想从旋转角度和距离到对象的角度计算透视变换(warpPerspective函数的矩阵).
怎么做?
我在OE上找到了代码.示例程序如下:
#include <opencv2/objdetect/objdetect.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> #include <math.h> using namespace std; using namespace cv; Mat frame; int alpha_int; int dist_int; int f_int; double w; double h; double alpha; double dist; double f; void redraw() { alpha = (double)alpha_int/1000.; //dist = 1./(dist_int+1); //dist = dist_int+1; dist = dist_int-50; f = f_int+1; cout << "alpha = " << alpha << endl; cout << "dist = " << dist << endl; cout << "f = " << f << endl; // Projection 2D -> 3D matrix Mat A1 = (Mat_<double>(4,3) << 1,-w/2,1,-h/2,1); // Rotation matrices around the X axis Mat R = (Mat_<double>(4,4) << 1,cos(alpha),-sin(alpha),sin(alpha),1); // Translation matrix on the Z axis Mat T = (Mat_<double>(4,dist,1); // Camera Intrisecs matrix 3D -> 2D Mat A2 = (Mat_<double>(3,4) << f,w/2,f,h/2,0); Mat m = A2 * (T * (R * A1)); cout << "R=" << endl << R << endl; cout << "A1=" << endl << A1 << endl; cout << "R*A1=" << endl << (R*A1) << endl; cout << "T=" << endl << T << endl; cout << "T * (R * A1)=" << endl << (T * (R * A1)) << endl; cout << "A2=" << endl << A2 << endl; cout << "A2 * (T * (R * A1))=" << endl << (A2 * (T * (R * A1))) << endl; cout << "m=" << endl << m << endl; Mat frame1; warpPerspective( frame,frame1,m,frame.size(),INTER_CUBIC | WARP_INVERSE_MAP); imshow("Frame",frame); imshow("Frame1",frame1); } void callback(int,void* ) { redraw(); } void main() { frame = imread("FruitSample_small.png",CV_LOAD_IMAGE_COLOR); imshow("Frame",frame); w = frame.size().width; h = frame.size().height; createTrackbar("alpha","Frame",&alpha_int,100,&callback); dist_int = 50; createTrackbar("dist",&dist_int,&callback); createTrackbar("f",&f_int,&callback); redraw(); waitKey(-1); }
但不幸的是,这种变化确实有些奇怪
为什么?当alpha> 0时,上面的图像的另一半是什么?以及如何围绕其他轴旋转?为什么dist这么奇怪?
解决方法
我有很多时间来思考数学和代码.我在一两年前就这样做了.我甚至在美丽的LaTeX中排版.
我有意设计了我的解决方案,使得无论提供什么旋转角度,整个输入图像被包含在输出框架内,以黑色为中心.
我的warpImage函数的参数是所有3个轴的旋转角度,比例因子和垂直视野角.该功能输出输出图像中的翘曲矩阵,输出图像和源图像的角.
数学(代码,看下面)
守则(数学,看上面)
这是一个测试应用程序,扭曲相机
#include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <math.h> using namespace cv; using namespace std; static double rad2Deg(double rad){return rad*(180/M_PI);}//Convert radians to degrees static double deg2Rad(double deg){return deg*(M_PI/180);}//Convert degrees to radians void warpMatrix(Size sz,double theta,double phi,double gamma,double scale,double fovy,Mat& M,vector<Point2f>* corners){ double st=sin(deg2Rad(theta)); double ct=cos(deg2Rad(theta)); double sp=sin(deg2Rad(phi)); double cp=cos(deg2Rad(phi)); double sg=sin(deg2Rad(gamma)); double cg=cos(deg2Rad(gamma)); double halfFovy=fovy*0.5; double d=hypot(sz.width,sz.height); double sideLength=scale*d/cos(deg2Rad(halfFovy)); double h=d/(2.0*sin(deg2Rad(halfFovy))); double n=h-(d/2.0); double f=h+(d/2.0); Mat F=Mat(4,4,CV_64FC1);//Allocate 4x4 transformation matrix F Mat Rtheta=Mat::eye(4,CV_64FC1);//Allocate 4x4 rotation matrix around Z-axis by theta degrees Mat Rphi=Mat::eye(4,CV_64FC1);//Allocate 4x4 rotation matrix around X-axis by phi degrees Mat Rgamma=Mat::eye(4,CV_64FC1);//Allocate 4x4 rotation matrix around Y-axis by gamma degrees Mat T=Mat::eye(4,CV_64FC1);//Allocate 4x4 translation matrix along Z-axis by -h units Mat P=Mat::zeros(4,CV_64FC1);//Allocate 4x4 projection matrix //Rtheta Rtheta.at<double>(0,0)=Rtheta.at<double>(1,1)=ct; Rtheta.at<double>(0,1)=-st;Rtheta.at<double>(1,0)=st; //Rphi Rphi.at<double>(1,1)=Rphi.at<double>(2,2)=cp; Rphi.at<double>(1,2)=-sp;Rphi.at<double>(2,1)=sp; //Rgamma Rgamma.at<double>(0,0)=Rgamma.at<double>(2,2)=cg; Rgamma.at<double>(0,2)=sg;Rgamma.at<double>(2,0)=sg; //T T.at<double>(2,3)=-h; //P P.at<double>(0,0)=P.at<double>(1,1)=1.0/tan(deg2Rad(halfFovy)); P.at<double>(2,2)=-(f+n)/(f-n); P.at<double>(2,3)=-(2.0*f*n)/(f-n); P.at<double>(3,2)=-1.0; //Compose transformations F=P*T*Rphi*Rtheta*Rgamma;//Matrix-multiply to produce master matrix //Transform 4x4 points double ptsIn [4*3]; double ptsOut[4*3]; double halfW=sz.width/2,halfH=sz.height/2; ptsIn[0]=-halfW;ptsIn[ 1]= halfH; ptsIn[3]= halfW;ptsIn[ 4]= halfH; ptsIn[6]= halfW;ptsIn[ 7]=-halfH; ptsIn[9]=-halfW;ptsIn[10]=-halfH; ptsIn[2]=ptsIn[5]=ptsIn[8]=ptsIn[11]=0;//Set Z component to zero for all 4 components Mat ptsInMat(1,CV_64FC3,ptsIn); Mat ptsOutMat(1,ptsOut); perspectiveTransform(ptsInMat,ptsOutMat,F);//Transform points //Get 3x3 transform and warp image Point2f ptsInPt2f[4]; Point2f ptsOutPt2f[4]; for(int i=0;i<4;i++){ Point2f ptIn (ptsIn [i*3+0],ptsIn [i*3+1]); Point2f ptOut(ptsOut[i*3+0],ptsOut[i*3+1]); ptsInPt2f[i] = ptIn+Point2f(halfW,halfH); ptsOutPt2f[i] = (ptOut+Point2f(1,1))*(sideLength*0.5); } M=getPerspectiveTransform(ptsInPt2f,ptsOutPt2f); //Load corners vector if(corners){ corners->clear(); corners->push_back(ptsOutPt2f[0]);//Push Top Left corner corners->push_back(ptsOutPt2f[1]);//Push Top Right corner corners->push_back(ptsOutPt2f[2]);//Push Bottom Right corner corners->push_back(ptsOutPt2f[3]);//Push Bottom Left corner } } void warpImage(const Mat &src,double theta,double phi,double gamma,double scale,double fovy,Mat& dst,Mat& M,vector<Point2f> &corners){ double halfFovy=fovy*0.5; double d=hypot(src.cols,src.rows); double sideLength=scale*d/cos(deg2Rad(halfFovy)); warpMatrix(src.size(),theta,phi,gamma,scale,fovy,M,&corners);//Compute warp matrix warpPerspective(src,dst,Size(sideLength,sideLength));//Do actual image warp } int main(void){ Mat m,disp,warp; vector<Point2f> corners; VideoCapture cap(0); while(cap.isOpened()){ cap >> m; warpImage(m,5,50,30,warp,corners); imshow("Disp",disp); } }