modified sample find_obj_calonder
authorMaria Dimashova <no@email>
Thu, 29 Jul 2010 11:14:54 +0000 (11:14 +0000)
committerMaria Dimashova <no@email>
Thu, 29 Jul 2010 11:14:54 +0000 (11:14 +0000)
samples/c/find_obj_calonder.cpp

index c1b990a..cdb284f 100644 (file)
@@ -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<Mat> 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<BaseKeypoint> trainPoints;
+    vector<IplImage> 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<Mat> 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<KeyPoint> kps; detector.detect( trainImgs[imgIdx], kps );
 
-        // Extract keypoints from train images
-        SurfFeatureDetector detector;
-        vector<vector<Point2f> > trainPoints( trainImgs.size() );
-        for( size_t i = 0; i < trainImgs.size(); i++ )
+        for( size_t pointIdx = 0; pointIdx < kps.size(); pointIdx++ )
         {
-            vector<KeyPoint> 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<KeyPoint> testKeypoints1; detector.detect( testImg1, testKeypoints1 );
-    vector<KeyPoint> testKeypoints2; detector.detect( testImg2, testKeypoints2 );
-    vector<Point2f> testPoints1; KeyPoint::convert( testKeypoints1, testPoints1 );
-    vector<Point2f> testPoints2; KeyPoint::convert( testKeypoints2, testPoints2 );
-
-    // Calculate Calonder descriptors
-    int signatureSize = classifier.getSignatureSize();
-    vector<float> r1(testPoints1.size()*signatureSize), r2(testPoints2.size()*signatureSize);
-    vector<float>::iterator rit = r1.begin();
-    for( size_t i = 0; i < testPoints1.size(); i++ )
-    {
-        vector<float> 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<float> s;
-        classifier( testImg2, testPoints2[i], s );
-        copy( s.begin(), s.end(), rit );
-        rit += s.size();
-    }
+    vector<KeyPoint> keypoints1; detector.detect( img1, keypoints1 );
+    vector<KeyPoint> 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<float> de( classifierFilename );
+    Mat descriptors1;  de.compute( img1, keypoints1, descriptors1 );
+    Mat descriptors2;  de.compute( img2, keypoints2, descriptors2 );
 
     // Match descriptors
     BruteForceMatcher<L1<float> > matcher;
@@ -136,23 +113,43 @@ int main( int argc, char **argv )
     vector<int> matches;
     matcher.match( descriptors1, matches );
 
-    // Draw results
     // Prepare inlier mask
     vector<char> matchesMask( matches.size(), 0 );
-    Mat points1t; perspectiveTransform(Mat(testPoints1), points1t, H12);
+    vector<Point2f> points1; KeyPoint::convert( keypoints1, points1 );
+    vector<Point2f> points2; KeyPoint::convert( keypoints2, points2 );
+    Mat points1t; perspectiveTransform(Mat(points1), points1t, H12);
     vector<int>::const_iterator mit = matches.begin();
     for( size_t mi = 0; mi < matches.size(); mi++ )
     {
-        if( norm(testPoints2[matches[mi]] - points1t.at<Point2f>(mi,0)) < 4 ) // inlier
+        if( norm(points2[matches[mi]] - points1t.at<Point2f>(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;
 }