1、仿射变换是透射变换的一个特例。其仿射变换是线性的,其需要的是2*3的矩阵和三个控点。透视变换是非线性的,
其需要的是3*3的矩阵和四个控点,具体的可以opencv2书里的,后面附带透射变换和仿射变换的程序
当我们绕着图像原点进行图像旋转时,其旋转矩阵M是:
此变换如果在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)。通用的变换公式为:
u,v是原始图片左边,对应得到变换后的图片坐标x,y,其中
。则原始图像点转换到目标图像时的
坐标如下:
注意: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;
}
*/