コード例 #1
0
int kpmRansacHomograhyEstimation(CorspMap* corspMap, int inlierIndex[], int *num, float h[3][3])
{
    if( corspMap->num <= 3 ) return -1;
    else if( corspMap->num == 4 ) {
        Point2f pt1[4];
        Point2f pt2[4];
        for( int i = 0; i < 4; i++ ) {
            inlierIndex[i] = i;
            pt1[i].x = corspMap->mp[i].x1;
            pt1[i].y = corspMap->mp[i].y1;
            pt2[i].x = corspMap->mp[i].x2;
            pt2[i].y = corspMap->mp[i].y2;
        }
        *num = 4;
        return ComputeHomography(pt1, pt2, h);
    }
    else if( corspMap->num < 10 ) {
        return RansacHomograhyEstimationSub2( corspMap, inlierIndex, num, h );
    }
    else {
        return RansacHomograhyEstimationSub1( corspMap, inlierIndex, num, h );
    }
}
コード例 #2
0
ファイル: FeatureAlign.cpp プロジェクト: dtwitty/panoramas
/******************* TO DO *********************
 * leastSquaresFit:
 *	INPUT:
 *		f1, f2: source feature sets
 *		matches: correspondences between f1 and f2
 *		m: motion model
 *      inliers: inlier match indices (indexes into 'matches' array)
 *		M: transformation matrix (output)
 *	OUTPUT:
 *		compute the transformation from f1 to f2 using only the inliers
 *		and return it in M
 */
int leastSquaresFit(const FeatureSet &f1, const FeatureSet &f2,
            const vector<FeatureMatch> &matches, MotionModel m,
            const vector<int> &inliers, CTransform3x3& M)
{
    // This function needs to handle two possible motion models,
    // This function needs to handle two possible motion models,
    // pure translations and full homographies.

    switch (m) {
        case eTranslate: {
            // for spherically warped images, the transformation is a
            // for spherically warped images, the transformation is a
            // translation and only has two degrees of freedom
            //
            // therefore, we simply compute the average translation vector
            // between the feature in f1 and its match in f2 for all inliers
            double u = 0;
            double v = 0;

            for (int i=0; i < (int) inliers.size(); i++) {
			    // BEGIN TODO
			    // use this loop to compute the average translation vector
			    // over all inliers
              int m1 = matches.at(inliers.at(i)).id1;
              int m2 = matches.at(inliers.at(i)).id2;
              u += f1[m1].x - f2[m2].x;
              v += f1[m1].y - f2[m2].y;
printf("TODO: %s:%d\n", __FILE__, __LINE__);

                // END TODO
            }

            u /= inliers.size();
            v /= inliers.size();

            M = CTransform3x3::Translation((float) u, (float) v);

            break;
        }

        case eHomography: {
			    M = CTransform3x3();

            // BEGIN TODO
		    // Compute a homography M using all inliers.
		    // This should call ComputeHomography.
          vector<FeatureMatch> inmatches;
          for (int bo = 0; bo < inliers.size(); bo++)
          {
            FeatureMatch mat;
            mat = matches.at(inliers.at(bo));
            inmatches.push_back(mat);
          }
          M = ComputeHomography(f1, f2, inmatches);


            break;
        }

        case eRotate3D: {
            cout << "3D Rotation is not supported by this project";
            break;
        }
    }

            // END TODO


    return 0;
}
コード例 #3
0
ファイル: FeatureAlign.cpp プロジェクト: dtwitty/panoramas
/******************* TO DO *********************
 * alignPair:
 *	INPUT:
 *		f1, f2: source feature sets
 *		matches: correspondences between f1 and f2
 *               Each match in 'matches' contains two feature ids of
 *               Each match in 'matches' contains two feature ids of
 *               matching features, id1 (in f1) and id2 (in f2).
 *		m: motion model
 *		nRANSAC: number of RANSAC iterations
 *		RANSACthresh: RANSAC distance threshold
 *		M: transformation matrix (output)
 *
 *	OUTPUT:
 *		repeat for nRANSAC iterations:
 *			choose a minimal set of feature matches
 *			estimate the transformation implied by these matches
 *			count the number of inliers
 *		for the transformation with the maximum number of inliers,
 *		compute the least squares motion estimate using the inliers,
 *		and store it in M
 */
int alignPair(const FeatureSet &f1, const FeatureSet &f2,
          const vector<FeatureMatch> &matches, MotionModel m,
          int nRANSAC, double RANSACthresh, CTransform3x3 &M)
{
    // BEGIN TODO
    // Write this entire method.  You need to handle two types of
    // motion models, pure translations (m == eTranslation) and
    // full homographies (m == eHomography).  However, you should
    // only have one outer loop to perform the RANSAC code, as
    // BEGIN TODO
    // Write this entire method.  You need to handle two types of
    // motion models, pure translations (m == eTranslation) and
    // full homographies (m == eHomography).  However, you should
    // only have one outer loop to perform the RANSAC code, as
    // the use of RANSAC is almost identical for both cases.
    //
    // Your homography handling code should call ComputeHomography.
    // This function should also call countInliers and, at the end,
    // leastSquaresFit.
    cout << "alignalignalignalign";
    cout << f1.size();
    cout << '\n';
    cout << f2.size();
    cout << '\n';
    cout << matches.size();
    cout << '\n';
    int maxInliers = -1;
    int sz = matches.size();
    for (int i = 0; i < nRANSAC; i++) {
        int n = rand() % sz;
        FeatureMatch randomMatch = matches.at(n);
        CTransform3x3 trans;
        switch (m) {
            case eTranslate: {
                Feature first = f1[randomMatch.id1];
                Feature second = f2[randomMatch.id2];
                float xTranslation = (float)(second.x - first.x);
                float yTranslation = (float)(second.y - first.y);
                cout << "Translation: X "; cout << xTranslation;
                cout << ", Y ";
                cout << yTranslation; cout << '\n';
                trans = CTransform3x3::Translation(xTranslation, yTranslation);
                break;
            }
            case eHomography: {
                int indices[] = {0, 0, 0, 0};
                for (int chooseRand = 0; chooseRand < 4; chooseRand++)
                {
                  indices[chooseRand] = rand() % sz;
                  for (int p = 0; p < chooseRand; p++)
                  {
                    if (indices[p] = indices[chooseRand]);
                    {
                      indices[chooseRand] = rand() % sz;
                      p--;
                    }
                  }
                }
                vector<FeatureMatch> selectedMatches;
                selectedMatches.resize(4);
                for (int c = 0; c < 4; c++)
                {
                  int idx = indices[c];
                  FeatureMatch fm;
                  fm.id1 = matches.at(idx).id1;
                  fm.id2 = matches.at(idx).id2;
                  selectedMatches.push_back(fm);
                }
                trans = ComputeHomography(f1, f2, selectedMatches);
                break;
              }
            }

            vector<int> inliers;
            countInliers(f1,f2,matches,m,trans,RANSACthresh,inliers);
            cout << "Inliers: "; cout << inliers.size(); cout << '\n';
            if (inliers.size() > maxInliers) {
                maxInliers = inliers.size();
                M = trans;
            }

        }
    // END TODO

    return 0;
}
コード例 #4
0
static int RansacHomograhyEstimationSub1(CorspMap* corspMap, int inlierIndex[], int *num, float h[3][3])
{
    static int  *tempIndex;
    static int   tempIndexMax = 0;
    int          tempNum;
    int          maxLoopCount = 200;
	int          loopCount    = 0;

    if( corspMap->num <= 4 ) return -1;

    if( tempIndexMax < corspMap->num ) {
        tempIndexMax = (corspMap->num/100 + 1)*100;
        tempIndex = (int*)malloc(sizeof(int)*tempIndexMax);
    }
    
    *num = 0;
    while( loopCount < maxLoopCount ) {
        Point2f pt1[4];
        Point2f pt2[4];
        int     sample[4];
		for(int i = 0 ; i < 4 ; i++ ) {
            static int s = 0;
            int        j;
            if( s++ == 0 ) srand((unsigned int)time(NULL));
            if( s == 128 ) s = 0;
            
            int pos = (int)((float )corspMap->num * rand() / (RAND_MAX + 1.0F));
            for(j = 0; j < i; j++ ) {
                if( pos == sample[j] ) break;
            }
            if( j < i ) {
                i--;
                continue;
            }
            else {
                sample[i] = pos;
            }
			pt1[i].x = (float)corspMap->mp[pos].x1;
			pt1[i].y = (float)corspMap->mp[pos].y1;
			pt2[i].x = (float)corspMap->mp[pos].x2;
			pt2[i].y = (float)corspMap->mp[pos].y2;
		}
        
		if( (!IsGoodSample(pt1)) || (!IsGoodSample(pt2)) ) {loopCount++; continue;}
        
        float htemp[3][3];
        if( ComputeHomography(pt1, pt2, htemp) < 0 ) {loopCount++; continue;}
        
        tempNum = 0;
        for(int i = 0; i < corspMap->num; i++ ) {
            float xx2, yy2, ww2, err;
            xx2 = htemp[0][0] * corspMap->mp[i].x2 + htemp[0][1] * corspMap->mp[i].y2 + htemp[0][2];
            yy2 = htemp[1][0] * corspMap->mp[i].x2 + htemp[1][1] * corspMap->mp[i].y2 + htemp[1][2];
            ww2 = htemp[2][0] * corspMap->mp[i].x2 + htemp[2][1] * corspMap->mp[i].y2 + htemp[2][2];
            xx2 /= ww2;
            yy2 /= ww2;
            err = (xx2 - corspMap->mp[i].x1)*(xx2 - corspMap->mp[i].x1) + (yy2 - corspMap->mp[i].y1)*(yy2 - corspMap->mp[i].y1);
            if( err < INLIER_THRESH ) {
                tempIndex[tempNum] = i;
                tempNum++;
            }
        }

        if( tempNum > *num ) {
            *num = tempNum;
            for(int j=0;j<3;j++) for(int i=0;i<3;i++) h[j][i] = htemp[j][i];
            for(int i=0; i<*num; i++) inlierIndex[i] = tempIndex[i];
            
            static const float p = log(1.0F-0.99F);
            float e;
            int   N;
			e = (float)tempNum / (float)corspMap->num;
			N = (int)(p / log(1 - e*e*e*e));
            if( N < maxLoopCount ) maxLoopCount = N;
		}
        loopCount++;
	}
    //printf("sampleCount= %d, outlierProb=%f\n", loopCount, 1.0F-(float)(*num)/(float)corspMap->num);
    
    return 0;
}
コード例 #5
0
static int RansacHomograhyEstimationSub2(CorspMap* corspMap, int inlierIndex[], int *num, float h[3][3])
{
    Point2f     pt1[4];
    Point2f     pt2[4];
    int         tempIndex[10];
    int         tempNum;
    int         loopCount = 0;
    
    if( corspMap->num <= 4 ) return -1;
    if( corspMap->num >= 10 ) return -1;
    
    *num = 0;
    for( int i1 = 0; i1 < corspMap->num; i1++ ) {
        pt1[0].x = (float)corspMap->mp[i1].x1;
        pt1[0].y = (float)corspMap->mp[i1].y1;
        pt2[0].x = (float)corspMap->mp[i1].x2;
        pt2[0].y = (float)corspMap->mp[i1].y2;
        for( int i2 = i1+1; i2 < corspMap->num; i2++ ) {
            pt1[1].x = (float)corspMap->mp[i2].x1;
            pt1[1].y = (float)corspMap->mp[i2].y1;
            pt2[1].x = (float)corspMap->mp[i2].x2;
            pt2[1].y = (float)corspMap->mp[i2].y2;
            for( int i3 = i2+1; i3 < corspMap->num; i3++ ) {
                pt1[2].x = (float)corspMap->mp[i3].x1;
                pt1[2].y = (float)corspMap->mp[i3].y1;
                pt2[2].x = (float)corspMap->mp[i3].x2;
                pt2[2].y = (float)corspMap->mp[i3].y2;
                for( int i4 = i3+1; i4 < corspMap->num; i4++ ) {
                    pt1[3].x = (float)corspMap->mp[i4].x1;
                    pt1[3].y = (float)corspMap->mp[i4].y1;
                    pt2[3].x = (float)corspMap->mp[i4].x2;
                    pt2[3].y = (float)corspMap->mp[i4].y2;

                    if( (!IsGoodSample(pt1)) || (!IsGoodSample(pt2)) ) {loopCount++; continue;}
                    
                    float htemp[3][3];
                    if( ComputeHomography(pt1, pt2, htemp) < 0 ) {loopCount++; continue;}
                    
                    tempNum = 0;
                    for(int i = 0; i < corspMap->num; i++ ) {
                        float xx2, yy2, ww2, err;
                        xx2 = htemp[0][0] * corspMap->mp[i].x2 + htemp[0][1] * corspMap->mp[i].y2 + htemp[0][2];
                        yy2 = htemp[1][0] * corspMap->mp[i].x2 + htemp[1][1] * corspMap->mp[i].y2 + htemp[1][2];
                        ww2 = htemp[2][0] * corspMap->mp[i].x2 + htemp[2][1] * corspMap->mp[i].y2 + htemp[2][2];
                        xx2 /= ww2;
                        yy2 /= ww2;
                        err = (xx2 - corspMap->mp[i].x1)*(xx2 - corspMap->mp[i].x1) + (yy2 - corspMap->mp[i].y1)*(yy2 - corspMap->mp[i].y1);
                        if( err < INLIER_THRESH ) {
                            tempIndex[tempNum] = i;
                            tempNum++;
                        }
                    }
                    
                    if( tempNum > *num ) {
                        *num = tempNum;
                        for(int j=0;j<3;j++) for(int i=0;i<3;i++) h[j][i] = htemp[j][i];
                        for(int i=0; i<*num; i++) inlierIndex[i] = tempIndex[i];
                        
                        static const float p = log(1.0F-0.99F);
                        float e;
                        int   N;
                        e = (float)tempNum / (float)corspMap->num;
                        N = (int)(p / log(1 - e*e*e*e));
                        if( N < loopCount ) {
                            //printf("sampleCount= %d, outlierProb=%f\n", loopCount, 1.0F-(float)(*num)/(float)corspMap->num);
                            return 0;                            
                        }
                    }
                    loopCount++;
                }
            }
        }
    }
    
    //printf("sampleCount= %d, outlierProb=%f\n", loopCount, 1.0F-(float)(*num)/(float)corspMap->num);
    return 0;
}
コード例 #6
0
/*******************************************************************************
Compute homography transformation between images using RANSAC.

    matches: set of matching points between images
    numMatches: number of matching points
    numIterations: number of iterations to run RANSAC
    inlierThreshold: maximum distance between points that are considered to be inliers
    hom: returned homography transformation (image1 -> image2)
    homInv: returned inverse homography transformation (image2 -> image1)
    image1Display: first image used to display matches
    image2Display: second image used to display matches
*******************************************************************************/
void MainWindow::RANSAC(CMatches *matches, int numMatches, int numIterations, double inlierThreshold,
                        double hom[3][3], double homInv[3][3], QImage &image1Display, QImage &image2Display)
{
	// We'll be comparing groups of 4 points
	#define MATCH_GROUP_SIZE 4
	
	// If there are fewer than matchGroupSize matches, this won't work, so return.
	if(numMatches < MATCH_GROUP_SIZE)
	{
		return;
	}
	
	CMatches potentialInliers[MATCH_GROUP_SIZE];
	int numInliers, maxInliers, randomMatchID;
	int usedMatchIDs[MATCH_GROUP_SIZE];
	double potentialInlierHom[3][3];
	double bestHom[3][3];
	
	for(int i = 0; i < MATCH_GROUP_SIZE; i++)
	{
		usedMatchIDs[i] = -1;
	}

	// Initialize random seed
	srand( time(NULL) );	

	maxInliers = -1;

	for (int iter = 0; iter < numIterations; iter++)
	{
		// Randomly select 4 pairs of potentially matching points from matches
		for(int i = 0; i < MATCH_GROUP_SIZE; i++)
		{
			// Make sure that the match selected is unique
			bool matchUnique = false;
			while(!matchUnique)
			{
				matchUnique = true;
				randomMatchID = rand() % numMatches;
			
				// Compare generated match to every other match,
				// and make sure we're not reusing one
				for(int j = 0; j < i; j++)
				{
					
					// Check for a match with a previously used match
					if(randomMatchID == usedMatchIDs[j])
					{
						matchUnique = false;
						continue;
					}
				}
			}
			
			// Once we've reached this point, we know that we have a unique match,
			// so let's add the randomly generated match to the array of potential inliers
			potentialInliers[i] = matches[randomMatchID];
			
			// Make sure we don't use the same match again
			usedMatchIDs[i] = randomMatchID;
		}

		// Now that we have four unique, randomly selected matches,
		// compute the homography relating the four selected matches
		ComputeHomography(potentialInliers, MATCH_GROUP_SIZE, potentialInlierHom, true);

		// Using the computed homography, compute the number of inliers against all of the matches
		numInliers = ComputeInlierCount(potentialInlierHom, matches, numMatches, inlierThreshold);

		// If this homography produces the highest number of inliers, store it as the best homography
		if(numInliers > maxInliers)
		{
			maxInliers = numInliers;
			for(int i = 0; i < 3; i++)
			{
				for(int j = 0; j < 3; j++)
				{
					bestHom[i][j] = potentialInlierHom[i][j];
				}
			}
		}
	}

	CMatches *inliers = new CMatches[maxInliers];

    // Given the highest scoring homography, once again find all the inliers
	GetInliers(bestHom, matches, numMatches, inlierThreshold, inliers);
	numInliers = ComputeInlierCount(bestHom, matches, numMatches, inlierThreshold);

	// Compute a new refined homography using all of the inliers
	ComputeHomography(inliers, maxInliers, hom, true);

	// Compute an inverse homography as well
	ComputeHomography(inliers, maxInliers, homInv, false);
	
	// Display the inlier matches
    DrawMatches(inliers, numInliers, image1Display, image2Display);

	delete inliers;
}
コード例 #7
0
ファイル: Project2.cpp プロジェクト: mandary/ComputerVision
/*******************************************************************************
Compute homography transformation between images using RANSAC.
    matches - set of matching points between images
    numMatches - number of matching points
    numIterations - number of iterations to run RANSAC
    inlierThreshold - maximum distance between points that are considered to be inliers
    hom - returned homography transformation (image1 -> image2)
    homInv - returned inverse homography transformation (image2 -> image1)
    image1Display - image used to display matches
    image2Display - image used to display matches
*******************************************************************************/
void MainWindow::RANSAC(CMatches *matches, int numMatches, int numIterations, double inlierThreshold,
                        double hom[3][3], double homInv[3][3], QImage &image1Display, QImage &image2Display)
{
    int i, j;
    CMatches randomMatches[4];
    double h[3][3];

    int max = 0;

    for(i = 0; i < numIterations; i++) {

        // Randomly select 4 matching pairs
        
        for(j = 0; j < 4; j++) {
            int num = rand() % numMatches;

            randomMatches[j].m_X1 = matches[num].m_X1;
            randomMatches[j].m_X2 = matches[num].m_X2;
            randomMatches[j].m_Y1 = matches[num].m_Y1;
            randomMatches[j].m_Y2 = matches[num].m_Y2;
        }

        // Compute Homography for the 4 random matches and inliers count
        if(ComputeHomography(randomMatches, 4, h, true)) {
            int count = ComputeInlierCount(h, matches, numMatches, inlierThreshold);

            // Check if the homography is the best
            if(count > max) {
                max = count;
                int x, y;
                for(x = 0; x < 3; x++) {
                    for(y = 0; y < 3; y++) {
                        hom[x][y] = h[x][y];
                    }
                }
            }
        }
    }

    CMatches *inliers = new CMatches[max];
    int numInliers = 0;

    for(i = 0; i < numMatches; i++) {
        double x2, y2;

        Project(matches[i].m_X1, matches[i].m_Y1, x2, y2, hom);

        double distance = pow(x2 - matches[i].m_X2, 2.0) + pow(y2 - matches[i].m_Y2, 2.0);

        if(distance < inlierThreshold * inlierThreshold) {
            inliers[numInliers].m_X1 = matches[i].m_X1;
            inliers[numInliers].m_Y1 = matches[i].m_Y1;
            inliers[numInliers].m_X2 = matches[i].m_X2;
            inliers[numInliers].m_Y2 = matches[i].m_Y2;

            numInliers++;
        }

    }

    // Recompute the best homography and inverse homography
    ComputeHomography(inliers, numInliers, hom, true);
    ComputeHomography(inliers, numInliers, homInv, false);

    // After you're done computing the inliers, display the corresponding matches.
    DrawMatches(inliers, numInliers, image1Display, image2Display);

    // Clean up
    delete [] inliers;

}