OpenCV第三个assignment:将图片分类,比如一类图片有中华香烟,另一类图片有芙蓉王香烟
2012-10-25 02:48 美女驴 阅读(1611) 评论(0) 编辑 收藏 举报这是我上计算机视觉的作业,由于图片是由老师独家提供,所以把图片放到网上不是很合适,我也是抛砖引玉,假设一类图片是中华香烟,另一类图片是芙蓉王香烟,那么我们如何建立一个框架来
自动检测这两类图片,下面我贴上源码:我的程序平台是visual studio 2008 + OpenCV 2.3.1
#include <stdio.h> #include <iostream> #include "stdafx.h" #include <opencv2/opencv.hpp> #include "stdio.h" #include "string.h" using namespace cv;
//下面为进行分类的图片序号,其中图片序号不是连续的是因为我们得到的图片总会有一些是不能用的,去除那些不能用的就是下面这些图片啦 //中华香烟 8,9,10,12,14,15,16,18,20,21,22,24,26,27,29,30,31,32,34,36,37,38,40,42,43,44,46,48,49,50,52,54,55,56,"58",59,60,62,64,65,67,69,70,72 //芙蓉王香烟 1,2,"3",4,5,6,7,13,19,25,35,41,47,53,63,68 void main() { //=============Detect feature points and extract their corresponding descriptors for each object image========================================================== Mat img_object1 = imread("58.jpg", CV_LOAD_IMAGE_GRAYSCALE ); //读入一张中华香烟图片作为分类参考,这就是object 1 image Mat img_object2 = imread("3.jpg", CV_LOAD_IMAGE_GRAYSCALE ); //读入一张芙蓉王香烟图片作为分类参考,这就是object 2 image if( !img_object1.data || !img_object2.data ) { std::cout<< " --(!) Error reading images " << std::endl; } int FieldTest1[58] = {1,2,4,5,6,7,8,9,10,12,13,14,15,16,18,19,20,21,22,24,25,26,27,29,30,31,32,34,35,36,37,38,40,41,42,43,44,46,47,48,49,50,52,53,54,55,56,59,60,62,63,64,65,67,68,69,70,72}; //Detect the keypoints using SURF Detector int minHessian = 400; SurfFeatureDetector detector( minHessian ); std::vector<KeyPoint> keypoints_object1, keypoints_object2; detector.detect( img_object1, keypoints_object1 ); detector.detect( img_object2, keypoints_object2 ); //Draw Keypoints Mat img_keypoints_1; Mat img_keypoints_2; drawKeypoints(img_object1, keypoints_object1, img_keypoints_1,Scalar::all(-1), DrawMatchesFlags::DEFAULT); drawKeypoints(img_object2, keypoints_object2, img_keypoints_2,Scalar::all(-1), DrawMatchesFlags::DEFAULT); imshow("object1_keypoints", img_keypoints_1); imshow("object2_keypoints", img_keypoints_2); //Calculate descriptors (feature vectors) SurfDescriptorExtractor extractor; Mat descriptors_object1, descriptors_object2; extractor.compute( img_object1, keypoints_object1, descriptors_object1 ); extractor.compute( img_object2, keypoints_object2, descriptors_object2 ); //================for each usable scene image, detect feature points and extract its descriptors, then use match score to identify 每一张scene图片是属于哪一类香烟的================= std::vector<int> result_zhonghua,result_furong; // store final result char* filename = (char*)malloc(30); // scene image name int Num; //index number of array FieldTest1 for(Num = 0;Num <58 ; Num++) { sprintf(filename,"%d.jpg",FieldTest1[Num]); // obtain the filename of each scene image printf("The scene image is %s \n", filename); //print the filename on screen //Detect keypoints and extract descriptors for each scene image Mat img_scene; std::vector<KeyPoint> keypoints_scene; Mat img_keypoints; Mat descriptors_scene; img_scene = imread(filename, CV_LOAD_IMAGE_GRAYSCALE ); detector.detect(img_scene, keypoints_scene); drawKeypoints(img_scene, keypoints_scene, img_keypoints,Scalar::all(-1), DrawMatchesFlags::DEFAULT); imshow("scene_keypoints", img_keypoints); extractor.compute( img_scene, keypoints_scene, descriptors_scene); //Matching descriptor vectors using FLANN matcher FlannBasedMatcher matcher; std::vector< vector<DMatch> > matches1,matches2; matcher.knnMatch( descriptors_scene,descriptors_object1, matches1,2 ); //match scene image with object1 image matcher.knnMatch( descriptors_scene,descriptors_object2, matches2,2 ); //match scene image with object2 image //Find good matches according to some requirements std::vector< DMatch > good_matches1,good_matches2; for (int i =0; i<matches1.size();i++) { if(matches1[i].size()<2) continue; DMatch &m11 = matches1[i][0]; DMatch &m12 = matches1[i][1]; if(m11.distance <= 0.8*m12.distance) good_matches1.push_back(m11); } for (int i =0; i<matches2.size();i++) { if(matches2[i].size()<2) continue; DMatch &m21 = matches2[i][0]; DMatch &m22 = matches2[i][1]; if(m21.distance <= 0.8*m22.distance) good_matches2.push_back(m21); } //Display the good matches Mat img_matches1; Mat img_matches2; drawMatches( img_scene, keypoints_scene, img_object1, keypoints_object1, good_matches1, img_matches1, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); imshow( "scene&object1 good match", img_matches1 ); drawMatches( img_scene, keypoints_scene, img_object2, keypoints_object2, good_matches2, img_matches2, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); imshow( "scene&object2 good match", img_matches2 ); //Obtain keypoint pairs for each good match std::vector<Point2f> obj1; std::vector<Point2f> obj2; std::vector<Point2f> scene1; std::vector<Point2f> scene2; for( int i = 0; i < good_matches1.size(); i++) { obj1.push_back(keypoints_object1[good_matches1[i].trainIdx].pt); scene1.push_back(keypoints_scene[good_matches1[i].queryIdx].pt); } for( int i = 0; i < good_matches2.size(); i++) { obj2.push_back(keypoints_object2[good_matches2[i].trainIdx].pt); scene2.push_back(keypoints_scene[good_matches2[i].queryIdx].pt); } //Find the perspective transform matrix Mat H1 = findHomography(obj1,scene1,CV_RANSAC);// find the perspective transform from object1 image to scene image by using RANSAC method Mat H2 = findHomography(obj2,scene2,CV_RANSAC);// find the perspective transform from object2 image to scene image by using RANSAC method //Use transform matrix to obtain its train keypoint for each query keypoint, and this obtained train keypoint has distance with the matched train keypoint std::vector<Point2f> obj1_scene1; std::vector<Point2f> obj2_scene2; perspectiveTransform(obj1, obj1_scene1, H1);//the obatined train keypoints for obj1 perspectiveTransform(obj2, obj2_scene2, H2);//the obainted train keypoints for obj2 double residu1 = 0,residu2 = 0; double residu_each1 = 0, residu_each2 = 0; double number1 = double(obj1.size()); double number2 = double(obj2.size()); //Calculate the errors between obtained train keypoints and matched train keypoints for each good match, residu1 and residu2, //And considering the number of keypoint pairs in two matches are different, so we use residu1_each and residu2_each instead for(int i = 0; i < obj1.size(); i++) { residu1 += sqrt((obj1_scene1[i].x - scene1[i].x)*(obj1_scene1[i].x - scene1[i].x)+(obj1_scene1[i].y - scene1[i].y)*(obj1_scene1[i].y - scene1[i].y)); } residu_each1 = residu1/number1; for(int i = 0; i < obj2.size(); i++) { residu2 += sqrt((obj2_scene2[i].x - scene2[i].x)*(obj2_scene2[i].x - scene2[i].x)+(obj2_scene2[i].y - scene2[i].y)*(obj2_scene2[i].y - scene2[i].y)); } residu_each2 = residu2/number2; //Print related parameters for debugging printf("residu_object1_2_scene : %f \n", residu1 ); printf("residu_object2_2_scene : %f \n", residu2 ); printf("obj1.size: %d\n",obj1.size()); printf("obj2.size: %d\n",obj2.size()); printf("residu_each1: %f\n",residu_each1); printf("residu_each2: %f\n",residu_each2); //Identify which kind of PAD each scene image belongs to and store them in the result vectors if(residu_each1 < residu_each2) { result_zhonghua.push_back(FieldTest1[Num]); printf("%s is zhonghua cigre \n", filename); } else { result_furong.push_back(FieldTest1[Num]); printf("%s is furong cigre \n", filename); } } //Print the index number of zhonghua images that we identify printf("The zhonghua images are: "); for(int i = 0; i < result_zhonghua.size();i++) { std::cout<<result_zhonghua[i]<<" "; } std::cout<<std::endl; //Print the index number of salt images that we identify printf("The furong images are: "); for(int i = 0;i < result_furong.size();i++) { std::cout<<result_furong[i]<<" "; } std::cout<<std::endl; waitKey(0); cvDestroyAllWindows(); }
代码总体上来说不难,话说关于matcher这一部分,我尝试用了FLANN和Brute Force发现效果不佳,因为我一直在用matcher.match,后来我还是用了FLANN,但是这次选用matcher.knnMatch,效果非常好,正确率几乎是百分之百,但是我提醒大家,由于在findhomography中我们使用了RANSAC算法,所以每次结果都会有一点不同。。。
参考资料:
http://docs.opencv.org/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html