Ejemplo n.º 1
0
	//--------------------------------------------------
	// As of writing this, you can use:
	// FAST, STAR, SIFT, SURF, MSER, GFTT, HARRIS, L
	vector<KeyPoint> MatchableImage::findFeatures(string alg_name)
	{
		log(LOG_LEVEL_DEBUG, "finding features using %s", alg_name.c_str());
		
		
		if(featuresCurrent && featureAlgUsed.compare(alg_name)==0) return features;
		
		if(empty())
		{
			log(LOG_LEVEL_ERROR, "in findFeatures(), image is empty");
		}
		
		
		// "L" isn't in the "createDetector" thingie.
		// TO DO:  Figure out what these vars do & how to pass them in!
		// For that matter, how to pass in parameters to any of the other feature detectors?
		if(alg_name.compare("L")==0)
		{
			Size patchSize(32, 32);
			int radius = 7;
			int threshold = 20;
			int nOctaves=2;
			int nViews=2000;
			int clusteringDistance = 2;
			ldetector = LDetector(radius, threshold, nOctaves, nViews, patchSize.width, clusteringDistance);
			ldetector.setVerbose(true);
			
			double backgroundMin=0;
			double backgroundMax=256;
			double noiseRange=5;
			bool randomBlur=true;
			double lambdaMin=0.8;
			double lambdaMax=1.2;
			double thetaMin=-CV_PI/2;
			double thetaMax=CV_PI/2;
			double phiMin=-CV_PI/2;
			double phiMax=CV_PI/2;
			gen = PatchGenerator(backgroundMin, backgroundMax, noiseRange, randomBlur, 
								 lambdaMin, lambdaMax, thetaMin, thetaMax, phiMin, phiMax);
			int maxPoints=100;
			ldetector.getMostStable2D(bw(), features, maxPoints, gen);
		}
		else 
		{
			Ptr<FeatureDetector> detector = createFeatureDetector( alg_name );
			if(detector==0)
			{
				log(LOG_LEVEL_ERROR, "Feature detector %s not found!", alg_name.c_str());
			}
			
			detector->detect( bw(), features );
		}
		
		log(LOG_LEVEL_DEBUG, "in findFeatures(), %d features", features.size());
		featuresCurrent = true;
		descriptorsCurrent = false;
		matcherTrained=false;
		featureAlgUsed=alg_name;
		return features;
	}
Ostream& processorBoundaryPatch::operator<<(Ostream& os) const
{
    os  << patchName() << nl << token::BEGIN_BLOCK << nl
        << "    type         " << patchType() << token::END_STATEMENT << nl
        << "    nFaces       " << patchSize() << token::END_STATEMENT << nl
        << "    startFace    " << patchStart() << token::END_STATEMENT << nl
        << "    myProcNo     " << myProcNo_ << token::END_STATEMENT << nl
        << "    neighbProcNo " << neighbProcNo_
        << token::END_STATEMENT << nl
        << token::END_BLOCK << endl;

    return os;
}
Ejemplo n.º 3
0
	//--------------------------------------------------
	// As of writing this, you can use:
	// ONEWAY, FERN, BruteForce, BruteForce-L1, Planar
	void MatchableImage::trainMatcher(string alg_name)
	{
		if(matcherTrained && matchAlgUsed.compare(alg_name)==0) return;
		
		log(LOG_LEVEL_DEBUG, "Training matcher %s", alg_name.c_str());
		
		/*
		// These don't require descriptors.  It's all rolled up in the matcher.
		if(!alg_name.compare("FERN")||!alg_name.compare("ONEWAY")||!alg_name.compare("CALONDER"))
		{
			findFeatures();
			genericDescriptorMatch = createDescriptorMatcher(alg_name, "fern_params.xml");
			
			log(LOG_LEVEL_DEBUG, "training matcher");
			Mat img = bw();
			genericDescriptorMatch->add( img, features );
			
		}
		*/
		
		if(!alg_name.compare("BruteForce")||!alg_name.compare("BruteForce-L1"))
		{
			findDescriptors();
			descriptorMatcher = createDescriptorMatcher(alg_name.c_str());
			descriptorMatcher->clear();
			descriptorMatcher->add( descriptors ); 
		}
		
		if(!alg_name.compare("Planar"))
		{
			if(featureAlgUsed.compare("L")!=0)
			{
				log(LOG_LEVEL_DEBUG, "Planar detector works best with L detector.  Switching!");
				findFeatures("L");
			}
			
			Size patchSize(32, 32);
			planarDetector.setVerbose(true);
			planarDetector.train(pyramid(ldetector.nOctaves-1), features, patchSize.width, 100, 11, 10000, ldetector, gen);
			
		}
		matchAlgUsed = alg_name;
	}
Ejemplo n.º 4
0
void getNCCBlock(const ImgG& img, double x, double y, NCCBlock& blk) {
	cv::Mat cvImg(img.rows, img.cols, CV_8UC1, img.data);
	cv::Size patchSize(2 * SL_NCCBLK_HW + 1, 2 * SL_NCCBLK_HW + 1);
	cv::Mat patch;
	cv::getRectSubPix(cvImg, patchSize, cv::Point2d(x, y), patch);

	memcpy(blk.I, patch.data, SL_NCCBLK_LEN);

	/*compute NCC parameters*/
	double a = 0, b = 0;
	blk.avgI = 0;
	for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
		a += blk.I[j];
		b += double(blk.I[j]) * blk.I[j];
		blk.avgI += blk.I[j];
	}
	blk.A = a;
	blk.B = b;
	blk.C = 1 / sqrt(SL_NCCBLK_LEN * b - a * a);
	blk.avgI /= SL_NCCBLK_LEN;
}
Ejemplo n.º 5
0
void getNCCBlocks(const ImgG& scaledImg, Mat_d& pts, PtrVec<NCCBlock>& nccBlks,
		double scale) {
	if (pts.empty())
		return;

	nccBlks.clear();
	nccBlks.reserve(pts.rows * 2);

	int bw = 2 * SL_NCCBLK_HW + 1;

	if (scale == 1.0) {
		cv::Mat cvImg(scaledImg.rows, scaledImg.cols, CV_8UC1, scaledImg.data);
		cv::Size patchSize(bw, bw);
		cv::Mat patch;

		for (int i = 0; i < pts.rows; i++) {
			double x = pts.data[2 * i];
			double y = pts.data[2 * i + 1];
			cv::getRectSubPix(cvImg, patchSize, cv::Point2d(x, y), patch);
			NCCBlock* blk = new NCCBlock(0);
			/* copy image block */
			for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
				blk->I[j] = patch.data[j];
			}
			/* compute NCC parameters */
			double a = 0, b = 0;
			blk->avgI = 0;
			for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
				a += blk->I[j];
				b += double(blk->I[j]) * blk->I[j];
				blk->avgI += blk->I[j];
			}
			blk->A = a;
			blk->B = b;
			blk->C = 1 / sqrt(SL_NCCBLK_LEN * b - a * a);
			blk->avgI /= SL_NCCBLK_LEN;
			nccBlks.push_back(blk);
		}
	} else {
		cv::Mat cvOrgImg(scaledImg.rows, scaledImg.cols, CV_8UC1,
				scaledImg.data);
		cv::Mat cvImg;
		cv::resize(cvOrgImg, cvImg, cv::Size(), scale, scale);
		cv::Size patchSize(bw, bw);
		cv::Mat patch;

		for (int i = 0; i < pts.rows; i++) {
			double x = pts.data[2 * i] * scale;
			double y = pts.data[2 * i + 1] * scale;
			cv::getRectSubPix(cvImg, patchSize, cv::Point2d(x, y), patch);
			NCCBlock* blk = new NCCBlock(0);

			/* copy image block */
			for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
				blk->I[j] = patch.data[j];
			}
			/* compute NCC parameters */
			double a = 0, b = 0;
			blk->avgI = 0;
			for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
				a += blk->I[j];
				b += double(blk->I[j]) * blk->I[j];
				blk->avgI += blk->I[j];
			}
			blk->A = a;
			blk->B = b;
			blk->C = 1 / sqrt(SL_NCCBLK_LEN * b - a * a);
			blk->avgI /= SL_NCCBLK_LEN;
			nccBlks.push_back(blk);
		}
	}
}
Ejemplo n.º 6
0
void getNCCBlocks(const ImgG& scaledImg,
		const std::vector<FeaturePoint*>& vecFeatPts, PtrVec<NCCBlock>& nccBlks,
		double scale) {
	if (vecFeatPts.empty())
		return;

	nccBlks.clear();
	nccBlks.reserve(vecFeatPts.size() * 2);
	int bw = 2 * SL_NCCBLK_HW + 1;

	if (scale == 1.0) {
		cv::Mat cvImg(scaledImg.rows, scaledImg.cols, CV_8UC1, scaledImg.data);
		cv::Size patchSize(bw, bw);
		cv::Mat patch;

		for (size_t i = 0; i < vecFeatPts.size(); i++) {
			FeaturePoint* pFt = vecFeatPts[i];
			cv::getRectSubPix(cvImg, patchSize, cv::Point2d(pFt->xo, pFt->yo),
					patch);
			NCCBlock* blk = new NCCBlock(pFt);
			/* copy image block */
			for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
				blk->I[j] = patch.data[j];
			}
			/* compute NCC parameters */
			double a = 0, b = 0;
			blk->avgI = 0;
			for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
				a += blk->I[j];
				b += double(blk->I[j]) * blk->I[j];
				blk += blk->I[j];
			}
			blk->A = a;
			blk->B = b;
			blk->C = 1 / sqrt(SL_NCCBLK_LEN * b - a * a);
			blk->avgI /= SL_NCCBLK_LEN;
			nccBlks.push_back(blk);
		}
	} else {
		cv::Mat cvOrgImg(scaledImg.rows, scaledImg.cols, CV_8UC1,
				scaledImg.data);
		cv::Mat cvImg;
		cv::resize(cvOrgImg, cvImg, cv::Size(), scale, scale);

		cv::Size patchSize(bw, bw);
		cv::Mat patch;

		for (size_t i = 0; i < vecFeatPts.size(); i++) {
			FeaturePoint* pFt = vecFeatPts[i];
			cv::getRectSubPix(cvImg, patchSize,
					cv::Point2d(pFt->xo * scale, pFt->yo * scale), patch);
			NCCBlock* blk = new NCCBlock(pFt);
			/* copy image block */
			for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
				blk->I[j] = patch.data[j];
			}
			/* compute NCC parameters */
			double a = 0, b = 0;
			blk->avgI = 0;
			for (int j = 0; j < SL_NCCBLK_LEN; ++j) {
				a += blk->I[j];
				b += double(blk->I[j]) * blk->I[j];
				blk->avgI += blk->I[j];
			}
			blk->A = a;
			blk->B = b;
			blk->C = 1 / sqrt(SL_NCCBLK_LEN * b - a * a);
			blk->avgI /= SL_NCCBLK_LEN;
			nccBlks.push_back(blk);
		}
	}
}
Ejemplo n.º 7
0
// name   : detect function
// input  : image and dataset
// output : classification result and detect picture
CDetectionResult CRForest::detection(CTestDataset &testSet) const {
    int classNum = classDatabase.vNode.size();//contain class number
    std::vector<CTestPatch> testPatch;
    std::vector<const LeafNode*> result;

    //std::vector<const LeafNode*> storedLN(0);
    //std::vector<std::vector<CParamset> > cluster(0);
    //std::vector<CParamset> clusterMean(0);

    cv::vector<cv::Mat> outputImage(classNum);
    cv::vector<cv::Mat> voteImage(classNum);//voteImage(classNum);
    //cv::vector<cv::Mat_<std::vector<CParamset> > > voteParam(classNum);

    std::vector<int> totalVote(classNum,0);

    //boost::timer t;

    //boost::timer::auto_cpu_timer t;
    //boost::timer::nanosecond_type time;

    std::vector<paramHist**> voteParam2(classNum);

    //timer.start();

    testSet.loadImage(conf);

    testSet.extractFeatures(conf);

    //std::cout << "extracted feature " << t.elapsed() << " sec" << std::endl;

    //testSet.releaseImage();

    //t.restart()
    // image row and col
    int imgRow = testSet.img.at(0)->rows;
    int imgCol = testSet.img.at(0)->cols;

    #pragma omp parallel
    {
        #pragma omp for
        for(int i = 0; i < classNum; ++i) {
            outputImage.at(i) = testSet.img.at(0)->clone();
            voteImage.at(i) = cv::Mat::zeros(imgRow,imgCol,CV_32FC1);
            voteParam2.at(i) = new paramHist*[imgRow];
            for(int j = 0; j < imgRow; ++j)
                voteParam2.at(i)[j] = new paramHist[imgCol];
        }
    }

    //paramHist voteParam[testSet.img.at(0)->rows][testSet.img.at(0)->cols][classNum];
    // extract feature from test image
    //features.clear();
    //extractFeatureChannels(image.at(0), features);
    // add depth image to features
    //features.push_back(image.at(1));
    // extract patches from features

    extractTestPatches(testSet,testPatch,this->conf);

    //std::cout << "extracted feature " << t.elapsed() << " sec" << std::endl;

    std::cout << "patch num: " << testPatch.size() << std::endl;
    std::cout << "detecting..." << std::endl;
    // regression and vote for every patch

    std::cout << "class num = " << classNum << std::endl;

    for(int j = 0; j < testPatch.size(); ++j) {
        // regression current patch
        result.clear();
        this->regression(result, testPatch.at(j));

        // for each tree leaf
        for(int m = 0; m < result.size(); ++m) {
            #pragma omp parallel
            {
                #pragma omp for

                for(int l = 0; l < result.at(m)->pfg.size(); ++l) {
                    if(result.at(m)->pfg.at(l) > 0.9) {
                        int cl = classDatabase.search(result.at(m)->param.at(l).at(0).getClassName());

                        for(int n = 0; n < result.at(m)->param.at(cl).size(); ++n) {
                            cv::Point patchSize(conf.p_height/2,conf.p_width/2);

                            cv::Point rPoint = result.at(m)->param.at(cl).at(n).getCenterPoint();

                            if(conf.learningMode != 2) {
                                cv::Mat tempDepth = *testPatch[j].getDepth();
                                cv::Rect tempRect = testPatch[j].getRoi();
                                cv::Mat realDepth = tempDepth(tempRect);
                                double centerDepth = realDepth.at<ushort>(tempRect.height / 2 + 1, tempRect.width / 2 + 1) + conf.mindist;

                                rPoint *= centerDepth;
                                rPoint.x /= 1000;
                                rPoint.y /= 1000;


                            }

                            cv::Point pos(testPatch.at(j).getRoi().x + patchSize.x +  rPoint.x,
                                          testPatch.at(j).getRoi().y + patchSize.y +  rPoint.y);
                            // vote to result image
                            if(pos.x > 0 && pos.y > 0 && pos.x < voteImage.at(cl).cols && pos.y < voteImage.at(cl).rows) {
                                double v = result.at(m)->pfg.at(cl) / ( result.size() * result.at(m)->param.at(l).size());
                                voteImage.at(cl).at<float>(pos.y,pos.x) += v;//(result.at(m)->pfg.at(c) - 0.9);// * 100;//weight * 500;
                                voteParam2.at(cl)[pos.y][pos.x].roll.at<double>(0,result.at(m)->param.at(l).at(n).getAngle()[0]) += v * 10000;
                                voteParam2.at(cl)[pos.y][pos.x].pitch.at<double>(0,result.at(m)->param.at(l).at(n).getAngle()[1]) += v * 10000;
                                voteParam2.at(cl)[pos.y][pos.x].yaw.at<double>(0,result.at(m)->param.at(l).at(n).getAngle()[2]) += v * 10000;
                                //std::cout << result.at(m)->param.at(l).at(n).getAngle() << std::endl;
                                //std::cout << v << std::endl;
                                totalVote.at(cl) += 1;
                            }

                        } //for(int n = 0; n < result.at(m)->param.at(cl).size(); ++n){
                    } //if(result.at(m)->pfg.at(l) > 0.9){
                } //for(int l = 0; l < result.at(m)->pfg.size(); ++l){

            }//pragma omp parallel

        } // for every leaf
    } // for every patch

    // vote end

    #pragma omp parallel
    {
        #pragma omp for
        // find balance by mean shift
        for(int i = 0; i < classNum; ++i) {
            cv::GaussianBlur(voteImage.at(i),voteImage.at(i), cv::Size(21,21),0);
        }
    }

    // measure time
    //    double time = t.elapsed();
    //    std::cout << time << "sec" << std::endl;
    //    std::cout << 1 / (time) << "Hz" << std::endl;

    // output image to file
    std::string opath;
    //    if(!conf.demoMode){
    //        //create result directory
    //        opath = testSet.getRgbImagePath();
    //        opath.erase(opath.find_last_of(PATH_SEP));
    //        std::string imageFilename = testSet.getRgbImagePath();
    //        imageFilename.erase(imageFilename.find_last_of("."));
    //        //imageFilename.erase(imageFilename.begin(),imageFilename.find_last_of(PATH_SEP));
    //        imageFilename = imageFilename.substr(imageFilename.rfind(PATH_SEP),imageFilename.length());

    //        //opath += PATH_SEP;
    //        opath += imageFilename;
    //        std::string execstr = "mkdir -p ";
    //        execstr += opath;
    //        system( execstr.c_str() );

    //        for(int c = 0; c < classNum; ++c){
    //            std::stringstream cToString;
    //            cToString << c;
    //            std::string outputName = "output" + cToString.str() + ".png";
    //            std::string outputName2 = opath + PATH_SEP + "vote_" + classDatabase.vNode.at(c).name + ".png";
    //            //cv::imwrite(outputName.c_str(),outputImage.at(c));
    //            //cv::cvtColor(voteImage)

    //            cv::Mat writeImage;
    //            //hist.convertTo(hist, hist.type(), 200 * 1.0/second_val,0);
    //            voteImage.at(c).convertTo(writeImage, CV_8UC1, 254);
    //            cv::imwrite(outputName2.c_str(),writeImage);
    //        }
    //    }

    // create detection result
    CDetectionResult detectResult;
    detectResult.voteImage = voteImage;

    // show ground truth
    std::cout << "show ground truth" << std::endl;
    //    std::cout << dataSet.className.size() << std::endl;
    //    std::cout << dataSet.centerPoint.size() << std::endl;
    for(int i = 0; i < testSet.param.size(); ++i) {
        testSet.param.at(i).showParam();
    }

    // show detection reslut
    std::cout << "show result" << std::endl;
    // for every class
    for(int c = 0; c < classNum; ++c) {
        double min,max;
        cv::Point minLoc,maxLoc;
        cv::minMaxLoc(voteImage.at(c),&min,&max,&minLoc,&maxLoc);

        double min_pose_value[3], max_pose_value[3];
        cv::Point min_pose[3], max_pose[3];

        paramHist hist;

        for(int x = 0; x < conf.paramRadius; ++x) {
            for(int y = 0; y < conf.paramRadius; ++y) {
                if( maxLoc.x + x < imgCol &&  maxLoc.y + y < imgRow)
                    hist += voteParam2.at(c)[maxLoc.y + y][maxLoc.x + x];
                if(maxLoc.x - x > 0 && maxLoc.y - y > 0)
                    hist += voteParam2.at(c)[maxLoc.y - y][maxLoc.x - x];
            }
        }

        //hist.showHist();

        //        for(int p = 0; p < 360; ++p){
        //            std::cout << p << " " <<  voteParam2.at(c)[maxLoc.y][maxLoc.x].yaw.at<double>(0,p) << std::endl;
        //        }

        //voteParam2.at(c)[maxLoc.y][maxLoc.x].showHist();

        cv::minMaxLoc(hist.roll, &min_pose_value[0], &max_pose_value[0], &min_pose[0], &max_pose[0]);
        cv::minMaxLoc(hist.pitch, &min_pose_value[1], &max_pose_value[1], &min_pose[1], &max_pose[1]);
        cv::minMaxLoc(hist.yaw, &min_pose_value[2], &max_pose_value[2], &min_pose[2], &max_pose[2]);

        // draw detected class bounding box to result image
        // if you whant add condition of detection threshold, add here
        cv::Size tempSize = classDatabase.vNode.at(c).classSize;
        cv::Rect_<int> outRect(maxLoc.x - tempSize.width / 2,maxLoc.y - tempSize.height / 2 , tempSize.width,tempSize.height);
        cv::rectangle(outputImage.at(c),outRect,cv::Scalar(0,0,200),3);
        cv::putText(outputImage.at(c),classDatabase.vNode.at(c).name,cv::Point(outRect.x,outRect.y),cv::FONT_HERSHEY_SIMPLEX,1.2, cv::Scalar(0,0,200), 2, CV_AA);

        // draw grand truth to result image
        if(!conf.demoMode) {
            for(int i = 0; i < testSet.param.size(); ++i) {
                int tempClassNum = classDatabase.search(testSet.param.at(i).getClassName());
                if(tempClassNum != -1) {
                    cv::Size tempSize = classDatabase.vNode.at(tempClassNum).classSize;
                    cv::Rect_<int> outRect(testSet.param.at(i).getCenterPoint().x - tempSize.width / 2,testSet.param.at(i).getCenterPoint().y - tempSize.height / 2 , tempSize.width,tempSize.height);
                    cv::rectangle(outputImage.at(tempClassNum),outRect,cv::Scalar(200,0,0),3);
                    cv::putText(outputImage.at(tempClassNum),classDatabase.vNode.at(c).name,cv::Point(testSet.param.at(i).getCenterPoint().x, testSet.param.at(i).getCenterPoint().y),cv::FONT_HERSHEY_SIMPLEX,1.2, cv::Scalar(200,0,0), 2, CV_AA);
                }
            }
        }

        // show result
        std::cout << c << " Name : " << classDatabase.vNode.at(c).name <<
                  "\tvote : " << totalVote.at(c) <<
                  " Score : " << voteImage.at(c).at<float>(maxLoc.y, maxLoc.x) <<
                  " CenterPoint : " << maxLoc << std::endl <<
                  " Pose : roll " << max_pose[0].x <<
                  " pitch : " << max_pose[1].x <<
                  " yaw : " << max_pose[2].x << std::endl;

        // if not in demo mode, output image to file
        if(!conf.demoMode) {
            std::string outputName = opath + PATH_SEP + "detectionResult" + "_" + classDatabase.vNode.at(c).name + ".png";
            cv::imwrite(outputName.c_str(),outputImage.at(c));
        }

        CDetectedClass detectedClass;
        detectedClass.name = classDatabase.vNode.at(c).name;
        detectedClass.angle[0] = max_pose[0].x;

        // calc euclidean dist to nearest object
        double minError = DBL_MAX;
        std::string nearestObject;
        for(int d = 0; d < testSet.param.size(); ++d) {
            double tempError = euclideanDist(maxLoc,testSet.param.at(d).getCenterPoint());//= std::sqrt(std::pow((double)(maxLoc.x - testSet.param.at(0).getCenterPoint().x), 2) + std::pow((double)(maxLoc.y - testSet.param.at(0).getCenterPoint().y), 2));
            //std::cout << tempError << std::endl;
            if(tempError < minError) {
                minError = tempError;
                nearestObject = testSet.param.at(d).getClassName();
            }
        }

        // calc and output result
        detectedClass.error = minError;
        detectedClass.nearestClass = nearestObject;
        detectedClass.score = voteImage.at(c).at<float>(maxLoc.y, maxLoc.x);
        detectResult.detectedClass.push_back(detectedClass);
    } // for every class

    for(int k = 0; k < classNum; ++k) {
        for(int i = 0; i < imgRow; ++i) {
            delete[] voteParam2.at(k)[i];
        }
    }

    return detectResult;
}
int main(int argc, char *const *argv)
{
  std::vector<std::string> lbdNames;
  lbdNames.push_back("Freak");
  lbdNames.push_back("Random Freak");
  lbdNames.push_back("Brief");
  lbdNames.push_back("Ex. Freak");

  int measures = 512;
  int psize = 32;
  int iterations = 100;
  int samples = 20;

  int c = 0;
  while( (c = getopt(argc, argv, "i:p:m:s:")) != -1)
  {
    switch(c)
    {
    case 'i':
      iterations = atoi(optarg);
      break;
    case 'p':
      psize = atoi(optarg);
      break;
    case 'm':
      measures = atoi(optarg);
      break;
    case 's':
      samples = atoi(optarg);
      break;
    default:
      break;
    }
  }

  cv::Mat testImage = cv::imread(argv[argc-1], 0);
  if (!testImage.data)
  {
    std::cerr << "Error reading: " << argv[argc-1] << std::endl;
    return -1;
  }

  cv::Mat imagef;
  testImage.convertTo(imagef, CV_32F, 1.0/255.0);

  cv::RNG rng(getpid());

  cv::Size patchSize(psize,psize);

  for (int i = 0; i < lbdNames.size(); ++i)
  {
    lts2::LBDOperator *LBD = lts2::CreateLbdOperator(i, measures);
    LBD->initWithPatchSize(patchSize);
    float norm = 0.0;

    for (int k = 0; k < samples; ++k)
    {
      // Select a random patch
      cv::Rect ROI;
      ROI.x = rng(imagef.cols-psize);
      ROI.y = rng(imagef.rows-psize);
      ROI.width = patchSize.width;
      ROI.height = patchSize.height;

      cv::Mat patch;
      imagef(ROI).copyTo(patch);

      // Compute the norm
      float current_norm = lts2::LinearOperator::EstimateOperatorNorm(*LBD, patch, iterations);

      norm = MAX(norm, current_norm);
    }

    std::cout << lbdNames[i] << " has norm: " << norm << std::endl;
    delete LBD;
  }

  return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
  if (argc < 2)
  {
    print_usage(stdout, argv);
    return 0;
  }

  int lbdType = 0;
  int pside = 32;
  int M = 512;
  int normalize = 0;

  static struct option long_options[] = {
    {"lbd", required_argument, 0, 0},
    {0, 0, 0, 0}
  };

  int optionIndex;
  int c = getopt_long(argc, argv, "i:m:n:p:", long_options, &optionIndex);
  
  while (c != -1)
  {
    switch (c)
    {
    case 0:
      if (optionIndex == 0)
      {
        if (strncmp(optarg, "freak", 5) == 0) lbdType = (int)lbd::eTypeFreak;
        else if (strncmp(optarg, "brief", 5) == 0) lbdType = (int)lbd::eTypeBrief;
        else if (strncmp(optarg, "exfreak", 7) == 0) lbdType = (int)lbd::eTypeExFreak;
        else lbdType = lbd::eTypeRandomFreak;
      }
      break;
      
    case 'm':
      M = MAX(1, atoi(optarg));
      break;

    case 'n':
      normalize = atoi(optarg);
      break;

    case 'p':
      pside = atoi(optarg);
      pside += (pside % 2);   // Enforce even size
      break;

    case '?':
      std::cerr << "Unknown option: -" << c << " (ignored)\n";
      break;

    default:
      break;
    }

    c = getopt_long(argc, argv, "m:n:p:", long_options, &optionIndex);
  }

  cv::Size patchSize(pside,pside);
  lts2::LBDOperator *LBD = lts2::CreateLbdOperator(lbdType, M);
  LBD->initWithPatchSize(patchSize);

  cv::Mat result;
  LBD->drawSelfInImage(result, normalize);
  cv::normalize(result, result, 0.0, 1.0, cv::NORM_MINMAX);

  std::stringstream windowNameStr;

  cv::Mat res8;
  result.convertTo(res8, CV_8U, 255.0);

  cv::imwrite(argv[argc-1], res8);

  return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
  if (argc < 2)
  {
    print_usage(stdout, argv);
    return 0;
  }

  int lbdType = 0;
  int pside = 32;
  int normalize = 1;

  static struct option long_options[] = {
    {"lbd", required_argument, 0, 0},
    {0, 0, 0, 0}
  };

  int optionIndex;
  int c = getopt_long(argc, argv, "n:p:", long_options, &optionIndex);

  while (c != -1)
  {
    switch (c)
    {
    case 0:
      if (optionIndex == 0)
      {
        if (strncmp(optarg, "freak", 5) == 0) lbdType = (int)lbd::eTypeFreak;
        else if (strncmp(optarg, "brief", 5) == 0) lbdType = (int)lbd::eTypeBrief;
        else if (strncmp(optarg, "exfreak", 7) == 0) lbdType = (int)lbd::eTypeExFreak;
        else lbdType = lbd::eTypeRandomFreak;
      }
      break;
      
    case 'n':
      normalize = atoi(optarg);
      break;

    case 'p':
      pside = atoi(optarg);
      pside += (pside % 2);   // Enforce even size
      break;

    case '?':
      std::cerr << "Unknown option: -" << c << " (ignored)\n";
      break;

    default:
      break;
    }

    c = getopt_long(argc, argv, "n:p:", long_options, &optionIndex);
  }

  int N = atoi(argv[argc-2]);

  cv::Size patchSize(pside,pside);
  lts2::LBDOperator *LBD = lts2::CreateLbdOperator(lbdType);
  LBD->initWithPatchSize(patchSize);

  std::string lbdName;
  switch(lbdType)
  {
  case lbd::eTypeFreak:
    lbdName = "freak";
    break;
  case lbd::eTypeExFreak:
    lbdName = "exfreak";
    break;
  case lbd::eTypeRandomFreak:
    lbdName = "rafreak";
    break;
  case lbd::eTypeBrief:
    lbdName = "brief";
    break;
  }

  std::vector<cv::Mat> frame;
  LBD->drawBasis(frame, normalize);
  cv::Mat res8;

  for (int i = 0; i < N; ++i)
  {
    std::stringstream nameStream;
    nameStream << argv[argc-1] << "/" << lbdName << "-";
    nameStream << std::setw(3) << std::setfill('0') << (i+1);
    nameStream << ".png";

    frame[i].convertTo(res8, CV_8U, 255.0);

    cv::imwrite(nameStream.str(), res8);
  }

  return EXIT_SUCCESS;
}