Path: blob/master/modules/calib3d/src/triangulate.cpp
16354 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2009, Intel Corporation and others, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/4041#include "precomp.hpp"42#include "opencv2/calib3d/calib3d_c.h"4344// cvCorrectMatches function is Copyright (C) 2009, Jostein Austvik Jacobsen.45// cvTriangulatePoints function is derived from icvReconstructPointsFor3View, originally by Valery Mosyagin.4647// HZ, R. Hartley and A. Zisserman, Multiple View Geometry in Computer Vision, Cambridge Univ. Press, 2003.48495051// This method is the same as icvReconstructPointsFor3View, with only a few numbers adjusted for two-view geometry52CV_IMPL void53cvTriangulatePoints(CvMat* projMatr1, CvMat* projMatr2, CvMat* projPoints1, CvMat* projPoints2, CvMat* points4D)54{55if( projMatr1 == 0 || projMatr2 == 0 ||56projPoints1 == 0 || projPoints2 == 0 ||57points4D == 0)58CV_Error( CV_StsNullPtr, "Some of parameters is a NULL pointer" );5960if( !CV_IS_MAT(projMatr1) || !CV_IS_MAT(projMatr2) ||61!CV_IS_MAT(projPoints1) || !CV_IS_MAT(projPoints2) ||62!CV_IS_MAT(points4D) )63CV_Error( CV_StsUnsupportedFormat, "Input parameters must be matrices" );6465int numPoints = projPoints1->cols;6667if( numPoints < 1 )68CV_Error( CV_StsOutOfRange, "Number of points must be more than zero" );6970if( projPoints2->cols != numPoints || points4D->cols != numPoints )71CV_Error( CV_StsUnmatchedSizes, "Number of points must be the same" );7273if( projPoints1->rows != 2 || projPoints2->rows != 2)74CV_Error( CV_StsUnmatchedSizes, "Number of proj points coordinates must be == 2" );7576if( points4D->rows != 4 )77CV_Error( CV_StsUnmatchedSizes, "Number of world points coordinates must be == 4" );7879if( projMatr1->cols != 4 || projMatr1->rows != 3 ||80projMatr2->cols != 4 || projMatr2->rows != 3)81CV_Error( CV_StsUnmatchedSizes, "Size of projection matrices must be 3x4" );8283// preallocate SVD matrices on stack84cv::Matx<double, 4, 4> matrA;85cv::Matx<double, 4, 4> matrU;86cv::Matx<double, 4, 1> matrW;87cv::Matx<double, 4, 4> matrV;8889CvMat* projPoints[2] = {projPoints1, projPoints2};90CvMat* projMatrs[2] = {projMatr1, projMatr2};9192/* Solve system for each point */93for( int i = 0; i < numPoints; i++ )/* For each point */94{95/* Fill matrix for current point */96for( int j = 0; j < 2; j++ )/* For each view */97{98double x,y;99x = cvmGet(projPoints[j],0,i);100y = cvmGet(projPoints[j],1,i);101for( int k = 0; k < 4; k++ )102{103matrA(j*2+0, k) = x * cvmGet(projMatrs[j],2,k) - cvmGet(projMatrs[j],0,k);104matrA(j*2+1, k) = y * cvmGet(projMatrs[j],2,k) - cvmGet(projMatrs[j],1,k);105}106}107/* Solve system for current point */108cv::SVD::compute(matrA, matrW, matrU, matrV);109110/* Copy computed point */111cvmSet(points4D,0,i,matrV(3,0));/* X */112cvmSet(points4D,1,i,matrV(3,1));/* Y */113cvmSet(points4D,2,i,matrV(3,2));/* Z */114cvmSet(points4D,3,i,matrV(3,3));/* W */115}116}117118119/*120* The Optimal Triangulation Method (see HZ for details)121* For each given point correspondence points1[i] <-> points2[i], and a fundamental matrix F,122* computes the corrected correspondences new_points1[i] <-> new_points2[i] that minimize the123* geometric error d(points1[i],new_points1[i])^2 + d(points2[i],new_points2[i])^2 (where d(a,b)124* is the geometric distance between points a and b) subject to the epipolar constraint125* new_points2' * F * new_points1 = 0.126*127* F_ : 3x3 fundamental matrix128* points1_ : 1xN matrix containing the first set of points129* points2_ : 1xN matrix containing the second set of points130* new_points1 : the optimized points1_. if this is NULL, the corrected points are placed back in points1_131* new_points2 : the optimized points2_. if this is NULL, the corrected points are placed back in points2_132*/133CV_IMPL void134cvCorrectMatches(CvMat *F_, CvMat *points1_, CvMat *points2_, CvMat *new_points1, CvMat *new_points2)135{136cv::Ptr<CvMat> tmp33;137cv::Ptr<CvMat> tmp31, tmp31_2;138cv::Ptr<CvMat> T1i, T2i;139cv::Ptr<CvMat> R1, R2;140cv::Ptr<CvMat> TFT, TFTt, RTFTR;141cv::Ptr<CvMat> U, S, V;142cv::Ptr<CvMat> e1, e2;143cv::Ptr<CvMat> polynomial;144cv::Ptr<CvMat> result;145cv::Ptr<CvMat> points1, points2;146cv::Ptr<CvMat> F;147148if (!CV_IS_MAT(F_) || !CV_IS_MAT(points1_) || !CV_IS_MAT(points2_) )149CV_Error( CV_StsUnsupportedFormat, "Input parameters must be matrices" );150if (!( F_->cols == 3 && F_->rows == 3))151CV_Error( CV_StsUnmatchedSizes, "The fundamental matrix must be a 3x3 matrix");152if (!(((F_->type & CV_MAT_TYPE_MASK) >> 3) == 0 ))153CV_Error( CV_StsUnsupportedFormat, "The fundamental matrix must be a single-channel matrix" );154if (!(points1_->rows == 1 && points2_->rows == 1 && points1_->cols == points2_->cols))155CV_Error( CV_StsUnmatchedSizes, "The point-matrices must have one row, and an equal number of columns" );156if (((points1_->type & CV_MAT_TYPE_MASK) >> 3) != 1 )157CV_Error( CV_StsUnmatchedSizes, "The first set of points must contain two channels; one for x and one for y" );158if (((points2_->type & CV_MAT_TYPE_MASK) >> 3) != 1 )159CV_Error( CV_StsUnmatchedSizes, "The second set of points must contain two channels; one for x and one for y" );160if (new_points1 != NULL) {161CV_Assert(CV_IS_MAT(new_points1));162if (new_points1->cols != points1_->cols || new_points1->rows != 1)163CV_Error( CV_StsUnmatchedSizes, "The first output matrix must have the same dimensions as the input matrices" );164if (CV_MAT_CN(new_points1->type) != 2)165CV_Error( CV_StsUnsupportedFormat, "The first output matrix must have two channels; one for x and one for y" );166}167if (new_points2 != NULL) {168CV_Assert(CV_IS_MAT(new_points2));169if (new_points2->cols != points2_->cols || new_points2->rows != 1)170CV_Error( CV_StsUnmatchedSizes, "The second output matrix must have the same dimensions as the input matrices" );171if (CV_MAT_CN(new_points2->type) != 2)172CV_Error( CV_StsUnsupportedFormat, "The second output matrix must have two channels; one for x and one for y" );173}174175// Make sure F uses double precision176F.reset(cvCreateMat(3,3,CV_64FC1));177cvConvert(F_, F);178179// Make sure points1 uses double precision180points1.reset(cvCreateMat(points1_->rows,points1_->cols,CV_64FC2));181cvConvert(points1_, points1);182183// Make sure points2 uses double precision184points2.reset(cvCreateMat(points2_->rows,points2_->cols,CV_64FC2));185cvConvert(points2_, points2);186187tmp33.reset(cvCreateMat(3,3,CV_64FC1));188tmp31.reset(cvCreateMat(3,1,CV_64FC1)), tmp31_2.reset(cvCreateMat(3,1,CV_64FC1));189T1i.reset(cvCreateMat(3,3,CV_64FC1)), T2i.reset(cvCreateMat(3,3,CV_64FC1));190R1.reset(cvCreateMat(3,3,CV_64FC1)), R2.reset(cvCreateMat(3,3,CV_64FC1));191TFT.reset(cvCreateMat(3,3,CV_64FC1)), TFTt.reset(cvCreateMat(3,3,CV_64FC1)), RTFTR.reset(cvCreateMat(3,3,CV_64FC1));192U.reset(cvCreateMat(3,3,CV_64FC1));193S.reset(cvCreateMat(3,3,CV_64FC1));194V.reset(cvCreateMat(3,3,CV_64FC1));195e1.reset(cvCreateMat(3,1,CV_64FC1)), e2.reset(cvCreateMat(3,1,CV_64FC1));196197double x1, y1, x2, y2;198double scale;199double f1, f2, a, b, c, d;200polynomial.reset(cvCreateMat(1,7,CV_64FC1));201result.reset(cvCreateMat(1,6,CV_64FC2));202double t_min, s_val, t, s;203for (int p = 0; p < points1->cols; ++p) {204// Replace F by T2-t * F * T1-t205x1 = points1->data.db[p*2];206y1 = points1->data.db[p*2+1];207x2 = points2->data.db[p*2];208y2 = points2->data.db[p*2+1];209210cvSetZero(T1i);211cvSetReal2D(T1i,0,0,1);212cvSetReal2D(T1i,1,1,1);213cvSetReal2D(T1i,2,2,1);214cvSetReal2D(T1i,0,2,x1);215cvSetReal2D(T1i,1,2,y1);216cvSetZero(T2i);217cvSetReal2D(T2i,0,0,1);218cvSetReal2D(T2i,1,1,1);219cvSetReal2D(T2i,2,2,1);220cvSetReal2D(T2i,0,2,x2);221cvSetReal2D(T2i,1,2,y2);222cvGEMM(T2i,F,1,0,0,tmp33,CV_GEMM_A_T);223cvSetZero(TFT);224cvGEMM(tmp33,T1i,1,0,0,TFT);225226// Compute the right epipole e1 from F * e1 = 0227cvSetZero(U);228cvSetZero(S);229cvSetZero(V);230cvSVD(TFT,S,U,V);231scale = sqrt(cvGetReal2D(V,0,2)*cvGetReal2D(V,0,2) + cvGetReal2D(V,1,2)*cvGetReal2D(V,1,2));232cvSetReal2D(e1,0,0,cvGetReal2D(V,0,2)/scale);233cvSetReal2D(e1,1,0,cvGetReal2D(V,1,2)/scale);234cvSetReal2D(e1,2,0,cvGetReal2D(V,2,2)/scale);235if (cvGetReal2D(e1,2,0) < 0) {236cvSetReal2D(e1,0,0,-cvGetReal2D(e1,0,0));237cvSetReal2D(e1,1,0,-cvGetReal2D(e1,1,0));238cvSetReal2D(e1,2,0,-cvGetReal2D(e1,2,0));239}240241// Compute the left epipole e2 from e2' * F = 0 => F' * e2 = 0242cvSetZero(TFTt);243cvTranspose(TFT, TFTt);244cvSetZero(U);245cvSetZero(S);246cvSetZero(V);247cvSVD(TFTt,S,U,V);248cvSetZero(e2);249scale = sqrt(cvGetReal2D(V,0,2)*cvGetReal2D(V,0,2) + cvGetReal2D(V,1,2)*cvGetReal2D(V,1,2));250cvSetReal2D(e2,0,0,cvGetReal2D(V,0,2)/scale);251cvSetReal2D(e2,1,0,cvGetReal2D(V,1,2)/scale);252cvSetReal2D(e2,2,0,cvGetReal2D(V,2,2)/scale);253if (cvGetReal2D(e2,2,0) < 0) {254cvSetReal2D(e2,0,0,-cvGetReal2D(e2,0,0));255cvSetReal2D(e2,1,0,-cvGetReal2D(e2,1,0));256cvSetReal2D(e2,2,0,-cvGetReal2D(e2,2,0));257}258259// Replace F by R2 * F * R1'260cvSetZero(R1);261cvSetReal2D(R1,0,0,cvGetReal2D(e1,0,0));262cvSetReal2D(R1,0,1,cvGetReal2D(e1,1,0));263cvSetReal2D(R1,1,0,-cvGetReal2D(e1,1,0));264cvSetReal2D(R1,1,1,cvGetReal2D(e1,0,0));265cvSetReal2D(R1,2,2,1);266cvSetZero(R2);267cvSetReal2D(R2,0,0,cvGetReal2D(e2,0,0));268cvSetReal2D(R2,0,1,cvGetReal2D(e2,1,0));269cvSetReal2D(R2,1,0,-cvGetReal2D(e2,1,0));270cvSetReal2D(R2,1,1,cvGetReal2D(e2,0,0));271cvSetReal2D(R2,2,2,1);272cvGEMM(R2,TFT,1,0,0,tmp33);273cvGEMM(tmp33,R1,1,0,0,RTFTR,CV_GEMM_B_T);274275// Set f1 = e1(3), f2 = e2(3), a = F22, b = F23, c = F32, d = F33276f1 = cvGetReal2D(e1,2,0);277f2 = cvGetReal2D(e2,2,0);278a = cvGetReal2D(RTFTR,1,1);279b = cvGetReal2D(RTFTR,1,2);280c = cvGetReal2D(RTFTR,2,1);281d = cvGetReal2D(RTFTR,2,2);282283// Form the polynomial g(t) = k6*t^6 + k5*t^5 + k4*t^4 + k3*t^3 + k2*t^2 + k1*t + k0284// from f1, f2, a, b, c and d285cvSetReal2D(polynomial,0,6,( +b*c*c*f1*f1*f1*f1*a-a*a*d*f1*f1*f1*f1*c ));286cvSetReal2D(polynomial,0,5,( +f2*f2*f2*f2*c*c*c*c+2*a*a*f2*f2*c*c-a*a*d*d*f1*f1*f1*f1+b*b*c*c*f1*f1*f1*f1+a*a*a*a ));287cvSetReal2D(polynomial,0,4,( +4*a*a*a*b+2*b*c*c*f1*f1*a+4*f2*f2*f2*f2*c*c*c*d+4*a*b*f2*f2*c*c+4*a*a*f2*f2*c*d-2*a*a*d*f1*f1*c-a*d*d*f1*f1*f1*f1*b+b*b*c*f1*f1*f1*f1*d ));288cvSetReal2D(polynomial,0,3,( +6*a*a*b*b+6*f2*f2*f2*f2*c*c*d*d+2*b*b*f2*f2*c*c+2*a*a*f2*f2*d*d-2*a*a*d*d*f1*f1+2*b*b*c*c*f1*f1+8*a*b*f2*f2*c*d ));289cvSetReal2D(polynomial,0,2,( +4*a*b*b*b+4*b*b*f2*f2*c*d+4*f2*f2*f2*f2*c*d*d*d-a*a*d*c+b*c*c*a+4*a*b*f2*f2*d*d-2*a*d*d*f1*f1*b+2*b*b*c*f1*f1*d ));290cvSetReal2D(polynomial,0,1,( +f2*f2*f2*f2*d*d*d*d+b*b*b*b+2*b*b*f2*f2*d*d-a*a*d*d+b*b*c*c ));291cvSetReal2D(polynomial,0,0,( -a*d*d*b+b*b*c*d ));292293// Solve g(t) for t to get 6 roots294cvSetZero(result);295cvSolvePoly(polynomial, result, 100, 20);296297// Evaluate the cost function s(t) at the real part of the 6 roots298t_min = DBL_MAX;299s_val = 1./(f1*f1) + (c*c)/(a*a+f2*f2*c*c);300for (int ti = 0; ti < 6; ++ti) {301t = result->data.db[2*ti];302s = (t*t)/(1 + f1*f1*t*t) + ((c*t + d)*(c*t + d))/((a*t + b)*(a*t + b) + f2*f2*(c*t + d)*(c*t + d));303if (s < s_val) {304s_val = s;305t_min = t;306}307}308309// find the optimal x1 and y1 as the points on l1 and l2 closest to the origin310tmp31->data.db[0] = t_min*t_min*f1;311tmp31->data.db[1] = t_min;312tmp31->data.db[2] = t_min*t_min*f1*f1+1;313tmp31->data.db[0] /= tmp31->data.db[2];314tmp31->data.db[1] /= tmp31->data.db[2];315tmp31->data.db[2] /= tmp31->data.db[2];316cvGEMM(T1i,R1,1,0,0,tmp33,CV_GEMM_B_T);317cvGEMM(tmp33,tmp31,1,0,0,tmp31_2);318x1 = tmp31_2->data.db[0];319y1 = tmp31_2->data.db[1];320321tmp31->data.db[0] = f2*pow(c*t_min+d,2);322tmp31->data.db[1] = -(a*t_min+b)*(c*t_min+d);323tmp31->data.db[2] = f2*f2*pow(c*t_min+d,2) + pow(a*t_min+b,2);324tmp31->data.db[0] /= tmp31->data.db[2];325tmp31->data.db[1] /= tmp31->data.db[2];326tmp31->data.db[2] /= tmp31->data.db[2];327cvGEMM(T2i,R2,1,0,0,tmp33,CV_GEMM_B_T);328cvGEMM(tmp33,tmp31,1,0,0,tmp31_2);329x2 = tmp31_2->data.db[0];330y2 = tmp31_2->data.db[1];331332// Return the points in the matrix format that the user wants333points1->data.db[p*2] = x1;334points1->data.db[p*2+1] = y1;335points2->data.db[p*2] = x2;336points2->data.db[p*2+1] = y2;337}338339if( new_points1 )340cvConvert( points1, new_points1 );341if( new_points2 )342cvConvert( points2, new_points2 );343}344345void cv::triangulatePoints( InputArray _projMatr1, InputArray _projMatr2,346InputArray _projPoints1, InputArray _projPoints2,347OutputArray _points4D )348{349CV_INSTRUMENT_REGION();350351Mat matr1 = _projMatr1.getMat(), matr2 = _projMatr2.getMat();352Mat points1 = _projPoints1.getMat(), points2 = _projPoints2.getMat();353354if((points1.rows == 1 || points1.cols == 1) && points1.channels() == 2)355points1 = points1.reshape(1, static_cast<int>(points1.total())).t();356357if((points2.rows == 1 || points2.cols == 1) && points2.channels() == 2)358points2 = points2.reshape(1, static_cast<int>(points2.total())).t();359360CvMat cvMatr1 = cvMat(matr1), cvMatr2 = cvMat(matr2);361CvMat cvPoints1 = cvMat(points1), cvPoints2 = cvMat(points2);362363_points4D.create(4, points1.cols, points1.type());364Mat cvPoints4D_ = _points4D.getMat();365CvMat cvPoints4D = cvMat(cvPoints4D_);366367cvTriangulatePoints(&cvMatr1, &cvMatr2, &cvPoints1, &cvPoints2, &cvPoints4D);368}369370void cv::correctMatches( InputArray _F, InputArray _points1, InputArray _points2,371OutputArray _newPoints1, OutputArray _newPoints2 )372{373CV_INSTRUMENT_REGION();374375Mat F = _F.getMat();376Mat points1 = _points1.getMat(), points2 = _points2.getMat();377378CvMat cvPoints1 = cvMat(points1), cvPoints2 = cvMat(points2);379CvMat cvF = cvMat(F);380381_newPoints1.create(points1.size(), points1.type());382_newPoints2.create(points2.size(), points2.type());383Mat cvNewPoints1_ = _newPoints1.getMat(), cvNewPoints2_ = _newPoints2.getMat();384CvMat cvNewPoints1 = cvMat(cvNewPoints1_), cvNewPoints2 = cvMat(cvNewPoints2_);385386cvCorrectMatches(&cvF, &cvPoints1, &cvPoints2, &cvNewPoints1, &cvNewPoints2);387}388389390