Esempio n. 1
0
int main(int argc, char** argv)
{
    if(argc != 10) {
        std::cerr << "Usage: " << argv[0] << " w h match.txt good_match.txt ntrials verb noseed mode stop" <<std::endl;
        std::cerr << "w: width of image" <<std::endl;
        std::cerr << "h: height of image" <<std::endl;
        std::cerr << "match.txt: x1 y1 x2 y2 for each line" <<std::endl;
        std::cerr << "good_match.txt: good matchings (x1 y1 x2 y2 for each line)" <<std::endl;
        std::cerr << "ntrials: maximum number of ransac trials" <<std::endl;
        std::cerr << "verb: verbose mode (1 enabled, 0 disabled)" <<std::endl;
        std::cerr << "seed: random seed (0=reinitialize)" <<std::endl;
        std::cerr << "mode: 0=all 1=ransac 2=optimized ransac (ORSA) 3=automatic" <<std::endl;
        std::cerr << "stop: stop when first meaningful F is found (1 enabled, 0 disabled)" <<std::endl;
        return 1;
    }

    int width = 0, height = 0; // dimensions of image
    int ntrials = 0;           // maximum number of ransac trials
    bool verb = false;         // verbose
    unsigned long seed = 0;    // seed value (0=reinitialize)
    int mode = -1;    // 0=all 1=ransac 2=optimized ransac (ORSA) 3=automatic
    bool stop = false;         // stop when first meaningful F is found   

    if(! (std::istringstream(argv[1]) >> width).eof()) width = 0;
    if(! (std::istringstream(argv[2]) >> height).eof()) height = 0;
    if(width <=0 || height <= 0) {
        std::cerr << "Wrong dimensions of image" << std::endl;
        return 1;
    }

    std::vector<Match> match;
    if(! loadMatch(argv[3],match)) {
        std::cerr << "Failed reading " << argv[3] << std::endl;
        return 1;
    }

    if(! (std::istringstream(argv[5]) >> ntrials).eof() || ntrials <= 0) {
        std::cerr << "ntrials should be greater than 0" << std::endl;
        return 1;
    }

    if(! (std::istringstream(argv[6]) >> verb).eof()) {
        std::cerr << "verb can only be 0 or 1" << std::endl;
        return 1;
    }

    if(! (std::istringstream(argv[7]) >> seed).eof()) {
        std::cerr << "seed must be a non-negative integer value" << std::endl;
        return 1;
    }

    if(! (std::istringstream(argv[8]) >> mode).eof() || mode < 0 || mode > 3) {
        std::cerr << "mode can only be 0, 1, 2, or 3" << std::endl;
        return 1;
    }

    if(! (std::istringstream(argv[9]) >> stop).eof()) {
        std::cerr << "stop can only be 0 or 1" << std::endl;
        return 1;
    }

    // Initialize random seed if necessary
    if(seed == 0) {
        seed = (long int)time(NULL);
        if(verb)
            std::cout << "seed: " << seed << std::endl; // Useful for debugging
    }
    srand(seed);

    // Remove duplicates (frequent with SIFT)
    std::sort(match.begin(), match.end());
    std::vector<Match>::iterator end = std::unique(match.begin(), match.end());
    if(end != match.end()) {
        if(verb)
            std::cout << "Remove " << std::distance(end,match.end())
                      << "/" << match.size() << " duplicate matches"<<std::endl;
        match.erase(end, match.end());
    }

    // Normalize coordinates
    std::vector<Match> matchBackup(match);
    float nx = (float)width;
    float ny = (float)height;
    float norm = 1.0f/sqrt((float)(nx*ny));
    for(size_t i=0; i<match.size(); i++) {
        match[i].x1 =  (match[i].x1-0.5f*nx)*norm;
        match[i].y1 =  (match[i].y1-0.5f*ny)*norm;
        match[i].x2 =  (match[i].x2-0.5f*nx)*norm;
        match[i].y2 =  (match[i].y2-0.5f*ny)*norm;
    }
    libNumerics::matrix<float> N(3,3); // Normalization matrix
    N = 0;
    N(0,0) = N(1,1) = norm; N(2,2) = 1.0f;
    N(0,2) = -0.5f*nx*norm;
    N(1,2) = -0.5f*ny*norm;

    // log proba of a uniform point in image within a band of 1 pixel from line
    float logalpha0 = log10(2.0f)+0.5f*log10((nx*nx+ny*ny)/float(nx*ny));
    std::vector<size_t> inliers;
    float error;

	libNumerics::matrix<float> F = orsa(match, ntrials, verb, mode, stop, logalpha0, inliers, error);
    error /= norm;
    if(verb) {
        std::cout << "F= " << N.t()*F*N <<std::endl; // Denormalization
        std::cout << "Geometric error threshold: " << error <<std::endl;
    }

    // Write the good matchings into a file
    std::vector<Match> good_match;
    std::vector<size_t>::const_iterator it = inliers.begin();
    for(; it != inliers.end(); it++)
        good_match.push_back(matchBackup[*it]);

    if(! saveMatch(argv[4], good_match)) {
        std::cerr << "Failed saving good matchings into " <<argv[4] <<std::endl;
        return 1;
    }

    return 0;
}
int compute_asift_matches(int num_of_tilts1, int num_of_tilts2, int w1, int h1, int w2, int h2, int verb, vector< vector< keypointslist > >& keys1, vector< vector< keypointslist > >& keys2, matchingslist &matchings, siftPar &siftparameters)
// Match the ASIFT keypoints.
// Input:
// num_of_tilts1, num_of_tilts2: number of tilts that have been simulated on the two images. (They can be different.)
// w1, h1, w2, h2: widht/height of image1/image2.
// verb: 1/0 --> show/don not show verbose messages. (1 for debugging)
// keys1, keys2: ASIFT keypoints of image1/image2. (They should be calculated with compute_asift_keypoints.)
// matchings (output): the coordinates (col1, row1, col2, row2) of all the matching points.
//
// Output: the number of matching points.
{
	float t_min, t_k, t;
	int num_tilt1, num_tilt2, tt, num_rot_t2, num_rot1, rr;
	int cc;

	int tt2, rr2, num_rot1_2;
	float t_im2;

	/* It stores the coordinates of ALL matches points of ALL affine simulations  */
	vector< vector <float> > Minfoall;

	int Tmin = 8;
	float nfa_max = -2;

	num_rot_t2 = 10;

	t_min = 1;
	t_k = sqrt(2.);

	num_tilt1 = num_of_tilts1;
	num_tilt2 = num_of_tilts2;

	if ( ( num_tilt1 < 1 ) || ( num_tilt2 < 1 ) )
	{
		printf("Number of tilts num_tilt should be equal or larger than 1. \n");
		exit(-1);
	}


	/* Initialize the vector structure for the matching points */
	std::vector< vector< vector < vector < matchingslist > > > > matchings_vec(num_tilt1);
	std::vector< vector< vector< vector< vector< vector <float> > > > > > Minfoall_vec(num_tilt1);
	for (tt = 1; tt <= num_tilt1; tt++)
	{
		t = t_min * pow(t_k, tt-1);
		if ( t == 1 )
		{
			num_rot1 = 1;
		}
		else
		{
			num_rot1 = round(num_rot_t2*t/2);
			if ( num_rot1%2 == 1 )
			{
				num_rot1 = num_rot1 + 1;
			}
			num_rot1 = num_rot1 / 2;
		}

		matchings_vec[tt-1].resize(num_rot1);
		Minfoall_vec[tt-1].resize(num_rot1);

		for  ( rr = 1; rr <= num_rot1; rr++ )
		{

			matchings_vec[tt-1][rr-1].resize(num_tilt2);
			Minfoall_vec[tt-1][rr-1].resize(num_tilt2);

			for (tt2 = 1; tt2 <= num_tilt2; tt2++)
			{
				t_im2 = t_min * pow(t_k, tt2-1);
				if ( t_im2 == 1 )
				{
					num_rot1_2 = 1;
				}
				else
				{
					num_rot1_2 = round(num_rot_t2*t_im2/2);
					if ( num_rot1_2%2 == 1 )
					{
						num_rot1_2 = num_rot1_2 + 1;
					}
					num_rot1_2 = num_rot1_2 / 2;
				}

				matchings_vec[tt-1][rr-1][tt2-1].resize(num_rot1_2);
				Minfoall_vec[tt-1][rr-1][tt2-1].resize(num_rot1_2);
			}
		}
	}


	///*
	// * setup the tilt and rotation parameters
	// * for all the loops, this vector will hold
	// * the following parameters:
	// * tt, num_rot1, rr, tt2, num_rot1_2, rr2
	// */
	//vector<int> tilt_rot;
	///* loop on tilts for image 1 */
	//for (int tt = 1; tt <= num_tilt1; tt++)
	//{
	//    float t = t_min * pow(t_k, tt-1);
	//    int num_rot1;
	//    /* if tilt t = 1, do not simulate rotation. */
	//    if ( 1 == tt )
	//		num_rot1 = 1;
	//    else
	//    {
	//		/* number of rotations to simulate */
	//		num_rot1 = round(num_rot_t2 * t / 2);
	//		if ( num_rot1%2 == 1 )
	//			num_rot1 = num_rot1 + 1;
	//		num_rot1 = num_rot1 / 2;
	//    }
	//    /* loop on rotations for image 1 */
	//    for  (int rr = 1; rr <= num_rot1; rr++ )
	//    {
	//		/* loop on tilts for image 2 */
	//		for (int tt2 = 1; tt2 <= num_tilt2; tt2++)
	//		{
	//			float t_im2 = t_min * pow(t_k, tt2-1);
	//			int num_rot1_2;
	//			if ( tt2 == 1 )
	//				num_rot1_2 = 1;
	//			else
	//			{
	//				num_rot1_2 = round(num_rot_t2 * t_im2 / 2);
	//				if ( num_rot1_2%2 == 1 )
	//					num_rot1_2 = num_rot1_2 + 1;
	//				num_rot1_2 = num_rot1_2 / 2;
	//			}
	//			/* loop on rotations for image 2 */
	//			for  (int rr2 = 1; rr2 <= num_rot1_2; rr2++ )
	//			{
	//				tilt_rot.push_back(tt);
	//				tilt_rot.push_back(num_rot1);
	//				tilt_rot.push_back(rr);
	//				tilt_rot.push_back(tt2);
	//				tilt_rot.push_back(num_rot1_2);
	//				tilt_rot.push_back(rr2);
	//			}
	//		}
	//    }
	//}

	/* Calculate the number of simulations */
#ifdef _OPENMP
	omp_set_nested(1);
#endif
	// loop on tilts for image 1.
#pragma omp parallel for private(tt)
	for (int tt = 1; tt <= num_tilt1; tt++)
	{

		float t = t_min * pow(t_k, tt-1);

		/* Attention: the t1, t2 do not follow the same convention as in compute_asift_keypoints */
		float t1 = t;
		float t2 = 1;

		int num_rot1;

		// If tilt t = 1, do not simulate rotation.
		if ( tt == 1 )
		{
			num_rot1 = 1;
		}
		else
		{
			// The number of rotations to simulate under the current tilt.
			num_rot1 = round(num_rot_t2*t/2);
			if ( num_rot1%2 == 1 )
			{
				num_rot1 = num_rot1 + 1;
			}
			num_rot1 = num_rot1 / 2;
		}


		float delta_theta = PI/num_rot1;

		// Loop on rotations for image 1.
#pragma omp parallel for private(rr)
		for  ( int rr = 1; rr <= num_rot1; rr++ )
		{
			float theta = delta_theta * (rr-1);
			theta = theta * 180 / PI;

			/* Read the keypoints of image 1 */
			keypointslist keypoints1 = keys1[tt-1][rr-1];

			// loop on tilts for image 2.
#pragma omp parallel for private(tt2)
			for (int tt2 = 1; tt2 <= num_tilt2; tt2++)
			{
				float t_im2 = t_min * pow(t_k, tt2-1);

				/* Attention: the t1, t2 do not follow the same convention as in asift_v1.c */
				float t_im2_1 = t_im2;
				float t_im2_2 = 1;

				int num_rot1_2;

				if ( tt2 == 1 )
				{
					num_rot1_2 = 1;
				}
				else
				{
					num_rot1_2 = round(num_rot_t2*t_im2/2);
					if ( num_rot1_2%2 == 1 )
					{
						num_rot1_2 = num_rot1_2 + 1;
					}
					num_rot1_2 = num_rot1_2 / 2;
				}

				float delta_theta2 = PI/num_rot1_2;

#pragma omp parallel for private(rr2)
				// Loop on rotations for image 2.
				for  ( int rr2 = 1; rr2 <= num_rot1_2; rr2++ )
				{
					float theta2 = delta_theta2 * (rr2-1);
					theta2 = theta2 * 180 / PI;

					/* Read the keypoints of image2. */
					keypointslist keypoints2 = keys2[tt2-1][rr2-1];


					// Match the keypoints of image1 and image2.
					matchingslist matchings1;
					compute_sift_matches(keypoints1,keypoints2,matchings1,siftparameters);

					if ( verb )
					{
						printf("t1=%.2f, theta1=%.2f, num keys1 = %d, t2=%.2f, theta2=%.2f, num keys2 = %d, num matches=%d\n", t, theta, (int) keypoints1.size(), t_im2, theta2, (int) keypoints2.size(), (int) matchings1.size());
					}

					/* Store the matches */
					if ( matchings1.size() > 0 )
					{
						matchings_vec[tt-1][rr-1][tt2-1][rr2-1] = matchingslist(matchings1.size());
            Minfoall_vec[tt-1][rr-1][tt2-1][rr2-1].resize(matchings1.size());

						for ( int cc = 0; cc < (int) matchings1.size(); cc++ )
						{
							///// In the coordinates the affine transformations have been normalized already in compute_asift_keypoints. So no need to normalize here.
							// Normalize the coordinates of the matched points by compensating the simulate affine transformations
							//	compensate_affine_coor(matchings1[cc], w1, h1, w2, h2, t1, t2, theta, t_im2_1, t_im2_2, theta2);

							matchings_vec[tt-1][rr-1][tt2-1][rr2-1][cc] = matchings1[cc];

							vector<float> Minfo_1match(6);
							Minfo_1match[0] = t1;
							Minfo_1match[1] = t2;
							Minfo_1match[2] = theta;
							Minfo_1match[3] = t_im2_1;
							Minfo_1match[4] = t_im2_2;
							Minfo_1match[5] = theta2;
							Minfoall_vec[tt-1][rr-1][tt2-1][rr2-1][cc] = Minfo_1match;
						}
					}
				}
			}
		}
	}

	// Move the matches to a 1D vector
	for (tt = 1; tt <= num_tilt1; tt++)
	{
		t = t_min * pow(t_k, tt-1);

		if ( t == 1 )
		{
			num_rot1 = 1;
		}
		else
		{
			num_rot1 = round(num_rot_t2*t/2);
			if ( num_rot1%2 == 1 )
			{
				num_rot1 = num_rot1 + 1;
			}
			num_rot1 = num_rot1 / 2;
		}

		for  ( rr = 1; rr <= num_rot1; rr++ )
		{
			for (tt2 = 1; tt2 <= num_tilt2; tt2++)
			{
				t_im2 = t_min * pow(t_k, tt2-1);
				if ( t_im2 == 1 )
				{
					num_rot1_2 = 1;
				}
				else
				{
					num_rot1_2 = round(num_rot_t2*t_im2/2);
					if ( num_rot1_2%2 == 1 )
					{
						num_rot1_2 = num_rot1_2 + 1;
					}
					num_rot1_2 = num_rot1_2 / 2;
				}

				for  ( rr2 = 1; rr2 <= num_rot1_2; rr2++ )
				{
					for ( cc=0; cc < (int) matchings_vec[tt-1][rr-1][tt2-1][rr2-1].size(); cc++ )
					{
						matchings.push_back(matchings_vec[tt-1][rr-1][tt2-1][rr2-1][cc]);
						Minfoall.push_back(Minfoall_vec[tt-1][rr-1][tt2-1][rr2-1][cc]);
					}
				}
			}
		}
	}

	if ( verb )
	{
	  printf("The number of matches is %d \n", (int) matchings.size());
	}


	if ( matchings.size() > 0 )
	{
	  /* Remove the repetitive matches that appear in different simulations and retain only one. */
		// Since tilts are simuated on both image 1 and image 2, it is normal to have repetitive matches.
		matchingslist matchings_unique;
		vector< vector<float> > Minfoall_unique;
		unique_match1(matchings, matchings_unique, Minfoall, Minfoall_unique);
		matchings = matchings_unique;
		Minfoall = Minfoall_unique;

		if ( verb )
			{
			  printf("The number of unique matches is %d \n", (int) matchings.size());
			}

		// There often appear to be some one-to-multiple/multiple-to-one matches (one point in image 1 matches with many points in image 2/vice versa).
		// This is an artifact of SIFT on interpolated images, as the interpolation tends to create some auto-similar structures (steps for example).
		// These matches need to be removed.
		  /* Separating the removal of  multiple-to-one and one-to-multiple in two steps:
		 - first remove multiple-to-one
		 - then remove one-to-multiple
		 This allows to avoid removing some good matches: multiple-to-one matches is much more frequent than one-to-multiple. Sometimes some of the feature points in image 1 that take part in "multiple-to-one" bad matches have also correct matches in image 2. The modified scheme avoid removing these good matches. */

		// Remove to multiple-to-one matches
		matchings_unique.clear();
		Minfoall_unique.clear();
		clean_match2(matchings, matchings_unique, Minfoall, Minfoall_unique);
		matchings = matchings_unique;
		Minfoall = Minfoall_unique;

		// Remove to one-to-multiple matches
		matchings_unique.clear();
		Minfoall_unique.clear();
		clean_match1(matchings, matchings_unique, Minfoall, Minfoall_unique);
		matchings = matchings_unique;
		Minfoall = Minfoall_unique;


		if ( verb )
		{
			printf("The number of final matches is %d \n", (int) matchings.size());
		}

		// If enough matches to do epipolar filtering
		if ( (int) matchings.size() >= Tmin )
		{
			//////// Use ORSA to filter out the incorrect matches.
			// store the coordinates of the matching points
			vector<Match> match_coor;
			for ( cc = 0; cc < (int) matchings.size(); cc++ )
			{
				Match match1_coor;
				match1_coor.x1 = matchings[cc].first.x;
				match1_coor.y1 = matchings[cc].first.y;
				match1_coor.x2 = matchings[cc].second.x;
				match1_coor.y2 = matchings[cc].second.y;

				match_coor.push_back(match1_coor);
			}

			std::vector<float> index;
			// Guoshen Yu, 2010.09.23
			// index.clear();

			int t_value_orsa=10000;
			int verb_value_orsa=0;
			int n_flag_value_orsa=0;
			int mode_value_orsa=2;
			int stop_value_orsa=0;

			// epipolar filtering with the Moisan-Stival ORSA algorithm.
//			float nfa = orsa(w1, h1, match_coor, index, t_value_orsa, verb_value_orsa, n_flag_value_orsa, mode_value_orsa, stop_value_orsa);
			float nfa = orsa((w1+w2)/2, (h1+h2)/2, match_coor, index, t_value_orsa, verb_value_orsa, n_flag_value_orsa, mode_value_orsa, stop_value_orsa);


			// if the matching is significant, register the good matches
			if ( nfa < nfa_max )
			{
				// extract meaningful matches
				matchings_unique.clear();
				Minfoall_unique.clear();
				for ( cc = 0; cc < (int) index.size(); cc++ )
				{
					matchings_unique.push_back(matchings[(int)index[cc]]);
					Minfoall_unique.push_back(Minfoall[(int)index[cc]]);
				}
				matchings = matchings_unique;
				Minfoall = Minfoall_unique;

				cout << "The two images match! " << matchings.size() << " matchings are identified. log(nfa)=" << nfa << "." << endl;
			}
			else
			{
				matchings.clear();
				Minfoall.clear();
				cout << "The two images do not match. The matching is not significant: log(nfa)=" << nfa << "." << endl;
			}
		}
		else
		{
			matchings.clear();
			Minfoall.clear();
			cout << "The two images do not match. Not enough matches to do epipolar filtering." << endl;
		}
	}
	else
	{
		cout << "The two images do not match.\n" << endl;
	}

	return matchings.size();

}