基本上就是learning opencv一书第4章,练习7的答案了。
先来个自己写的透视变换代码:
- //透视变换
- #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;
- //df1 = df2 = df3 = df4 = df5 = df6 = df7 = df8 = 0;
- 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)
- {
- //dstQuad[0].x = src->width*delta*(df1%101);
- //dstQuad[0].y = src->height*delta*(df2%101);
- //dstQuad[1].x = src->width - 1+src->width*delta*(df3%101);
- //dstQuad[1].y = src->height*delta*(df4%101);
- //dstQuad[2].x = src->width*delta*(df5%101);
- //dstQuad[2].y = src->height - 1+src->height*delta*(df6%101);
- //dstQuad[3].x = src->width - 1+src->width*delta*(df7%101);
- //dstQuad[3].y = src->height - 1+src->height*delta*(df8%101);
- 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();
- 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;
- }
这个程序的运行效果,是比较容易分析的,就是变换一张图片的四个角的位置后,引起图像的相应变化,而每个角就是二维平面的一个点具有x和y属性,4个点的x,y间接保存到df1到df8变量中。
注意cvCloneImage函数和cvCopyImage函数的区别,前来可用来分配内存,后者不负责内存分配,只负责值的传递。这个代码不包含图像的放大、缩小、旋转功能,不过如果愿意的话,完全可以用例子中的函数自己写这些功能,因为放大、缩小、旋转图像不过是任意变换图像四个角的特例。
再来个自己写的仿射变换代码:
- //仿射变换
- #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;
- }
这个程序中加入图片的放大、缩小、旋转功能,另外仿射变换也是透视变换的一个特例,因为仿射变换过程中图像始终是平行四边形的。所以要确定仿射变换的目标图像,只需要三个点的坐标,因为三个点可以确定一个平行四边形,比透视变换少一个点的坐标。