From 6cf6a2277269c9dec8ad26b6002e2d9f70b4a168 Mon Sep 17 00:00:00 2001 From: Maria Dimashova Date: Thu, 29 Jul 2010 11:14:54 +0000 Subject: [PATCH] modified sample find_obj_calonder --- samples/c/find_obj_calonder.cpp | 181 ++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 92 deletions(-) diff --git a/samples/c/find_obj_calonder.cpp b/samples/c/find_obj_calonder.cpp index c1b990a..cdb284f 100644 --- a/samples/c/find_obj_calonder.cpp +++ b/samples/c/find_obj_calonder.cpp @@ -8,7 +8,9 @@ using namespace std; using namespace cv; - +/* + * Generates random perspective transform of image + */ void warpPerspectiveRand( const Mat& src, Mat& dst, Mat& H, RNG& rng ) { H.create(3, 3, CV_32FC1); @@ -25,110 +27,85 @@ void warpPerspectiveRand( const Mat& src, Mat& dst, Mat& H, RNG& rng ) warpPerspective( src, dst, H, src.size() ); } -int main( int argc, char **argv ) +/* + * Trains Calonder classifier and writes trained classifier in file: + * imgFilename - name of .txt file which contains list of full filenames of train images, + * classifierFilename - name of binary file in which classifier will be written. + * + * To train Calonder classifier RTreeClassifier class need to be used. + */ +void trainCalonderClassifier( const string& classifierFilename, const string& imgFilename ) { - #if 0 - if( argc != 4 && argc != 3 ) + // Reads train images + ifstream is( imgFilename.c_str(), ifstream::in ); + vector trainImgs; + while( !is.eof() ) { - cout << "Format:" << endl << - " classifier(xml to write) test_image file_with_train_images_filenames(txt)" << - " or" << endl << - " classifier(xml to read) test_image" << endl; - return -1; + string str; + getline( is, str ); + if (str.empty()) break; + Mat img = imread( str, CV_LOAD_IMAGE_GRAYSCALE ); + if( !img.empty() ) + trainImgs.push_back( img ); } + if( trainImgs.empty() ) + { + cout << "All train images can not be read." << endl; + exit(-1); + } + cout << trainImgs.size() << " train images were read." << endl; - CalonderClassifier classifier; - if( argc == 4 ) // Train + // Extracts keypoints from train images + SurfFeatureDetector detector; + vector trainPoints; + vector iplTrainImgs(trainImgs.size()); + for( size_t imgIdx = 0; imgIdx < trainImgs.size(); imgIdx++ ) { - // Read train images and test image - ifstream fst( argv[3], ifstream::in ); - vector trainImgs; - while( !fst.eof() ) - { - string str; - getline( fst, str ); - if (str.empty()) break; - Mat img = imread( str, CV_LOAD_IMAGE_GRAYSCALE ); - if( !img.empty() ) - trainImgs.push_back( img ); - } - if( trainImgs.empty() ) - { - cout << "All train images can not be read." << endl; - return -1; - } - cout << trainImgs.size() << " train images were read." << endl; + iplTrainImgs[imgIdx] = trainImgs[imgIdx]; + vector kps; detector.detect( trainImgs[imgIdx], kps ); - // Extract keypoints from train images - SurfFeatureDetector detector; - vector > trainPoints( trainImgs.size() ); - for( size_t i = 0; i < trainImgs.size(); i++ ) + for( size_t pointIdx = 0; pointIdx < kps.size(); pointIdx++ ) { - vector kps; - detector.detect( trainImgs[i], kps ); - KeyPoint::convert( kps, trainPoints[i] ); + Point2f p = kps[pointIdx].pt; + trainPoints.push_back( BaseKeypoint(cvRound(p.x), cvRound(p.y), &iplTrainImgs[imgIdx]) ); } - - // Train Calonder classifier on extracted points - classifier.setVerbose( true); - classifier.train( trainPoints, trainImgs ); - - // Write Calonder classifier - FileStorage fs( argv[1], FileStorage::WRITE ); - if( fs.isOpened() ) classifier.write( fs ); - } - else - { - // Read Calonder classifier - FileStorage fs( argv[1], FileStorage::READ ); - if( fs.isOpened() ) classifier.read( fs.root() ); } - if( classifier.empty() ) - { - cout << "Calonder classifier is empty" << endl; - return -1; - } + // Trains Calonder classifier on extracted points + RTreeClassifier classifier; + classifier.train( trainPoints, theRNG(), 48, 9, 100 ); + // Writes classifier + classifier.write( classifierFilename.c_str() ); +} - // Test Calonder classifier on test image and warped one - Mat testImg1 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE ), testImg2, H12; - if( testImg1.empty() ) +/* + * Test Calonder classifier to match keypoints on given image: + * classifierFilename - name of file from which classifier will be read, + * imgFilename - test image filename. + * + * To calculate keypoint descriptors you may use RTreeClassifier class (as to train), + * but it is convenient to use CalonderDescriptorExtractor class which is wrapper of + * RTreeClassifier. + */ +void testCalonderClassifier( const string& classifierFilename, const string& imgFilename ) +{ + Mat img1 = imread( imgFilename, CV_LOAD_IMAGE_GRAYSCALE ), img2, H12; + if( img1.empty() ) { cout << "Test image can not be read." << endl; - return -1; + exit(-1); } - warpPerspectiveRand( testImg1, testImg2, H12, theRNG() ); - + warpPerspectiveRand( img1, img2, H12, theRNG() ); // Exstract keypoints from test images SurfFeatureDetector detector; - vector testKeypoints1; detector.detect( testImg1, testKeypoints1 ); - vector testKeypoints2; detector.detect( testImg2, testKeypoints2 ); - vector testPoints1; KeyPoint::convert( testKeypoints1, testPoints1 ); - vector testPoints2; KeyPoint::convert( testKeypoints2, testPoints2 ); - - // Calculate Calonder descriptors - int signatureSize = classifier.getSignatureSize(); - vector r1(testPoints1.size()*signatureSize), r2(testPoints2.size()*signatureSize); - vector::iterator rit = r1.begin(); - for( size_t i = 0; i < testPoints1.size(); i++ ) - { - vector s; - classifier( testImg1, testPoints1[i], s ); - copy( s.begin(), s.end(), rit ); - rit += s.size(); - } - rit = r2.begin(); - for( size_t i = 0; i < testPoints2.size(); i++ ) - { - vector s; - classifier( testImg2, testPoints2[i], s ); - copy( s.begin(), s.end(), rit ); - rit += s.size(); - } + vector keypoints1; detector.detect( img1, keypoints1 ); + vector keypoints2; detector.detect( img2, keypoints2 ); - Mat descriptors1(testPoints1.size(), classifier.getSignatureSize(), CV_32FC1, &r1[0] ), - descriptors2(testPoints2.size(), classifier.getSignatureSize(), CV_32FC1, &r2[0] ); + // Compute descriptors + CalonderDescriptorExtractor de( classifierFilename ); + Mat descriptors1; de.compute( img1, keypoints1, descriptors1 ); + Mat descriptors2; de.compute( img2, keypoints2, descriptors2 ); // Match descriptors BruteForceMatcher > matcher; @@ -136,23 +113,43 @@ int main( int argc, char **argv ) vector matches; matcher.match( descriptors1, matches ); - // Draw results // Prepare inlier mask vector matchesMask( matches.size(), 0 ); - Mat points1t; perspectiveTransform(Mat(testPoints1), points1t, H12); + vector points1; KeyPoint::convert( keypoints1, points1 ); + vector points2; KeyPoint::convert( keypoints2, points2 ); + Mat points1t; perspectiveTransform(Mat(points1), points1t, H12); vector::const_iterator mit = matches.begin(); for( size_t mi = 0; mi < matches.size(); mi++ ) { - if( norm(testPoints2[matches[mi]] - points1t.at(mi,0)) < 4 ) // inlier + if( norm(points2[matches[mi]] - points1t.at(mi,0)) < 4 ) // inlier matchesMask[mi] = 1; } + // Draw Mat drawImg; - drawMatches( testImg1, testKeypoints1, testImg2, testKeypoints2, matches, drawImg, CV_RGB(0, 255, 0), CV_RGB(0, 0, 255), matchesMask ); + drawMatches( img1, keypoints1, img2, keypoints2, matches, drawImg, CV_RGB(0, 255, 0), CV_RGB(0, 0, 255), matchesMask ); string winName = "Matches"; namedWindow( winName, WINDOW_AUTOSIZE ); imshow( winName, drawImg ); waitKey(); -#endif +} + + +int main( int argc, char **argv ) +{ + if( argc != 4 && argc != 3 ) + { + cout << "Format:" << endl << + " classifier_file(to write) test_image file_with_train_images_filenames(txt)" << + " or" << endl << + " classifier_file(to read) test_image" << endl; + return -1; + } + + if( argc == 4 ) + trainCalonderClassifier( argv[1], argv[3] ); + + testCalonderClassifier( argv[1], argv[2] ); + return 0; } -- 2.7.4