1、仿射变换是透射变换的一个特例。其仿射变换是线性的,其需要的是2*3的矩阵和三个控点。透视变换是非线性的,

其需要的是3*3的矩阵和四个控点,具体的可以opencv2书里的,后面附带透射变换和仿射变换的程序

 

 

当我们绕着图像原点进行图像旋转时,其旋转矩阵M是:

opencv 仿射变换 复原 opencv仿射变换函数_仿射变换

 

 

opencv 仿射变换 复原 opencv仿射变换函数_#include_02

 

此变换如果在sin和cos前面加个系数,则是进行旋转和缩放。

 

如果要进行绕图像任意位置的旋转,则需计其:M=[
α β−βα(1−α)centerx−βcenteryβcenterx+(1−α)centery]   其中a的scale*cos(angle),

 

b为scale*sin(angle),这个是具有缩放因子的,把scale置1则是无缩放的,(记住其不是先绕原点旋转,

然后再平移的),这个矩阵可以

由OPencv提供的函数 getRotationMatrix2D获得。应用例子为

 

2、透视变换跟仿射变换不同,其需要的是3*3的矩阵,其例子如下:

 

透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。通用的变换公式为:

opencv 仿射变换 复原 opencv仿射变换函数_opencv 仿射变换 复原_03

u,v是原始图片左边,对应得到变换后的图片坐标x,y,其中

opencv 仿射变换 复原 opencv仿射变换函数_f5_04

。则原始图像点转换到目标图像时的

坐标如下:

 

opencv 仿射变换 复原 opencv仿射变换函数_#include_05

 

 

注意:estimateRigidTransform是用在仿射变换里进行刷选三个标准点进行计算仿射变换矩阵的。


findHomography是用在投射变换里进行筛选四个标准点进行计算透射变换矩阵的。


 

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
/// 全局变量
char* source_window = "Source image";
char* warp_window = "Warp";
char* warp_rotate_window = "Warp + Rotate";
/** @function main */
 int main( int argc, 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], 1 );
   /// 设置目标图像的大小和类型与源图像一致
   warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
   /// 设置源图像和目标图像上的三组点以计算仿射变换
   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 );
    /*这里的getAffineTransform函数获得的是包含了这两个三角形之间的缩放平移和旋转关系,这里跟在稳像时用*/
   ///estimateRigidTransform获取三个最稳定的角点,然后计算其仿射变换矩阵,其实可以利用这个函数来获取,但是其利用随机抽样一致性算法计算得到的点  
   ///可能大于三个,所以不能使用getaffinetransform获取,要使用函数来获取变换矩阵,如果已知角度和        旋转点则使用getrotationMatrix2D函数来获取矩阵  
   warp_mat = getAffineTransform( srcTri, dstTri );   
   /// 对源图像应用上面求得的仿射变换
   warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
   /* 对图像扭曲后再旋转 */
   /// 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
   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, CV_WINDOW_AUTOSIZE );
   imshow( source_window, src );
   <strong>namedWindow( warp_window, CV_WINDOW_AUTOSIZE );</strong>
   imshow( warp_window, warp_dst );
   namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE );
   imshow( warp_rotate_window, warp_rotate_dst );
   /// 等待用户按任意按键退出程序
   waitKey(0);
   return 0;
  }

 

两种变换的程序:

 

// 透射变换.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

//透视变换  
#include <cv.h>  
#include  <highgui.h>  
#include <math.h>  

int main(int argc, char** argv)
{
	CvPoint2D32f srcQuad[4], dstQuad[4];
	CvMat* warp_matrix = cvCreateMat(3, 3, CV_32FC1);
	IplImage *src, *dst;
	src = cvLoadImage("lena.jpg", 1);
	if (!src)
		return -1;
	cvNamedWindow("Perspective_warp", 1);
	int pressKey;
	int df1(1), df2(1), df3(1), df4(1), df5(1), df6(1), df7(1), df8(1);
	//定义四个控点
	df1 = 5; df2 = 33; df3 = 90; df4 = 25; df5 = 20; df6 = 70; df7 = 80; df8 = 90;
	dst = cvCloneImage(src);
	dst->origin = src->origin;
	cvZero(dst);

	//这个是定义原先的四个点
	srcQuad[0].x = 0;
	srcQuad[0].y = 0;
	srcQuad[1].x = src->width - 1;
	srcQuad[1].y = 0;
	srcQuad[2].x = 0;
	srcQuad[2].y = src->height - 1;
	srcQuad[3].x = src->width - 1;
	srcQuad[3].y = src->height - 1;
	float delta = 0.01;
	while (1)
	{
		 //定义变换后的四个点,目的是通过这八个点来求出其3*3的透视变换矩阵
		dstQuad[0].x = src->width*delta*abs(df1 % 101);
		dstQuad[0].y = src->height*delta*abs(df2 % 101);
		dstQuad[1].x = src->width*delta*abs(df3 % 101);
		dstQuad[1].y = src->height*delta*abs(df4 % 101);
		dstQuad[2].x = src->width*delta*abs(df5 % 101);
		dstQuad[2].y = src->height*delta*abs(df6 % 101);
		dstQuad[3].x = src->width*delta*abs(df7 % 101);
		dstQuad[3].y = src->height*delta*abs(df8 % 101);
		//这是透射变换的函数,其与仿射变换的函数不同 
		cvGetPerspectiveTransform(srcQuad, dstQuad, warp_matrix);
		cvWarpPerspective(src, dst, warp_matrix);
		//--------------------------字符显示-----------------------------------------  
		CvFont font = cvFont(1, 1);
		char buf[8];
		char dspStr1[32] = { '/0' };  //  
		char dspStr2[32] = { '/0' };  //  
		char dspStr3[32] = { '/0' };  //  

		memset(buf, '/0', sizeof(buf));
		strcat(dspStr1, "|");
		strcat(dspStr1, itoa(abs(df6 % 101), buf, 10));
		strcat(dspStr1, ",");
		strcat(dspStr1, itoa(abs(df7 % 101), buf, 10));
		strcat(dspStr1, ",");
		strcat(dspStr1, itoa(abs(df8 % 101), buf, 10));
		strcat(dspStr1, "|");

		strcat(dspStr2, "|");
		strcat(dspStr2, itoa(abs(df4 % 101), buf, 10));
		strcat(dspStr2, ",00,");
		strcat(dspStr2, itoa(abs(df5 % 101), buf, 10));
		strcat(dspStr2, "|");
		 
		strcat(dspStr3, "|");
		strcat(dspStr3, itoa(abs(df1 % 101), buf, 10));
		strcat(dspStr3, ",");
		strcat(dspStr3, itoa(abs(df2 % 101), buf, 10));
		strcat(dspStr3, ",");
		strcat(dspStr3, itoa(abs(df3 % 101), buf, 10));
		strcat(dspStr3, "|");

		cvPutText(dst, dspStr1, cvPoint(dst->width - 120, 20), &font, cvScalar(0, 0xff));
		cvPutText(dst, dspStr2, cvPoint(dst->width - 120, 40), &font, cvScalar(0, 0xff));
		cvPutText(dst, dspStr3, cvPoint(dst->width - 120, 60), &font, cvScalar(0, 0xff));
		//-------------------------------------------------------------------  
		cvShowImage("Perspective_warp", dst);
		pressKey = cvWaitKey(0);
		printf("%x pressed/n", pressKey);
		switch (pressKey)
		{
		case '1':
			df1++;
			break;
		case 0x230000:
			df1--;
			break;
		case '2':
			df2++;
			break;
		case 0x280000:
			df2--;
			break;
		case '3':
			df3++;
			break;
		case 0x220000:
			df3--;
			break;
		case '4':
			df4++;
			break;
		case 0x250000:
			df4--;
			break;
		case '6':
			df5++;
			break;
		case 0x270000:
			df5--;
			break;
		case '7':
			df6++;
			break;
		case 0x240000:
			df6--;
			break;
		case '8':
			df7++;
			break;
		case 0x260000:
			df7--;
			break;
		case '9':
			df8++;
			break;
		case 0x210000:
			df8--;
			break;
		case 27:
			cvReleaseImage(&dst);
			cvDestroyWindow("Perspective_warp");
			cvReleaseMat(&warp_matrix);
			return 0;
		default:break;
		}
	}
	return 0;
}
/*
//仿射变换
#include <cv.h>
#include <highgui.h>

int main(int argc,char** argv)
{
CvPoint2D32f srcTri[3],dstTri[3];
CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1);
CvMat* warp_mat = cvCreateMat(2,3,CV_32FC1);
IplImage *src,*dst, *srcBak;
//int df1(0),df2(33),df3(85),df4(25),df5(15),df6(70);
int df1(0),df2(0),df3(0),df4(0),df5(0),df6(0);
double angle(-50.0),scale(0.6);
float delta = 0.01;
int pressKey;

if(!(src=cvLoadImage("../ac.jpg",1)) )
{
return -1;
}
srcTri[0].x = 0;
srcTri[0].y = 0;
srcTri[1].x = src->width-1;
srcTri[1].y = 0;
srcTri[2].x = 0;
srcTri[2].y = src->height-1;
dst = cvCloneImage(src);
srcBak = cvCloneImage(src);
cvCopy(src,srcBak);
dst->origin = src->origin;
cvZero(dst);
cvNamedWindow("at",1);
CvFont font = cvFont(1,1);

while(1)
{
dstTri[0].x = srcBak->width*delta*(df1%101);
dstTri[0].y = srcBak->height*delta*(df2%101);
dstTri[1].x = src->width-1 + srcBak->width*delta*(df3%101);
dstTri[1].y = srcBak->height*delta*(df4%101);
dstTri[2].x = srcBak->width*delta*(df5%101);
dstTri[2].y = src->height-1 + srcBak->height*delta*(df6%101);

cvGetAffineTransform(srcTri,dstTri,warp_mat);
cvWarpAffine(srcBak,dst,warp_mat);
cvCopy(dst,src);
//compute rotation matrix
CvPoint2D32f center = cvPoint2D32f(src->width/2,src->height/2);
cv2DRotationMatrix(center,angle,scale,rot_mat);
//do the transformation
cvWarpAffine(src,dst,rot_mat);
//--------------------------字符显示-----------------------------------------
char buf[8];
char dspStr1[32] = {'/0'};  //
char dspStr2[32] = {'/0'};  //
char dspStr3[32] = {'/0'};  //

memset(buf,'/0',sizeof(buf));
strcat(dspStr1,"|");
strcat(dspStr1,itoa(df4%101,buf,10));
strcat(dspStr1,",");
strcat(dspStr1,itoa(df5%101,buf,10));
strcat(dspStr1,",");
strcat(dspStr1,itoa(df6%101,buf,10));
strcat(dspStr1,"|");

strcat(dspStr2,"|angle=");
strcat(dspStr2,itoa(int(angle),buf,10));
strcat(dspStr2,",scale=");
strcat(dspStr2,itoa(int(scale*100),buf,10));
strcat(dspStr2,"%|");
//「」┌└┘┐|
strcat(dspStr3,"|");
strcat(dspStr3,itoa(df1%101,buf,10));
strcat(dspStr3,",");
strcat(dspStr3,itoa(df2%101,buf,10));
strcat(dspStr3,",");
strcat(dspStr3,itoa(df3%101,buf,10));
strcat(dspStr3,"|");
cvPutText(dst,dspStr1,cvPoint(dst->width-120,20),&font,cvScalar(0,0xff));
cvPutText(dst,dspStr2,cvPoint(dst->width-210,40),&font,cvScalar(0,0xff));
cvPutText(dst,dspStr3,cvPoint(dst->width-120,60),&font,cvScalar(0,0xff));
//-------------------------------------------------------------------------------------
cvShowImage("at",dst);
pressKey = cvWaitKey();
//  printf("src->width:%d/n",src->width);
printf("%c pressed/n",pressKey);
switch(pressKey)
{
case '1':
df1++;
break;
case 0x230000:
df1--;
break;
case '2':
df2++;
break;
case 0x280000:
df2--;
break;
case '3':
df3++;
break;
case 0x220000:
df3--;
break;
case '4':   //旋转角度
angle++;
break;
case 0x250000:
angle--;
break;
case '6':   //缩放
scale+=0.01;
break;
case 0x270000:
scale-=0.01;
break;
case '7':
df4++;
break;
case 0x240000:
df4--;
break;
case '8':
df5++;
break;
case 0x260000:
df5--;
break;
case '9':
df6++;
break;
case 0x210000:
df6--;
break;
case 27:
cvReleaseImage(&dst);
cvDestroyWindow("at");
cvReleaseMat(&rot_mat);
cvReleaseMat(&warp_mat);
return 0;
default:break;
}
}

cvReleaseImage(&dst);
cvReleaseMat(&rot_mat);
cvReleaseMat(&warp_mat);
return 0;
}
*/