首页 > 技术文章 > 【练习8.10】直接使用cvFindContour的结果图片和cvDrawContour的方式提取Hu矩,观察在图片缩放或旋转时的稳定性

tingshuixuan2012 2015-05-24 13:16 原文

 

页内索引
题目要求 程序代码 结果图片 要言妙道 借鉴参考

 

 

  

题目要求:

 旋转缩放图像

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 的输入图像会直接被涂改

 

 

借鉴参考:

 

推荐阅读