|
|
|
@ -41,650 +41,120 @@ |
|
|
|
|
//M*/
|
|
|
|
|
|
|
|
|
|
#include "cvtest.h" |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
|
|
|
|
|
#include "highgui.h" |
|
|
|
|
#include <vector> |
|
|
|
|
#include <string> |
|
|
|
|
using namespace std; |
|
|
|
|
#include <fstream> |
|
|
|
|
#include <iostream> |
|
|
|
|
|
|
|
|
|
using namespace cv; |
|
|
|
|
using namespace std; |
|
|
|
|
|
|
|
|
|
#define GET_RES 0 |
|
|
|
|
class CV_CalonderTest : public CvTest |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
CV_CalonderTest(); |
|
|
|
|
~CV_CalonderTest();
|
|
|
|
|
protected:
|
|
|
|
|
CV_CalonderTest() : CvTest("CalonderDescriptorExtractor", "CalonderDescriptorExtractor::compute") {} |
|
|
|
|
protected: |
|
|
|
|
void run(int); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cvmSet6(CvMat* m, int row, int col, float val1, float val2, float val3, float val4, float val5, float val6); |
|
|
|
|
void FindAffineTransform(const vector<CvPoint>& p1, const vector<CvPoint>& p2, CvMat* affine); |
|
|
|
|
void MapVectorAffine(const vector<CvPoint>& p1, vector<CvPoint>& p2, CvMat* transform); |
|
|
|
|
float CalcAffineReprojectionError(const vector<CvPoint>& p1, const vector<CvPoint>& p2, CvMat* transform); |
|
|
|
|
void ExtractFeatures(const IplImage* image, vector<CvPoint>& points); |
|
|
|
|
void TrainDetector(RTreeClassifier& detector, int/* patch_size*/, const vector<CvPoint>& train_points,const IplImage* train_image, int n_keypoints = 0); |
|
|
|
|
void GetCorrespondences(const RTreeClassifier& detector, int patch_size, |
|
|
|
|
const vector<CvPoint>& objectKeypoints, const vector<CvPoint>& imageKeypoints, const IplImage* image, |
|
|
|
|
vector<CvPoint>& object, vector<CvPoint>& features); |
|
|
|
|
|
|
|
|
|
// Scales the source image (x and y) and rotate to the angle (Positive values mean counter-clockwise rotation)
|
|
|
|
|
void RotateAndScale(const IplImage* src, IplImage* dst, float angle, float scale_x, float scale_y); |
|
|
|
|
// Scales the source image point and rotate to the angle (Positive values mean counter-clockwise rotation)
|
|
|
|
|
void RotateAndScale(const CvPoint& src, CvPoint& dst, const CvPoint& center, float angle, float scale_x, float scale_y); |
|
|
|
|
float RunTestsSeries(const IplImage* train_image, vector<CvPoint>& keypoints/*, bool drawResults = false*/); |
|
|
|
|
//returns 1 in the case of success, 0 otherwise
|
|
|
|
|
int SaveKeypoints(const vector<CvPoint>& points, const char* path); |
|
|
|
|
////returns 1 in the case of success, 0 otherwise
|
|
|
|
|
int LoadKeypoints(vector<CvPoint>& points, const char* path); |
|
|
|
|
|
|
|
|
|
void ExtractKeypointSignatures(const IplImage* test_image, int patch_size, const RTreeClassifier& detector, const vector<CvPoint>& keypoints, vector<vector<float> >& signatures); |
|
|
|
|
//returns 1 in the case of success, 0 otherwise
|
|
|
|
|
int SaveKeypointSignatures(const char* path, const vector<vector<float> >& signatures); |
|
|
|
|
//returns 1 in the case of success, 0 otherwise
|
|
|
|
|
int LoadKeypointSignatures(const char* path, vector<vector<float> >& signatures); |
|
|
|
|
|
|
|
|
|
//returns 1 in the case signatures are identical, 0 otherwise
|
|
|
|
|
int CompareSignatures(const vector<vector<float> > & signatures1, const vector<vector<float> >& signatures2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
void CV_CalonderTest::cvmSet6(CvMat* m, int row, int col, float val1, float val2, float val3, float val4, float val5, float val6) |
|
|
|
|
void writeMatInBin( const Mat& mat, const string& filename ) |
|
|
|
|
{ |
|
|
|
|
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); |
|
|
|
|
ofstream os( filename.c_str() ); |
|
|
|
|
int type = mat.type(); |
|
|
|
|
os.write( (char*)&mat.rows, sizeof(int) ); |
|
|
|
|
os.write( (char*)&mat.cols, sizeof(int) ); |
|
|
|
|
os.write( (char*)&type, sizeof(int) ); |
|
|
|
|
os.write( (char*)&mat.step, sizeof(int) ); |
|
|
|
|
os.write( (char*)mat.data, mat.step*mat.rows ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CV_CalonderTest::FindAffineTransform(const vector<CvPoint>& p1, const vector<CvPoint>& p2, CvMat* affine) |
|
|
|
|
Mat readMatFromBin( const string& filename ) |
|
|
|
|
{ |
|
|
|
|
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++) |
|
|
|
|
{ |
|
|
|
|
cvmSet6(A, 2*i, 0, (float)p1[i].x, (float)p1[i].y, 1, 0, 0, 0); |
|
|
|
|
cvmSet6(A, 2*i + 1, 0, 0, 0, 0, (float)p1[i].x, (float)p1[i].y, 1); |
|
|
|
|
cvmSet(B, 2*i, 0, (double)p2[i].x); |
|
|
|
|
cvmSet(B, 2*i + 1, 0, (double)p2[i].y); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
ifstream is( filename.c_str() ); |
|
|
|
|
int rows, cols, type, step; |
|
|
|
|
is.read( (char*)&rows, sizeof(int) ); |
|
|
|
|
is.read( (char*)&cols, sizeof(int) ); |
|
|
|
|
is.read( (char*)&type, sizeof(int) ); |
|
|
|
|
is.read( (char*)&step, sizeof(int) ); |
|
|
|
|
|
|
|
|
|
uchar* data = (uchar*)cvAlloc(step*rows); |
|
|
|
|
is.read( (char*)data, step*rows ); |
|
|
|
|
return Mat( rows, cols, type, data ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CV_CalonderTest::MapVectorAffine(const vector<CvPoint>& p1, vector<CvPoint>& p2, CvMat* transform) |
|
|
|
|
void CV_CalonderTest::run(int) |
|
|
|
|
{ |
|
|
|
|
double a = cvmGet(transform, 0, 0); |
|
|
|
|
double b = cvmGet(transform, 0, 1); |
|
|
|
|
double c = cvmGet(transform, 0, 2); |
|
|
|
|
double d = cvmGet(transform, 1, 0); |
|
|
|
|
double e = cvmGet(transform, 1, 1); |
|
|
|
|
double f = cvmGet(transform, 1, 2); |
|
|
|
|
|
|
|
|
|
for(int i = 0; i < (int)p1.size(); i++) |
|
|
|
|
string dir = string(ts->get_data_path()) + "/calonder"; |
|
|
|
|
Mat img = imread(dir +"/boat.png",0); |
|
|
|
|
if( img.empty() ) |
|
|
|
|
{ |
|
|
|
|
double x = a*p1[i].x + b*p1[i].y + c; |
|
|
|
|
double y = d*p1[i].x + e*p1[i].y + f; |
|
|
|
|
p2.push_back(cvPoint((int)x, (int)y)); |
|
|
|
|
ts->printf(CvTS::LOG, "Test image can not be read\n"); |
|
|
|
|
ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vector<KeyPoint> keypoints; |
|
|
|
|
#if GET_RES |
|
|
|
|
FastFeatureDetector fd; |
|
|
|
|
fd.detect(img, keypoints); |
|
|
|
|
|
|
|
|
|
float CV_CalonderTest::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++) |
|
|
|
|
FileStorage fs( dir + "/keypoints.xml", FileStorage::WRITE ); |
|
|
|
|
if( fs.isOpened() ) |
|
|
|
|
write( fs, "keypoints", keypoints ); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
//float l = length(p2[i] - mapped_p1[i]);
|
|
|
|
|
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)); |
|
|
|
|
ts->printf(CvTS::LOG, "File for writting keypoints can not be opened\n"); |
|
|
|
|
ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
error /= p2.size(); |
|
|
|
|
|
|
|
|
|
return error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CV_CalonderTest::ExtractFeatures(const IplImage* image, vector<CvPoint>& points) |
|
|
|
|
{ |
|
|
|
|
points.clear(); |
|
|
|
|
CvMemStorage* storage = cvCreateMemStorage(0); |
|
|
|
|
CvSeq *keypoints = 0, *descriptors = 0; |
|
|
|
|
CvSURFParams params = cvSURFParams(1000, 1); |
|
|
|
|
cvExtractSURF( image, 0, &keypoints, &descriptors, storage, params ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CvSURFPoint* point; |
|
|
|
|
for (int i=0;i<keypoints->total;i++) |
|
|
|
|
{ |
|
|
|
|
point=(CvSURFPoint*)cvGetSeqElem(keypoints,i); |
|
|
|
|
points.push_back(cvPoint((int)(point->pt.x),(int)(point->pt.y))); |
|
|
|
|
} |
|
|
|
|
cvReleaseMemStorage(&storage); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CV_CalonderTest::TrainDetector(RTreeClassifier& detector, int/* patch_size*/, const vector<CvPoint>& train_points,const IplImage* train_image, int n_keypoints) |
|
|
|
|
{ |
|
|
|
|
vector<BaseKeypoint> base_set; |
|
|
|
|
int n = (int)(train_points.size()); |
|
|
|
|
if (n_keypoints) |
|
|
|
|
n = n_keypoints; |
|
|
|
|
for (int i=0;i<n;i++) |
|
|
|
|
{ |
|
|
|
|
base_set.push_back(BaseKeypoint(train_points[i].x,train_points[i].y,const_cast<IplImage*>(train_image))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//Detector training
|
|
|
|
|
//CvRNG r = cvRNG(1);
|
|
|
|
|
RNG rng( cvRandInt(this->ts->get_rng())); |
|
|
|
|
PatchGenerator gen(0,255,2,false,0.7,1.3,-CV_PI/3,CV_PI/3,-CV_PI/3,CV_PI/3); |
|
|
|
|
|
|
|
|
|
//int64 t0 = cvGetTickCount();
|
|
|
|
|
detector.train(base_set,rng,gen,6,DEFAULT_DEPTH,3000,(int)base_set.size(),detector.DEFAULT_NUM_QUANT_BITS,false); |
|
|
|
|
//int64 t1 = cvGetTickCount();
|
|
|
|
|
//printf("Train: %f s\n",(float)(t1-t0)/cvGetTickFrequency()*1e-6);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CV_CalonderTest::GetCorrespondences(const RTreeClassifier& detector, int patch_size, |
|
|
|
|
const vector<CvPoint>& objectKeypoints, const vector<CvPoint>& imageKeypoints, const IplImage* image, |
|
|
|
|
vector<CvPoint>& object, vector<CvPoint>& features) |
|
|
|
|
{ |
|
|
|
|
IplImage* test_image = cvCloneImage(image); |
|
|
|
|
object.clear(); |
|
|
|
|
features.clear(); |
|
|
|
|
|
|
|
|
|
float* signature = new float[(const_cast<RTreeClassifier&>(detector)).original_num_classes()]; |
|
|
|
|
float* best_corr; |
|
|
|
|
int* best_corr_idx; |
|
|
|
|
if (imageKeypoints.size() > 0) |
|
|
|
|
{ |
|
|
|
|
best_corr = new float[(int)imageKeypoints.size()]; |
|
|
|
|
best_corr_idx = new int[(int)imageKeypoints.size()]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int i=0; i < (int)imageKeypoints.size(); i++) |
|
|
|
|
{ |
|
|
|
|
int part_idx = -1; |
|
|
|
|
float prob = 0.0f; |
|
|
|
|
//CvPoint center = cvPoint((int)(imageKeypoints[i].x),(int)(imageKeypoints[i].y));
|
|
|
|
|
|
|
|
|
|
CvRect roi = cvRect((int)(imageKeypoints[i].x) - patch_size/2,(int)(imageKeypoints[i].y) - patch_size/2, patch_size, patch_size); |
|
|
|
|
cvSetImageROI(test_image, roi); |
|
|
|
|
roi = cvGetImageROI(test_image); |
|
|
|
|
if(roi.width != patch_size || roi.height != patch_size) |
|
|
|
|
{ |
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
(const_cast<RTreeClassifier&>(detector)).getSignature(roi_image, signature); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j< (const_cast<RTreeClassifier&>(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; |
|
|
|
|
|
|
|
|
|
for (int j=0;j<(int)objectKeypoints.size();j++) |
|
|
|
|
{ |
|
|
|
|
float prob = 0.0f; |
|
|
|
|
int idx = -1; |
|
|
|
|
for (int i = 0; i<(int)imageKeypoints.size();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) |
|
|
|
|
{ |
|
|
|
|
object.push_back(objectKeypoints[j]); |
|
|
|
|
features.push_back(imageKeypoints[idx]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (best_corr) |
|
|
|
|
delete[] best_corr; |
|
|
|
|
if (best_corr_idx) |
|
|
|
|
delete[] best_corr_idx; |
|
|
|
|
} |
|
|
|
|
cvReleaseImage(&test_image); |
|
|
|
|
if (signature) |
|
|
|
|
delete[] signature; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Scales the source image (x and y) and rotate to the angle (Positive values mean counter-clockwise rotation)
|
|
|
|
|
void CV_CalonderTest::RotateAndScale(const IplImage* src, IplImage* dst, float angle, float scale_x, float scale_y) |
|
|
|
|
{ |
|
|
|
|
IplImage* temp = cvCreateImage(cvSize((int)(src->width*scale_x),(int)(src->height*scale_y)),src->depth,src->nChannels); |
|
|
|
|
|
|
|
|
|
cvResize(src,temp); |
|
|
|
|
|
|
|
|
|
CvMat* transform = cvCreateMat(2,3,CV_32FC1); |
|
|
|
|
cv2DRotationMatrix(cvPoint2D32f(((double)temp->width)/2,((double)temp->height)/2), angle*180/CV_PI, |
|
|
|
|
1.0f, transform ); |
|
|
|
|
|
|
|
|
|
cvWarpAffine( temp, dst, transform,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS); |
|
|
|
|
cvReleaseImage(&temp); |
|
|
|
|
cvReleaseMat(&transform); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Scales the source image point and rotate to the angle (Positive values mean counter-clockwise rotation)
|
|
|
|
|
void CV_CalonderTest::RotateAndScale(const CvPoint& src, CvPoint& dst, const CvPoint& center, float angle, float scale_x, float scale_y) |
|
|
|
|
{ |
|
|
|
|
CvPoint temp; |
|
|
|
|
temp.x = (int)(src.x*scale_x); |
|
|
|
|
temp.y = (int)(src.y*scale_y); |
|
|
|
|
|
|
|
|
|
CvMat* transform = cvCreateMat(2,3,CV_32FC1); |
|
|
|
|
cv2DRotationMatrix(cvPoint2D32f((double)center.x*scale_x,(double)center.y*scale_y), angle*180/CV_PI, |
|
|
|
|
1.0f, transform ); |
|
|
|
|
|
|
|
|
|
double a = cvmGet(transform, 0, 0); |
|
|
|
|
double b = cvmGet(transform, 0, 1); |
|
|
|
|
double c = cvmGet(transform, 0, 2); |
|
|
|
|
double d = cvmGet(transform, 1, 0); |
|
|
|
|
double e = cvmGet(transform, 1, 1); |
|
|
|
|
double f = cvmGet(transform, 1, 2); |
|
|
|
|
|
|
|
|
|
double x = a*temp.x + b*temp.y + c; |
|
|
|
|
double y = d*temp.x + e*temp.y + f; |
|
|
|
|
dst= cvPoint((int)x, (int)y); |
|
|
|
|
|
|
|
|
|
cvReleaseMat(&transform); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float CV_CalonderTest::RunTestsSeries(const IplImage* train_image, vector<CvPoint>& keypoints) |
|
|
|
|
{ |
|
|
|
|
float angles[] = {(float)-CV_PI/4,(float)CV_PI/4}; |
|
|
|
|
float scales_x[] = {0.85f,1.15f}; |
|
|
|
|
float scales_y[] = {0.85f,1.15f}; |
|
|
|
|
int n_angles = 4; |
|
|
|
|
int n_scales_x = 3; |
|
|
|
|
int n_scales_y = 3; |
|
|
|
|
int accuracy = 4; |
|
|
|
|
int are_keypoints_loaded = (int)keypoints.size(); |
|
|
|
|
|
|
|
|
|
int total_cases = n_angles*n_scales_x*n_scales_y; |
|
|
|
|
int n_case = 0; |
|
|
|
|
|
|
|
|
|
int length = max(train_image->width,train_image->height); |
|
|
|
|
int move_x = (int)(1.5*scales_x[0]*length); |
|
|
|
|
int move_y = (int)(1.5*scales_y[0]*length); |
|
|
|
|
IplImage* test_image = cvCreateImage(cvSize((int)(scales_x[1]*(move_x+length*1.5)),(int)(scales_y[1]*(move_y+length*1.5))), |
|
|
|
|
train_image->depth, train_image->nChannels); |
|
|
|
|
cvSet(test_image,cvScalar(0)); |
|
|
|
|
|
|
|
|
|
cvSetImageROI(test_image,cvRect(move_x,move_y,train_image->width,train_image->height)); |
|
|
|
|
cvCopy(train_image,test_image); |
|
|
|
|
cvResetImageROI(test_image); |
|
|
|
|
|
|
|
|
|
vector<CvPoint> objectKeypoints; |
|
|
|
|
if (!are_keypoints_loaded) |
|
|
|
|
{ |
|
|
|
|
ExtractFeatures(train_image,objectKeypoints); |
|
|
|
|
for (int i=0;i<(int)objectKeypoints.size();i++) |
|
|
|
|
{ |
|
|
|
|
keypoints.push_back(objectKeypoints[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
for (int i=0;i<(int)keypoints.size();i++) |
|
|
|
|
{ |
|
|
|
|
objectKeypoints.push_back(keypoints[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//Checking signatures are identical
|
|
|
|
|
vector <vector<float> > signatures1; |
|
|
|
|
string signatures_path = string(ts->get_data_path()) + "calonder/signatures.txt"; |
|
|
|
|
int can_load_signatures = LoadKeypointSignatures(signatures_path.c_str(),signatures1); |
|
|
|
|
// end of region
|
|
|
|
|
|
|
|
|
|
RTreeClassifier detector; |
|
|
|
|
int patch_size = PATCH_SIZE; |
|
|
|
|
//this->update_progress(1,0,total_cases,5);
|
|
|
|
|
TrainDetector(detector,patch_size,objectKeypoints,train_image,20); |
|
|
|
|
|
|
|
|
|
//Checking signatures are identical
|
|
|
|
|
vector <vector<float> > signatures2; |
|
|
|
|
ExtractKeypointSignatures(train_image,patch_size,detector,objectKeypoints,signatures2); |
|
|
|
|
if (!can_load_signatures) |
|
|
|
|
{ |
|
|
|
|
//SaveKeypointSignatures(signatures_path.c_str(),signatures2);
|
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// if (!CompareSignatures(signatures1,signatures2))
|
|
|
|
|
// return 0;
|
|
|
|
|
} |
|
|
|
|
// end of region
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int points_total = 0; |
|
|
|
|
int points_correct = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vector<CvPoint> imageKeypoints; |
|
|
|
|
vector<CvPoint> object; |
|
|
|
|
vector<CvPoint> features; |
|
|
|
|
IplImage* temp = cvCloneImage(test_image); |
|
|
|
|
|
|
|
|
|
int progress = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//int64 t0 = cvGetTickCount();
|
|
|
|
|
//printf("\n\n-----------\nTest started\n-----------\n");
|
|
|
|
|
for (float angle = angles[0]; angle<=angles[1];angle+=(n_angles > 1 ?(angles[1]-angles[0])/n_angles : 1)) |
|
|
|
|
{ |
|
|
|
|
for (float scale_x = scales_x[0]; scale_x<=scales_x[1];scale_x+=(n_scales_x > 1 ? (scales_x[1]-scales_x[0])/n_scales_x : 1)) |
|
|
|
|
{ |
|
|
|
|
for (float scale_y = scales_y[0]; scale_y<=scales_y[1];scale_y+=(n_scales_y > 1 ? (scales_y[1]-scales_y[0])/n_scales_y : 1)) |
|
|
|
|
{ |
|
|
|
|
//printf("---\nAngle: %f, scaleX: %f, scaleY: %f\n", angle,scale_x,scale_y);
|
|
|
|
|
cvSet(temp,cvScalar(0)); |
|
|
|
|
imageKeypoints.clear(); |
|
|
|
|
object.clear(); |
|
|
|
|
features.clear(); |
|
|
|
|
|
|
|
|
|
RotateAndScale(test_image,temp,angle,scale_x,scale_y); |
|
|
|
|
ExtractFeatures(temp,imageKeypoints); |
|
|
|
|
GetCorrespondences(detector,patch_size,objectKeypoints,imageKeypoints,temp,object,features); |
|
|
|
|
|
|
|
|
|
int correct = 0; |
|
|
|
|
CvPoint res; |
|
|
|
|
for (int i = 0; i< (int)object.size(); i++) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
CvPoint current = object[i]; |
|
|
|
|
current.x+=move_x; |
|
|
|
|
current.y+=move_y; |
|
|
|
|
RotateAndScale(current,res,cvPoint(temp->width/2,temp->height/2),angle,scale_x,scale_y); |
|
|
|
|
int dist = (res.x - features[i].x)*(res.x - features[i].x)+(res.y - features[i].y)*(res.y - features[i].y); |
|
|
|
|
if (dist < accuracy*accuracy) |
|
|
|
|
correct++; |
|
|
|
|
} |
|
|
|
|
//printf("Image points: %d\nCorrespondences found: %d/%d\n", (int)imageKeypoints.size(), correct, (int)object.size());
|
|
|
|
|
points_correct+=correct; |
|
|
|
|
points_total+=(int)object.size(); |
|
|
|
|
progress = update_progress( progress, n_case++, total_cases, 0 ); |
|
|
|
|
//if (drawResults)
|
|
|
|
|
//{
|
|
|
|
|
// DrawResult(train_image, temp,object,features);
|
|
|
|
|
//}
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// int64 t1 = cvGetTickCount();
|
|
|
|
|
//printf("%f s\n",(float)(t1-t0)/cvGetTickFrequency()*1e-6);
|
|
|
|
|
cvReleaseImage(&temp); |
|
|
|
|
cvReleaseImage(&test_image); |
|
|
|
|
//printf("\n\n-----------\nTest completed\n-----------\n");
|
|
|
|
|
//printf("Total correspondences found: %d/%d\n", points_correct, points_total);
|
|
|
|
|
//FILE* f = fopen("test_result.txt","w");
|
|
|
|
|
//fprintf(f,"Total correspondences found: %d/%d\n", points_correct, points_total);
|
|
|
|
|
//fclose(f);
|
|
|
|
|
if (points_total < 1) |
|
|
|
|
{ |
|
|
|
|
points_correct = 0; |
|
|
|
|
points_total = 1; |
|
|
|
|
} |
|
|
|
|
return (float)points_correct/(float)points_total; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CV_CalonderTest::CV_CalonderTest() : CvTest("calonder","RTreeClassifier") |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CV_CalonderTest::~CV_CalonderTest() {} |
|
|
|
|
|
|
|
|
|
int CV_CalonderTest::SaveKeypoints(const vector<CvPoint>& points, const char* path) |
|
|
|
|
{ |
|
|
|
|
FILE* f = fopen(path,"w"); |
|
|
|
|
if (f==NULL) |
|
|
|
|
{ |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
for (int i=0;i<(int)points.size();i++) |
|
|
|
|
{ |
|
|
|
|
fprintf(f,"%d,%d\n",points[i].x,points[i].y); |
|
|
|
|
} |
|
|
|
|
fclose(f); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int CV_CalonderTest::LoadKeypoints(vector<CvPoint>& points, const char* path) |
|
|
|
|
{ |
|
|
|
|
FILE* f = fopen(path,"r"); |
|
|
|
|
points.clear(); |
|
|
|
|
|
|
|
|
|
if (f==NULL) |
|
|
|
|
{ |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (!feof(f)) |
|
|
|
|
{ |
|
|
|
|
int x,y; |
|
|
|
|
fscanf(f,"%d,%d\n",&x,&y); |
|
|
|
|
points.push_back(cvPoint(x,y)); |
|
|
|
|
} |
|
|
|
|
fclose(f); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CV_CalonderTest::ExtractKeypointSignatures(const IplImage* test_image, int patch_size, const RTreeClassifier& detector, const vector<CvPoint>& keypoints, vector<vector<float> >& signatures) |
|
|
|
|
{ |
|
|
|
|
IplImage* _test_image = cvCloneImage(test_image); |
|
|
|
|
signatures.clear(); |
|
|
|
|
|
|
|
|
|
float* signature = new float[(const_cast<RTreeClassifier&>(detector)).original_num_classes()]; |
|
|
|
|
|
|
|
|
|
for (int i=0;i<(int)keypoints.size();i++) |
|
|
|
|
{ |
|
|
|
|
CvRect roi = cvRect((int)(keypoints[i].x) - patch_size/2,(int)(keypoints[i].y) - patch_size/2, patch_size, patch_size); |
|
|
|
|
cvSetImageROI(_test_image, roi); |
|
|
|
|
roi = cvGetImageROI(_test_image); |
|
|
|
|
if(roi.width != patch_size || roi.height != patch_size) |
|
|
|
|
{ |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cvSetImageROI(_test_image, roi); |
|
|
|
|
IplImage* roi_image = cvCreateImage(cvSize(roi.width, roi.height), _test_image->depth, _test_image->nChannels); |
|
|
|
|
cvCopy(_test_image,roi_image); |
|
|
|
|
|
|
|
|
|
(const_cast<RTreeClassifier&>(detector)).getSignature(roi_image, signature); |
|
|
|
|
|
|
|
|
|
vector<float> vec; |
|
|
|
|
|
|
|
|
|
for (int j=0;j<(const_cast<RTreeClassifier&>(detector)).original_num_classes();j++) |
|
|
|
|
{ |
|
|
|
|
vec.push_back(signature[j]); |
|
|
|
|
} |
|
|
|
|
signatures.push_back(vec); |
|
|
|
|
|
|
|
|
|
cvReleaseImage(&roi_image); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
delete[] signature; |
|
|
|
|
cvReleaseImage(&_test_image); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int CV_CalonderTest::SaveKeypointSignatures(const char* path, const vector<vector<float> >& signatures) |
|
|
|
|
{ |
|
|
|
|
FILE* f = fopen(path,"w"); |
|
|
|
|
if (!f) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
for (int i=0;i<(int)signatures.size();i++) |
|
|
|
|
{ |
|
|
|
|
for (int j=0;j<(int)signatures[i].size();j++) |
|
|
|
|
{ |
|
|
|
|
fprintf(f,"%f",signatures[i][j]); |
|
|
|
|
if (j<((int)signatures[i].size()-1)) |
|
|
|
|
fprintf(f,","); |
|
|
|
|
} |
|
|
|
|
if (i<((int)signatures.size()-1)) |
|
|
|
|
fprintf(f,"\n"); |
|
|
|
|
} |
|
|
|
|
fclose(f); |
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int CV_CalonderTest::LoadKeypointSignatures(const char* path, vector<vector<float> >& signatures) |
|
|
|
|
{ |
|
|
|
|
signatures.clear(); |
|
|
|
|
FILE* f = fopen(path,"r"); |
|
|
|
|
if (!f) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
char line[4096]; |
|
|
|
|
vector<float> vec; |
|
|
|
|
char* tok; |
|
|
|
|
|
|
|
|
|
while(fgets(line,4096,f)) |
|
|
|
|
{ |
|
|
|
|
vec.clear();
|
|
|
|
|
float val; |
|
|
|
|
tok = strtok(line,","); |
|
|
|
|
if (tok) |
|
|
|
|
{ |
|
|
|
|
sscanf(tok,"%f",&val); |
|
|
|
|
vec.push_back(val); |
|
|
|
|
tok = strtok(NULL,","); |
|
|
|
|
while (tok) |
|
|
|
|
{ |
|
|
|
|
sscanf(tok,"%f",&val); |
|
|
|
|
vec.push_back(val); |
|
|
|
|
tok = strtok(NULL,","); |
|
|
|
|
} |
|
|
|
|
signatures.push_back(vec); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fclose(f); |
|
|
|
|
return(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int CV_CalonderTest::CompareSignatures(const vector<vector<float> >& signatures1, const vector<vector<float> >& signatures2) |
|
|
|
|
{ |
|
|
|
|
if (signatures1.size() != signatures2.size()) |
|
|
|
|
{ |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float accuracy = 0.05f; |
|
|
|
|
for (int i=0;i<(int)signatures1.size();i++) |
|
|
|
|
{ |
|
|
|
|
if (signatures1[i].size() != signatures2[i].size()) |
|
|
|
|
{ |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
for (int j=0;j<(int)signatures1[i].size();j++) |
|
|
|
|
{ |
|
|
|
|
if (abs(signatures1[i][j]-signatures2[i][j]) > accuracy) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CV_CalonderTest::run( int /* start_from */) |
|
|
|
|
{ |
|
|
|
|
string train_image_path = string(ts->get_data_path()) + "calonder/baboon200.jpg"; |
|
|
|
|
string train_keypoints_path = string(ts->get_data_path()) + "calonder/train_features.txt"; |
|
|
|
|
IplImage* train_image = cvLoadImage(train_image_path.c_str(),0); |
|
|
|
|
|
|
|
|
|
if (!train_image) |
|
|
|
|
{ |
|
|
|
|
ts->printf( CvTS::LOG, "Unable to open train image calonder/baboon200.jpg"); |
|
|
|
|
ts->set_failed_test_info(CvTS::FAIL_MISSING_TEST_DATA); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#else |
|
|
|
|
FileStorage fs( dir + "/keypoints.xml", FileStorage::READ); |
|
|
|
|
if( fs.isOpened() ) |
|
|
|
|
read( fs.getFirstTopLevelNode(), keypoints ); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
ts->printf(CvTS::LOG, "File for reading keypoints can not be opened\n"); |
|
|
|
|
ts->set_failed_test_info( CvTS::FAIL_INVALID_TEST_DATA ); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
CalonderDescriptorExtractor<float> fde(dir + "/classifier.rtc"); |
|
|
|
|
|
|
|
|
|
Mat fdescriptors; |
|
|
|
|
double t = getTickCount(); |
|
|
|
|
fde.compute(img, keypoints, fdescriptors); |
|
|
|
|
t = getTickCount() - t; |
|
|
|
|
ts->printf(CvTS::LOG, "\nAverage time of computiting float descriptor = %g ms\n", t/((double)cvGetTickFrequency()*1000.)/fdescriptors.rows ); |
|
|
|
|
|
|
|
|
|
#if GET_RES |
|
|
|
|
assert(fdescriptors.type() == CV_32FC1); |
|
|
|
|
writeMatInBin( fdescriptors, "" ); |
|
|
|
|
#else |
|
|
|
|
Mat ros_fdescriptors = readMatFromBin( dir + "/ros_float_desc" ); |
|
|
|
|
double fnorm = norm(fdescriptors, ros_fdescriptors, NORM_INF ); |
|
|
|
|
ts->printf(CvTS::LOG, "nofm (inf) BTW valid and calculated float descriptors = %f\n", fnorm ); |
|
|
|
|
if( fnorm > FLT_EPSILON ) |
|
|
|
|
ts->set_failed_test_info( CvTS::FAIL_BAD_ACCURACY ); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// Testing rtree classifier
|
|
|
|
|
float min_accuracy = 0.35f; |
|
|
|
|
vector<CvPoint> train_keypoints; |
|
|
|
|
train_keypoints.clear(); |
|
|
|
|
float correctness; |
|
|
|
|
if (!LoadKeypoints(train_keypoints,train_keypoints_path.c_str())) |
|
|
|
|
{ |
|
|
|
|
correctness = RunTestsSeries(train_image,train_keypoints); |
|
|
|
|
SaveKeypoints(train_keypoints,train_keypoints_path.c_str()); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
correctness = RunTestsSeries(train_image,train_keypoints); |
|
|
|
|
} |
|
|
|
|
if (correctness > min_accuracy) |
|
|
|
|
ts->set_failed_test_info(CvTS::OK); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
ts->set_failed_test_info(CvTS::FAIL_BAD_ACCURACY); |
|
|
|
|
ts->printf( CvTS::LOG, "Correct correspondences: %f, less than %f",correctness,min_accuracy); |
|
|
|
|
} |
|
|
|
|
CalonderDescriptorExtractor<uchar> cde(dir + "/classifier.rtc"); |
|
|
|
|
Mat cdescriptors; |
|
|
|
|
t = getTickCount(); |
|
|
|
|
cde.compute(img, keypoints, cdescriptors); |
|
|
|
|
t = getTickCount() - t; |
|
|
|
|
ts->printf(CvTS::LOG, "Average time of computiting uchar descriptor = %g ms\n", t/((double)cvGetTickFrequency()*1000.)/cdescriptors.rows ); |
|
|
|
|
|
|
|
|
|
#if GET_RES |
|
|
|
|
assert(cdescriptors.type() == CV_8UC1); |
|
|
|
|
writeMatInBin( fdescriptors, "" ); |
|
|
|
|
#else |
|
|
|
|
Mat ros_cdescriptors = readMatFromBin( dir + "/ros_uchar_desc" ); |
|
|
|
|
double cnorm = norm(cdescriptors, ros_cdescriptors, NORM_INF ); |
|
|
|
|
ts->printf(CvTS::LOG, "nofm (inf) BTW valid and calculated uchar descriptors = %f\n", cnorm ); |
|
|
|
|
if( cnorm > FLT_EPSILON ) |
|
|
|
|
ts->set_failed_test_info( CvTS::FAIL_BAD_ACCURACY ); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CV_CalonderTest calonder_test; |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
CV_CalonderTest calonderTest; |
|
|
|
|