modified FernClassifier::train(); remove old RTreeClassifier and added new implementation CalonderClassifier; removed old find_obj_calonder and added new one
This commit is contained in:
@@ -1,309 +1,154 @@
|
||||
//Calonder descriptor sample
|
||||
#include <stdio.h>
|
||||
|
||||
#if 0
|
||||
#include <cxcore.h>
|
||||
#include <cv.h>
|
||||
#include <cvaux.h>
|
||||
#include <highgui.h>
|
||||
#include <vector>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
// Number of training points (set to -1 to use all points)
|
||||
const int n_points = -1;
|
||||
|
||||
//Draw the border of projection of train image calculed by averaging detected correspondences
|
||||
const bool draw_border = true;
|
||||
|
||||
void cvmSet6(CvMat* m, int row, int col, float val1, float val2, float val3, float val4, float val5, float val6)
|
||||
void warpPerspectiveRand( const Mat& src, Mat& dst, Mat& H, RNG& rng )
|
||||
{
|
||||
cvmSet(m, row, col, val1);
|
||||
cvmSet(m, row, col + 1, val2);
|
||||
cvmSet(m, row, col + 2, val3);
|
||||
cvmSet(m, row, col + 3, val4);
|
||||
cvmSet(m, row, col + 4, val5);
|
||||
cvmSet(m, row, col + 5, val6);
|
||||
H.create(3, 3, CV_32FC1);
|
||||
H.at<float>(0,0) = rng.uniform( 0.8f, 1.2f);
|
||||
H.at<float>(0,1) = rng.uniform(-0.1f, 0.1f);
|
||||
H.at<float>(0,2) = rng.uniform(-0.1f, 0.1f)*src.cols;
|
||||
H.at<float>(1,0) = rng.uniform(-0.1f, 0.1f);
|
||||
H.at<float>(1,1) = rng.uniform( 0.8f, 1.2f);
|
||||
H.at<float>(1,2) = rng.uniform(-0.1f, 0.1f)*src.rows;
|
||||
H.at<float>(2,0) = rng.uniform( -1e-4f, 1e-4f);
|
||||
H.at<float>(2,1) = rng.uniform( -1e-4f, 1e-4f);
|
||||
H.at<float>(2,2) = rng.uniform( 0.8f, 1.2f);
|
||||
|
||||
warpPerspective( src, dst, H, src.size() );
|
||||
}
|
||||
|
||||
void FindAffineTransform(const vector<CvPoint>& p1, const vector<CvPoint>& p2, CvMat* affine)
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
int eq_num = 2*(int)p1.size();
|
||||
CvMat* A = cvCreateMat(eq_num, 6, CV_32FC1);
|
||||
CvMat* B = cvCreateMat(eq_num, 1, CV_32FC1);
|
||||
CvMat* X = cvCreateMat(6, 1, CV_32FC1);
|
||||
|
||||
for(int i = 0; i < (int)p1.size(); i++)
|
||||
if( argc != 4 && argc != 3 )
|
||||
{
|
||||
cvmSet6(A, 2*i, 0, p1[i].x, p1[i].y, 1, 0, 0, 0);
|
||||
cvmSet6(A, 2*i + 1, 0, 0, 0, 0, p1[i].x, p1[i].y, 1);
|
||||
cvmSet(B, 2*i, 0, p2[i].x);
|
||||
cvmSet(B, 2*i + 1, 0, p2[i].y);
|
||||
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;
|
||||
}
|
||||
|
||||
cvSolve(A, B, X, CV_SVD);
|
||||
|
||||
cvmSet(affine, 0, 0, cvmGet(X, 0, 0));
|
||||
cvmSet(affine, 0, 1, cvmGet(X, 1, 0));
|
||||
cvmSet(affine, 0, 2, cvmGet(X, 2, 0));
|
||||
cvmSet(affine, 1, 0, cvmGet(X, 3, 0));
|
||||
cvmSet(affine, 1, 1, cvmGet(X, 4, 0));
|
||||
cvmSet(affine, 1, 2, cvmGet(X, 5, 0));
|
||||
|
||||
cvReleaseMat(&A);
|
||||
cvReleaseMat(&B);
|
||||
cvReleaseMat(&X);
|
||||
}
|
||||
|
||||
void MapVectorAffine(const vector<CvPoint>& p1, vector<CvPoint>& p2, CvMat* transform)
|
||||
{
|
||||
float a = cvmGet(transform, 0, 0);
|
||||
float b = cvmGet(transform, 0, 1);
|
||||
float c = cvmGet(transform, 0, 2);
|
||||
float d = cvmGet(transform, 1, 0);
|
||||
float e = cvmGet(transform, 1, 1);
|
||||
float f = cvmGet(transform, 1, 2);
|
||||
|
||||
for(int i = 0; i < (int)p1.size(); i++)
|
||||
CalonderClassifier classifier;
|
||||
if( argc == 4 ) // Train
|
||||
{
|
||||
float x = a*p1[i].x + b*p1[i].y + c;
|
||||
float y = d*p1[i].x + e*p1[i].y + f;
|
||||
p2.push_back(cvPoint(x, y));
|
||||
// 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;
|
||||
|
||||
// Extract keypoints from train images
|
||||
SurfFeatureDetector detector;
|
||||
vector<vector<Point2f> > trainPoints( trainImgs.size() );
|
||||
for( size_t i = 0; i < trainImgs.size(); i++ )
|
||||
{
|
||||
vector<KeyPoint> kps;
|
||||
detector.detect( trainImgs[i], kps );
|
||||
KeyPoint::convert( kps, trainPoints[i] );
|
||||
}
|
||||
|
||||
// Train Calonder classifier on extracted points
|
||||
classifier.setVerbose( true);
|
||||
classifier.train( trainPoints, trainImgs );
|
||||
|
||||
// Write Calonder classifier
|
||||
FileStorage fs( argv[1], FileStorage::WRITE );
|
||||
classifier.write( fs );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float CalcAffineReprojectionError(const vector<CvPoint>& p1, const vector<CvPoint>& p2, CvMat* transform)
|
||||
{
|
||||
vector<CvPoint> mapped_p1;
|
||||
MapVectorAffine(p1, mapped_p1, transform);
|
||||
float error = 0;
|
||||
for(int i = 0; i < (int)p2.size(); i++)
|
||||
else
|
||||
{
|
||||
error += ((p2[i].x - mapped_p1[i].x)*(p2[i].x - mapped_p1[i].x)+(p2[i].y - mapped_p1[i].y)*(p2[i].y - mapped_p1[i].y));
|
||||
// Read Calonder classifier
|
||||
FileStorage fs( argv[1], FileStorage::READ );
|
||||
classifier.read( fs.root() );
|
||||
}
|
||||
|
||||
error /= p2.size();
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main( int, char** )
|
||||
{
|
||||
printf("calonder_sample is under construction\n");
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
IplImage* test_image;
|
||||
IplImage* train_image;
|
||||
if (argc < 3)
|
||||
{
|
||||
|
||||
test_image = cvLoadImage("box_in_scene.png",0);
|
||||
train_image = cvLoadImage("box.png ",0);
|
||||
if (!test_image || !train_image)
|
||||
{
|
||||
printf("Usage: calonder_sample <train_image> <test_image>");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
test_image = cvLoadImage(argv[2],0);
|
||||
train_image = cvLoadImage(argv[1],0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!train_image)
|
||||
{
|
||||
printf("Unable to load train image\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!test_image)
|
||||
{
|
||||
printf("Unable to load test image\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CvMemStorage* storage = cvCreateMemStorage(0);
|
||||
CvSeq *objectKeypoints = 0, *objectDescriptors = 0;
|
||||
CvSeq *imageKeypoints = 0, *imageDescriptors = 0;
|
||||
CvSURFParams params = cvSURFParams(500, 1);
|
||||
cvExtractSURF( test_image, 0, &imageKeypoints, &imageDescriptors, storage, params );
|
||||
cvExtractSURF( train_image, 0, &objectKeypoints, &objectDescriptors, storage, params );
|
||||
|
||||
|
||||
cv::RTreeClassifier detector;
|
||||
int patch_width = cv::PATCH_SIZE;
|
||||
int patch_height = cv::PATCH_SIZE;
|
||||
vector<cv::BaseKeypoint> base_set;
|
||||
int i=0;
|
||||
CvSURFPoint* point;
|
||||
|
||||
|
||||
for (i=0;i<(n_points > 0 ? n_points : objectKeypoints->total);i++)
|
||||
{
|
||||
point=(CvSURFPoint*)cvGetSeqElem(objectKeypoints,i);
|
||||
base_set.push_back(cv::BaseKeypoint(point->pt.x,point->pt.y,train_image));
|
||||
}
|
||||
|
||||
//Detector training
|
||||
cv::RNG rng( cvGetTickCount() );
|
||||
cv::PatchGenerator gen(0,255,2,false,0.7,1.3,-CV_PI/3,CV_PI/3,-CV_PI/3,CV_PI/3);
|
||||
|
||||
printf("RTree Classifier training...\n");
|
||||
detector.train(base_set,rng,gen,24,cv::DEFAULT_DEPTH,2000,(int)base_set.size(),detector.DEFAULT_NUM_QUANT_BITS);
|
||||
printf("Done\n");
|
||||
|
||||
float* signature = new float[detector.original_num_classes()];
|
||||
float* best_corr;
|
||||
int* best_corr_idx;
|
||||
if (imageKeypoints->total > 0)
|
||||
{
|
||||
best_corr = new float[imageKeypoints->total];
|
||||
best_corr_idx = new int[imageKeypoints->total];
|
||||
}
|
||||
|
||||
for(i=0; i < imageKeypoints->total; i++)
|
||||
{
|
||||
point=(CvSURFPoint*)cvGetSeqElem(imageKeypoints,i);
|
||||
int part_idx = -1;
|
||||
float prob = 0.0f;
|
||||
|
||||
|
||||
CvRect roi = cvRect((int)(point->pt.x) - patch_width/2,(int)(point->pt.y) - patch_height/2, patch_width, patch_height);
|
||||
cvSetImageROI(test_image, roi);
|
||||
roi = cvGetImageROI(test_image);
|
||||
if(roi.width != patch_width || roi.height != patch_height)
|
||||
{
|
||||
best_corr_idx[i] = part_idx;
|
||||
best_corr[i] = prob;
|
||||
}
|
||||
else
|
||||
{
|
||||
cvSetImageROI(test_image, roi);
|
||||
IplImage* roi_image = cvCreateImage(cvSize(roi.width, roi.height), test_image->depth, test_image->nChannels);
|
||||
cvCopy(test_image,roi_image);
|
||||
|
||||
detector.getSignature(roi_image, signature);
|
||||
|
||||
|
||||
for (int j = 0; j< detector.original_num_classes();j++)
|
||||
{
|
||||
if (prob < signature[j])
|
||||
{
|
||||
part_idx = j;
|
||||
prob = signature[j];
|
||||
}
|
||||
}
|
||||
|
||||
best_corr_idx[i] = part_idx;
|
||||
best_corr[i] = prob;
|
||||
|
||||
|
||||
if (roi_image)
|
||||
cvReleaseImage(&roi_image);
|
||||
}
|
||||
cvResetImageROI(test_image);
|
||||
}
|
||||
|
||||
float min_prob = 0.0f;
|
||||
vector<CvPoint> object;
|
||||
vector<CvPoint> features;
|
||||
|
||||
for (int j=0;j<objectKeypoints->total;j++)
|
||||
{
|
||||
float prob = 0.0f;
|
||||
int idx = -1;
|
||||
for (i = 0; i<imageKeypoints->total;i++)
|
||||
{
|
||||
if ((best_corr_idx[i]!=j)||(best_corr[i] < min_prob))
|
||||
continue;
|
||||
|
||||
if (best_corr[i] > prob)
|
||||
{
|
||||
prob = best_corr[i];
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
if (idx >=0)
|
||||
{
|
||||
point=(CvSURFPoint*)cvGetSeqElem(objectKeypoints,j);
|
||||
object.push_back(cvPoint((int)point->pt.x,(int)point->pt.y));
|
||||
point=(CvSURFPoint*)cvGetSeqElem(imageKeypoints,idx);
|
||||
features.push_back(cvPoint((int)point->pt.x,(int)point->pt.y));
|
||||
}
|
||||
}
|
||||
if ((int)object.size() > 3)
|
||||
{
|
||||
CvMat* affine = cvCreateMat(2, 3, CV_32FC1);
|
||||
FindAffineTransform(object,features,affine);
|
||||
|
||||
vector<CvPoint> corners;
|
||||
vector<CvPoint> mapped_corners;
|
||||
corners.push_back(cvPoint(0,0));
|
||||
corners.push_back(cvPoint(0,train_image->height));
|
||||
corners.push_back(cvPoint(train_image->width,0));
|
||||
corners.push_back(cvPoint(train_image->width,train_image->height));
|
||||
MapVectorAffine(corners,mapped_corners,affine);
|
||||
|
||||
//Drawing the result
|
||||
IplImage* result = cvCreateImage(cvSize(test_image->width > train_image->width ? test_image->width : train_image->width,
|
||||
train_image->height + test_image->height),
|
||||
test_image->depth, test_image->nChannels);
|
||||
cvSetImageROI(result,cvRect(0,0,train_image->width, train_image->height));
|
||||
cvCopy(train_image,result);
|
||||
cvResetImageROI(result);
|
||||
cvSetImageROI(result,cvRect(0,train_image->height,test_image->width, test_image->height));
|
||||
cvCopy(test_image,result);
|
||||
cvResetImageROI(result);
|
||||
|
||||
for (int i=0;i<(int)features.size();i++)
|
||||
{
|
||||
cvLine(result,object[i],cvPoint(features[i].x,features[i].y+train_image->height),cvScalar(255));
|
||||
}
|
||||
|
||||
if (draw_border)
|
||||
{
|
||||
cvLine(result,cvPoint(mapped_corners[0].x, mapped_corners[0].y+train_image->height),
|
||||
cvPoint(mapped_corners[1].x, mapped_corners[1].y+train_image->height),cvScalar(150),3);
|
||||
cvLine(result,cvPoint(mapped_corners[0].x, mapped_corners[0].y+train_image->height),
|
||||
cvPoint(mapped_corners[2].x, mapped_corners[2].y+train_image->height),cvScalar(150),3);
|
||||
cvLine(result,cvPoint(mapped_corners[1].x, mapped_corners[1].y+train_image->height),
|
||||
cvPoint(mapped_corners[3].x, mapped_corners[3].y+train_image->height),cvScalar(150),3);
|
||||
cvLine(result,cvPoint(mapped_corners[2].x, mapped_corners[2].y+train_image->height),
|
||||
cvPoint(mapped_corners[3].x, mapped_corners[3].y+train_image->height),cvScalar(150),3);
|
||||
}
|
||||
|
||||
cvSaveImage("Result.jpg",result);
|
||||
cvNamedWindow("Result",0);
|
||||
cvShowImage("Result",result);
|
||||
cvWaitKey();
|
||||
cvReleaseMat(&affine);
|
||||
cvReleaseImage(&result);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unable to find correspondence\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (signature)
|
||||
delete[] signature;
|
||||
if (best_corr)
|
||||
delete[] best_corr;
|
||||
cvReleaseMemStorage(&storage);
|
||||
cvReleaseImage(&train_image);
|
||||
cvReleaseImage(&test_image);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if( classifier.empty() )
|
||||
{
|
||||
cout << "Calonder classifier is empty" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test Calonder classifier on test image and warped one
|
||||
Mat testImg1 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE ), testImg2, H12;
|
||||
if( testImg1.empty() )
|
||||
{
|
||||
cout << "Test image can not be read." << endl;
|
||||
return -1;
|
||||
}
|
||||
warpPerspectiveRand( testImg1, testImg2, 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();
|
||||
}
|
||||
|
||||
Mat descriptors1(testPoints1.size(), classifier.getSignatureSize(), CV_32FC1, &r1[0] ),
|
||||
descriptors2(testPoints2.size(), classifier.getSignatureSize(), CV_32FC1, &r2[0] );
|
||||
|
||||
// Match descriptors
|
||||
BruteForceMatcher<L1<float> > matcher;
|
||||
matcher.add( descriptors2 );
|
||||
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<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
|
||||
matchesMask[mi] = 1;
|
||||
}
|
||||
// Draw
|
||||
Mat drawImg;
|
||||
drawMatches( testImg1, testKeypoints1, testImg2, testKeypoints2, matches, drawImg, CV_RGB(0, 255, 0), CV_RGB(0, 0, 255), matchesMask );
|
||||
string winName = "Matches";
|
||||
namedWindow( winName, WINDOW_AUTOSIZE );
|
||||
imshow( winName, drawImg );
|
||||
waitKey();
|
||||
}
|
||||
|
Reference in New Issue
Block a user