【练习8.10】直接使用cvFindContour的结果图片和cvDrawContour的方式提取Hu矩,观察在图片缩放或旋转时的稳定性
题目要求 | 程序代码 | 结果图片 | 要言妙道 | 借鉴参考 |
旋转缩放图像
a、使用《学习OpenCV》书中提到的技巧,先使用cvDrawContour绘制找到的轮廓在提取矩
b、直接使用cvFindContour的结果图片提取矩
1 // OpenCVExerciseTesting.cpp : 定义控制台应用程序的入口点。 2 // 3 // string file_full_name = "D:\\Work\\Work_Programming\\Source\\Image\\OpenCVExerciseImage\\第8章\\r20.jpg"; 4 5 6 #include "stdafx.h" 7 #include<string> 8 #include <cv.h> 9 #include <highgui.h> 10 #include <iostream> 11 #include<math.h> 12 13 #include <opencv2/legacy/legacy.hpp> 14 //#pragma comment(lib, "opencv_legacy2411.lib") 15 16 using namespace cv; 17 using namespace std; 18 19 //函数声明-->--->-->--->-->--->-->--->// 20 //void imRotate(IplImage *src, IplImage *dst, double angle, CvPoint2D32f center, double scale); 21 22 IplImage * ImageZoomOrRotatopn(IplImage * image, double scale=1.0, double angle=0.0); 23 void CalcHuMoments(IplImage * image_source, string window_name); 24 void CalcHuMoments2(IplImage * image_source, string window_name); 25 26 //<--<--<--<--<--<--<--<--<--函数声明// 27 28 int _tmain(int argc, _TCHAR* argv[]) 29 { 30 string file_full_name = "D:\\Work\\Work_Programming\\Source\\Image\\OpenCVExerciseImage\\第8章\\字符A.jpg"; 31 IplImage * image_source = cvLoadImage(file_full_name.c_str(), CV_LOAD_IMAGE_GRAYSCALE); 32 CV_Assert(image_source); 33 34 //原始图像 35 string window_name = "字符A原始图像"; 36 CalcHuMoments(image_source, window_name); 37 38 39 //旋转图像 40 IplImage *image_1 = ImageZoomOrRotatopn(image_source, 1.0, 73); 41 window_name = "字符A旋转73度图像"; 42 CalcHuMoments(image_1, window_name); 43 44 //缩放图像 45 IplImage *image_2 = ImageZoomOrRotatopn(image_source, 1.5, 0.0); 46 window_name = "字符A放大1.5倍图像"; 47 CalcHuMoments(image_2, window_name); 48 49 50 file_full_name = "D:\\Work\\Work_Programming\\Source\\Image\\OpenCVExerciseImage\\第8章\\字符F.jpg"; 51 IplImage * image_other = cvLoadImage(file_full_name.c_str(), CV_LOAD_IMAGE_GRAYSCALE); 52 CV_Assert(image_other); 53 54 //其它图像测试 55 window_name = "其它图像"; 56 CalcHuMoments(image_other, window_name); 57 58 //============================================================================== 59 60 cout << endl << endl; 61 62 //不使用cvDrawContour画的轮廓计算矩,直接使用cvFindContour的结果 63 IplImage * image_temp = cvCloneImage(image_source); 64 CalcHuMoments2(image_temp, window_name); 65 66 CalcHuMoments2(image_1, window_name); 67 68 CalcHuMoments2(image_2, window_name); 69 70 CalcHuMoments2(image_other, window_name); 71 72 //system("pause"); 73 cvWaitKey(0); 74 75 //cvReleaseImage(&image_source); 76 //cvReleaseImage(&image_source_2); 77 cvDestroyAllWindows(); 78 79 return 0; 80 } 81 82 IplImage * ImageZoomOrRotatopn(IplImage * image, double scale, double angle) 83 { 84 IplImage * affinedImage = cvCloneImage(image); 85 CvMat *rot_mat = cvCreateMat(2, 3, CV_32FC1); 86 CvPoint2D32f center = cvPoint2D32f(image->width / 2, image->height / 2); 87 cv2DRotationMatrix(center, angle, scale, rot_mat); 88 cvWarpAffine(image, affinedImage, rot_mat); 89 return affinedImage; 90 } 91 92 void CalcHuMoments(IplImage * image_source,string window_name) 93 { 94 CvMoments moments; 95 CvHuMoments Hu_moments; 96 IplImage * image_contour = cvCloneImage(image_source); 97 cvZero(image_contour); 98 99 IplImage * image_binary = cvCloneImage(image_source); 100 cvZero(image_binary); 101 cvThreshold(image_source, image_binary, 100, 255, CV_THRESH_BINARY);//重要,调用从vFindContour前先二值化图像 102 103 CvMemStorage *storage = cvCreateMemStorage(); 104 CvSeq * first_contour=NULL; 105 int contour_num; 106 contour_num = cvFindContours(image_binary, storage, &first_contour);// , sizeof(CvContour), CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE); 107 cvDrawContours(image_contour, first_contour, cvScalar(255), cvScalar(255), 5);//重要,将轮廓绘制到图像,供下一步调用 108 109 cvShowImage(window_name.c_str(), image_contour); 110 111 cvMoments(image_contour, &moments, 1); 112 cvGetHuMoments(&moments, &Hu_moments); 113 cout << window_name<< "Hu矩结果:" << endl; 114 cout << setiosflags(ios::scientific) << setprecision(4) << Hu_moments.hu1 << " "; 115 cout << Hu_moments.hu2 << " "; 116 cout << Hu_moments.hu3 << " "; 117 cout << Hu_moments.hu4 << " "; 118 cout << Hu_moments.hu5 << " "; 119 cout << Hu_moments.hu6 << " "; 120 cout << Hu_moments.hu7 << endl; 121 122 //cout << "(" << setprecision(3) << dec <</* scalar <<*/ ")" << " "; 123 //for (int i = 0; i<7; ++i){ 124 // cout << setiosflags(ios::scientific) << setprecision(4) << ((double*)&Hu_moments)[i] << ' '; 125 //} 126 //cout << endl; 127 128 cvReleaseImage(&image_contour); 129 cvReleaseImage(&image_binary); 130 cvClearSeq(first_contour); 131 cvReleaseMemStorage(&storage); 132 } 133 134 void CalcHuMoments2(IplImage * image_source, string window_name) 135 { 136 CvMemStorage *storage = cvCreateMemStorage(); 137 CvSeq * contour = NULL; 138 139 cvThreshold(image_source, image_source, 100, 255, CV_THRESH_BINARY); 140 141 cvFindContours(image_source, storage, &contour); 142 //cvShowImage(window_name.c_str(), image_source); 143 CvMoments moments; 144 CvHuMoments huMoments; 145 cvMoments(image_source, &moments, 1); 146 cvGetHuMoments(&moments, &huMoments); 147 148 cout << "CalcHuMoments2输出" << endl; 149 ////cout << "(" << setprecision(3) << dec << scalar << ")" << " "; 150 //for (int i = 0; i<7; ++i){ 151 // cout << setiosflags(ios::scientific) << setprecision(4) << ((double*)&huMoments)[i] << ' '; 152 //} 153 //cout << endl; 154 cout << window_name << "Hu矩结果:" << endl; 155 cout << setiosflags(ios::scientific) << setprecision(4) << huMoments.hu1 << " "; 156 cout << huMoments.hu2 << " "; 157 cout << huMoments.hu3 << " "; 158 cout << huMoments.hu4 << " "; 159 cout << huMoments.hu5 << " "; 160 cout << huMoments.hu6 << " "; 161 cout << huMoments.hu7 << endl; 162 163 cvClearSeq(contour); 164 cvReleaseMemStorage(&storage); 165 } 166 167 //void imRotate(IplImage *src, IplImage *dst, double angle, CvPoint2D32f center, double scale) 168 //{ 169 // assert(src->width == dst->width && src->height == dst->height &&src->depth == dst->depth &&src->nChannels == dst->nChannels); 170 // CvMat *mapMatrix = cvCreateMat(2, 3, CV_32FC1); 171 // cv2DRotationMatrix(center, angle, scale, mapMatrix); //旋转缩放为仿射变换,此处求变换矩阵 172 // 173 // cvWarpAffine(src, dst, mapMatrix); 174 //}
①函数 cvFindContours 从二值图像寻找图像。此二值图像可以是从cvCanny函数得到的有边缘像素的图像,或者是从cvThreshold及cvAdaptiveThreshold得到的图像,这时的边缘是正合负区域之间的边界。如果在cvFindContours前没有二值化图像,会发现本练习第一个原始图像找轮廓后画出的轮廓没有结果,而且最后的hu矩完全无规律
② 一个有用的小技巧是:用从vDrawContour描绘一幅轮廓的图像后,调用一个矩的处理函数处理该图像
③再次强调 cvFindContour 的输入图像会直接被涂改
‖==========钟于原创 乐于分享 宁静致远 毋忆典藏==========‖