基本上就是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; }
这个程序中加入图片的放大、缩小、旋转功能,另外仿射变换也是透视变换的一个特例,因为仿射变换过程中图像始终是平行四边形的。所以要确定仿射变换的目标图像,只需要三个点的坐标,因为三个点可以确定一个平行四边形,比透视变换少一个点的坐标。