Path: blob/master/modules/calib3d/src/calibration.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// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#include "precomp.hpp"43#include "opencv2/imgproc/imgproc_c.h"44#include "distortion_model.hpp"45#include "opencv2/calib3d/calib3d_c.h"46#include <stdio.h>47#include <iterator>4849/*50This is stright-forward port v3 of Matlab calibration engine by Jean-Yves Bouguet51that is (in a large extent) based on the paper:52Z. Zhang. "A flexible new technique for camera calibration".53IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(11):1330-1334, 2000.54The 1st initial port was done by Valery Mosyagin.55*/5657using namespace cv;5859// reimplementation of dAB.m60CV_IMPL void cvCalcMatMulDeriv( const CvMat* A, const CvMat* B, CvMat* dABdA, CvMat* dABdB )61{62int i, j, M, N, L;63int bstep;6465CV_Assert( CV_IS_MAT(A) && CV_IS_MAT(B) );66CV_Assert( CV_ARE_TYPES_EQ(A, B) &&67(CV_MAT_TYPE(A->type) == CV_32F || CV_MAT_TYPE(A->type) == CV_64F) );68CV_Assert( A->cols == B->rows );6970M = A->rows;71L = A->cols;72N = B->cols;73bstep = B->step/CV_ELEM_SIZE(B->type);7475if( dABdA )76{77CV_Assert( CV_ARE_TYPES_EQ(A, dABdA) &&78dABdA->rows == A->rows*B->cols && dABdA->cols == A->rows*A->cols );79}8081if( dABdB )82{83CV_Assert( CV_ARE_TYPES_EQ(A, dABdB) &&84dABdB->rows == A->rows*B->cols && dABdB->cols == B->rows*B->cols );85}8687if( CV_MAT_TYPE(A->type) == CV_32F )88{89for( i = 0; i < M*N; i++ )90{91int i1 = i / N, i2 = i % N;9293if( dABdA )94{95float* dcda = (float*)(dABdA->data.ptr + dABdA->step*i);96const float* b = (const float*)B->data.ptr + i2;9798for( j = 0; j < M*L; j++ )99dcda[j] = 0;100for( j = 0; j < L; j++ )101dcda[i1*L + j] = b[j*bstep];102}103104if( dABdB )105{106float* dcdb = (float*)(dABdB->data.ptr + dABdB->step*i);107const float* a = (const float*)(A->data.ptr + A->step*i1);108109for( j = 0; j < L*N; j++ )110dcdb[j] = 0;111for( j = 0; j < L; j++ )112dcdb[j*N + i2] = a[j];113}114}115}116else117{118for( i = 0; i < M*N; i++ )119{120int i1 = i / N, i2 = i % N;121122if( dABdA )123{124double* dcda = (double*)(dABdA->data.ptr + dABdA->step*i);125const double* b = (const double*)B->data.ptr + i2;126127for( j = 0; j < M*L; j++ )128dcda[j] = 0;129for( j = 0; j < L; j++ )130dcda[i1*L + j] = b[j*bstep];131}132133if( dABdB )134{135double* dcdb = (double*)(dABdB->data.ptr + dABdB->step*i);136const double* a = (const double*)(A->data.ptr + A->step*i1);137138for( j = 0; j < L*N; j++ )139dcdb[j] = 0;140for( j = 0; j < L; j++ )141dcdb[j*N + i2] = a[j];142}143}144}145}146147// reimplementation of compose_motion.m148CV_IMPL void cvComposeRT( const CvMat* _rvec1, const CvMat* _tvec1,149const CvMat* _rvec2, const CvMat* _tvec2,150CvMat* _rvec3, CvMat* _tvec3,151CvMat* dr3dr1, CvMat* dr3dt1,152CvMat* dr3dr2, CvMat* dr3dt2,153CvMat* dt3dr1, CvMat* dt3dt1,154CvMat* dt3dr2, CvMat* dt3dt2 )155{156double _r1[3], _r2[3];157double _R1[9], _d1[9*3], _R2[9], _d2[9*3];158CvMat r1 = cvMat(3,1,CV_64F,_r1), r2 = cvMat(3,1,CV_64F,_r2);159CvMat R1 = cvMat(3,3,CV_64F,_R1), R2 = cvMat(3,3,CV_64F,_R2);160CvMat dR1dr1 = cvMat(9,3,CV_64F,_d1), dR2dr2 = cvMat(9,3,CV_64F,_d2);161162CV_Assert( CV_IS_MAT(_rvec1) && CV_IS_MAT(_rvec2) );163164CV_Assert( CV_MAT_TYPE(_rvec1->type) == CV_32F ||165CV_MAT_TYPE(_rvec1->type) == CV_64F );166167CV_Assert( _rvec1->rows == 3 && _rvec1->cols == 1 && CV_ARE_SIZES_EQ(_rvec1, _rvec2) );168169cvConvert( _rvec1, &r1 );170cvConvert( _rvec2, &r2 );171172cvRodrigues2( &r1, &R1, &dR1dr1 );173cvRodrigues2( &r2, &R2, &dR2dr2 );174175if( _rvec3 || dr3dr1 || dr3dr2 )176{177double _r3[3], _R3[9], _dR3dR1[9*9], _dR3dR2[9*9], _dr3dR3[9*3];178double _W1[9*3], _W2[3*3];179CvMat r3 = cvMat(3,1,CV_64F,_r3), R3 = cvMat(3,3,CV_64F,_R3);180CvMat dR3dR1 = cvMat(9,9,CV_64F,_dR3dR1), dR3dR2 = cvMat(9,9,CV_64F,_dR3dR2);181CvMat dr3dR3 = cvMat(3,9,CV_64F,_dr3dR3);182CvMat W1 = cvMat(3,9,CV_64F,_W1), W2 = cvMat(3,3,CV_64F,_W2);183184cvMatMul( &R2, &R1, &R3 );185cvCalcMatMulDeriv( &R2, &R1, &dR3dR2, &dR3dR1 );186187cvRodrigues2( &R3, &r3, &dr3dR3 );188189if( _rvec3 )190cvConvert( &r3, _rvec3 );191192if( dr3dr1 )193{194cvMatMul( &dr3dR3, &dR3dR1, &W1 );195cvMatMul( &W1, &dR1dr1, &W2 );196cvConvert( &W2, dr3dr1 );197}198199if( dr3dr2 )200{201cvMatMul( &dr3dR3, &dR3dR2, &W1 );202cvMatMul( &W1, &dR2dr2, &W2 );203cvConvert( &W2, dr3dr2 );204}205}206207if( dr3dt1 )208cvZero( dr3dt1 );209if( dr3dt2 )210cvZero( dr3dt2 );211212if( _tvec3 || dt3dr2 || dt3dt1 )213{214double _t1[3], _t2[3], _t3[3], _dxdR2[3*9], _dxdt1[3*3], _W3[3*3];215CvMat t1 = cvMat(3,1,CV_64F,_t1), t2 = cvMat(3,1,CV_64F,_t2);216CvMat t3 = cvMat(3,1,CV_64F,_t3);217CvMat dxdR2 = cvMat(3, 9, CV_64F, _dxdR2);218CvMat dxdt1 = cvMat(3, 3, CV_64F, _dxdt1);219CvMat W3 = cvMat(3, 3, CV_64F, _W3);220221CV_Assert( CV_IS_MAT(_tvec1) && CV_IS_MAT(_tvec2) );222CV_Assert( CV_ARE_SIZES_EQ(_tvec1, _tvec2) && CV_ARE_SIZES_EQ(_tvec1, _rvec1) );223224cvConvert( _tvec1, &t1 );225cvConvert( _tvec2, &t2 );226cvMatMulAdd( &R2, &t1, &t2, &t3 );227228if( _tvec3 )229cvConvert( &t3, _tvec3 );230231if( dt3dr2 || dt3dt1 )232{233cvCalcMatMulDeriv( &R2, &t1, &dxdR2, &dxdt1 );234if( dt3dr2 )235{236cvMatMul( &dxdR2, &dR2dr2, &W3 );237cvConvert( &W3, dt3dr2 );238}239if( dt3dt1 )240cvConvert( &dxdt1, dt3dt1 );241}242}243244if( dt3dt2 )245cvSetIdentity( dt3dt2 );246if( dt3dr1 )247cvZero( dt3dr1 );248}249250CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )251{252int depth, elem_size;253int i, k;254double J[27] = {0};255CvMat matJ = cvMat( 3, 9, CV_64F, J );256257if( !CV_IS_MAT(src) )258CV_Error( !src ? CV_StsNullPtr : CV_StsBadArg, "Input argument is not a valid matrix" );259260if( !CV_IS_MAT(dst) )261CV_Error( !dst ? CV_StsNullPtr : CV_StsBadArg,262"The first output argument is not a valid matrix" );263264depth = CV_MAT_DEPTH(src->type);265elem_size = CV_ELEM_SIZE(depth);266267if( depth != CV_32F && depth != CV_64F )268CV_Error( CV_StsUnsupportedFormat, "The matrices must have 32f or 64f data type" );269270if( !CV_ARE_DEPTHS_EQ(src, dst) )271CV_Error( CV_StsUnmatchedFormats, "All the matrices must have the same data type" );272273if( jacobian )274{275if( !CV_IS_MAT(jacobian) )276CV_Error( CV_StsBadArg, "Jacobian is not a valid matrix" );277278if( !CV_ARE_DEPTHS_EQ(src, jacobian) || CV_MAT_CN(jacobian->type) != 1 )279CV_Error( CV_StsUnmatchedFormats, "Jacobian must have 32fC1 or 64fC1 datatype" );280281if( (jacobian->rows != 9 || jacobian->cols != 3) &&282(jacobian->rows != 3 || jacobian->cols != 9))283CV_Error( CV_StsBadSize, "Jacobian must be 3x9 or 9x3" );284}285286if( src->cols == 1 || src->rows == 1 )287{288int step = src->rows > 1 ? src->step / elem_size : 1;289290if( src->rows + src->cols*CV_MAT_CN(src->type) - 1 != 3 )291CV_Error( CV_StsBadSize, "Input matrix must be 1x3, 3x1 or 3x3" );292293if( dst->rows != 3 || dst->cols != 3 || CV_MAT_CN(dst->type) != 1 )294CV_Error( CV_StsBadSize, "Output matrix must be 3x3, single-channel floating point matrix" );295296Point3d r;297if( depth == CV_32F )298{299r.x = src->data.fl[0];300r.y = src->data.fl[step];301r.z = src->data.fl[step*2];302}303else304{305r.x = src->data.db[0];306r.y = src->data.db[step];307r.z = src->data.db[step*2];308}309310double theta = norm(r);311312if( theta < DBL_EPSILON )313{314cvSetIdentity( dst );315316if( jacobian )317{318memset( J, 0, sizeof(J) );319J[5] = J[15] = J[19] = -1;320J[7] = J[11] = J[21] = 1;321}322}323else324{325double c = cos(theta);326double s = sin(theta);327double c1 = 1. - c;328double itheta = theta ? 1./theta : 0.;329330r *= itheta;331332Matx33d rrt( r.x*r.x, r.x*r.y, r.x*r.z, r.x*r.y, r.y*r.y, r.y*r.z, r.x*r.z, r.y*r.z, r.z*r.z );333Matx33d r_x( 0, -r.z, r.y,334r.z, 0, -r.x,335-r.y, r.x, 0 );336337// R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x]338Matx33d R = c*Matx33d::eye() + c1*rrt + s*r_x;339340Mat(R).convertTo(cvarrToMat(dst), dst->type);341342if( jacobian )343{344const double I[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };345double drrt[] = { r.x+r.x, r.y, r.z, r.y, 0, 0, r.z, 0, 0,3460, r.x, 0, r.x, r.y+r.y, r.z, 0, r.z, 0,3470, 0, r.x, 0, 0, r.y, r.x, r.y, r.z+r.z };348double d_r_x_[] = { 0, 0, 0, 0, 0, -1, 0, 1, 0,3490, 0, 1, 0, 0, 0, -1, 0, 0,3500, -1, 0, 1, 0, 0, 0, 0, 0 };351for( i = 0; i < 3; i++ )352{353double ri = i == 0 ? r.x : i == 1 ? r.y : r.z;354double a0 = -s*ri, a1 = (s - 2*c1*itheta)*ri, a2 = c1*itheta;355double a3 = (c - s*itheta)*ri, a4 = s*itheta;356for( k = 0; k < 9; k++ )357J[i*9+k] = a0*I[k] + a1*rrt.val[k] + a2*drrt[i*9+k] +358a3*r_x.val[k] + a4*d_r_x_[i*9+k];359}360}361}362}363else if( src->cols == 3 && src->rows == 3 )364{365Matx33d U, Vt;366Vec3d W;367double theta, s, c;368int step = dst->rows > 1 ? dst->step / elem_size : 1;369370if( (dst->rows != 1 || dst->cols*CV_MAT_CN(dst->type) != 3) &&371(dst->rows != 3 || dst->cols != 1 || CV_MAT_CN(dst->type) != 1))372CV_Error( CV_StsBadSize, "Output matrix must be 1x3 or 3x1" );373374Matx33d R = cvarrToMat(src);375376if( !checkRange(R, true, NULL, -100, 100) )377{378cvZero(dst);379if( jacobian )380cvZero(jacobian);381return 0;382}383384SVD::compute(R, W, U, Vt);385R = U*Vt;386387Point3d r(R(2, 1) - R(1, 2), R(0, 2) - R(2, 0), R(1, 0) - R(0, 1));388389s = std::sqrt((r.x*r.x + r.y*r.y + r.z*r.z)*0.25);390c = (R(0, 0) + R(1, 1) + R(2, 2) - 1)*0.5;391c = c > 1. ? 1. : c < -1. ? -1. : c;392theta = acos(c);393394if( s < 1e-5 )395{396double t;397398if( c > 0 )399r = Point3d(0, 0, 0);400else401{402t = (R(0, 0) + 1)*0.5;403r.x = std::sqrt(MAX(t,0.));404t = (R(1, 1) + 1)*0.5;405r.y = std::sqrt(MAX(t,0.))*(R(0, 1) < 0 ? -1. : 1.);406t = (R(2, 2) + 1)*0.5;407r.z = std::sqrt(MAX(t,0.))*(R(0, 2) < 0 ? -1. : 1.);408if( fabs(r.x) < fabs(r.y) && fabs(r.x) < fabs(r.z) && (R(1, 2) > 0) != (r.y*r.z > 0) )409r.z = -r.z;410theta /= norm(r);411r *= theta;412}413414if( jacobian )415{416memset( J, 0, sizeof(J) );417if( c > 0 )418{419J[5] = J[15] = J[19] = -0.5;420J[7] = J[11] = J[21] = 0.5;421}422}423}424else425{426double vth = 1/(2*s);427428if( jacobian )429{430double t, dtheta_dtr = -1./s;431// var1 = [vth;theta]432// var = [om1;var1] = [om1;vth;theta]433double dvth_dtheta = -vth*c/s;434double d1 = 0.5*dvth_dtheta*dtheta_dtr;435double d2 = 0.5*dtheta_dtr;436// dvar1/dR = dvar1/dtheta*dtheta/dR = [dvth/dtheta; 1] * dtheta/dtr * dtr/dR437double dvardR[5*9] =438{4390, 0, 0, 0, 0, 1, 0, -1, 0,4400, 0, -1, 0, 0, 0, 1, 0, 0,4410, 1, 0, -1, 0, 0, 0, 0, 0,442d1, 0, 0, 0, d1, 0, 0, 0, d1,443d2, 0, 0, 0, d2, 0, 0, 0, d2444};445// var2 = [om;theta]446double dvar2dvar[] =447{448vth, 0, 0, r.x, 0,4490, vth, 0, r.y, 0,4500, 0, vth, r.z, 0,4510, 0, 0, 0, 1452};453double domegadvar2[] =454{455theta, 0, 0, r.x*vth,4560, theta, 0, r.y*vth,4570, 0, theta, r.z*vth458};459460CvMat _dvardR = cvMat( 5, 9, CV_64FC1, dvardR );461CvMat _dvar2dvar = cvMat( 4, 5, CV_64FC1, dvar2dvar );462CvMat _domegadvar2 = cvMat( 3, 4, CV_64FC1, domegadvar2 );463double t0[3*5];464CvMat _t0 = cvMat( 3, 5, CV_64FC1, t0 );465466cvMatMul( &_domegadvar2, &_dvar2dvar, &_t0 );467cvMatMul( &_t0, &_dvardR, &matJ );468469// transpose every row of matJ (treat the rows as 3x3 matrices)470CV_SWAP(J[1], J[3], t); CV_SWAP(J[2], J[6], t); CV_SWAP(J[5], J[7], t);471CV_SWAP(J[10], J[12], t); CV_SWAP(J[11], J[15], t); CV_SWAP(J[14], J[16], t);472CV_SWAP(J[19], J[21], t); CV_SWAP(J[20], J[24], t); CV_SWAP(J[23], J[25], t);473}474475vth *= theta;476r *= vth;477}478479if( depth == CV_32F )480{481dst->data.fl[0] = (float)r.x;482dst->data.fl[step] = (float)r.y;483dst->data.fl[step*2] = (float)r.z;484}485else486{487dst->data.db[0] = r.x;488dst->data.db[step] = r.y;489dst->data.db[step*2] = r.z;490}491}492493if( jacobian )494{495if( depth == CV_32F )496{497if( jacobian->rows == matJ.rows )498cvConvert( &matJ, jacobian );499else500{501float Jf[3*9];502CvMat _Jf = cvMat( matJ.rows, matJ.cols, CV_32FC1, Jf );503cvConvert( &matJ, &_Jf );504cvTranspose( &_Jf, jacobian );505}506}507else if( jacobian->rows == matJ.rows )508cvCopy( &matJ, jacobian );509else510cvTranspose( &matJ, jacobian );511}512513return 1;514}515516517static const char* cvDistCoeffErr = "Distortion coefficients must be 1x4, 4x1, 1x5, 5x1, 1x8, 8x1, 1x12, 12x1, 1x14 or 14x1 floating-point vector";518519static void cvProjectPoints2Internal( const CvMat* objectPoints,520const CvMat* r_vec,521const CvMat* t_vec,522const CvMat* A,523const CvMat* distCoeffs,524CvMat* imagePoints, CvMat* dpdr CV_DEFAULT(NULL),525CvMat* dpdt CV_DEFAULT(NULL), CvMat* dpdf CV_DEFAULT(NULL),526CvMat* dpdc CV_DEFAULT(NULL), CvMat* dpdk CV_DEFAULT(NULL),527CvMat* dpdo CV_DEFAULT(NULL),528double aspectRatio CV_DEFAULT(0) )529{530Ptr<CvMat> matM, _m;531Ptr<CvMat> _dpdr, _dpdt, _dpdc, _dpdf, _dpdk;532Ptr<CvMat> _dpdo;533534int i, j, count;535int calc_derivatives;536const CvPoint3D64f* M;537CvPoint2D64f* m;538double r[3], R[9], dRdr[27], t[3], a[9], k[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, fx, fy, cx, cy;539Matx33d matTilt = Matx33d::eye();540Matx33d dMatTiltdTauX(0,0,0,0,0,0,0,-1,0);541Matx33d dMatTiltdTauY(0,0,0,0,0,0,1,0,0);542CvMat _r, _t, _a = cvMat( 3, 3, CV_64F, a ), _k;543CvMat matR = cvMat( 3, 3, CV_64F, R ), _dRdr = cvMat( 3, 9, CV_64F, dRdr );544double *dpdr_p = 0, *dpdt_p = 0, *dpdk_p = 0, *dpdf_p = 0, *dpdc_p = 0;545double* dpdo_p = 0;546int dpdr_step = 0, dpdt_step = 0, dpdk_step = 0, dpdf_step = 0, dpdc_step = 0;547int dpdo_step = 0;548bool fixedAspectRatio = aspectRatio > FLT_EPSILON;549550if( !CV_IS_MAT(objectPoints) || !CV_IS_MAT(r_vec) ||551!CV_IS_MAT(t_vec) || !CV_IS_MAT(A) ||552/*!CV_IS_MAT(distCoeffs) ||*/ !CV_IS_MAT(imagePoints) )553CV_Error( CV_StsBadArg, "One of required arguments is not a valid matrix" );554555int total = objectPoints->rows * objectPoints->cols * CV_MAT_CN(objectPoints->type);556if(total % 3 != 0)557{558//we have stopped support of homogeneous coordinates because it cause ambiguity in interpretation of the input data559CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );560}561count = total / 3;562563if( CV_IS_CONT_MAT(objectPoints->type) &&564(CV_MAT_DEPTH(objectPoints->type) == CV_32F || CV_MAT_DEPTH(objectPoints->type) == CV_64F)&&565((objectPoints->rows == 1 && CV_MAT_CN(objectPoints->type) == 3) ||566(objectPoints->rows == count && CV_MAT_CN(objectPoints->type)*objectPoints->cols == 3) ||567(objectPoints->rows == 3 && CV_MAT_CN(objectPoints->type) == 1 && objectPoints->cols == count)))568{569matM.reset(cvCreateMat( objectPoints->rows, objectPoints->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(objectPoints->type)) ));570cvConvert(objectPoints, matM);571}572else573{574// matM = cvCreateMat( 1, count, CV_64FC3 );575// cvConvertPointsHomogeneous( objectPoints, matM );576CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );577}578579if( CV_IS_CONT_MAT(imagePoints->type) &&580(CV_MAT_DEPTH(imagePoints->type) == CV_32F || CV_MAT_DEPTH(imagePoints->type) == CV_64F) &&581((imagePoints->rows == 1 && CV_MAT_CN(imagePoints->type) == 2) ||582(imagePoints->rows == count && CV_MAT_CN(imagePoints->type)*imagePoints->cols == 2) ||583(imagePoints->rows == 2 && CV_MAT_CN(imagePoints->type) == 1 && imagePoints->cols == count)))584{585_m.reset(cvCreateMat( imagePoints->rows, imagePoints->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(imagePoints->type)) ));586cvConvert(imagePoints, _m);587}588else589{590// _m = cvCreateMat( 1, count, CV_64FC2 );591CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );592}593594M = (CvPoint3D64f*)matM->data.db;595m = (CvPoint2D64f*)_m->data.db;596597if( (CV_MAT_DEPTH(r_vec->type) != CV_64F && CV_MAT_DEPTH(r_vec->type) != CV_32F) ||598(((r_vec->rows != 1 && r_vec->cols != 1) ||599r_vec->rows*r_vec->cols*CV_MAT_CN(r_vec->type) != 3) &&600((r_vec->rows != 3 && r_vec->cols != 3) || CV_MAT_CN(r_vec->type) != 1)))601CV_Error( CV_StsBadArg, "Rotation must be represented by 1x3 or 3x1 "602"floating-point rotation vector, or 3x3 rotation matrix" );603604if( r_vec->rows == 3 && r_vec->cols == 3 )605{606_r = cvMat( 3, 1, CV_64FC1, r );607cvRodrigues2( r_vec, &_r );608cvRodrigues2( &_r, &matR, &_dRdr );609cvCopy( r_vec, &matR );610}611else612{613_r = cvMat( r_vec->rows, r_vec->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(r_vec->type)), r );614cvConvert( r_vec, &_r );615cvRodrigues2( &_r, &matR, &_dRdr );616}617618if( (CV_MAT_DEPTH(t_vec->type) != CV_64F && CV_MAT_DEPTH(t_vec->type) != CV_32F) ||619(t_vec->rows != 1 && t_vec->cols != 1) ||620t_vec->rows*t_vec->cols*CV_MAT_CN(t_vec->type) != 3 )621CV_Error( CV_StsBadArg,622"Translation vector must be 1x3 or 3x1 floating-point vector" );623624_t = cvMat( t_vec->rows, t_vec->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(t_vec->type)), t );625cvConvert( t_vec, &_t );626627if( (CV_MAT_TYPE(A->type) != CV_64FC1 && CV_MAT_TYPE(A->type) != CV_32FC1) ||628A->rows != 3 || A->cols != 3 )629CV_Error( CV_StsBadArg, "Instrinsic parameters must be 3x3 floating-point matrix" );630631cvConvert( A, &_a );632fx = a[0]; fy = a[4];633cx = a[2]; cy = a[5];634635if( fixedAspectRatio )636fx = fy*aspectRatio;637638if( distCoeffs )639{640if( !CV_IS_MAT(distCoeffs) ||641(CV_MAT_DEPTH(distCoeffs->type) != CV_64F &&642CV_MAT_DEPTH(distCoeffs->type) != CV_32F) ||643(distCoeffs->rows != 1 && distCoeffs->cols != 1) ||644(distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 4 &&645distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 5 &&646distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 8 &&647distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 12 &&648distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 14) )649CV_Error( CV_StsBadArg, cvDistCoeffErr );650651_k = cvMat( distCoeffs->rows, distCoeffs->cols,652CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), k );653cvConvert( distCoeffs, &_k );654if(k[12] != 0 || k[13] != 0)655{656detail::computeTiltProjectionMatrix(k[12], k[13],657&matTilt, &dMatTiltdTauX, &dMatTiltdTauY);658}659}660661if( dpdr )662{663if( !CV_IS_MAT(dpdr) ||664(CV_MAT_TYPE(dpdr->type) != CV_32FC1 &&665CV_MAT_TYPE(dpdr->type) != CV_64FC1) ||666dpdr->rows != count*2 || dpdr->cols != 3 )667CV_Error( CV_StsBadArg, "dp/drot must be 2Nx3 floating-point matrix" );668669if( CV_MAT_TYPE(dpdr->type) == CV_64FC1 )670{671_dpdr.reset(cvCloneMat(dpdr));672}673else674_dpdr.reset(cvCreateMat( 2*count, 3, CV_64FC1 ));675dpdr_p = _dpdr->data.db;676dpdr_step = _dpdr->step/sizeof(dpdr_p[0]);677}678679if( dpdt )680{681if( !CV_IS_MAT(dpdt) ||682(CV_MAT_TYPE(dpdt->type) != CV_32FC1 &&683CV_MAT_TYPE(dpdt->type) != CV_64FC1) ||684dpdt->rows != count*2 || dpdt->cols != 3 )685CV_Error( CV_StsBadArg, "dp/dT must be 2Nx3 floating-point matrix" );686687if( CV_MAT_TYPE(dpdt->type) == CV_64FC1 )688{689_dpdt.reset(cvCloneMat(dpdt));690}691else692_dpdt.reset(cvCreateMat( 2*count, 3, CV_64FC1 ));693dpdt_p = _dpdt->data.db;694dpdt_step = _dpdt->step/sizeof(dpdt_p[0]);695}696697if( dpdf )698{699if( !CV_IS_MAT(dpdf) ||700(CV_MAT_TYPE(dpdf->type) != CV_32FC1 && CV_MAT_TYPE(dpdf->type) != CV_64FC1) ||701dpdf->rows != count*2 || dpdf->cols != 2 )702CV_Error( CV_StsBadArg, "dp/df must be 2Nx2 floating-point matrix" );703704if( CV_MAT_TYPE(dpdf->type) == CV_64FC1 )705{706_dpdf.reset(cvCloneMat(dpdf));707}708else709_dpdf.reset(cvCreateMat( 2*count, 2, CV_64FC1 ));710dpdf_p = _dpdf->data.db;711dpdf_step = _dpdf->step/sizeof(dpdf_p[0]);712}713714if( dpdc )715{716if( !CV_IS_MAT(dpdc) ||717(CV_MAT_TYPE(dpdc->type) != CV_32FC1 && CV_MAT_TYPE(dpdc->type) != CV_64FC1) ||718dpdc->rows != count*2 || dpdc->cols != 2 )719CV_Error( CV_StsBadArg, "dp/dc must be 2Nx2 floating-point matrix" );720721if( CV_MAT_TYPE(dpdc->type) == CV_64FC1 )722{723_dpdc.reset(cvCloneMat(dpdc));724}725else726_dpdc.reset(cvCreateMat( 2*count, 2, CV_64FC1 ));727dpdc_p = _dpdc->data.db;728dpdc_step = _dpdc->step/sizeof(dpdc_p[0]);729}730731if( dpdk )732{733if( !CV_IS_MAT(dpdk) ||734(CV_MAT_TYPE(dpdk->type) != CV_32FC1 && CV_MAT_TYPE(dpdk->type) != CV_64FC1) ||735dpdk->rows != count*2 || (dpdk->cols != 14 && dpdk->cols != 12 && dpdk->cols != 8 && dpdk->cols != 5 && dpdk->cols != 4 && dpdk->cols != 2) )736CV_Error( CV_StsBadArg, "dp/df must be 2Nx14, 2Nx12, 2Nx8, 2Nx5, 2Nx4 or 2Nx2 floating-point matrix" );737738if( !distCoeffs )739CV_Error( CV_StsNullPtr, "distCoeffs is NULL while dpdk is not" );740741if( CV_MAT_TYPE(dpdk->type) == CV_64FC1 )742{743_dpdk.reset(cvCloneMat(dpdk));744}745else746_dpdk.reset(cvCreateMat( dpdk->rows, dpdk->cols, CV_64FC1 ));747dpdk_p = _dpdk->data.db;748dpdk_step = _dpdk->step/sizeof(dpdk_p[0]);749}750751if( dpdo )752{753if( !CV_IS_MAT( dpdo ) || ( CV_MAT_TYPE( dpdo->type ) != CV_32FC1754&& CV_MAT_TYPE( dpdo->type ) != CV_64FC1 )755|| dpdo->rows != count * 2 || dpdo->cols != count * 3 )756CV_Error( CV_StsBadArg, "dp/do must be 2Nx3N floating-point matrix" );757758if( CV_MAT_TYPE( dpdo->type ) == CV_64FC1 )759{760_dpdo.reset( cvCloneMat( dpdo ) );761}762else763_dpdo.reset( cvCreateMat( 2 * count, 3 * count, CV_64FC1 ) );764cvZero(_dpdo);765dpdo_p = _dpdo->data.db;766dpdo_step = _dpdo->step / sizeof( dpdo_p[0] );767}768769calc_derivatives = dpdr || dpdt || dpdf || dpdc || dpdk || dpdo;770771for( i = 0; i < count; i++ )772{773double X = M[i].x, Y = M[i].y, Z = M[i].z;774double x = R[0]*X + R[1]*Y + R[2]*Z + t[0];775double y = R[3]*X + R[4]*Y + R[5]*Z + t[1];776double z = R[6]*X + R[7]*Y + R[8]*Z + t[2];777double r2, r4, r6, a1, a2, a3, cdist, icdist2;778double xd, yd, xd0, yd0, invProj;779Vec3d vecTilt;780Vec3d dVecTilt;781Matx22d dMatTilt;782Vec2d dXdYd;783784double z0 = z;785z = z ? 1./z : 1;786x *= z; y *= z;787788r2 = x*x + y*y;789r4 = r2*r2;790r6 = r4*r2;791a1 = 2*x*y;792a2 = r2 + 2*x*x;793a3 = r2 + 2*y*y;794cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6;795icdist2 = 1./(1 + k[5]*r2 + k[6]*r4 + k[7]*r6);796xd0 = x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4;797yd0 = y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4;798799// additional distortion by projecting onto a tilt plane800vecTilt = matTilt*Vec3d(xd0, yd0, 1);801invProj = vecTilt(2) ? 1./vecTilt(2) : 1;802xd = invProj * vecTilt(0);803yd = invProj * vecTilt(1);804805m[i].x = xd*fx + cx;806m[i].y = yd*fy + cy;807808if( calc_derivatives )809{810if( dpdc_p )811{812dpdc_p[0] = 1; dpdc_p[1] = 0; // dp_xdc_x; dp_xdc_y813dpdc_p[dpdc_step] = 0;814dpdc_p[dpdc_step+1] = 1;815dpdc_p += dpdc_step*2;816}817818if( dpdf_p )819{820if( fixedAspectRatio )821{822dpdf_p[0] = 0; dpdf_p[1] = xd*aspectRatio; // dp_xdf_x; dp_xdf_y823dpdf_p[dpdf_step] = 0;824dpdf_p[dpdf_step+1] = yd;825}826else827{828dpdf_p[0] = xd; dpdf_p[1] = 0;829dpdf_p[dpdf_step] = 0;830dpdf_p[dpdf_step+1] = yd;831}832dpdf_p += dpdf_step*2;833}834for (int row = 0; row < 2; ++row)835for (int col = 0; col < 2; ++col)836dMatTilt(row,col) = matTilt(row,col)*vecTilt(2)837- matTilt(2,col)*vecTilt(row);838double invProjSquare = (invProj*invProj);839dMatTilt *= invProjSquare;840if( dpdk_p )841{842dXdYd = dMatTilt*Vec2d(x*icdist2*r2, y*icdist2*r2);843dpdk_p[0] = fx*dXdYd(0);844dpdk_p[dpdk_step] = fy*dXdYd(1);845dXdYd = dMatTilt*Vec2d(x*icdist2*r4, y*icdist2*r4);846dpdk_p[1] = fx*dXdYd(0);847dpdk_p[dpdk_step+1] = fy*dXdYd(1);848if( _dpdk->cols > 2 )849{850dXdYd = dMatTilt*Vec2d(a1, a3);851dpdk_p[2] = fx*dXdYd(0);852dpdk_p[dpdk_step+2] = fy*dXdYd(1);853dXdYd = dMatTilt*Vec2d(a2, a1);854dpdk_p[3] = fx*dXdYd(0);855dpdk_p[dpdk_step+3] = fy*dXdYd(1);856if( _dpdk->cols > 4 )857{858dXdYd = dMatTilt*Vec2d(x*icdist2*r6, y*icdist2*r6);859dpdk_p[4] = fx*dXdYd(0);860dpdk_p[dpdk_step+4] = fy*dXdYd(1);861862if( _dpdk->cols > 5 )863{864dXdYd = dMatTilt*Vec2d(865x*cdist*(-icdist2)*icdist2*r2, y*cdist*(-icdist2)*icdist2*r2);866dpdk_p[5] = fx*dXdYd(0);867dpdk_p[dpdk_step+5] = fy*dXdYd(1);868dXdYd = dMatTilt*Vec2d(869x*cdist*(-icdist2)*icdist2*r4, y*cdist*(-icdist2)*icdist2*r4);870dpdk_p[6] = fx*dXdYd(0);871dpdk_p[dpdk_step+6] = fy*dXdYd(1);872dXdYd = dMatTilt*Vec2d(873x*cdist*(-icdist2)*icdist2*r6, y*cdist*(-icdist2)*icdist2*r6);874dpdk_p[7] = fx*dXdYd(0);875dpdk_p[dpdk_step+7] = fy*dXdYd(1);876if( _dpdk->cols > 8 )877{878dXdYd = dMatTilt*Vec2d(r2, 0);879dpdk_p[8] = fx*dXdYd(0); //s1880dpdk_p[dpdk_step+8] = fy*dXdYd(1); //s1881dXdYd = dMatTilt*Vec2d(r4, 0);882dpdk_p[9] = fx*dXdYd(0); //s2883dpdk_p[dpdk_step+9] = fy*dXdYd(1); //s2884dXdYd = dMatTilt*Vec2d(0, r2);885dpdk_p[10] = fx*dXdYd(0);//s3886dpdk_p[dpdk_step+10] = fy*dXdYd(1); //s3887dXdYd = dMatTilt*Vec2d(0, r4);888dpdk_p[11] = fx*dXdYd(0);//s4889dpdk_p[dpdk_step+11] = fy*dXdYd(1); //s4890if( _dpdk->cols > 12 )891{892dVecTilt = dMatTiltdTauX * Vec3d(xd0, yd0, 1);893dpdk_p[12] = fx * invProjSquare * (894dVecTilt(0) * vecTilt(2) - dVecTilt(2) * vecTilt(0));895dpdk_p[dpdk_step+12] = fy*invProjSquare * (896dVecTilt(1) * vecTilt(2) - dVecTilt(2) * vecTilt(1));897dVecTilt = dMatTiltdTauY * Vec3d(xd0, yd0, 1);898dpdk_p[13] = fx * invProjSquare * (899dVecTilt(0) * vecTilt(2) - dVecTilt(2) * vecTilt(0));900dpdk_p[dpdk_step+13] = fy * invProjSquare * (901dVecTilt(1) * vecTilt(2) - dVecTilt(2) * vecTilt(1));902}903}904}905}906}907dpdk_p += dpdk_step*2;908}909910if( dpdt_p )911{912double dxdt[] = { z, 0, -x*z }, dydt[] = { 0, z, -y*z };913for( j = 0; j < 3; j++ )914{915double dr2dt = 2*x*dxdt[j] + 2*y*dydt[j];916double dcdist_dt = k[0]*dr2dt + 2*k[1]*r2*dr2dt + 3*k[4]*r4*dr2dt;917double dicdist2_dt = -icdist2*icdist2*(k[5]*dr2dt + 2*k[6]*r2*dr2dt + 3*k[7]*r4*dr2dt);918double da1dt = 2*(x*dydt[j] + y*dxdt[j]);919double dmxdt = (dxdt[j]*cdist*icdist2 + x*dcdist_dt*icdist2 + x*cdist*dicdist2_dt +920k[2]*da1dt + k[3]*(dr2dt + 4*x*dxdt[j]) + k[8]*dr2dt + 2*r2*k[9]*dr2dt);921double dmydt = (dydt[j]*cdist*icdist2 + y*dcdist_dt*icdist2 + y*cdist*dicdist2_dt +922k[2]*(dr2dt + 4*y*dydt[j]) + k[3]*da1dt + k[10]*dr2dt + 2*r2*k[11]*dr2dt);923dXdYd = dMatTilt*Vec2d(dmxdt, dmydt);924dpdt_p[j] = fx*dXdYd(0);925dpdt_p[dpdt_step+j] = fy*dXdYd(1);926}927dpdt_p += dpdt_step*2;928}929930if( dpdr_p )931{932double dx0dr[] =933{934X*dRdr[0] + Y*dRdr[1] + Z*dRdr[2],935X*dRdr[9] + Y*dRdr[10] + Z*dRdr[11],936X*dRdr[18] + Y*dRdr[19] + Z*dRdr[20]937};938double dy0dr[] =939{940X*dRdr[3] + Y*dRdr[4] + Z*dRdr[5],941X*dRdr[12] + Y*dRdr[13] + Z*dRdr[14],942X*dRdr[21] + Y*dRdr[22] + Z*dRdr[23]943};944double dz0dr[] =945{946X*dRdr[6] + Y*dRdr[7] + Z*dRdr[8],947X*dRdr[15] + Y*dRdr[16] + Z*dRdr[17],948X*dRdr[24] + Y*dRdr[25] + Z*dRdr[26]949};950for( j = 0; j < 3; j++ )951{952double dxdr = z*(dx0dr[j] - x*dz0dr[j]);953double dydr = z*(dy0dr[j] - y*dz0dr[j]);954double dr2dr = 2*x*dxdr + 2*y*dydr;955double dcdist_dr = (k[0] + 2*k[1]*r2 + 3*k[4]*r4)*dr2dr;956double dicdist2_dr = -icdist2*icdist2*(k[5] + 2*k[6]*r2 + 3*k[7]*r4)*dr2dr;957double da1dr = 2*(x*dydr + y*dxdr);958double dmxdr = (dxdr*cdist*icdist2 + x*dcdist_dr*icdist2 + x*cdist*dicdist2_dr +959k[2]*da1dr + k[3]*(dr2dr + 4*x*dxdr) + (k[8] + 2*r2*k[9])*dr2dr);960double dmydr = (dydr*cdist*icdist2 + y*dcdist_dr*icdist2 + y*cdist*dicdist2_dr +961k[2]*(dr2dr + 4*y*dydr) + k[3]*da1dr + (k[10] + 2*r2*k[11])*dr2dr);962dXdYd = dMatTilt*Vec2d(dmxdr, dmydr);963dpdr_p[j] = fx*dXdYd(0);964dpdr_p[dpdr_step+j] = fy*dXdYd(1);965}966dpdr_p += dpdr_step*2;967}968969if( dpdo_p )970{971double dxdo[] = { z * ( R[0] - x * z * z0 * R[6] ),972z * ( R[1] - x * z * z0 * R[7] ),973z * ( R[2] - x * z * z0 * R[8] ) };974double dydo[] = { z * ( R[3] - y * z * z0 * R[6] ),975z * ( R[4] - y * z * z0 * R[7] ),976z * ( R[5] - y * z * z0 * R[8] ) };977for( j = 0; j < 3; j++ )978{979double dr2do = 2 * x * dxdo[j] + 2 * y * dydo[j];980double dr4do = 2 * r2 * dr2do;981double dr6do = 3 * r4 * dr2do;982double da1do = 2 * y * dxdo[j] + 2 * x * dydo[j];983double da2do = dr2do + 4 * x * dxdo[j];984double da3do = dr2do + 4 * y * dydo[j];985double dcdist_do986= k[0] * dr2do + k[1] * dr4do + k[4] * dr6do;987double dicdist2_do = -icdist2 * icdist2988* ( k[5] * dr2do + k[6] * dr4do + k[7] * dr6do );989double dxd0_do = cdist * icdist2 * dxdo[j]990+ x * icdist2 * dcdist_do + x * cdist * dicdist2_do991+ k[2] * da1do + k[3] * da2do + k[8] * dr2do992+ k[9] * dr4do;993double dyd0_do = cdist * icdist2 * dydo[j]994+ y * icdist2 * dcdist_do + y * cdist * dicdist2_do995+ k[2] * da3do + k[3] * da1do + k[10] * dr2do996+ k[11] * dr4do;997dXdYd = dMatTilt * Vec2d( dxd0_do, dyd0_do );998dpdo_p[i * 3 + j] = fx * dXdYd( 0 );999dpdo_p[dpdo_step + i * 3 + j] = fy * dXdYd( 1 );1000}1001dpdo_p += dpdo_step * 2;1002}1003}1004}10051006if( _m != imagePoints )1007cvConvert( _m, imagePoints );10081009if( _dpdr != dpdr )1010cvConvert( _dpdr, dpdr );10111012if( _dpdt != dpdt )1013cvConvert( _dpdt, dpdt );10141015if( _dpdf != dpdf )1016cvConvert( _dpdf, dpdf );10171018if( _dpdc != dpdc )1019cvConvert( _dpdc, dpdc );10201021if( _dpdk != dpdk )1022cvConvert( _dpdk, dpdk );10231024if( _dpdo != dpdo )1025cvConvert( _dpdo, dpdo );1026}10271028CV_IMPL void cvProjectPoints2( const CvMat* objectPoints,1029const CvMat* r_vec,1030const CvMat* t_vec,1031const CvMat* A,1032const CvMat* distCoeffs,1033CvMat* imagePoints, CvMat* dpdr,1034CvMat* dpdt, CvMat* dpdf,1035CvMat* dpdc, CvMat* dpdk,1036double aspectRatio )1037{1038cvProjectPoints2Internal( objectPoints, r_vec, t_vec, A, distCoeffs, imagePoints, dpdr, dpdt,1039dpdf, dpdc, dpdk, NULL, aspectRatio );1040}10411042CV_IMPL void cvFindExtrinsicCameraParams2( const CvMat* objectPoints,1043const CvMat* imagePoints, const CvMat* A,1044const CvMat* distCoeffs, CvMat* rvec, CvMat* tvec,1045int useExtrinsicGuess )1046{1047const int max_iter = 20;1048Ptr<CvMat> matM, _Mxy, _m, _mn, matL;10491050int i, count;1051double a[9], ar[9]={1,0,0,0,1,0,0,0,1}, R[9];1052double MM[9], U[9], V[9], W[3];1053cv::Scalar Mc;1054double param[6];1055CvMat matA = cvMat( 3, 3, CV_64F, a );1056CvMat _Ar = cvMat( 3, 3, CV_64F, ar );1057CvMat matR = cvMat( 3, 3, CV_64F, R );1058CvMat _r = cvMat( 3, 1, CV_64F, param );1059CvMat _t = cvMat( 3, 1, CV_64F, param + 3 );1060CvMat _Mc = cvMat( 1, 3, CV_64F, Mc.val );1061CvMat _MM = cvMat( 3, 3, CV_64F, MM );1062CvMat matU = cvMat( 3, 3, CV_64F, U );1063CvMat matV = cvMat( 3, 3, CV_64F, V );1064CvMat matW = cvMat( 3, 1, CV_64F, W );1065CvMat _param = cvMat( 6, 1, CV_64F, param );1066CvMat _dpdr, _dpdt;10671068CV_Assert( CV_IS_MAT(objectPoints) && CV_IS_MAT(imagePoints) &&1069CV_IS_MAT(A) && CV_IS_MAT(rvec) && CV_IS_MAT(tvec) );10701071count = MAX(objectPoints->cols, objectPoints->rows);1072matM.reset(cvCreateMat( 1, count, CV_64FC3 ));1073_m.reset(cvCreateMat( 1, count, CV_64FC2 ));10741075cvConvertPointsHomogeneous( objectPoints, matM );1076cvConvertPointsHomogeneous( imagePoints, _m );1077cvConvert( A, &matA );10781079CV_Assert( (CV_MAT_DEPTH(rvec->type) == CV_64F || CV_MAT_DEPTH(rvec->type) == CV_32F) &&1080(rvec->rows == 1 || rvec->cols == 1) && rvec->rows*rvec->cols*CV_MAT_CN(rvec->type) == 3 );10811082CV_Assert( (CV_MAT_DEPTH(tvec->type) == CV_64F || CV_MAT_DEPTH(tvec->type) == CV_32F) &&1083(tvec->rows == 1 || tvec->cols == 1) && tvec->rows*tvec->cols*CV_MAT_CN(tvec->type) == 3 );10841085CV_Assert((count >= 4) || (count == 3 && useExtrinsicGuess)); // it is unsafe to call LM optimisation without an extrinsic guess in the case of 3 points. This is because there is no guarantee that it will converge on the correct solution.10861087_mn.reset(cvCreateMat( 1, count, CV_64FC2 ));1088_Mxy.reset(cvCreateMat( 1, count, CV_64FC2 ));10891090// normalize image points1091// (unapply the intrinsic matrix transformation and distortion)1092cvUndistortPoints( _m, _mn, &matA, distCoeffs, 0, &_Ar );10931094if( useExtrinsicGuess )1095{1096CvMat _r_temp = cvMat(rvec->rows, rvec->cols,1097CV_MAKETYPE(CV_64F,CV_MAT_CN(rvec->type)), param );1098CvMat _t_temp = cvMat(tvec->rows, tvec->cols,1099CV_MAKETYPE(CV_64F,CV_MAT_CN(tvec->type)), param + 3);1100cvConvert( rvec, &_r_temp );1101cvConvert( tvec, &_t_temp );1102}1103else1104{1105Mc = cvAvg(matM);1106cvReshape( matM, matM, 1, count );1107cvMulTransposed( matM, &_MM, 1, &_Mc );1108cvSVD( &_MM, &matW, 0, &matV, CV_SVD_MODIFY_A + CV_SVD_V_T );11091110// initialize extrinsic parameters1111if( W[2]/W[1] < 1e-3)1112{1113// a planar structure case (all M's lie in the same plane)1114double tt[3], h[9], h1_norm, h2_norm;1115CvMat* R_transform = &matV;1116CvMat T_transform = cvMat( 3, 1, CV_64F, tt );1117CvMat matH = cvMat( 3, 3, CV_64F, h );1118CvMat _h1, _h2, _h3;11191120if( V[2]*V[2] + V[5]*V[5] < 1e-10 )1121cvSetIdentity( R_transform );11221123if( cvDet(R_transform) < 0 )1124cvScale( R_transform, R_transform, -1 );11251126cvGEMM( R_transform, &_Mc, -1, 0, 0, &T_transform, CV_GEMM_B_T );11271128for( i = 0; i < count; i++ )1129{1130const double* Rp = R_transform->data.db;1131const double* Tp = T_transform.data.db;1132const double* src = matM->data.db + i*3;1133double* dst = _Mxy->data.db + i*2;11341135dst[0] = Rp[0]*src[0] + Rp[1]*src[1] + Rp[2]*src[2] + Tp[0];1136dst[1] = Rp[3]*src[0] + Rp[4]*src[1] + Rp[5]*src[2] + Tp[1];1137}11381139cvFindHomography( _Mxy, _mn, &matH );11401141if( cvCheckArr(&matH, CV_CHECK_QUIET) )1142{1143cvGetCol( &matH, &_h1, 0 );1144_h2 = _h1; _h2.data.db++;1145_h3 = _h2; _h3.data.db++;1146h1_norm = std::sqrt(h[0]*h[0] + h[3]*h[3] + h[6]*h[6]);1147h2_norm = std::sqrt(h[1]*h[1] + h[4]*h[4] + h[7]*h[7]);11481149cvScale( &_h1, &_h1, 1./MAX(h1_norm, DBL_EPSILON) );1150cvScale( &_h2, &_h2, 1./MAX(h2_norm, DBL_EPSILON) );1151cvScale( &_h3, &_t, 2./MAX(h1_norm + h2_norm, DBL_EPSILON));1152cvCrossProduct( &_h1, &_h2, &_h3 );11531154cvRodrigues2( &matH, &_r );1155cvRodrigues2( &_r, &matH );1156cvMatMulAdd( &matH, &T_transform, &_t, &_t );1157cvMatMul( &matH, R_transform, &matR );1158}1159else1160{1161cvSetIdentity( &matR );1162cvZero( &_t );1163}11641165cvRodrigues2( &matR, &_r );1166}1167else1168{1169// non-planar structure. Use DLT method1170double* L;1171double LL[12*12], LW[12], LV[12*12], sc;1172CvMat _LL = cvMat( 12, 12, CV_64F, LL );1173CvMat _LW = cvMat( 12, 1, CV_64F, LW );1174CvMat _LV = cvMat( 12, 12, CV_64F, LV );1175CvMat _RRt, _RR, _tt;1176CvPoint3D64f* M = (CvPoint3D64f*)matM->data.db;1177CvPoint2D64f* mn = (CvPoint2D64f*)_mn->data.db;11781179matL.reset(cvCreateMat( 2*count, 12, CV_64F ));1180L = matL->data.db;11811182for( i = 0; i < count; i++, L += 24 )1183{1184double x = -mn[i].x, y = -mn[i].y;1185L[0] = L[16] = M[i].x;1186L[1] = L[17] = M[i].y;1187L[2] = L[18] = M[i].z;1188L[3] = L[19] = 1.;1189L[4] = L[5] = L[6] = L[7] = 0.;1190L[12] = L[13] = L[14] = L[15] = 0.;1191L[8] = x*M[i].x;1192L[9] = x*M[i].y;1193L[10] = x*M[i].z;1194L[11] = x;1195L[20] = y*M[i].x;1196L[21] = y*M[i].y;1197L[22] = y*M[i].z;1198L[23] = y;1199}12001201cvMulTransposed( matL, &_LL, 1 );1202cvSVD( &_LL, &_LW, 0, &_LV, CV_SVD_MODIFY_A + CV_SVD_V_T );1203_RRt = cvMat( 3, 4, CV_64F, LV + 11*12 );1204cvGetCols( &_RRt, &_RR, 0, 3 );1205cvGetCol( &_RRt, &_tt, 3 );1206if( cvDet(&_RR) < 0 )1207cvScale( &_RRt, &_RRt, -1 );1208sc = cvNorm(&_RR);1209CV_Assert(fabs(sc) > DBL_EPSILON);1210cvSVD( &_RR, &matW, &matU, &matV, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );1211cvGEMM( &matU, &matV, 1, 0, 0, &matR, CV_GEMM_A_T );1212cvScale( &_tt, &_t, cvNorm(&matR)/sc );1213cvRodrigues2( &matR, &_r );1214}1215}12161217cvReshape( matM, matM, 3, 1 );1218cvReshape( _mn, _mn, 2, 1 );12191220// refine extrinsic parameters using iterative algorithm1221CvLevMarq solver( 6, count*2, cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,max_iter,FLT_EPSILON), true);1222cvCopy( &_param, solver.param );12231224for(;;)1225{1226CvMat *matJ = 0, *_err = 0;1227const CvMat *__param = 0;1228bool proceed = solver.update( __param, matJ, _err );1229cvCopy( __param, &_param );1230if( !proceed || !_err )1231break;1232cvReshape( _err, _err, 2, 1 );1233if( matJ )1234{1235cvGetCols( matJ, &_dpdr, 0, 3 );1236cvGetCols( matJ, &_dpdt, 3, 6 );1237cvProjectPoints2( matM, &_r, &_t, &matA, distCoeffs,1238_err, &_dpdr, &_dpdt, 0, 0, 0 );1239}1240else1241{1242cvProjectPoints2( matM, &_r, &_t, &matA, distCoeffs,1243_err, 0, 0, 0, 0, 0 );1244}1245cvSub(_err, _m, _err);1246cvReshape( _err, _err, 1, 2*count );1247}1248cvCopy( solver.param, &_param );12491250_r = cvMat( rvec->rows, rvec->cols,1251CV_MAKETYPE(CV_64F,CV_MAT_CN(rvec->type)), param );1252_t = cvMat( tvec->rows, tvec->cols,1253CV_MAKETYPE(CV_64F,CV_MAT_CN(tvec->type)), param + 3 );12541255cvConvert( &_r, rvec );1256cvConvert( &_t, tvec );1257}12581259CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints,1260const CvMat* imagePoints, const CvMat* npoints,1261CvSize imageSize, CvMat* cameraMatrix,1262double aspectRatio )1263{1264Ptr<CvMat> matA, _b, _allH;12651266int i, j, pos, nimages, ni = 0;1267double a[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 1 };1268double H[9] = {0}, f[2] = {0};1269CvMat _a = cvMat( 3, 3, CV_64F, a );1270CvMat matH = cvMat( 3, 3, CV_64F, H );1271CvMat _f = cvMat( 2, 1, CV_64F, f );12721273assert( CV_MAT_TYPE(npoints->type) == CV_32SC1 &&1274CV_IS_MAT_CONT(npoints->type) );1275nimages = npoints->rows + npoints->cols - 1;12761277if( (CV_MAT_TYPE(objectPoints->type) != CV_32FC3 &&1278CV_MAT_TYPE(objectPoints->type) != CV_64FC3) ||1279(CV_MAT_TYPE(imagePoints->type) != CV_32FC2 &&1280CV_MAT_TYPE(imagePoints->type) != CV_64FC2) )1281CV_Error( CV_StsUnsupportedFormat, "Both object points and image points must be 2D" );12821283if( objectPoints->rows != 1 || imagePoints->rows != 1 )1284CV_Error( CV_StsBadSize, "object points and image points must be a single-row matrices" );12851286matA.reset(cvCreateMat( 2*nimages, 2, CV_64F ));1287_b.reset(cvCreateMat( 2*nimages, 1, CV_64F ));1288a[2] = (!imageSize.width) ? 0.5 : (imageSize.width)*0.5;1289a[5] = (!imageSize.height) ? 0.5 : (imageSize.height)*0.5;1290_allH.reset(cvCreateMat( nimages, 9, CV_64F ));12911292// extract vanishing points in order to obtain initial value for the focal length1293for( i = 0, pos = 0; i < nimages; i++, pos += ni )1294{1295double* Ap = matA->data.db + i*4;1296double* bp = _b->data.db + i*2;1297ni = npoints->data.i[i];1298double h[3], v[3], d1[3], d2[3];1299double n[4] = {0,0,0,0};1300CvMat _m, matM;1301cvGetCols( objectPoints, &matM, pos, pos + ni );1302cvGetCols( imagePoints, &_m, pos, pos + ni );13031304cvFindHomography( &matM, &_m, &matH );1305memcpy( _allH->data.db + i*9, H, sizeof(H) );13061307H[0] -= H[6]*a[2]; H[1] -= H[7]*a[2]; H[2] -= H[8]*a[2];1308H[3] -= H[6]*a[5]; H[4] -= H[7]*a[5]; H[5] -= H[8]*a[5];13091310for( j = 0; j < 3; j++ )1311{1312double t0 = H[j*3], t1 = H[j*3+1];1313h[j] = t0; v[j] = t1;1314d1[j] = (t0 + t1)*0.5;1315d2[j] = (t0 - t1)*0.5;1316n[0] += t0*t0; n[1] += t1*t1;1317n[2] += d1[j]*d1[j]; n[3] += d2[j]*d2[j];1318}13191320for( j = 0; j < 4; j++ )1321n[j] = 1./std::sqrt(n[j]);13221323for( j = 0; j < 3; j++ )1324{1325h[j] *= n[0]; v[j] *= n[1];1326d1[j] *= n[2]; d2[j] *= n[3];1327}13281329Ap[0] = h[0]*v[0]; Ap[1] = h[1]*v[1];1330Ap[2] = d1[0]*d2[0]; Ap[3] = d1[1]*d2[1];1331bp[0] = -h[2]*v[2]; bp[1] = -d1[2]*d2[2];1332}13331334cvSolve( matA, _b, &_f, CV_NORMAL + CV_SVD );1335a[0] = std::sqrt(fabs(1./f[0]));1336a[4] = std::sqrt(fabs(1./f[1]));1337if( aspectRatio != 0 )1338{1339double tf = (a[0] + a[4])/(aspectRatio + 1.);1340a[0] = aspectRatio*tf;1341a[4] = tf;1342}13431344cvConvert( &_a, cameraMatrix );1345}13461347static void subMatrix(const cv::Mat& src, cv::Mat& dst, const std::vector<uchar>& cols,1348const std::vector<uchar>& rows) {1349int nonzeros_cols = cv::countNonZero(cols);1350cv::Mat tmp(src.rows, nonzeros_cols, CV_64FC1);13511352for (int i = 0, j = 0; i < (int)cols.size(); i++)1353{1354if (cols[i])1355{1356src.col(i).copyTo(tmp.col(j++));1357}1358}13591360int nonzeros_rows = cv::countNonZero(rows);1361dst.create(nonzeros_rows, nonzeros_cols, CV_64FC1);1362for (int i = 0, j = 0; i < (int)rows.size(); i++)1363{1364if (rows[i])1365{1366tmp.row(i).copyTo(dst.row(j++));1367}1368}1369}13701371static double cvCalibrateCamera2Internal( const CvMat* objectPoints,1372const CvMat* imagePoints, const CvMat* npoints,1373CvSize imageSize, int iFixedPoint, CvMat* cameraMatrix, CvMat* distCoeffs,1374CvMat* rvecs, CvMat* tvecs, CvMat* newObjPoints, CvMat* stdDevs,1375CvMat* perViewErrors, int flags, CvTermCriteria termCrit )1376{1377const int NINTRINSIC = CV_CALIB_NINTRINSIC;1378double reprojErr = 0;13791380Matx33d A;1381double k[14] = {0};1382CvMat matA = cvMat(3, 3, CV_64F, A.val), _k;1383int i, nimages, maxPoints = 0, ni = 0, pos, total = 0, nparams, npstep, cn;1384double aspectRatio = 0.;13851386// 0. check the parameters & allocate buffers1387if( !CV_IS_MAT(objectPoints) || !CV_IS_MAT(imagePoints) ||1388!CV_IS_MAT(npoints) || !CV_IS_MAT(cameraMatrix) || !CV_IS_MAT(distCoeffs) )1389CV_Error( CV_StsBadArg, "One of required vector arguments is not a valid matrix" );13901391if( imageSize.width <= 0 || imageSize.height <= 0 )1392CV_Error( CV_StsOutOfRange, "image width and height must be positive" );13931394if( CV_MAT_TYPE(npoints->type) != CV_32SC1 ||1395(npoints->rows != 1 && npoints->cols != 1) )1396CV_Error( CV_StsUnsupportedFormat,1397"the array of point counters must be 1-dimensional integer vector" );1398if(flags & CALIB_TILTED_MODEL)1399{1400//when the tilted sensor model is used the distortion coefficients matrix must have 14 parameters1401if (distCoeffs->cols*distCoeffs->rows != 14)1402CV_Error( CV_StsBadArg, "The tilted sensor model must have 14 parameters in the distortion matrix" );1403}1404else1405{1406//when the thin prism model is used the distortion coefficients matrix must have 12 parameters1407if(flags & CALIB_THIN_PRISM_MODEL)1408if (distCoeffs->cols*distCoeffs->rows != 12)1409CV_Error( CV_StsBadArg, "Thin prism model must have 12 parameters in the distortion matrix" );1410}14111412nimages = npoints->rows*npoints->cols;1413npstep = npoints->rows == 1 ? 1 : npoints->step/CV_ELEM_SIZE(npoints->type);14141415if( rvecs )1416{1417cn = CV_MAT_CN(rvecs->type);1418if( !CV_IS_MAT(rvecs) ||1419(CV_MAT_DEPTH(rvecs->type) != CV_32F && CV_MAT_DEPTH(rvecs->type) != CV_64F) ||1420((rvecs->rows != nimages || (rvecs->cols*cn != 3 && rvecs->cols*cn != 9)) &&1421(rvecs->rows != 1 || rvecs->cols != nimages || cn != 3)) )1422CV_Error( CV_StsBadArg, "the output array of rotation vectors must be 3-channel "1423"1xn or nx1 array or 1-channel nx3 or nx9 array, where n is the number of views" );1424}14251426if( tvecs )1427{1428cn = CV_MAT_CN(tvecs->type);1429if( !CV_IS_MAT(tvecs) ||1430(CV_MAT_DEPTH(tvecs->type) != CV_32F && CV_MAT_DEPTH(tvecs->type) != CV_64F) ||1431((tvecs->rows != nimages || tvecs->cols*cn != 3) &&1432(tvecs->rows != 1 || tvecs->cols != nimages || cn != 3)) )1433CV_Error( CV_StsBadArg, "the output array of translation vectors must be 3-channel "1434"1xn or nx1 array or 1-channel nx3 array, where n is the number of views" );1435}14361437bool releaseObject = iFixedPoint > 0 && iFixedPoint < npoints->data.i[0] - 1;14381439if( stdDevs && !releaseObject )1440{1441cn = CV_MAT_CN(stdDevs->type);1442if( !CV_IS_MAT(stdDevs) ||1443(CV_MAT_DEPTH(stdDevs->type) != CV_32F && CV_MAT_DEPTH(stdDevs->type) != CV_64F) ||1444((stdDevs->rows != (nimages*6 + NINTRINSIC) || stdDevs->cols*cn != 1) &&1445(stdDevs->rows != 1 || stdDevs->cols != (nimages*6 + NINTRINSIC) || cn != 1)) )1446#define STR__(x) #x1447#define STR_(x) STR__(x)1448CV_Error( CV_StsBadArg, "the output array of standard deviations vectors must be 1-channel "1449"1x(n*6 + NINTRINSIC) or (n*6 + NINTRINSIC)x1 array, where n is the number of views,"1450" NINTRINSIC = " STR_(CV_CALIB_NINTRINSIC));1451}14521453if( (CV_MAT_TYPE(cameraMatrix->type) != CV_32FC1 &&1454CV_MAT_TYPE(cameraMatrix->type) != CV_64FC1) ||1455cameraMatrix->rows != 3 || cameraMatrix->cols != 3 )1456CV_Error( CV_StsBadArg,1457"Intrinsic parameters must be 3x3 floating-point matrix" );14581459if( (CV_MAT_TYPE(distCoeffs->type) != CV_32FC1 &&1460CV_MAT_TYPE(distCoeffs->type) != CV_64FC1) ||1461(distCoeffs->cols != 1 && distCoeffs->rows != 1) ||1462(distCoeffs->cols*distCoeffs->rows != 4 &&1463distCoeffs->cols*distCoeffs->rows != 5 &&1464distCoeffs->cols*distCoeffs->rows != 8 &&1465distCoeffs->cols*distCoeffs->rows != 12 &&1466distCoeffs->cols*distCoeffs->rows != 14) )1467CV_Error( CV_StsBadArg, cvDistCoeffErr );14681469for( i = 0; i < nimages; i++ )1470{1471ni = npoints->data.i[i*npstep];1472if( ni < 4 )1473{1474CV_Error_( CV_StsOutOfRange, ("The number of points in the view #%d is < 4", i));1475}1476maxPoints = MAX( maxPoints, ni );1477total += ni;1478}14791480if( newObjPoints )1481{1482cn = CV_MAT_CN(newObjPoints->type);1483if( !CV_IS_MAT(newObjPoints) ||1484(CV_MAT_DEPTH(newObjPoints->type) != CV_32F && CV_MAT_DEPTH(newObjPoints->type) != CV_64F) ||1485((newObjPoints->rows != maxPoints || newObjPoints->cols*cn != 3) &&1486(newObjPoints->rows != 1 || newObjPoints->cols != maxPoints || cn != 3)) )1487CV_Error( CV_StsBadArg, "the output array of refined object points must be 3-channel "1488"1xn or nx1 array or 1-channel nx3 array, where n is the number of object points per view" );1489}14901491if( stdDevs && releaseObject )1492{1493cn = CV_MAT_CN(stdDevs->type);1494if( !CV_IS_MAT(stdDevs) ||1495(CV_MAT_DEPTH(stdDevs->type) != CV_32F && CV_MAT_DEPTH(stdDevs->type) != CV_64F) ||1496((stdDevs->rows != (nimages*6 + NINTRINSIC + maxPoints*3) || stdDevs->cols*cn != 1) &&1497(stdDevs->rows != 1 || stdDevs->cols != (nimages*6 + NINTRINSIC + maxPoints*3) || cn != 1)) )1498CV_Error( CV_StsBadArg, "the output array of standard deviations vectors must be 1-channel "1499"1x(n*6 + NINTRINSIC + m*3) or (n*6 + NINTRINSIC + m*3)x1 array, where n is the number of views,"1500" NINTRINSIC = " STR_(CV_CALIB_NINTRINSIC) ", m is the number of object points per view");1501}15021503Mat matM( 1, total, CV_64FC3 );1504Mat _m( 1, total, CV_64FC2 );1505Mat allErrors(1, total, CV_64FC2);15061507if(CV_MAT_CN(objectPoints->type) == 3) {1508cvarrToMat(objectPoints).convertTo(matM, CV_64F);1509} else {1510convertPointsHomogeneous(cvarrToMat(objectPoints), matM);1511}15121513if(CV_MAT_CN(imagePoints->type) == 2) {1514cvarrToMat(imagePoints).convertTo(_m, CV_64F);1515} else {1516convertPointsHomogeneous(cvarrToMat(imagePoints), _m);1517}15181519nparams = NINTRINSIC + nimages*6;1520if( releaseObject )1521nparams += maxPoints * 3;1522Mat _Ji( maxPoints*2, NINTRINSIC, CV_64FC1, Scalar(0));1523Mat _Je( maxPoints*2, 6, CV_64FC1 );1524Mat _Jo( maxPoints*2, maxPoints*3, CV_64FC1, Scalar(0) );1525Mat _err( maxPoints*2, 1, CV_64FC1 );15261527_k = cvMat( distCoeffs->rows, distCoeffs->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), k);1528if( distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) < 8 )1529{1530if( distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) < 5 )1531flags |= CALIB_FIX_K3;1532flags |= CALIB_FIX_K4 | CALIB_FIX_K5 | CALIB_FIX_K6;1533}1534const double minValidAspectRatio = 0.01;1535const double maxValidAspectRatio = 100.0;15361537// 1. initialize intrinsic parameters & LM solver1538if( flags & CALIB_USE_INTRINSIC_GUESS )1539{1540cvConvert( cameraMatrix, &matA );1541if( A(0, 0) <= 0 || A(1, 1) <= 0 )1542CV_Error( CV_StsOutOfRange, "Focal length (fx and fy) must be positive" );1543if( A(0, 2) < 0 || A(0, 2) >= imageSize.width ||1544A(1, 2) < 0 || A(1, 2) >= imageSize.height )1545CV_Error( CV_StsOutOfRange, "Principal point must be within the image" );1546if( fabs(A(0, 1)) > 1e-5 )1547CV_Error( CV_StsOutOfRange, "Non-zero skew is not supported by the function" );1548if( fabs(A(1, 0)) > 1e-5 || fabs(A(2, 0)) > 1e-5 ||1549fabs(A(2, 1)) > 1e-5 || fabs(A(2,2)-1) > 1e-5 )1550CV_Error( CV_StsOutOfRange,1551"The intrinsic matrix must have [fx 0 cx; 0 fy cy; 0 0 1] shape" );1552A(0, 1) = A(1, 0) = A(2, 0) = A(2, 1) = 0.;1553A(2, 2) = 1.;15541555if( flags & CALIB_FIX_ASPECT_RATIO )1556{1557aspectRatio = A(0, 0)/A(1, 1);15581559if( aspectRatio < minValidAspectRatio || aspectRatio > maxValidAspectRatio )1560CV_Error( CV_StsOutOfRange,1561"The specified aspect ratio (= cameraMatrix[0][0] / cameraMatrix[1][1]) is incorrect" );1562}1563cvConvert( distCoeffs, &_k );1564}1565else1566{1567Scalar mean, sdv;1568meanStdDev(matM, mean, sdv);1569if( fabs(mean[2]) > 1e-5 || fabs(sdv[2]) > 1e-5 )1570CV_Error( CV_StsBadArg,1571"For non-planar calibration rigs the initial intrinsic matrix must be specified" );1572for( i = 0; i < total; i++ )1573matM.at<Point3d>(i).z = 0.;15741575if( flags & CALIB_FIX_ASPECT_RATIO )1576{1577aspectRatio = cvmGet(cameraMatrix,0,0);1578aspectRatio /= cvmGet(cameraMatrix,1,1);1579if( aspectRatio < minValidAspectRatio || aspectRatio > maxValidAspectRatio )1580CV_Error( CV_StsOutOfRange,1581"The specified aspect ratio (= cameraMatrix[0][0] / cameraMatrix[1][1]) is incorrect" );1582}1583CvMat _matM = cvMat(matM), m = cvMat(_m);1584cvInitIntrinsicParams2D( &_matM, &m, npoints, imageSize, &matA, aspectRatio );1585}15861587CvLevMarq solver( nparams, 0, termCrit );15881589if(flags & CALIB_USE_LU) {1590solver.solveMethod = DECOMP_LU;1591}1592else if(flags & CALIB_USE_QR) {1593solver.solveMethod = DECOMP_QR;1594}15951596{1597double* param = solver.param->data.db;1598uchar* mask = solver.mask->data.ptr;15991600param[0] = A(0, 0); param[1] = A(1, 1); param[2] = A(0, 2); param[3] = A(1, 2);1601std::copy(k, k + 14, param + 4);16021603if(flags & CALIB_FIX_ASPECT_RATIO)1604mask[0] = 0;1605if( flags & CALIB_FIX_FOCAL_LENGTH )1606mask[0] = mask[1] = 0;1607if( flags & CALIB_FIX_PRINCIPAL_POINT )1608mask[2] = mask[3] = 0;1609if( flags & CALIB_ZERO_TANGENT_DIST )1610{1611param[6] = param[7] = 0;1612mask[6] = mask[7] = 0;1613}1614if( !(flags & CALIB_RATIONAL_MODEL) )1615flags |= CALIB_FIX_K4 + CALIB_FIX_K5 + CALIB_FIX_K6;1616if( !(flags & CALIB_THIN_PRISM_MODEL))1617flags |= CALIB_FIX_S1_S2_S3_S4;1618if( !(flags & CALIB_TILTED_MODEL))1619flags |= CALIB_FIX_TAUX_TAUY;16201621mask[ 4] = !(flags & CALIB_FIX_K1);1622mask[ 5] = !(flags & CALIB_FIX_K2);1623if( flags & CALIB_FIX_TANGENT_DIST )1624{1625mask[6] = mask[7] = 0;1626}1627mask[ 8] = !(flags & CALIB_FIX_K3);1628mask[ 9] = !(flags & CALIB_FIX_K4);1629mask[10] = !(flags & CALIB_FIX_K5);1630mask[11] = !(flags & CALIB_FIX_K6);16311632if(flags & CALIB_FIX_S1_S2_S3_S4)1633{1634mask[12] = 0;1635mask[13] = 0;1636mask[14] = 0;1637mask[15] = 0;1638}1639if(flags & CALIB_FIX_TAUX_TAUY)1640{1641mask[16] = 0;1642mask[17] = 0;1643}16441645if(releaseObject)1646{1647// copy object points1648std::copy( matM.ptr<double>(), matM.ptr<double>( 0, maxPoints - 1 ) + 3,1649param + NINTRINSIC + nimages * 6 );1650// fix points1651mask[NINTRINSIC + nimages * 6] = 0;1652mask[NINTRINSIC + nimages * 6 + 1] = 0;1653mask[NINTRINSIC + nimages * 6 + 2] = 0;1654mask[NINTRINSIC + nimages * 6 + iFixedPoint * 3] = 0;1655mask[NINTRINSIC + nimages * 6 + iFixedPoint * 3 + 1] = 0;1656mask[NINTRINSIC + nimages * 6 + iFixedPoint * 3 + 2] = 0;1657mask[nparams - 1] = 0;1658}1659}16601661// 2. initialize extrinsic parameters1662for( i = 0, pos = 0; i < nimages; i++, pos += ni )1663{1664CvMat _ri, _ti;1665ni = npoints->data.i[i*npstep];16661667cvGetRows( solver.param, &_ri, NINTRINSIC + i*6, NINTRINSIC + i*6 + 3 );1668cvGetRows( solver.param, &_ti, NINTRINSIC + i*6 + 3, NINTRINSIC + i*6 + 6 );16691670CvMat _Mi = cvMat(matM.colRange(pos, pos + ni));1671CvMat _mi = cvMat(_m.colRange(pos, pos + ni));16721673cvFindExtrinsicCameraParams2( &_Mi, &_mi, &matA, &_k, &_ri, &_ti );1674}16751676// 3. run the optimization1677for(;;)1678{1679const CvMat* _param = 0;1680CvMat *_JtJ = 0, *_JtErr = 0;1681double* _errNorm = 0;1682bool proceed = solver.updateAlt( _param, _JtJ, _JtErr, _errNorm );1683double *param = solver.param->data.db, *pparam = solver.prevParam->data.db;1684bool calcJ = solver.state == CvLevMarq::CALC_J || (!proceed && stdDevs);16851686if( flags & CALIB_FIX_ASPECT_RATIO )1687{1688param[0] = param[1]*aspectRatio;1689pparam[0] = pparam[1]*aspectRatio;1690}16911692A(0, 0) = param[0]; A(1, 1) = param[1]; A(0, 2) = param[2]; A(1, 2) = param[3];1693std::copy(param + 4, param + 4 + 14, k);16941695if ( !proceed && !stdDevs && !perViewErrors )1696break;1697else if ( !proceed && stdDevs )1698cvZero(_JtJ);16991700reprojErr = 0;17011702for( i = 0, pos = 0; i < nimages; i++, pos += ni )1703{1704CvMat _ri, _ti;1705ni = npoints->data.i[i*npstep];17061707cvGetRows( solver.param, &_ri, NINTRINSIC + i*6, NINTRINSIC + i*6 + 3 );1708cvGetRows( solver.param, &_ti, NINTRINSIC + i*6 + 3, NINTRINSIC + i*6 + 6 );17091710CvMat _Mi = cvMat(matM.colRange(pos, pos + ni));1711if( releaseObject )1712{1713cvGetRows( solver.param, &_Mi, NINTRINSIC + nimages * 6,1714NINTRINSIC + nimages * 6 + ni * 3 );1715cvReshape( &_Mi, &_Mi, 3, 1 );1716}1717CvMat _mi = cvMat(_m.colRange(pos, pos + ni));1718CvMat _me = cvMat(allErrors.colRange(pos, pos + ni));17191720_Je.resize(ni*2); _Ji.resize(ni*2); _err.resize(ni*2);1721_Jo.resize(ni*2);1722CvMat _dpdr = cvMat(_Je.colRange(0, 3));1723CvMat _dpdt = cvMat(_Je.colRange(3, 6));1724CvMat _dpdf = cvMat(_Ji.colRange(0, 2));1725CvMat _dpdc = cvMat(_Ji.colRange(2, 4));1726CvMat _dpdk = cvMat(_Ji.colRange(4, NINTRINSIC));1727CvMat _dpdo = cvMat(_Jo.colRange(0, ni * 3));1728CvMat _mp = cvMat(_err.reshape(2, 1));17291730if( calcJ )1731{1732cvProjectPoints2Internal( &_Mi, &_ri, &_ti, &matA, &_k, &_mp, &_dpdr, &_dpdt,1733(flags & CALIB_FIX_FOCAL_LENGTH) ? 0 : &_dpdf,1734(flags & CALIB_FIX_PRINCIPAL_POINT) ? 0 : &_dpdc, &_dpdk,1735&_dpdo,1736(flags & CALIB_FIX_ASPECT_RATIO) ? aspectRatio : 0);1737}1738else1739cvProjectPoints2( &_Mi, &_ri, &_ti, &matA, &_k, &_mp );17401741cvSub( &_mp, &_mi, &_mp );1742if (perViewErrors || stdDevs)1743cvCopy(&_mp, &_me);17441745if( calcJ )1746{1747Mat JtJ(cvarrToMat(_JtJ)), JtErr(cvarrToMat(_JtErr));17481749// see HZ: (A6.14) for details on the structure of the Jacobian1750JtJ(Rect(0, 0, NINTRINSIC, NINTRINSIC)) += _Ji.t() * _Ji;1751JtJ(Rect(NINTRINSIC + i * 6, NINTRINSIC + i * 6, 6, 6)) = _Je.t() * _Je;1752JtJ(Rect(NINTRINSIC + i * 6, 0, 6, NINTRINSIC)) = _Ji.t() * _Je;1753if( releaseObject )1754{1755JtJ(Rect(NINTRINSIC + nimages * 6, 0, maxPoints * 3, NINTRINSIC)) += _Ji.t() * _Jo;1756JtJ(Rect(NINTRINSIC + nimages * 6, NINTRINSIC + i * 6, maxPoints * 3, 6))1757+= _Je.t() * _Jo;1758JtJ(Rect(NINTRINSIC + nimages * 6, NINTRINSIC + nimages * 6, maxPoints * 3, maxPoints * 3))1759+= _Jo.t() * _Jo;1760}17611762JtErr.rowRange(0, NINTRINSIC) += _Ji.t() * _err;1763JtErr.rowRange(NINTRINSIC + i * 6, NINTRINSIC + (i + 1) * 6) = _Je.t() * _err;1764if( releaseObject )1765{1766JtErr.rowRange(NINTRINSIC + nimages * 6, nparams) += _Jo.t() * _err;1767}1768}17691770double viewErr = norm(_err, NORM_L2SQR);17711772if( perViewErrors )1773perViewErrors->data.db[i] = std::sqrt(viewErr / ni);17741775reprojErr += viewErr;1776}1777if( _errNorm )1778*_errNorm = reprojErr;17791780if( !proceed )1781{1782if( stdDevs )1783{1784Mat mask = cvarrToMat(solver.mask);1785int nparams_nz = countNonZero(mask);1786Mat JtJinv, JtJN;1787JtJN.create(nparams_nz, nparams_nz, CV_64F);1788subMatrix(cvarrToMat(_JtJ), JtJN, mask, mask);1789completeSymm(JtJN, false);1790cv::invert(JtJN, JtJinv, DECOMP_SVD);1791//sigma2 is deviation of the noise1792//see any papers about variance of the least squares estimator for1793//detailed description of the variance estimation methods1794double sigma2 = norm(allErrors, NORM_L2SQR) / (total - nparams_nz);1795Mat stdDevsM = cvarrToMat(stdDevs);1796int j = 0;1797for ( int s = 0; s < nparams; s++ )1798if( mask.data[s] )1799{1800stdDevsM.at<double>(s) = std::sqrt(JtJinv.at<double>(j,j) * sigma2);1801j++;1802}1803else1804stdDevsM.at<double>(s) = 0.;1805}1806break;1807}1808}18091810// 4. store the results1811cvConvert( &matA, cameraMatrix );1812cvConvert( &_k, distCoeffs );1813if( newObjPoints && releaseObject )1814{1815CvMat _Mi;1816cvGetRows( solver.param, &_Mi, NINTRINSIC + nimages * 6,1817NINTRINSIC + nimages * 6 + maxPoints * 3 );1818cvReshape( &_Mi, &_Mi, 3, 1 );1819cvConvert( &_Mi, newObjPoints );1820}18211822for( i = 0, pos = 0; i < nimages; i++ )1823{1824CvMat src, dst;18251826if( rvecs )1827{1828src = cvMat( 3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6 );1829if( rvecs->rows == nimages && rvecs->cols*CV_MAT_CN(rvecs->type) == 9 )1830{1831dst = cvMat( 3, 3, CV_MAT_DEPTH(rvecs->type),1832rvecs->data.ptr + rvecs->step*i );1833cvRodrigues2( &src, &matA );1834cvConvert( &matA, &dst );1835}1836else1837{1838dst = cvMat( 3, 1, CV_MAT_DEPTH(rvecs->type), rvecs->rows == 1 ?1839rvecs->data.ptr + i*CV_ELEM_SIZE(rvecs->type) :1840rvecs->data.ptr + rvecs->step*i );1841cvConvert( &src, &dst );1842}1843}1844if( tvecs )1845{1846src = cvMat( 3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6 + 3 );1847dst = cvMat( 3, 1, CV_MAT_DEPTH(tvecs->type), tvecs->rows == 1 ?1848tvecs->data.ptr + i*CV_ELEM_SIZE(tvecs->type) :1849tvecs->data.ptr + tvecs->step*i );1850cvConvert( &src, &dst );1851}1852}18531854return std::sqrt(reprojErr/total);1855}185618571858/* finds intrinsic and extrinsic camera parameters1859from a few views of known calibration pattern */1860CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,1861const CvMat* imagePoints, const CvMat* npoints,1862CvSize imageSize, CvMat* cameraMatrix, CvMat* distCoeffs,1863CvMat* rvecs, CvMat* tvecs, int flags, CvTermCriteria termCrit )1864{1865return cvCalibrateCamera2Internal(objectPoints, imagePoints, npoints, imageSize, -1, cameraMatrix,1866distCoeffs, rvecs, tvecs, NULL, NULL, NULL, flags, termCrit);1867}18681869CV_IMPL double cvCalibrateCamera4( const CvMat* objectPoints,1870const CvMat* imagePoints, const CvMat* npoints,1871CvSize imageSize, int iFixedPoint, CvMat* cameraMatrix, CvMat* distCoeffs,1872CvMat* rvecs, CvMat* tvecs, CvMat* newObjPoints, int flags, CvTermCriteria termCrit )1873{1874if( !CV_IS_MAT(npoints) )1875CV_Error( CV_StsBadArg, "npoints is not a valid matrix" );1876if( CV_MAT_TYPE(npoints->type) != CV_32SC1 ||1877(npoints->rows != 1 && npoints->cols != 1) )1878CV_Error( CV_StsUnsupportedFormat,1879"the array of point counters must be 1-dimensional integer vector" );18801881bool releaseObject = iFixedPoint > 0 && iFixedPoint < npoints->data.i[0] - 1;1882int nimages = npoints->rows * npoints->cols;1883int npstep = npoints->rows == 1 ? 1 : npoints->step / CV_ELEM_SIZE(npoints->type);1884int i, ni;1885// check object points. If not qualified, report errors.1886if( releaseObject )1887{1888if( !CV_IS_MAT(objectPoints) )1889CV_Error( CV_StsBadArg, "objectPoints is not a valid matrix" );1890Mat matM;1891if(CV_MAT_CN(objectPoints->type) == 3) {1892matM = cvarrToMat(objectPoints);1893} else {1894convertPointsHomogeneous(cvarrToMat(objectPoints), matM);1895}18961897matM = matM.reshape(3, 1);1898ni = npoints->data.i[0];1899for( i = 1; i < nimages; i++ )1900{1901if( npoints->data.i[i * npstep] != ni )1902{1903CV_Error( CV_StsBadArg, "All objectPoints[i].size() should be equal when "1904"object-releasing method is requested." );1905}1906Mat ocmp = matM.colRange(ni * i, ni * i + ni) != matM.colRange(0, ni);1907ocmp = ocmp.reshape(1);1908if( countNonZero(ocmp) )1909{1910CV_Error( CV_StsBadArg, "All objectPoints[i] should be identical when object-releasing"1911" method is requested." );1912}1913}1914}19151916return cvCalibrateCamera2Internal(objectPoints, imagePoints, npoints, imageSize, iFixedPoint,1917cameraMatrix, distCoeffs, rvecs, tvecs, newObjPoints, NULL,1918NULL, flags, termCrit);1919}19201921void cvCalibrationMatrixValues( const CvMat *calibMatr, CvSize imgSize,1922double apertureWidth, double apertureHeight, double *fovx, double *fovy,1923double *focalLength, CvPoint2D64f *principalPoint, double *pasp )1924{1925/* Validate parameters. */1926if(calibMatr == 0)1927CV_Error(CV_StsNullPtr, "Some of parameters is a NULL pointer!");19281929if(!CV_IS_MAT(calibMatr))1930CV_Error(CV_StsUnsupportedFormat, "Input parameters must be a matrices!");19311932double dummy = .0;1933Point2d pp;1934cv::calibrationMatrixValues(cvarrToMat(calibMatr), imgSize, apertureWidth, apertureHeight,1935fovx ? *fovx : dummy,1936fovy ? *fovy : dummy,1937focalLength ? *focalLength : dummy,1938pp,1939pasp ? *pasp : dummy);19401941if(principalPoint)1942*principalPoint = cvPoint2D64f(pp.x, pp.y);1943}194419451946//////////////////////////////// Stereo Calibration ///////////////////////////////////19471948static int dbCmp( const void* _a, const void* _b )1949{1950double a = *(const double*)_a;1951double b = *(const double*)_b;19521953return (a > b) - (a < b);1954}19551956static double cvStereoCalibrateImpl( const CvMat* _objectPoints, const CvMat* _imagePoints1,1957const CvMat* _imagePoints2, const CvMat* _npoints,1958CvMat* _cameraMatrix1, CvMat* _distCoeffs1,1959CvMat* _cameraMatrix2, CvMat* _distCoeffs2,1960CvSize imageSize, CvMat* matR, CvMat* matT,1961CvMat* matE, CvMat* matF,1962CvMat* perViewErr, int flags,1963CvTermCriteria termCrit )1964{1965const int NINTRINSIC = 18;1966Ptr<CvMat> npoints, imagePoints[2], objectPoints, RT0;1967double reprojErr = 0;19681969double A[2][9], dk[2][14]={{0}}, rlr[9];1970CvMat K[2], Dist[2], om_LR, T_LR;1971CvMat R_LR = cvMat(3, 3, CV_64F, rlr);1972int i, k, p, ni = 0, ofs, nimages, pointsTotal, maxPoints = 0;1973int nparams;1974bool recomputeIntrinsics = false;1975double aspectRatio[2] = {0};19761977CV_Assert( CV_IS_MAT(_imagePoints1) && CV_IS_MAT(_imagePoints2) &&1978CV_IS_MAT(_objectPoints) && CV_IS_MAT(_npoints) &&1979CV_IS_MAT(matR) && CV_IS_MAT(matT) );19801981CV_Assert( CV_ARE_TYPES_EQ(_imagePoints1, _imagePoints2) &&1982CV_ARE_DEPTHS_EQ(_imagePoints1, _objectPoints) );19831984CV_Assert( (_npoints->cols == 1 || _npoints->rows == 1) &&1985CV_MAT_TYPE(_npoints->type) == CV_32SC1 );19861987nimages = _npoints->cols + _npoints->rows - 1;1988npoints.reset(cvCreateMat( _npoints->rows, _npoints->cols, _npoints->type ));1989cvCopy( _npoints, npoints );19901991for( i = 0, pointsTotal = 0; i < nimages; i++ )1992{1993maxPoints = MAX(maxPoints, npoints->data.i[i]);1994pointsTotal += npoints->data.i[i];1995}19961997objectPoints.reset(cvCreateMat( _objectPoints->rows, _objectPoints->cols,1998CV_64FC(CV_MAT_CN(_objectPoints->type))));1999cvConvert( _objectPoints, objectPoints );2000cvReshape( objectPoints, objectPoints, 3, 1 );20012002for( k = 0; k < 2; k++ )2003{2004const CvMat* points = k == 0 ? _imagePoints1 : _imagePoints2;2005const CvMat* cameraMatrix = k == 0 ? _cameraMatrix1 : _cameraMatrix2;2006const CvMat* distCoeffs = k == 0 ? _distCoeffs1 : _distCoeffs2;20072008int cn = CV_MAT_CN(_imagePoints1->type);2009CV_Assert( (CV_MAT_DEPTH(_imagePoints1->type) == CV_32F ||2010CV_MAT_DEPTH(_imagePoints1->type) == CV_64F) &&2011((_imagePoints1->rows == pointsTotal && _imagePoints1->cols*cn == 2) ||2012(_imagePoints1->rows == 1 && _imagePoints1->cols == pointsTotal && cn == 2)) );20132014K[k] = cvMat(3,3,CV_64F,A[k]);2015Dist[k] = cvMat(1,14,CV_64F,dk[k]);20162017imagePoints[k].reset(cvCreateMat( points->rows, points->cols, CV_64FC(CV_MAT_CN(points->type))));2018cvConvert( points, imagePoints[k] );2019cvReshape( imagePoints[k], imagePoints[k], 2, 1 );20202021if( flags & (CALIB_FIX_INTRINSIC|CALIB_USE_INTRINSIC_GUESS|2022CALIB_FIX_ASPECT_RATIO|CALIB_FIX_FOCAL_LENGTH) )2023cvConvert( cameraMatrix, &K[k] );20242025if( flags & (CALIB_FIX_INTRINSIC|CALIB_USE_INTRINSIC_GUESS|2026CALIB_FIX_K1|CALIB_FIX_K2|CALIB_FIX_K3|CALIB_FIX_K4|CALIB_FIX_K5|CALIB_FIX_K6|CALIB_FIX_TANGENT_DIST) )2027{2028CvMat tdist = cvMat( distCoeffs->rows, distCoeffs->cols,2029CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), Dist[k].data.db );2030cvConvert( distCoeffs, &tdist );2031}20322033if( !(flags & (CALIB_FIX_INTRINSIC|CALIB_USE_INTRINSIC_GUESS)))2034{2035cvCalibrateCamera2( objectPoints, imagePoints[k],2036npoints, imageSize, &K[k], &Dist[k], NULL, NULL, flags );2037}2038}20392040if( flags & CALIB_SAME_FOCAL_LENGTH )2041{2042static const int avg_idx[] = { 0, 4, 2, 5, -1 };2043for( k = 0; avg_idx[k] >= 0; k++ )2044A[0][avg_idx[k]] = A[1][avg_idx[k]] = (A[0][avg_idx[k]] + A[1][avg_idx[k]])*0.5;2045}20462047if( flags & CALIB_FIX_ASPECT_RATIO )2048{2049for( k = 0; k < 2; k++ )2050aspectRatio[k] = A[k][0]/A[k][4];2051}20522053recomputeIntrinsics = (flags & CALIB_FIX_INTRINSIC) == 0;20542055Mat err( maxPoints*2, 1, CV_64F );2056Mat Je( maxPoints*2, 6, CV_64F );2057Mat J_LR( maxPoints*2, 6, CV_64F );2058Mat Ji( maxPoints*2, NINTRINSIC, CV_64F, Scalar(0) );20592060// we optimize for the inter-camera R(3),t(3), then, optionally,2061// for intrinisic parameters of each camera ((fx,fy,cx,cy,k1,k2,p1,p2) ~ 8 parameters).2062nparams = 6*(nimages+1) + (recomputeIntrinsics ? NINTRINSIC*2 : 0);20632064CvLevMarq solver( nparams, 0, termCrit );20652066if(flags & CALIB_USE_LU) {2067solver.solveMethod = DECOMP_LU;2068}20692070if( recomputeIntrinsics )2071{2072uchar* imask = solver.mask->data.ptr + nparams - NINTRINSIC*2;2073if( !(flags & CALIB_RATIONAL_MODEL) )2074flags |= CALIB_FIX_K4 | CALIB_FIX_K5 | CALIB_FIX_K6;2075if( !(flags & CALIB_THIN_PRISM_MODEL) )2076flags |= CALIB_FIX_S1_S2_S3_S4;2077if( !(flags & CALIB_TILTED_MODEL) )2078flags |= CALIB_FIX_TAUX_TAUY;2079if( flags & CALIB_FIX_ASPECT_RATIO )2080imask[0] = imask[NINTRINSIC] = 0;2081if( flags & CALIB_FIX_FOCAL_LENGTH )2082imask[0] = imask[1] = imask[NINTRINSIC] = imask[NINTRINSIC+1] = 0;2083if( flags & CALIB_FIX_PRINCIPAL_POINT )2084imask[2] = imask[3] = imask[NINTRINSIC+2] = imask[NINTRINSIC+3] = 0;2085if( flags & (CALIB_ZERO_TANGENT_DIST|CALIB_FIX_TANGENT_DIST) )2086imask[6] = imask[7] = imask[NINTRINSIC+6] = imask[NINTRINSIC+7] = 0;2087if( flags & CALIB_FIX_K1 )2088imask[4] = imask[NINTRINSIC+4] = 0;2089if( flags & CALIB_FIX_K2 )2090imask[5] = imask[NINTRINSIC+5] = 0;2091if( flags & CALIB_FIX_K3 )2092imask[8] = imask[NINTRINSIC+8] = 0;2093if( flags & CALIB_FIX_K4 )2094imask[9] = imask[NINTRINSIC+9] = 0;2095if( flags & CALIB_FIX_K5 )2096imask[10] = imask[NINTRINSIC+10] = 0;2097if( flags & CALIB_FIX_K6 )2098imask[11] = imask[NINTRINSIC+11] = 0;2099if( flags & CALIB_FIX_S1_S2_S3_S4 )2100{2101imask[12] = imask[NINTRINSIC+12] = 0;2102imask[13] = imask[NINTRINSIC+13] = 0;2103imask[14] = imask[NINTRINSIC+14] = 0;2104imask[15] = imask[NINTRINSIC+15] = 0;2105}2106if( flags & CALIB_FIX_TAUX_TAUY )2107{2108imask[16] = imask[NINTRINSIC+16] = 0;2109imask[17] = imask[NINTRINSIC+17] = 0;2110}2111}21122113// storage for initial [om(R){i}|t{i}] (in order to compute the median for each component)2114RT0.reset(cvCreateMat( 6, nimages, CV_64F ));2115/*2116Compute initial estimate of pose2117For each image, compute:2118R(om) is the rotation matrix of om2119om(R) is the rotation vector of R2120R_ref = R(om_right) * R(om_left)'2121T_ref_list = [T_ref_list; T_right - R_ref * T_left]2122om_ref_list = {om_ref_list; om(R_ref)]2123om = median(om_ref_list)2124T = median(T_ref_list)2125*/2126for( i = ofs = 0; i < nimages; ofs += ni, i++ )2127{2128ni = npoints->data.i[i];2129CvMat objpt_i;2130double _om[2][3], r[2][9], t[2][3];2131CvMat om[2], R[2], T[2], imgpt_i[2];21322133objpt_i = cvMat(1, ni, CV_64FC3, objectPoints->data.db + ofs*3);2134for( k = 0; k < 2; k++ )2135{2136imgpt_i[k] = cvMat(1, ni, CV_64FC2, imagePoints[k]->data.db + ofs*2);2137om[k] = cvMat(3, 1, CV_64F, _om[k]);2138R[k] = cvMat(3, 3, CV_64F, r[k]);2139T[k] = cvMat(3, 1, CV_64F, t[k]);21402141cvFindExtrinsicCameraParams2( &objpt_i, &imgpt_i[k], &K[k], &Dist[k], &om[k], &T[k] );2142cvRodrigues2( &om[k], &R[k] );2143if( k == 0 )2144{2145// save initial om_left and T_left2146solver.param->data.db[(i+1)*6] = _om[0][0];2147solver.param->data.db[(i+1)*6 + 1] = _om[0][1];2148solver.param->data.db[(i+1)*6 + 2] = _om[0][2];2149solver.param->data.db[(i+1)*6 + 3] = t[0][0];2150solver.param->data.db[(i+1)*6 + 4] = t[0][1];2151solver.param->data.db[(i+1)*6 + 5] = t[0][2];2152}2153}2154cvGEMM( &R[1], &R[0], 1, 0, 0, &R[0], CV_GEMM_B_T );2155cvGEMM( &R[0], &T[0], -1, &T[1], 1, &T[1] );2156cvRodrigues2( &R[0], &T[0] );2157RT0->data.db[i] = t[0][0];2158RT0->data.db[i + nimages] = t[0][1];2159RT0->data.db[i + nimages*2] = t[0][2];2160RT0->data.db[i + nimages*3] = t[1][0];2161RT0->data.db[i + nimages*4] = t[1][1];2162RT0->data.db[i + nimages*5] = t[1][2];2163}21642165if(flags & CALIB_USE_EXTRINSIC_GUESS)2166{2167Vec3d R, T;2168cvarrToMat(matT).convertTo(T, CV_64F);21692170if( matR->rows == 3 && matR->cols == 3 )2171Rodrigues(cvarrToMat(matR), R);2172else2173cvarrToMat(matR).convertTo(R, CV_64F);21742175solver.param->data.db[0] = R[0];2176solver.param->data.db[1] = R[1];2177solver.param->data.db[2] = R[2];2178solver.param->data.db[3] = T[0];2179solver.param->data.db[4] = T[1];2180solver.param->data.db[5] = T[2];2181}2182else2183{2184// find the medians and save the first 6 parameters2185for( i = 0; i < 6; i++ )2186{2187qsort( RT0->data.db + i*nimages, nimages, CV_ELEM_SIZE(RT0->type), dbCmp );2188solver.param->data.db[i] = nimages % 2 != 0 ? RT0->data.db[i*nimages + nimages/2] :2189(RT0->data.db[i*nimages + nimages/2 - 1] + RT0->data.db[i*nimages + nimages/2])*0.5;2190}2191}21922193if( recomputeIntrinsics )2194for( k = 0; k < 2; k++ )2195{2196double* iparam = solver.param->data.db + (nimages+1)*6 + k*NINTRINSIC;2197if( flags & CALIB_ZERO_TANGENT_DIST )2198dk[k][2] = dk[k][3] = 0;2199iparam[0] = A[k][0]; iparam[1] = A[k][4]; iparam[2] = A[k][2]; iparam[3] = A[k][5];2200iparam[4] = dk[k][0]; iparam[5] = dk[k][1]; iparam[6] = dk[k][2];2201iparam[7] = dk[k][3]; iparam[8] = dk[k][4]; iparam[9] = dk[k][5];2202iparam[10] = dk[k][6]; iparam[11] = dk[k][7];2203iparam[12] = dk[k][8];2204iparam[13] = dk[k][9];2205iparam[14] = dk[k][10];2206iparam[15] = dk[k][11];2207iparam[16] = dk[k][12];2208iparam[17] = dk[k][13];2209}22102211om_LR = cvMat(3, 1, CV_64F, solver.param->data.db);2212T_LR = cvMat(3, 1, CV_64F, solver.param->data.db + 3);22132214for(;;)2215{2216const CvMat* param = 0;2217CvMat *JtJ = 0, *JtErr = 0;2218double *_errNorm = 0;2219double _omR[3], _tR[3];2220double _dr3dr1[9], _dr3dr2[9], /*_dt3dr1[9],*/ _dt3dr2[9], _dt3dt1[9], _dt3dt2[9];2221CvMat dr3dr1 = cvMat(3, 3, CV_64F, _dr3dr1);2222CvMat dr3dr2 = cvMat(3, 3, CV_64F, _dr3dr2);2223//CvMat dt3dr1 = cvMat(3, 3, CV_64F, _dt3dr1);2224CvMat dt3dr2 = cvMat(3, 3, CV_64F, _dt3dr2);2225CvMat dt3dt1 = cvMat(3, 3, CV_64F, _dt3dt1);2226CvMat dt3dt2 = cvMat(3, 3, CV_64F, _dt3dt2);2227CvMat om[2], T[2], imgpt_i[2];22282229if( !solver.updateAlt( param, JtJ, JtErr, _errNorm ))2230break;2231reprojErr = 0;22322233cvRodrigues2( &om_LR, &R_LR );2234om[1] = cvMat(3,1,CV_64F,_omR);2235T[1] = cvMat(3,1,CV_64F,_tR);22362237if( recomputeIntrinsics )2238{2239double* iparam = solver.param->data.db + (nimages+1)*6;2240double* ipparam = solver.prevParam->data.db + (nimages+1)*6;22412242if( flags & CALIB_SAME_FOCAL_LENGTH )2243{2244iparam[NINTRINSIC] = iparam[0];2245iparam[NINTRINSIC+1] = iparam[1];2246ipparam[NINTRINSIC] = ipparam[0];2247ipparam[NINTRINSIC+1] = ipparam[1];2248}2249if( flags & CALIB_FIX_ASPECT_RATIO )2250{2251iparam[0] = iparam[1]*aspectRatio[0];2252iparam[NINTRINSIC] = iparam[NINTRINSIC+1]*aspectRatio[1];2253ipparam[0] = ipparam[1]*aspectRatio[0];2254ipparam[NINTRINSIC] = ipparam[NINTRINSIC+1]*aspectRatio[1];2255}2256for( k = 0; k < 2; k++ )2257{2258A[k][0] = iparam[k*NINTRINSIC+0];2259A[k][4] = iparam[k*NINTRINSIC+1];2260A[k][2] = iparam[k*NINTRINSIC+2];2261A[k][5] = iparam[k*NINTRINSIC+3];2262dk[k][0] = iparam[k*NINTRINSIC+4];2263dk[k][1] = iparam[k*NINTRINSIC+5];2264dk[k][2] = iparam[k*NINTRINSIC+6];2265dk[k][3] = iparam[k*NINTRINSIC+7];2266dk[k][4] = iparam[k*NINTRINSIC+8];2267dk[k][5] = iparam[k*NINTRINSIC+9];2268dk[k][6] = iparam[k*NINTRINSIC+10];2269dk[k][7] = iparam[k*NINTRINSIC+11];2270dk[k][8] = iparam[k*NINTRINSIC+12];2271dk[k][9] = iparam[k*NINTRINSIC+13];2272dk[k][10] = iparam[k*NINTRINSIC+14];2273dk[k][11] = iparam[k*NINTRINSIC+15];2274dk[k][12] = iparam[k*NINTRINSIC+16];2275dk[k][13] = iparam[k*NINTRINSIC+17];2276}2277}22782279for( i = ofs = 0; i < nimages; ofs += ni, i++ )2280{2281ni = npoints->data.i[i];2282CvMat objpt_i;22832284om[0] = cvMat(3,1,CV_64F,solver.param->data.db+(i+1)*6);2285T[0] = cvMat(3,1,CV_64F,solver.param->data.db+(i+1)*6+3);22862287if( JtJ || JtErr )2288cvComposeRT( &om[0], &T[0], &om_LR, &T_LR, &om[1], &T[1], &dr3dr1, 0,2289&dr3dr2, 0, 0, &dt3dt1, &dt3dr2, &dt3dt2 );2290else2291cvComposeRT( &om[0], &T[0], &om_LR, &T_LR, &om[1], &T[1] );22922293objpt_i = cvMat(1, ni, CV_64FC3, objectPoints->data.db + ofs*3);2294err.resize(ni*2); Je.resize(ni*2); J_LR.resize(ni*2); Ji.resize(ni*2);22952296CvMat tmpimagePoints = cvMat(err.reshape(2, 1));2297CvMat dpdf = cvMat(Ji.colRange(0, 2));2298CvMat dpdc = cvMat(Ji.colRange(2, 4));2299CvMat dpdk = cvMat(Ji.colRange(4, NINTRINSIC));2300CvMat dpdrot = cvMat(Je.colRange(0, 3));2301CvMat dpdt = cvMat(Je.colRange(3, 6));23022303for( k = 0; k < 2; k++ )2304{2305imgpt_i[k] = cvMat(1, ni, CV_64FC2, imagePoints[k]->data.db + ofs*2);23062307if( JtJ || JtErr )2308cvProjectPoints2( &objpt_i, &om[k], &T[k], &K[k], &Dist[k],2309&tmpimagePoints, &dpdrot, &dpdt, &dpdf, &dpdc, &dpdk,2310(flags & CALIB_FIX_ASPECT_RATIO) ? aspectRatio[k] : 0);2311else2312cvProjectPoints2( &objpt_i, &om[k], &T[k], &K[k], &Dist[k], &tmpimagePoints );2313cvSub( &tmpimagePoints, &imgpt_i[k], &tmpimagePoints );23142315if( solver.state == CvLevMarq::CALC_J )2316{2317int iofs = (nimages+1)*6 + k*NINTRINSIC, eofs = (i+1)*6;2318assert( JtJ && JtErr );23192320Mat _JtJ(cvarrToMat(JtJ)), _JtErr(cvarrToMat(JtErr));23212322if( k == 1 )2323{2324// d(err_{x|y}R) ~ de32325// convert de3/{dr3,dt3} => de3{dr1,dt1} & de3{dr2,dt2}2326for( p = 0; p < ni*2; p++ )2327{2328CvMat de3dr3 = cvMat( 1, 3, CV_64F, Je.ptr(p));2329CvMat de3dt3 = cvMat( 1, 3, CV_64F, de3dr3.data.db + 3 );2330CvMat de3dr2 = cvMat( 1, 3, CV_64F, J_LR.ptr(p) );2331CvMat de3dt2 = cvMat( 1, 3, CV_64F, de3dr2.data.db + 3 );2332double _de3dr1[3], _de3dt1[3];2333CvMat de3dr1 = cvMat( 1, 3, CV_64F, _de3dr1 );2334CvMat de3dt1 = cvMat( 1, 3, CV_64F, _de3dt1 );23352336cvMatMul( &de3dr3, &dr3dr1, &de3dr1 );2337cvMatMul( &de3dt3, &dt3dt1, &de3dt1 );23382339cvMatMul( &de3dr3, &dr3dr2, &de3dr2 );2340cvMatMulAdd( &de3dt3, &dt3dr2, &de3dr2, &de3dr2 );23412342cvMatMul( &de3dt3, &dt3dt2, &de3dt2 );23432344cvCopy( &de3dr1, &de3dr3 );2345cvCopy( &de3dt1, &de3dt3 );2346}23472348_JtJ(Rect(0, 0, 6, 6)) += J_LR.t()*J_LR;2349_JtJ(Rect(eofs, 0, 6, 6)) = J_LR.t()*Je;2350_JtErr.rowRange(0, 6) += J_LR.t()*err;2351}23522353_JtJ(Rect(eofs, eofs, 6, 6)) += Je.t()*Je;2354_JtErr.rowRange(eofs, eofs + 6) += Je.t()*err;23552356if( recomputeIntrinsics )2357{2358_JtJ(Rect(iofs, iofs, NINTRINSIC, NINTRINSIC)) += Ji.t()*Ji;2359_JtJ(Rect(iofs, eofs, NINTRINSIC, 6)) += Je.t()*Ji;2360if( k == 1 )2361{2362_JtJ(Rect(iofs, 0, NINTRINSIC, 6)) += J_LR.t()*Ji;2363}2364_JtErr.rowRange(iofs, iofs + NINTRINSIC) += Ji.t()*err;2365}2366}23672368double viewErr = norm(err, NORM_L2SQR);23692370if(perViewErr)2371perViewErr->data.db[i*2 + k] = std::sqrt(viewErr/ni);23722373reprojErr += viewErr;2374}2375}2376if(_errNorm)2377*_errNorm = reprojErr;2378}23792380cvRodrigues2( &om_LR, &R_LR );2381if( matR->rows == 1 || matR->cols == 1 )2382cvConvert( &om_LR, matR );2383else2384cvConvert( &R_LR, matR );2385cvConvert( &T_LR, matT );23862387if( recomputeIntrinsics )2388{2389cvConvert( &K[0], _cameraMatrix1 );2390cvConvert( &K[1], _cameraMatrix2 );23912392for( k = 0; k < 2; k++ )2393{2394CvMat* distCoeffs = k == 0 ? _distCoeffs1 : _distCoeffs2;2395CvMat tdist = cvMat( distCoeffs->rows, distCoeffs->cols,2396CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), Dist[k].data.db );2397cvConvert( &tdist, distCoeffs );2398}2399}24002401if( matE || matF )2402{2403double* t = T_LR.data.db;2404double tx[] =2405{24060, -t[2], t[1],2407t[2], 0, -t[0],2408-t[1], t[0], 02409};2410CvMat Tx = cvMat(3, 3, CV_64F, tx);2411double e[9], f[9];2412CvMat E = cvMat(3, 3, CV_64F, e);2413CvMat F = cvMat(3, 3, CV_64F, f);2414cvMatMul( &Tx, &R_LR, &E );2415if( matE )2416cvConvert( &E, matE );2417if( matF )2418{2419double ik[9];2420CvMat iK = cvMat(3, 3, CV_64F, ik);2421cvInvert(&K[1], &iK);2422cvGEMM( &iK, &E, 1, 0, 0, &E, CV_GEMM_A_T );2423cvInvert(&K[0], &iK);2424cvMatMul(&E, &iK, &F);2425cvConvertScale( &F, matF, fabs(f[8]) > 0 ? 1./f[8] : 1 );2426}2427}24282429return std::sqrt(reprojErr/(pointsTotal*2));2430}2431double cvStereoCalibrate( const CvMat* _objectPoints, const CvMat* _imagePoints1,2432const CvMat* _imagePoints2, const CvMat* _npoints,2433CvMat* _cameraMatrix1, CvMat* _distCoeffs1,2434CvMat* _cameraMatrix2, CvMat* _distCoeffs2,2435CvSize imageSize, CvMat* matR, CvMat* matT,2436CvMat* matE, CvMat* matF,2437int flags,2438CvTermCriteria termCrit )2439{2440return cvStereoCalibrateImpl(_objectPoints, _imagePoints1, _imagePoints2, _npoints, _cameraMatrix1,2441_distCoeffs1, _cameraMatrix2, _distCoeffs2, imageSize, matR, matT, matE,2442matF, NULL, flags, termCrit);2443}24442445static void2446icvGetRectangles( const CvMat* cameraMatrix, const CvMat* distCoeffs,2447const CvMat* R, const CvMat* newCameraMatrix, CvSize imgSize,2448cv::Rect_<float>& inner, cv::Rect_<float>& outer )2449{2450const int N = 9;2451int x, y, k;2452cv::Ptr<CvMat> _pts(cvCreateMat(1, N*N, CV_32FC2));2453CvPoint2D32f* pts = (CvPoint2D32f*)(_pts->data.ptr);24542455for( y = k = 0; y < N; y++ )2456for( x = 0; x < N; x++ )2457pts[k++] = cvPoint2D32f((float)x*imgSize.width/(N-1),2458(float)y*imgSize.height/(N-1));24592460cvUndistortPoints(_pts, _pts, cameraMatrix, distCoeffs, R, newCameraMatrix);24612462float iX0=-FLT_MAX, iX1=FLT_MAX, iY0=-FLT_MAX, iY1=FLT_MAX;2463float oX0=FLT_MAX, oX1=-FLT_MAX, oY0=FLT_MAX, oY1=-FLT_MAX;2464// find the inscribed rectangle.2465// the code will likely not work with extreme rotation matrices (R) (>45%)2466for( y = k = 0; y < N; y++ )2467for( x = 0; x < N; x++ )2468{2469CvPoint2D32f p = pts[k++];2470oX0 = MIN(oX0, p.x);2471oX1 = MAX(oX1, p.x);2472oY0 = MIN(oY0, p.y);2473oY1 = MAX(oY1, p.y);24742475if( x == 0 )2476iX0 = MAX(iX0, p.x);2477if( x == N-1 )2478iX1 = MIN(iX1, p.x);2479if( y == 0 )2480iY0 = MAX(iY0, p.y);2481if( y == N-1 )2482iY1 = MIN(iY1, p.y);2483}2484inner = cv::Rect_<float>(iX0, iY0, iX1-iX0, iY1-iY0);2485outer = cv::Rect_<float>(oX0, oY0, oX1-oX0, oY1-oY0);2486}248724882489void cvStereoRectify( const CvMat* _cameraMatrix1, const CvMat* _cameraMatrix2,2490const CvMat* _distCoeffs1, const CvMat* _distCoeffs2,2491CvSize imageSize, const CvMat* matR, const CvMat* matT,2492CvMat* _R1, CvMat* _R2, CvMat* _P1, CvMat* _P2,2493CvMat* matQ, int flags, double alpha, CvSize newImgSize,2494CvRect* roi1, CvRect* roi2 )2495{2496double _om[3], _t[3] = {0}, _uu[3]={0,0,0}, _r_r[3][3], _pp[3][4];2497double _ww[3], _wr[3][3], _z[3] = {0,0,0}, _ri[3][3], _w3[3];2498cv::Rect_<float> inner1, inner2, outer1, outer2;24992500CvMat om = cvMat(3, 1, CV_64F, _om);2501CvMat t = cvMat(3, 1, CV_64F, _t);2502CvMat uu = cvMat(3, 1, CV_64F, _uu);2503CvMat r_r = cvMat(3, 3, CV_64F, _r_r);2504CvMat pp = cvMat(3, 4, CV_64F, _pp);2505CvMat ww = cvMat(3, 1, CV_64F, _ww); // temps2506CvMat w3 = cvMat(3, 1, CV_64F, _w3); // temps2507CvMat wR = cvMat(3, 3, CV_64F, _wr);2508CvMat Z = cvMat(3, 1, CV_64F, _z);2509CvMat Ri = cvMat(3, 3, CV_64F, _ri);2510double nx = imageSize.width, ny = imageSize.height;2511int i, k;2512double nt, nw;25132514if( matR->rows == 3 && matR->cols == 3 )2515cvRodrigues2(matR, &om); // get vector rotation2516else2517cvConvert(matR, &om); // it's already a rotation vector2518cvConvertScale(&om, &om, -0.5); // get average rotation2519cvRodrigues2(&om, &r_r); // rotate cameras to same orientation by averaging2520cvMatMul(&r_r, matT, &t);25212522int idx = fabs(_t[0]) > fabs(_t[1]) ? 0 : 1;25232524// if idx == 02525// e1 = T / ||T||2526// e2 = e1 x [0,0,1]25272528// if idx == 12529// e2 = T / ||T||2530// e1 = e2 x [0,0,1]25312532// e3 = e1 x e225332534_uu[2] = 1;2535cvCrossProduct(&uu, &t, &ww);2536nt = cvNorm(&t, 0, CV_L2);2537CV_Assert(fabs(nt) > 0);2538nw = cvNorm(&ww, 0, CV_L2);2539CV_Assert(fabs(nw) > 0);2540cvConvertScale(&ww, &ww, 1 / nw);2541cvCrossProduct(&t, &ww, &w3);2542nw = cvNorm(&w3, 0, CV_L2);2543CV_Assert(fabs(nw) > 0);2544cvConvertScale(&w3, &w3, 1 / nw);2545_uu[2] = 0;25462547for (i = 0; i < 3; ++i)2548{2549_wr[idx][i] = -_t[i] / nt;2550_wr[idx ^ 1][i] = -_ww[i];2551_wr[2][i] = _w3[i] * (1 - 2 * idx); // if idx == 1 -> opposite direction2552}25532554// apply to both views2555cvGEMM(&wR, &r_r, 1, 0, 0, &Ri, CV_GEMM_B_T);2556cvConvert( &Ri, _R1 );2557cvGEMM(&wR, &r_r, 1, 0, 0, &Ri, 0);2558cvConvert( &Ri, _R2 );2559cvMatMul(&Ri, matT, &t);25602561// calculate projection/camera matrices2562// these contain the relevant rectified image internal params (fx, fy=fx, cx, cy)2563double fc_new = DBL_MAX;2564CvPoint2D64f cc_new[2] = {};25652566newImgSize = newImgSize.width * newImgSize.height != 0 ? newImgSize : imageSize;2567const double ratio_x = (double)newImgSize.width / imageSize.width / 2;2568const double ratio_y = (double)newImgSize.height / imageSize.height / 2;2569const double ratio = idx == 1 ? ratio_x : ratio_y;2570fc_new = (cvmGet(_cameraMatrix1, idx ^ 1, idx ^ 1) + cvmGet(_cameraMatrix2, idx ^ 1, idx ^ 1)) * ratio;25712572for( k = 0; k < 2; k++ )2573{2574const CvMat* A = k == 0 ? _cameraMatrix1 : _cameraMatrix2;2575const CvMat* Dk = k == 0 ? _distCoeffs1 : _distCoeffs2;2576CvPoint2D32f _pts[4] = {};2577CvPoint3D32f _pts_3[4] = {};2578CvMat pts = cvMat(1, 4, CV_32FC2, _pts);2579CvMat pts_3 = cvMat(1, 4, CV_32FC3, _pts_3);25802581for( i = 0; i < 4; i++ )2582{2583int j = (i<2) ? 0 : 1;2584_pts[i].x = (float)((i % 2)*(nx));2585_pts[i].y = (float)(j*(ny));2586}2587cvUndistortPoints( &pts, &pts, A, Dk, 0, 0 );2588cvConvertPointsHomogeneous( &pts, &pts_3 );25892590//Change camera matrix to have cc=[0,0] and fc = fc_new2591double _a_tmp[3][3];2592CvMat A_tmp = cvMat(3, 3, CV_64F, _a_tmp);2593_a_tmp[0][0]=fc_new;2594_a_tmp[1][1]=fc_new;2595_a_tmp[0][2]=0.0;2596_a_tmp[1][2]=0.0;2597cvProjectPoints2( &pts_3, k == 0 ? _R1 : _R2, &Z, &A_tmp, 0, &pts );2598CvScalar avg = cvAvg(&pts);2599cc_new[k].x = (nx)/2 - avg.val[0];2600cc_new[k].y = (ny)/2 - avg.val[1];2601}26022603// vertical focal length must be the same for both images to keep the epipolar constraint2604// (for horizontal epipolar lines -- TBD: check for vertical epipolar lines)2605// use fy for fx also, for simplicity26062607// For simplicity, set the principal points for both cameras to be the average2608// of the two principal points (either one of or both x- and y- coordinates)2609if( flags & CALIB_ZERO_DISPARITY )2610{2611cc_new[0].x = cc_new[1].x = (cc_new[0].x + cc_new[1].x)*0.5;2612cc_new[0].y = cc_new[1].y = (cc_new[0].y + cc_new[1].y)*0.5;2613}2614else if( idx == 0 ) // horizontal stereo2615cc_new[0].y = cc_new[1].y = (cc_new[0].y + cc_new[1].y)*0.5;2616else // vertical stereo2617cc_new[0].x = cc_new[1].x = (cc_new[0].x + cc_new[1].x)*0.5;26182619cvZero( &pp );2620_pp[0][0] = _pp[1][1] = fc_new;2621_pp[0][2] = cc_new[0].x;2622_pp[1][2] = cc_new[0].y;2623_pp[2][2] = 1;2624cvConvert(&pp, _P1);26252626_pp[0][2] = cc_new[1].x;2627_pp[1][2] = cc_new[1].y;2628_pp[idx][3] = _t[idx]*fc_new; // baseline * focal length2629cvConvert(&pp, _P2);26302631alpha = MIN(alpha, 1.);26322633icvGetRectangles( _cameraMatrix1, _distCoeffs1, _R1, _P1, imageSize, inner1, outer1 );2634icvGetRectangles( _cameraMatrix2, _distCoeffs2, _R2, _P2, imageSize, inner2, outer2 );26352636{2637newImgSize = newImgSize.width*newImgSize.height != 0 ? newImgSize : imageSize;2638double cx1_0 = cc_new[0].x;2639double cy1_0 = cc_new[0].y;2640double cx2_0 = cc_new[1].x;2641double cy2_0 = cc_new[1].y;2642double cx1 = newImgSize.width*cx1_0/imageSize.width;2643double cy1 = newImgSize.height*cy1_0/imageSize.height;2644double cx2 = newImgSize.width*cx2_0/imageSize.width;2645double cy2 = newImgSize.height*cy2_0/imageSize.height;2646double s = 1.;26472648if( alpha >= 0 )2649{2650double s0 = std::max(std::max(std::max((double)cx1/(cx1_0 - inner1.x), (double)cy1/(cy1_0 - inner1.y)),2651(double)(newImgSize.width - cx1)/(inner1.x + inner1.width - cx1_0)),2652(double)(newImgSize.height - cy1)/(inner1.y + inner1.height - cy1_0));2653s0 = std::max(std::max(std::max(std::max((double)cx2/(cx2_0 - inner2.x), (double)cy2/(cy2_0 - inner2.y)),2654(double)(newImgSize.width - cx2)/(inner2.x + inner2.width - cx2_0)),2655(double)(newImgSize.height - cy2)/(inner2.y + inner2.height - cy2_0)),2656s0);26572658double s1 = std::min(std::min(std::min((double)cx1/(cx1_0 - outer1.x), (double)cy1/(cy1_0 - outer1.y)),2659(double)(newImgSize.width - cx1)/(outer1.x + outer1.width - cx1_0)),2660(double)(newImgSize.height - cy1)/(outer1.y + outer1.height - cy1_0));2661s1 = std::min(std::min(std::min(std::min((double)cx2/(cx2_0 - outer2.x), (double)cy2/(cy2_0 - outer2.y)),2662(double)(newImgSize.width - cx2)/(outer2.x + outer2.width - cx2_0)),2663(double)(newImgSize.height - cy2)/(outer2.y + outer2.height - cy2_0)),2664s1);26652666s = s0*(1 - alpha) + s1*alpha;2667}26682669fc_new *= s;2670cc_new[0] = cvPoint2D64f(cx1, cy1);2671cc_new[1] = cvPoint2D64f(cx2, cy2);26722673cvmSet(_P1, 0, 0, fc_new);2674cvmSet(_P1, 1, 1, fc_new);2675cvmSet(_P1, 0, 2, cx1);2676cvmSet(_P1, 1, 2, cy1);26772678cvmSet(_P2, 0, 0, fc_new);2679cvmSet(_P2, 1, 1, fc_new);2680cvmSet(_P2, 0, 2, cx2);2681cvmSet(_P2, 1, 2, cy2);2682cvmSet(_P2, idx, 3, s*cvmGet(_P2, idx, 3));26832684if(roi1)2685{2686*roi1 = cvRect(2687cv::Rect(cvCeil((inner1.x - cx1_0)*s + cx1),2688cvCeil((inner1.y - cy1_0)*s + cy1),2689cvFloor(inner1.width*s), cvFloor(inner1.height*s))2690& cv::Rect(0, 0, newImgSize.width, newImgSize.height)2691);2692}26932694if(roi2)2695{2696*roi2 = cvRect(2697cv::Rect(cvCeil((inner2.x - cx2_0)*s + cx2),2698cvCeil((inner2.y - cy2_0)*s + cy2),2699cvFloor(inner2.width*s), cvFloor(inner2.height*s))2700& cv::Rect(0, 0, newImgSize.width, newImgSize.height)2701);2702}2703}27042705if( matQ )2706{2707double q[] =2708{27091, 0, 0, -cc_new[0].x,27100, 1, 0, -cc_new[0].y,27110, 0, 0, fc_new,27120, 0, -1./_t[idx],2713(idx == 0 ? cc_new[0].x - cc_new[1].x : cc_new[0].y - cc_new[1].y)/_t[idx]2714};2715CvMat Q = cvMat(4, 4, CV_64F, q);2716cvConvert( &Q, matQ );2717}2718}271927202721void cvGetOptimalNewCameraMatrix( const CvMat* cameraMatrix, const CvMat* distCoeffs,2722CvSize imgSize, double alpha,2723CvMat* newCameraMatrix, CvSize newImgSize,2724CvRect* validPixROI, int centerPrincipalPoint )2725{2726cv::Rect_<float> inner, outer;2727newImgSize = newImgSize.width*newImgSize.height != 0 ? newImgSize : imgSize;27282729double M[3][3];2730CvMat matM = cvMat(3, 3, CV_64F, M);2731cvConvert(cameraMatrix, &matM);27322733if( centerPrincipalPoint )2734{2735double cx0 = M[0][2];2736double cy0 = M[1][2];2737double cx = (newImgSize.width)*0.5;2738double cy = (newImgSize.height)*0.5;27392740icvGetRectangles( cameraMatrix, distCoeffs, 0, cameraMatrix, imgSize, inner, outer );2741double s0 = std::max(std::max(std::max((double)cx/(cx0 - inner.x), (double)cy/(cy0 - inner.y)),2742(double)cx/(inner.x + inner.width - cx0)),2743(double)cy/(inner.y + inner.height - cy0));2744double s1 = std::min(std::min(std::min((double)cx/(cx0 - outer.x), (double)cy/(cy0 - outer.y)),2745(double)cx/(outer.x + outer.width - cx0)),2746(double)cy/(outer.y + outer.height - cy0));2747double s = s0*(1 - alpha) + s1*alpha;27482749M[0][0] *= s;2750M[1][1] *= s;2751M[0][2] = cx;2752M[1][2] = cy;27532754if( validPixROI )2755{2756inner = cv::Rect_<float>((float)((inner.x - cx0)*s + cx),2757(float)((inner.y - cy0)*s + cy),2758(float)(inner.width*s),2759(float)(inner.height*s));2760cv::Rect r(cvCeil(inner.x), cvCeil(inner.y), cvFloor(inner.width), cvFloor(inner.height));2761r &= cv::Rect(0, 0, newImgSize.width, newImgSize.height);2762*validPixROI = cvRect(r);2763}2764}2765else2766{2767// Get inscribed and circumscribed rectangles in normalized2768// (independent of camera matrix) coordinates2769icvGetRectangles( cameraMatrix, distCoeffs, 0, 0, imgSize, inner, outer );27702771// Projection mapping inner rectangle to viewport2772double fx0 = (newImgSize.width) / inner.width;2773double fy0 = (newImgSize.height) / inner.height;2774double cx0 = -fx0 * inner.x;2775double cy0 = -fy0 * inner.y;27762777// Projection mapping outer rectangle to viewport2778double fx1 = (newImgSize.width) / outer.width;2779double fy1 = (newImgSize.height) / outer.height;2780double cx1 = -fx1 * outer.x;2781double cy1 = -fy1 * outer.y;27822783// Interpolate between the two optimal projections2784M[0][0] = fx0*(1 - alpha) + fx1*alpha;2785M[1][1] = fy0*(1 - alpha) + fy1*alpha;2786M[0][2] = cx0*(1 - alpha) + cx1*alpha;2787M[1][2] = cy0*(1 - alpha) + cy1*alpha;27882789if( validPixROI )2790{2791icvGetRectangles( cameraMatrix, distCoeffs, 0, &matM, imgSize, inner, outer );2792cv::Rect r = inner;2793r &= cv::Rect(0, 0, newImgSize.width, newImgSize.height);2794*validPixROI = cvRect(r);2795}2796}27972798cvConvert(&matM, newCameraMatrix);2799}280028012802CV_IMPL int cvStereoRectifyUncalibrated(2803const CvMat* _points1, const CvMat* _points2,2804const CvMat* F0, CvSize imgSize,2805CvMat* _H1, CvMat* _H2, double threshold )2806{2807Ptr<CvMat> _m1, _m2, _lines1, _lines2;28082809int i, j, npoints;2810double cx, cy;2811double u[9], v[9], w[9], f[9], h1[9], h2[9], h0[9], e2[3] = {0};2812CvMat E2 = cvMat( 3, 1, CV_64F, e2 );2813CvMat U = cvMat( 3, 3, CV_64F, u );2814CvMat V = cvMat( 3, 3, CV_64F, v );2815CvMat W = cvMat( 3, 3, CV_64F, w );2816CvMat F = cvMat( 3, 3, CV_64F, f );2817CvMat H1 = cvMat( 3, 3, CV_64F, h1 );2818CvMat H2 = cvMat( 3, 3, CV_64F, h2 );2819CvMat H0 = cvMat( 3, 3, CV_64F, h0 );28202821CvPoint2D64f* m1;2822CvPoint2D64f* m2;2823CvPoint3D64f* lines1;2824CvPoint3D64f* lines2;28252826CV_Assert( CV_IS_MAT(_points1) && CV_IS_MAT(_points2) &&2827CV_ARE_SIZES_EQ(_points1, _points2) );28282829npoints = _points1->rows * _points1->cols * CV_MAT_CN(_points1->type) / 2;28302831_m1.reset(cvCreateMat( _points1->rows, _points1->cols, CV_64FC(CV_MAT_CN(_points1->type)) ));2832_m2.reset(cvCreateMat( _points2->rows, _points2->cols, CV_64FC(CV_MAT_CN(_points2->type)) ));2833_lines1.reset(cvCreateMat( 1, npoints, CV_64FC3 ));2834_lines2.reset(cvCreateMat( 1, npoints, CV_64FC3 ));28352836cvConvert( F0, &F );28372838cvSVD( (CvMat*)&F, &W, &U, &V, CV_SVD_U_T + CV_SVD_V_T );2839W.data.db[8] = 0.;2840cvGEMM( &U, &W, 1, 0, 0, &W, CV_GEMM_A_T );2841cvMatMul( &W, &V, &F );28422843cx = cvRound( (imgSize.width)*0.5 );2844cy = cvRound( (imgSize.height)*0.5 );28452846cvZero( _H1 );2847cvZero( _H2 );28482849cvConvert( _points1, _m1 );2850cvConvert( _points2, _m2 );2851cvReshape( _m1, _m1, 2, 1 );2852cvReshape( _m2, _m2, 2, 1 );28532854m1 = (CvPoint2D64f*)_m1->data.ptr;2855m2 = (CvPoint2D64f*)_m2->data.ptr;2856lines1 = (CvPoint3D64f*)_lines1->data.ptr;2857lines2 = (CvPoint3D64f*)_lines2->data.ptr;28582859if( threshold > 0 )2860{2861cvComputeCorrespondEpilines( _m1, 1, &F, _lines1 );2862cvComputeCorrespondEpilines( _m2, 2, &F, _lines2 );28632864// measure distance from points to the corresponding epilines, mark outliers2865for( i = j = 0; i < npoints; i++ )2866{2867if( fabs(m1[i].x*lines2[i].x +2868m1[i].y*lines2[i].y +2869lines2[i].z) <= threshold &&2870fabs(m2[i].x*lines1[i].x +2871m2[i].y*lines1[i].y +2872lines1[i].z) <= threshold )2873{2874if( j < i )2875{2876m1[j] = m1[i];2877m2[j] = m2[i];2878}2879j++;2880}2881}28822883npoints = j;2884if( npoints == 0 )2885return 0;2886}28872888_m1->cols = _m2->cols = npoints;2889memcpy( E2.data.db, U.data.db + 6, sizeof(e2));2890cvScale( &E2, &E2, e2[2] > 0 ? 1 : -1 );28912892double t[] =2893{28941, 0, -cx,28950, 1, -cy,28960, 0, 12897};2898CvMat T = cvMat(3, 3, CV_64F, t);2899cvMatMul( &T, &E2, &E2 );29002901int mirror = e2[0] < 0;2902double d = MAX(std::sqrt(e2[0]*e2[0] + e2[1]*e2[1]),DBL_EPSILON);2903double alpha = e2[0]/d;2904double beta = e2[1]/d;2905double r[] =2906{2907alpha, beta, 0,2908-beta, alpha, 0,29090, 0, 12910};2911CvMat R = cvMat(3, 3, CV_64F, r);2912cvMatMul( &R, &T, &T );2913cvMatMul( &R, &E2, &E2 );2914double invf = fabs(e2[2]) < 1e-6*fabs(e2[0]) ? 0 : -e2[2]/e2[0];2915double k[] =2916{29171, 0, 0,29180, 1, 0,2919invf, 0, 12920};2921CvMat K = cvMat(3, 3, CV_64F, k);2922cvMatMul( &K, &T, &H2 );2923cvMatMul( &K, &E2, &E2 );29242925double it[] =2926{29271, 0, cx,29280, 1, cy,29290, 0, 12930};2931CvMat iT = cvMat( 3, 3, CV_64F, it );2932cvMatMul( &iT, &H2, &H2 );29332934memcpy( E2.data.db, U.data.db + 6, sizeof(e2));2935cvScale( &E2, &E2, e2[2] > 0 ? 1 : -1 );29362937double e2_x[] =2938{29390, -e2[2], e2[1],2940e2[2], 0, -e2[0],2941-e2[1], e2[0], 02942};2943double e2_111[] =2944{2945e2[0], e2[0], e2[0],2946e2[1], e2[1], e2[1],2947e2[2], e2[2], e2[2],2948};2949CvMat E2_x = cvMat(3, 3, CV_64F, e2_x);2950CvMat E2_111 = cvMat(3, 3, CV_64F, e2_111);2951cvMatMulAdd(&E2_x, &F, &E2_111, &H0 );2952cvMatMul(&H2, &H0, &H0);2953CvMat E1=cvMat(3, 1, CV_64F, V.data.db+6);2954cvMatMul(&H0, &E1, &E1);29552956cvPerspectiveTransform( _m1, _m1, &H0 );2957cvPerspectiveTransform( _m2, _m2, &H2 );2958CvMat A = cvMat( 1, npoints, CV_64FC3, lines1 ), BxBy, B;2959double x[3] = {0};2960CvMat X = cvMat( 3, 1, CV_64F, x );2961cvConvertPointsHomogeneous( _m1, &A );2962cvReshape( &A, &A, 1, npoints );2963cvReshape( _m2, &BxBy, 1, npoints );2964cvGetCol( &BxBy, &B, 0 );2965cvSolve( &A, &B, &X, CV_SVD );29662967double ha[] =2968{2969x[0], x[1], x[2],29700, 1, 0,29710, 0, 12972};2973CvMat Ha = cvMat(3, 3, CV_64F, ha);2974cvMatMul( &Ha, &H0, &H1 );2975cvPerspectiveTransform( _m1, _m1, &Ha );29762977if( mirror )2978{2979double mm[] = { -1, 0, cx*2, 0, -1, cy*2, 0, 0, 1 };2980CvMat MM = cvMat(3, 3, CV_64F, mm);2981cvMatMul( &MM, &H1, &H1 );2982cvMatMul( &MM, &H2, &H2 );2983}29842985cvConvert( &H1, _H1 );2986cvConvert( &H2, _H2 );29872988return 1;2989}299029912992void cv::reprojectImageTo3D( InputArray _disparity,2993OutputArray __3dImage, InputArray _Qmat,2994bool handleMissingValues, int dtype )2995{2996CV_INSTRUMENT_REGION();29972998Mat disparity = _disparity.getMat(), Q = _Qmat.getMat();2999int stype = disparity.type();30003001CV_Assert( stype == CV_8UC1 || stype == CV_16SC1 ||3002stype == CV_32SC1 || stype == CV_32FC1 );3003CV_Assert( Q.size() == Size(4,4) );30043005if( dtype < 0 )3006dtype = CV_32FC3;3007else3008{3009dtype = CV_MAKETYPE(CV_MAT_DEPTH(dtype), 3);3010CV_Assert( dtype == CV_16SC3 || dtype == CV_32SC3 || dtype == CV_32FC3 );3011}30123013__3dImage.create(disparity.size(), CV_MAKETYPE(dtype, 3));3014Mat _3dImage = __3dImage.getMat();30153016const float bigZ = 10000.f;3017Matx44d _Q;3018Q.convertTo(_Q, CV_64F);30193020int x, cols = disparity.cols;3021CV_Assert( cols >= 0 );30223023std::vector<float> _sbuf(cols);3024std::vector<Vec3f> _dbuf(cols);3025float* sbuf = &_sbuf[0];3026Vec3f* dbuf = &_dbuf[0];3027double minDisparity = FLT_MAX;30283029// NOTE: here we quietly assume that at least one pixel in the disparity map is not defined.3030// and we set the corresponding Z's to some fixed big value.3031if( handleMissingValues )3032cv::minMaxIdx( disparity, &minDisparity, 0, 0, 0 );30333034for( int y = 0; y < disparity.rows; y++ )3035{3036float* sptr = sbuf;3037Vec3f* dptr = dbuf;30383039if( stype == CV_8UC1 )3040{3041const uchar* sptr0 = disparity.ptr<uchar>(y);3042for( x = 0; x < cols; x++ )3043sptr[x] = (float)sptr0[x];3044}3045else if( stype == CV_16SC1 )3046{3047const short* sptr0 = disparity.ptr<short>(y);3048for( x = 0; x < cols; x++ )3049sptr[x] = (float)sptr0[x];3050}3051else if( stype == CV_32SC1 )3052{3053const int* sptr0 = disparity.ptr<int>(y);3054for( x = 0; x < cols; x++ )3055sptr[x] = (float)sptr0[x];3056}3057else3058sptr = disparity.ptr<float>(y);30593060if( dtype == CV_32FC3 )3061dptr = _3dImage.ptr<Vec3f>(y);30623063for( x = 0; x < cols; x++)3064{3065double d = sptr[x];3066Vec4d homg_pt = _Q*Vec4d(x, y, d, 1.0);3067dptr[x] = Vec3d(homg_pt.val);3068dptr[x] /= homg_pt[3];30693070if( fabs(d-minDisparity) <= FLT_EPSILON )3071dptr[x][2] = bigZ;3072}30733074if( dtype == CV_16SC3 )3075{3076Vec3s* dptr0 = _3dImage.ptr<Vec3s>(y);3077for( x = 0; x < cols; x++ )3078{3079dptr0[x] = dptr[x];3080}3081}3082else if( dtype == CV_32SC3 )3083{3084Vec3i* dptr0 = _3dImage.ptr<Vec3i>(y);3085for( x = 0; x < cols; x++ )3086{3087dptr0[x] = dptr[x];3088}3089}3090}3091}309230933094void cvReprojectImageTo3D( const CvArr* disparityImage,3095CvArr* _3dImage, const CvMat* matQ,3096int handleMissingValues )3097{3098cv::Mat disp = cv::cvarrToMat(disparityImage);3099cv::Mat _3dimg = cv::cvarrToMat(_3dImage);3100cv::Mat mq = cv::cvarrToMat(matQ);3101CV_Assert( disp.size() == _3dimg.size() );3102int dtype = _3dimg.type();3103CV_Assert( dtype == CV_16SC3 || dtype == CV_32SC3 || dtype == CV_32FC3 );31043105cv::reprojectImageTo3D(disp, _3dimg, mq, handleMissingValues != 0, dtype );3106}310731083109CV_IMPL void3110cvRQDecomp3x3( const CvMat *matrixM, CvMat *matrixR, CvMat *matrixQ,3111CvMat *matrixQx, CvMat *matrixQy, CvMat *matrixQz,3112CvPoint3D64f *eulerAngles)3113{3114double matM[3][3], matR[3][3], matQ[3][3];3115CvMat M = cvMat(3, 3, CV_64F, matM);3116CvMat R = cvMat(3, 3, CV_64F, matR);3117CvMat Q = cvMat(3, 3, CV_64F, matQ);3118double z, c, s;31193120/* Validate parameters. */3121CV_Assert( CV_IS_MAT(matrixM) && CV_IS_MAT(matrixR) && CV_IS_MAT(matrixQ) &&3122matrixM->cols == 3 && matrixM->rows == 3 &&3123CV_ARE_SIZES_EQ(matrixM, matrixR) && CV_ARE_SIZES_EQ(matrixM, matrixQ));31243125cvConvert(matrixM, &M);31263127/* Find Givens rotation Q_x for x axis (left multiplication). */3128/*3129( 1 0 0 )3130Qx = ( 0 c s ), c = m33/sqrt(m32^2 + m33^2), s = m32/sqrt(m32^2 + m33^2)3131( 0 -s c )3132*/3133s = matM[2][1];3134c = matM[2][2];3135z = 1./std::sqrt(c * c + s * s + DBL_EPSILON);3136c *= z;3137s *= z;31383139double _Qx[3][3] = { {1, 0, 0}, {0, c, s}, {0, -s, c} };3140CvMat Qx = cvMat(3, 3, CV_64F, _Qx);31413142cvMatMul(&M, &Qx, &R);3143assert(fabs(matR[2][1]) < FLT_EPSILON);3144matR[2][1] = 0;31453146/* Find Givens rotation for y axis. */3147/*3148( c 0 -s )3149Qy = ( 0 1 0 ), c = m33/sqrt(m31^2 + m33^2), s = -m31/sqrt(m31^2 + m33^2)3150( s 0 c )3151*/3152s = -matR[2][0];3153c = matR[2][2];3154z = 1./std::sqrt(c * c + s * s + DBL_EPSILON);3155c *= z;3156s *= z;31573158double _Qy[3][3] = { {c, 0, -s}, {0, 1, 0}, {s, 0, c} };3159CvMat Qy = cvMat(3, 3, CV_64F, _Qy);3160cvMatMul(&R, &Qy, &M);31613162assert(fabs(matM[2][0]) < FLT_EPSILON);3163matM[2][0] = 0;31643165/* Find Givens rotation for z axis. */3166/*3167( c s 0 )3168Qz = (-s c 0 ), c = m22/sqrt(m21^2 + m22^2), s = m21/sqrt(m21^2 + m22^2)3169( 0 0 1 )3170*/31713172s = matM[1][0];3173c = matM[1][1];3174z = 1./std::sqrt(c * c + s * s + DBL_EPSILON);3175c *= z;3176s *= z;31773178double _Qz[3][3] = { {c, s, 0}, {-s, c, 0}, {0, 0, 1} };3179CvMat Qz = cvMat(3, 3, CV_64F, _Qz);31803181cvMatMul(&M, &Qz, &R);3182assert(fabs(matR[1][0]) < FLT_EPSILON);3183matR[1][0] = 0;31843185// Solve the decomposition ambiguity.3186// Diagonal entries of R, except the last one, shall be positive.3187// Further rotate R by 180 degree if necessary3188if( matR[0][0] < 0 )3189{3190if( matR[1][1] < 0 )3191{3192// rotate around z for 180 degree, i.e. a rotation matrix of3193// [-1, 0, 0],3194// [ 0, -1, 0],3195// [ 0, 0, 1]3196matR[0][0] *= -1;3197matR[0][1] *= -1;3198matR[1][1] *= -1;31993200_Qz[0][0] *= -1;3201_Qz[0][1] *= -1;3202_Qz[1][0] *= -1;3203_Qz[1][1] *= -1;3204}3205else3206{3207// rotate around y for 180 degree, i.e. a rotation matrix of3208// [-1, 0, 0],3209// [ 0, 1, 0],3210// [ 0, 0, -1]3211matR[0][0] *= -1;3212matR[0][2] *= -1;3213matR[1][2] *= -1;3214matR[2][2] *= -1;32153216cvTranspose( &Qz, &Qz );32173218_Qy[0][0] *= -1;3219_Qy[0][2] *= -1;3220_Qy[2][0] *= -1;3221_Qy[2][2] *= -1;3222}3223}3224else if( matR[1][1] < 0 )3225{3226// ??? for some reason, we never get here ???32273228// rotate around x for 180 degree, i.e. a rotation matrix of3229// [ 1, 0, 0],3230// [ 0, -1, 0],3231// [ 0, 0, -1]3232matR[0][1] *= -1;3233matR[0][2] *= -1;3234matR[1][1] *= -1;3235matR[1][2] *= -1;3236matR[2][2] *= -1;32373238cvTranspose( &Qz, &Qz );3239cvTranspose( &Qy, &Qy );32403241_Qx[1][1] *= -1;3242_Qx[1][2] *= -1;3243_Qx[2][1] *= -1;3244_Qx[2][2] *= -1;3245}32463247// calculate the euler angle3248if( eulerAngles )3249{3250eulerAngles->x = acos(_Qx[1][1]) * (_Qx[1][2] >= 0 ? 1 : -1) * (180.0 / CV_PI);3251eulerAngles->y = acos(_Qy[0][0]) * (_Qy[2][0] >= 0 ? 1 : -1) * (180.0 / CV_PI);3252eulerAngles->z = acos(_Qz[0][0]) * (_Qz[0][1] >= 0 ? 1 : -1) * (180.0 / CV_PI);3253}32543255/* Calculate orthogonal matrix. */3256/*3257Q = QzT * QyT * QxT3258*/3259cvGEMM( &Qz, &Qy, 1, 0, 0, &M, CV_GEMM_A_T + CV_GEMM_B_T );3260cvGEMM( &M, &Qx, 1, 0, 0, &Q, CV_GEMM_B_T );32613262/* Save R and Q matrices. */3263cvConvert( &R, matrixR );3264cvConvert( &Q, matrixQ );32653266if( matrixQx )3267cvConvert(&Qx, matrixQx);3268if( matrixQy )3269cvConvert(&Qy, matrixQy);3270if( matrixQz )3271cvConvert(&Qz, matrixQz);3272}327332743275CV_IMPL void3276cvDecomposeProjectionMatrix( const CvMat *projMatr, CvMat *calibMatr,3277CvMat *rotMatr, CvMat *posVect,3278CvMat *rotMatrX, CvMat *rotMatrY,3279CvMat *rotMatrZ, CvPoint3D64f *eulerAngles)3280{3281double tmpProjMatrData[16], tmpMatrixDData[16], tmpMatrixVData[16];3282CvMat tmpProjMatr = cvMat(4, 4, CV_64F, tmpProjMatrData);3283CvMat tmpMatrixD = cvMat(4, 4, CV_64F, tmpMatrixDData);3284CvMat tmpMatrixV = cvMat(4, 4, CV_64F, tmpMatrixVData);3285CvMat tmpMatrixM;32863287/* Validate parameters. */3288if(projMatr == 0 || calibMatr == 0 || rotMatr == 0 || posVect == 0)3289CV_Error(CV_StsNullPtr, "Some of parameters is a NULL pointer!");32903291if(!CV_IS_MAT(projMatr) || !CV_IS_MAT(calibMatr) || !CV_IS_MAT(rotMatr) || !CV_IS_MAT(posVect))3292CV_Error(CV_StsUnsupportedFormat, "Input parameters must be a matrices!");32933294if(projMatr->cols != 4 || projMatr->rows != 3)3295CV_Error(CV_StsUnmatchedSizes, "Size of projection matrix must be 3x4!");32963297if(calibMatr->cols != 3 || calibMatr->rows != 3 || rotMatr->cols != 3 || rotMatr->rows != 3)3298CV_Error(CV_StsUnmatchedSizes, "Size of calibration and rotation matrices must be 3x3!");32993300if(posVect->cols != 1 || posVect->rows != 4)3301CV_Error(CV_StsUnmatchedSizes, "Size of position vector must be 4x1!");33023303/* Compute position vector. */3304cvSetZero(&tmpProjMatr); // Add zero row to make matrix square.3305int i, k;3306for(i = 0; i < 3; i++)3307for(k = 0; k < 4; k++)3308cvmSet(&tmpProjMatr, i, k, cvmGet(projMatr, i, k));33093310cvSVD(&tmpProjMatr, &tmpMatrixD, NULL, &tmpMatrixV, CV_SVD_MODIFY_A + CV_SVD_V_T);33113312/* Save position vector. */3313for(i = 0; i < 4; i++)3314cvmSet(posVect, i, 0, cvmGet(&tmpMatrixV, 3, i)); // Solution is last row of V.33153316/* Compute calibration and rotation matrices via RQ decomposition. */3317cvGetCols(projMatr, &tmpMatrixM, 0, 3); // M is first square matrix of P.33183319CV_Assert(cvDet(&tmpMatrixM) != 0.0); // So far only finite cameras could be decomposed, so M has to be nonsingular [det(M) != 0].33203321cvRQDecomp3x3(&tmpMatrixM, calibMatr, rotMatr, rotMatrX, rotMatrY, rotMatrZ, eulerAngles);3322}3323332433253326namespace cv3327{33283329static void collectCalibrationData( InputArrayOfArrays objectPoints,3330InputArrayOfArrays imagePoints1,3331InputArrayOfArrays imagePoints2,3332int iFixedPoint,3333Mat& objPtMat, Mat& imgPtMat1, Mat* imgPtMat2,3334Mat& npoints )3335{3336int nimages = (int)objectPoints.total();3337int i, j = 0, ni = 0, total = 0;3338CV_Assert(nimages > 0 && nimages == (int)imagePoints1.total() &&3339(!imgPtMat2 || nimages == (int)imagePoints2.total()));33403341for( i = 0; i < nimages; i++ )3342{3343ni = objectPoints.getMat(i).checkVector(3, CV_32F);3344if( ni <= 0 )3345CV_Error(CV_StsUnsupportedFormat, "objectPoints should contain vector of vectors of points of type Point3f");3346int ni1 = imagePoints1.getMat(i).checkVector(2, CV_32F);3347if( ni1 <= 0 )3348CV_Error(CV_StsUnsupportedFormat, "imagePoints1 should contain vector of vectors of points of type Point2f");3349CV_Assert( ni == ni1 );33503351total += ni;3352}33533354npoints.create(1, (int)nimages, CV_32S);3355objPtMat.create(1, (int)total, CV_32FC3);3356imgPtMat1.create(1, (int)total, CV_32FC2);3357Point2f* imgPtData2 = 0;33583359if( imgPtMat2 )3360{3361imgPtMat2->create(1, (int)total, CV_32FC2);3362imgPtData2 = imgPtMat2->ptr<Point2f>();3363}33643365Point3f* objPtData = objPtMat.ptr<Point3f>();3366Point2f* imgPtData1 = imgPtMat1.ptr<Point2f>();33673368for( i = 0; i < nimages; i++, j += ni )3369{3370Mat objpt = objectPoints.getMat(i);3371Mat imgpt1 = imagePoints1.getMat(i);3372ni = objpt.checkVector(3, CV_32F);3373npoints.at<int>(i) = ni;3374for (int n = 0; n < ni; ++n)3375{3376objPtData[j + n] = objpt.ptr<Point3f>()[n];3377imgPtData1[j + n] = imgpt1.ptr<Point2f>()[n];3378}33793380if( imgPtData2 )3381{3382Mat imgpt2 = imagePoints2.getMat(i);3383int ni2 = imgpt2.checkVector(2, CV_32F);3384CV_Assert( ni == ni2 );3385for (int n = 0; n < ni2; ++n)3386{3387imgPtData2[j + n] = imgpt2.ptr<Point2f>()[n];3388}3389}3390}33913392ni = npoints.at<int>(0);3393bool releaseObject = iFixedPoint > 0 && iFixedPoint < ni - 1;3394// check object points. If not qualified, report errors.3395if( releaseObject )3396{3397for( i = 1; i < nimages; i++ )3398{3399if( npoints.at<int>(i) != ni )3400{3401CV_Error( CV_StsBadArg, "All objectPoints[i].size() should be equal when "3402"object-releasing method is requested." );3403}3404Mat ocmp = objPtMat.colRange(ni * i, ni * i + ni) != objPtMat.colRange(0, ni);3405ocmp = ocmp.reshape(1);3406if( countNonZero(ocmp) )3407{3408CV_Error( CV_StsBadArg, "All objectPoints[i] should be identical when object-releasing"3409" method is requested." );3410}3411}3412}3413}34143415static void collectCalibrationData( InputArrayOfArrays objectPoints,3416InputArrayOfArrays imagePoints1,3417InputArrayOfArrays imagePoints2,3418Mat& objPtMat, Mat& imgPtMat1, Mat* imgPtMat2,3419Mat& npoints )3420{3421collectCalibrationData( objectPoints, imagePoints1, imagePoints2, -1, objPtMat, imgPtMat1,3422imgPtMat2, npoints );3423}34243425static Mat prepareCameraMatrix(Mat& cameraMatrix0, int rtype)3426{3427Mat cameraMatrix = Mat::eye(3, 3, rtype);3428if( cameraMatrix0.size() == cameraMatrix.size() )3429cameraMatrix0.convertTo(cameraMatrix, rtype);3430return cameraMatrix;3431}34323433static Mat prepareDistCoeffs(Mat& distCoeffs0, int rtype, int outputSize = 14)3434{3435CV_Assert((int)distCoeffs0.total() <= outputSize);3436Mat distCoeffs = Mat::zeros(distCoeffs0.cols == 1 ? Size(1, outputSize) : Size(outputSize, 1), rtype);3437if( distCoeffs0.size() == Size(1, 4) ||3438distCoeffs0.size() == Size(1, 5) ||3439distCoeffs0.size() == Size(1, 8) ||3440distCoeffs0.size() == Size(1, 12) ||3441distCoeffs0.size() == Size(1, 14) ||3442distCoeffs0.size() == Size(4, 1) ||3443distCoeffs0.size() == Size(5, 1) ||3444distCoeffs0.size() == Size(8, 1) ||3445distCoeffs0.size() == Size(12, 1) ||3446distCoeffs0.size() == Size(14, 1) )3447{3448Mat dstCoeffs(distCoeffs, Rect(0, 0, distCoeffs0.cols, distCoeffs0.rows));3449distCoeffs0.convertTo(dstCoeffs, rtype);3450}3451return distCoeffs;3452}34533454} // namespace cv345534563457void cv::Rodrigues(InputArray _src, OutputArray _dst, OutputArray _jacobian)3458{3459CV_INSTRUMENT_REGION();34603461Mat src = _src.getMat();3462bool v2m = src.cols == 1 || src.rows == 1;3463_dst.create(3, v2m ? 3 : 1, src.depth());3464Mat dst = _dst.getMat();3465CvMat _csrc = cvMat(src), _cdst = cvMat(dst), _cjacobian;3466if( _jacobian.needed() )3467{3468_jacobian.create(v2m ? Size(9, 3) : Size(3, 9), src.depth());3469_cjacobian = cvMat(_jacobian.getMat());3470}3471bool ok = cvRodrigues2(&_csrc, &_cdst, _jacobian.needed() ? &_cjacobian : 0) > 0;3472if( !ok )3473dst = Scalar(0);3474}34753476void cv::matMulDeriv( InputArray _Amat, InputArray _Bmat,3477OutputArray _dABdA, OutputArray _dABdB )3478{3479CV_INSTRUMENT_REGION();34803481Mat A = _Amat.getMat(), B = _Bmat.getMat();3482_dABdA.create(A.rows*B.cols, A.rows*A.cols, A.type());3483_dABdB.create(A.rows*B.cols, B.rows*B.cols, A.type());3484Mat dABdA = _dABdA.getMat(), dABdB = _dABdB.getMat();3485CvMat matA = cvMat(A), matB = cvMat(B), c_dABdA = cvMat(dABdA), c_dABdB = cvMat(dABdB);3486cvCalcMatMulDeriv(&matA, &matB, &c_dABdA, &c_dABdB);3487}348834893490void cv::composeRT( InputArray _rvec1, InputArray _tvec1,3491InputArray _rvec2, InputArray _tvec2,3492OutputArray _rvec3, OutputArray _tvec3,3493OutputArray _dr3dr1, OutputArray _dr3dt1,3494OutputArray _dr3dr2, OutputArray _dr3dt2,3495OutputArray _dt3dr1, OutputArray _dt3dt1,3496OutputArray _dt3dr2, OutputArray _dt3dt2 )3497{3498Mat rvec1 = _rvec1.getMat(), tvec1 = _tvec1.getMat();3499Mat rvec2 = _rvec2.getMat(), tvec2 = _tvec2.getMat();3500int rtype = rvec1.type();3501_rvec3.create(rvec1.size(), rtype);3502_tvec3.create(tvec1.size(), rtype);3503Mat rvec3 = _rvec3.getMat(), tvec3 = _tvec3.getMat();35043505CvMat c_rvec1 = cvMat(rvec1), c_tvec1 = cvMat(tvec1), c_rvec2 = cvMat(rvec2),3506c_tvec2 = cvMat(tvec2), c_rvec3 = cvMat(rvec3), c_tvec3 = cvMat(tvec3);3507CvMat c_dr3dr1, c_dr3dt1, c_dr3dr2, c_dr3dt2, c_dt3dr1, c_dt3dt1, c_dt3dr2, c_dt3dt2;3508CvMat *p_dr3dr1=0, *p_dr3dt1=0, *p_dr3dr2=0, *p_dr3dt2=0, *p_dt3dr1=0, *p_dt3dt1=0, *p_dt3dr2=0, *p_dt3dt2=0;3509#define CV_COMPOSE_RT_PARAM(name) \3510Mat name; \3511if (_ ## name.needed())\3512{ \3513_ ## name.create(3, 3, rtype); \3514name = _ ## name.getMat(); \3515p_ ## name = &(c_ ## name = cvMat(name)); \3516}35173518CV_COMPOSE_RT_PARAM(dr3dr1); CV_COMPOSE_RT_PARAM(dr3dt1);3519CV_COMPOSE_RT_PARAM(dr3dr2); CV_COMPOSE_RT_PARAM(dr3dt2);3520CV_COMPOSE_RT_PARAM(dt3dr1); CV_COMPOSE_RT_PARAM(dt3dt1);3521CV_COMPOSE_RT_PARAM(dt3dr2); CV_COMPOSE_RT_PARAM(dt3dt2);3522#undef CV_COMPOSE_RT_PARAM35233524cvComposeRT(&c_rvec1, &c_tvec1, &c_rvec2, &c_tvec2, &c_rvec3, &c_tvec3,3525p_dr3dr1, p_dr3dt1, p_dr3dr2, p_dr3dt2,3526p_dt3dr1, p_dt3dt1, p_dt3dr2, p_dt3dt2);3527}352835293530void cv::projectPoints( InputArray _opoints,3531InputArray _rvec,3532InputArray _tvec,3533InputArray _cameraMatrix,3534InputArray _distCoeffs,3535OutputArray _ipoints,3536OutputArray _jacobian,3537double aspectRatio )3538{3539Mat opoints = _opoints.getMat();3540int npoints = opoints.checkVector(3), depth = opoints.depth();3541CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_64F));35423543CvMat dpdrot, dpdt, dpdf, dpdc, dpddist;3544CvMat *pdpdrot=0, *pdpdt=0, *pdpdf=0, *pdpdc=0, *pdpddist=0;35453546_ipoints.create(npoints, 1, CV_MAKETYPE(depth, 2), -1, true);3547Mat imagePoints = _ipoints.getMat();3548CvMat c_imagePoints = cvMat(imagePoints);3549CvMat c_objectPoints = cvMat(opoints);3550Mat cameraMatrix = _cameraMatrix.getMat();35513552Mat rvec = _rvec.getMat(), tvec = _tvec.getMat();3553CvMat c_cameraMatrix = cvMat(cameraMatrix);3554CvMat c_rvec = cvMat(rvec), c_tvec = cvMat(tvec);35553556double dc0buf[5]={0};3557Mat dc0(5,1,CV_64F,dc0buf);3558Mat distCoeffs = _distCoeffs.getMat();3559if( distCoeffs.empty() )3560distCoeffs = dc0;3561CvMat c_distCoeffs = cvMat(distCoeffs);3562int ndistCoeffs = distCoeffs.rows + distCoeffs.cols - 1;35633564Mat jacobian;3565if( _jacobian.needed() )3566{3567_jacobian.create(npoints*2, 3+3+2+2+ndistCoeffs, CV_64F);3568jacobian = _jacobian.getMat();3569pdpdrot = &(dpdrot = cvMat(jacobian.colRange(0, 3)));3570pdpdt = &(dpdt = cvMat(jacobian.colRange(3, 6)));3571pdpdf = &(dpdf = cvMat(jacobian.colRange(6, 8)));3572pdpdc = &(dpdc = cvMat(jacobian.colRange(8, 10)));3573pdpddist = &(dpddist = cvMat(jacobian.colRange(10, 10+ndistCoeffs)));3574}35753576cvProjectPoints2( &c_objectPoints, &c_rvec, &c_tvec, &c_cameraMatrix, &c_distCoeffs,3577&c_imagePoints, pdpdrot, pdpdt, pdpdf, pdpdc, pdpddist, aspectRatio );3578}35793580cv::Mat cv::initCameraMatrix2D( InputArrayOfArrays objectPoints,3581InputArrayOfArrays imagePoints,3582Size imageSize, double aspectRatio )3583{3584CV_INSTRUMENT_REGION();35853586Mat objPt, imgPt, npoints, cameraMatrix(3, 3, CV_64F);3587collectCalibrationData( objectPoints, imagePoints, noArray(),3588objPt, imgPt, 0, npoints );3589CvMat _objPt = cvMat(objPt), _imgPt = cvMat(imgPt), _npoints = cvMat(npoints), _cameraMatrix = cvMat(cameraMatrix);3590cvInitIntrinsicParams2D( &_objPt, &_imgPt, &_npoints,3591cvSize(imageSize), &_cameraMatrix, aspectRatio );3592return cameraMatrix;3593}3594359535963597double cv::calibrateCamera( InputArrayOfArrays _objectPoints,3598InputArrayOfArrays _imagePoints,3599Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs,3600OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags, TermCriteria criteria )3601{3602CV_INSTRUMENT_REGION();36033604return calibrateCamera(_objectPoints, _imagePoints, imageSize, _cameraMatrix, _distCoeffs,3605_rvecs, _tvecs, noArray(), noArray(), noArray(), flags, criteria);3606}36073608double cv::calibrateCamera(InputArrayOfArrays _objectPoints,3609InputArrayOfArrays _imagePoints,3610Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs,3611OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs,3612OutputArray stdDeviationsIntrinsics,3613OutputArray stdDeviationsExtrinsics,3614OutputArray _perViewErrors, int flags, TermCriteria criteria )3615{3616CV_INSTRUMENT_REGION();36173618return calibrateCameraRO(_objectPoints, _imagePoints, imageSize, -1, _cameraMatrix, _distCoeffs,3619_rvecs, _tvecs, noArray(), stdDeviationsIntrinsics, stdDeviationsExtrinsics,3620noArray(), _perViewErrors, flags, criteria);3621}36223623double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints,3624InputArrayOfArrays _imagePoints,3625Size imageSize, int iFixedPoint, InputOutputArray _cameraMatrix,3626InputOutputArray _distCoeffs,3627OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs,3628OutputArray newObjPoints,3629int flags, TermCriteria criteria)3630{3631CV_INSTRUMENT_REGION();36323633return calibrateCameraRO(_objectPoints, _imagePoints, imageSize, iFixedPoint, _cameraMatrix,3634_distCoeffs, _rvecs, _tvecs, newObjPoints, noArray(), noArray(),3635noArray(), noArray(), flags, criteria);3636}36373638double cv::calibrateCameraRO(InputArrayOfArrays _objectPoints,3639InputArrayOfArrays _imagePoints,3640Size imageSize, int iFixedPoint, InputOutputArray _cameraMatrix,3641InputOutputArray _distCoeffs,3642OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs,3643OutputArray newObjPoints,3644OutputArray stdDeviationsIntrinsics,3645OutputArray stdDeviationsExtrinsics,3646OutputArray stdDeviationsObjPoints,3647OutputArray _perViewErrors, int flags, TermCriteria criteria )3648{3649CV_INSTRUMENT_REGION();36503651int rtype = CV_64F;3652Mat cameraMatrix = _cameraMatrix.getMat();3653cameraMatrix = prepareCameraMatrix(cameraMatrix, rtype);3654Mat distCoeffs = _distCoeffs.getMat();3655distCoeffs = (flags & CALIB_THIN_PRISM_MODEL) && !(flags & CALIB_TILTED_MODEL) ? prepareDistCoeffs(distCoeffs, rtype, 12) :3656prepareDistCoeffs(distCoeffs, rtype);3657if( !(flags & CALIB_RATIONAL_MODEL) &&3658(!(flags & CALIB_THIN_PRISM_MODEL)) &&3659(!(flags & CALIB_TILTED_MODEL)))3660distCoeffs = distCoeffs.rows == 1 ? distCoeffs.colRange(0, 5) : distCoeffs.rowRange(0, 5);36613662int nimages = int(_objectPoints.total());3663CV_Assert( nimages > 0 );3664Mat objPt, imgPt, npoints, rvecM, tvecM, stdDeviationsM, errorsM;36653666bool rvecs_needed = _rvecs.needed(), tvecs_needed = _tvecs.needed(),3667stddev_needed = stdDeviationsIntrinsics.needed(), errors_needed = _perViewErrors.needed(),3668stddev_ext_needed = stdDeviationsExtrinsics.needed();3669bool newobj_needed = newObjPoints.needed();3670bool stddev_obj_needed = stdDeviationsObjPoints.needed();36713672bool rvecs_mat_vec = _rvecs.isMatVector();3673bool tvecs_mat_vec = _tvecs.isMatVector();36743675if( rvecs_needed )3676{3677_rvecs.create(nimages, 1, CV_64FC3);36783679if(rvecs_mat_vec)3680rvecM.create(nimages, 3, CV_64F);3681else3682rvecM = _rvecs.getMat();3683}36843685if( tvecs_needed )3686{3687_tvecs.create(nimages, 1, CV_64FC3);36883689if(tvecs_mat_vec)3690tvecM.create(nimages, 3, CV_64F);3691else3692tvecM = _tvecs.getMat();3693}36943695collectCalibrationData( _objectPoints, _imagePoints, noArray(), iFixedPoint,3696objPt, imgPt, 0, npoints );3697bool releaseObject = iFixedPoint > 0 && iFixedPoint < npoints.at<int>(0) - 1;36983699newobj_needed = newobj_needed && releaseObject;3700int np = npoints.at<int>( 0 );3701Mat newObjPt;3702if( newobj_needed ) {3703newObjPoints.create( 1, np, CV_32FC3 );3704newObjPt = newObjPoints.getMat();3705}37063707stddev_obj_needed = stddev_obj_needed && releaseObject;3708bool stddev_any_needed = stddev_needed || stddev_ext_needed || stddev_obj_needed;3709if( stddev_any_needed )3710{3711if( releaseObject )3712stdDeviationsM.create(nimages*6 + CV_CALIB_NINTRINSIC + np * 3, 1, CV_64F);3713else3714stdDeviationsM.create(nimages*6 + CV_CALIB_NINTRINSIC, 1, CV_64F);3715}37163717if( errors_needed )3718{3719_perViewErrors.create(nimages, 1, CV_64F);3720errorsM = _perViewErrors.getMat();3721}37223723CvMat c_objPt = cvMat(objPt), c_imgPt = cvMat(imgPt), c_npoints = cvMat(npoints);3724CvMat c_cameraMatrix = cvMat(cameraMatrix), c_distCoeffs = cvMat(distCoeffs);3725CvMat c_rvecM = cvMat(rvecM), c_tvecM = cvMat(tvecM), c_stdDev = cvMat(stdDeviationsM), c_errors = cvMat(errorsM);3726CvMat c_newObjPt = cvMat( newObjPt );37273728double reprojErr = cvCalibrateCamera2Internal(&c_objPt, &c_imgPt, &c_npoints, cvSize(imageSize),3729iFixedPoint,3730&c_cameraMatrix, &c_distCoeffs,3731rvecs_needed ? &c_rvecM : NULL,3732tvecs_needed ? &c_tvecM : NULL,3733newobj_needed ? &c_newObjPt : NULL,3734stddev_any_needed ? &c_stdDev : NULL,3735errors_needed ? &c_errors : NULL, flags, cvTermCriteria(criteria));37363737if( newobj_needed )3738newObjPt.copyTo(newObjPoints);37393740if( stddev_needed )3741{3742stdDeviationsIntrinsics.create(CV_CALIB_NINTRINSIC, 1, CV_64F);3743Mat stdDeviationsIntrinsicsMat = stdDeviationsIntrinsics.getMat();3744std::memcpy(stdDeviationsIntrinsicsMat.ptr(), stdDeviationsM.ptr(),3745CV_CALIB_NINTRINSIC*sizeof(double));3746}37473748if ( stddev_ext_needed )3749{3750stdDeviationsExtrinsics.create(nimages*6, 1, CV_64F);3751Mat stdDeviationsExtrinsicsMat = stdDeviationsExtrinsics.getMat();3752std::memcpy(stdDeviationsExtrinsicsMat.ptr(),3753stdDeviationsM.ptr() + CV_CALIB_NINTRINSIC*sizeof(double),3754nimages*6*sizeof(double));3755}37563757if( stddev_obj_needed )3758{3759stdDeviationsObjPoints.create( np * 3, 1, CV_64F );3760Mat stdDeviationsObjPointsMat = stdDeviationsObjPoints.getMat();3761std::memcpy( stdDeviationsObjPointsMat.ptr(), stdDeviationsM.ptr()3762+ ( CV_CALIB_NINTRINSIC + nimages * 6 ) * sizeof( double ),3763np * 3 * sizeof( double ) );3764}37653766// overly complicated and inefficient rvec/ tvec handling to support vector<Mat>3767for(int i = 0; i < nimages; i++ )3768{3769if( rvecs_needed && rvecs_mat_vec)3770{3771_rvecs.create(3, 1, CV_64F, i, true);3772Mat rv = _rvecs.getMat(i);3773memcpy(rv.ptr(), rvecM.ptr(i), 3*sizeof(double));3774}3775if( tvecs_needed && tvecs_mat_vec)3776{3777_tvecs.create(3, 1, CV_64F, i, true);3778Mat tv = _tvecs.getMat(i);3779memcpy(tv.ptr(), tvecM.ptr(i), 3*sizeof(double));3780}3781}37823783cameraMatrix.copyTo(_cameraMatrix);3784distCoeffs.copyTo(_distCoeffs);37853786return reprojErr;3787}378837893790void cv::calibrationMatrixValues( InputArray _cameraMatrix, Size imageSize,3791double apertureWidth, double apertureHeight,3792double& fovx, double& fovy, double& focalLength,3793Point2d& principalPoint, double& aspectRatio )3794{3795CV_INSTRUMENT_REGION();37963797if(_cameraMatrix.size() != Size(3, 3))3798CV_Error(CV_StsUnmatchedSizes, "Size of cameraMatrix must be 3x3!");37993800Matx33d K = _cameraMatrix.getMat();38013802CV_DbgAssert(imageSize.width != 0 && imageSize.height != 0 && K(0, 0) != 0.0 && K(1, 1) != 0.0);38033804/* Calculate pixel aspect ratio. */3805aspectRatio = K(1, 1) / K(0, 0);38063807/* Calculate number of pixel per realworld unit. */3808double mx, my;3809if(apertureWidth != 0.0 && apertureHeight != 0.0) {3810mx = imageSize.width / apertureWidth;3811my = imageSize.height / apertureHeight;3812} else {3813mx = 1.0;3814my = aspectRatio;3815}38163817/* Calculate fovx and fovy. */3818fovx = atan2(K(0, 2), K(0, 0)) + atan2(imageSize.width - K(0, 2), K(0, 0));3819fovy = atan2(K(1, 2), K(1, 1)) + atan2(imageSize.height - K(1, 2), K(1, 1));3820fovx *= 180.0 / CV_PI;3821fovy *= 180.0 / CV_PI;38223823/* Calculate focal length. */3824focalLength = K(0, 0) / mx;38253826/* Calculate principle point. */3827principalPoint = Point2d(K(0, 2) / mx, K(1, 2) / my);3828}38293830double cv::stereoCalibrate( InputArrayOfArrays _objectPoints,3831InputArrayOfArrays _imagePoints1,3832InputArrayOfArrays _imagePoints2,3833InputOutputArray _cameraMatrix1, InputOutputArray _distCoeffs1,3834InputOutputArray _cameraMatrix2, InputOutputArray _distCoeffs2,3835Size imageSize, OutputArray _Rmat, OutputArray _Tmat,3836OutputArray _Emat, OutputArray _Fmat, int flags,3837TermCriteria criteria)3838{3839if (flags & CALIB_USE_EXTRINSIC_GUESS)3840CV_Error(Error::StsBadFlag, "stereoCalibrate does not support CALIB_USE_EXTRINSIC_GUESS.");38413842Mat Rmat, Tmat;3843double ret = stereoCalibrate(_objectPoints, _imagePoints1, _imagePoints2, _cameraMatrix1, _distCoeffs1,3844_cameraMatrix2, _distCoeffs2, imageSize, Rmat, Tmat, _Emat, _Fmat,3845noArray(), flags, criteria);3846Rmat.copyTo(_Rmat);3847Tmat.copyTo(_Tmat);3848return ret;3849}38503851double cv::stereoCalibrate( InputArrayOfArrays _objectPoints,3852InputArrayOfArrays _imagePoints1,3853InputArrayOfArrays _imagePoints2,3854InputOutputArray _cameraMatrix1, InputOutputArray _distCoeffs1,3855InputOutputArray _cameraMatrix2, InputOutputArray _distCoeffs2,3856Size imageSize, InputOutputArray _Rmat, InputOutputArray _Tmat,3857OutputArray _Emat, OutputArray _Fmat,3858OutputArray _perViewErrors, int flags ,3859TermCriteria criteria)3860{3861int rtype = CV_64F;3862Mat cameraMatrix1 = _cameraMatrix1.getMat();3863Mat cameraMatrix2 = _cameraMatrix2.getMat();3864Mat distCoeffs1 = _distCoeffs1.getMat();3865Mat distCoeffs2 = _distCoeffs2.getMat();3866cameraMatrix1 = prepareCameraMatrix(cameraMatrix1, rtype);3867cameraMatrix2 = prepareCameraMatrix(cameraMatrix2, rtype);3868distCoeffs1 = prepareDistCoeffs(distCoeffs1, rtype);3869distCoeffs2 = prepareDistCoeffs(distCoeffs2, rtype);38703871if( !(flags & CALIB_RATIONAL_MODEL) &&3872(!(flags & CALIB_THIN_PRISM_MODEL)) &&3873(!(flags & CALIB_TILTED_MODEL)))3874{3875distCoeffs1 = distCoeffs1.rows == 1 ? distCoeffs1.colRange(0, 5) : distCoeffs1.rowRange(0, 5);3876distCoeffs2 = distCoeffs2.rows == 1 ? distCoeffs2.colRange(0, 5) : distCoeffs2.rowRange(0, 5);3877}38783879if((flags & CALIB_USE_EXTRINSIC_GUESS) == 0)3880{3881_Rmat.create(3, 3, rtype);3882_Tmat.create(3, 1, rtype);3883}38843885Mat objPt, imgPt, imgPt2, npoints;38863887collectCalibrationData( _objectPoints, _imagePoints1, _imagePoints2,3888objPt, imgPt, &imgPt2, npoints );3889CvMat c_objPt = cvMat(objPt), c_imgPt = cvMat(imgPt), c_imgPt2 = cvMat(imgPt2), c_npoints = cvMat(npoints);3890CvMat c_cameraMatrix1 = cvMat(cameraMatrix1), c_distCoeffs1 = cvMat(distCoeffs1);3891CvMat c_cameraMatrix2 = cvMat(cameraMatrix2), c_distCoeffs2 = cvMat(distCoeffs2);3892Mat matR_ = _Rmat.getMat(), matT_ = _Tmat.getMat();3893CvMat c_matR = cvMat(matR_), c_matT = cvMat(matT_), c_matE, c_matF, c_matErr;38943895bool E_needed = _Emat.needed(), F_needed = _Fmat.needed(), errors_needed = _perViewErrors.needed();38963897Mat matE_, matF_, matErr_;3898if( E_needed )3899{3900_Emat.create(3, 3, rtype);3901matE_ = _Emat.getMat();3902c_matE = cvMat(matE_);3903}3904if( F_needed )3905{3906_Fmat.create(3, 3, rtype);3907matF_ = _Fmat.getMat();3908c_matF = cvMat(matF_);3909}39103911if( errors_needed )3912{3913int nimages = int(_objectPoints.total());3914_perViewErrors.create(nimages, 2, CV_64F);3915matErr_ = _perViewErrors.getMat();3916c_matErr = cvMat(matErr_);3917}39183919double err = cvStereoCalibrateImpl(&c_objPt, &c_imgPt, &c_imgPt2, &c_npoints, &c_cameraMatrix1,3920&c_distCoeffs1, &c_cameraMatrix2, &c_distCoeffs2, cvSize(imageSize), &c_matR,3921&c_matT, E_needed ? &c_matE : NULL, F_needed ? &c_matF : NULL,3922errors_needed ? &c_matErr : NULL, flags, cvTermCriteria(criteria));39233924cameraMatrix1.copyTo(_cameraMatrix1);3925cameraMatrix2.copyTo(_cameraMatrix2);3926distCoeffs1.copyTo(_distCoeffs1);3927distCoeffs2.copyTo(_distCoeffs2);39283929return err;3930}393139323933void cv::stereoRectify( InputArray _cameraMatrix1, InputArray _distCoeffs1,3934InputArray _cameraMatrix2, InputArray _distCoeffs2,3935Size imageSize, InputArray _Rmat, InputArray _Tmat,3936OutputArray _Rmat1, OutputArray _Rmat2,3937OutputArray _Pmat1, OutputArray _Pmat2,3938OutputArray _Qmat, int flags,3939double alpha, Size newImageSize,3940Rect* validPixROI1, Rect* validPixROI2 )3941{3942Mat cameraMatrix1 = _cameraMatrix1.getMat(), cameraMatrix2 = _cameraMatrix2.getMat();3943Mat distCoeffs1 = _distCoeffs1.getMat(), distCoeffs2 = _distCoeffs2.getMat();3944Mat Rmat = _Rmat.getMat(), Tmat = _Tmat.getMat();3945CvMat c_cameraMatrix1 = cvMat(cameraMatrix1);3946CvMat c_cameraMatrix2 = cvMat(cameraMatrix2);3947CvMat c_distCoeffs1 = cvMat(distCoeffs1);3948CvMat c_distCoeffs2 = cvMat(distCoeffs2);3949CvMat c_R = cvMat(Rmat), c_T = cvMat(Tmat);39503951int rtype = CV_64F;3952_Rmat1.create(3, 3, rtype);3953_Rmat2.create(3, 3, rtype);3954_Pmat1.create(3, 4, rtype);3955_Pmat2.create(3, 4, rtype);3956Mat R1 = _Rmat1.getMat(), R2 = _Rmat2.getMat(), P1 = _Pmat1.getMat(), P2 = _Pmat2.getMat(), Q;3957CvMat c_R1 = cvMat(R1), c_R2 = cvMat(R2), c_P1 = cvMat(P1), c_P2 = cvMat(P2);3958CvMat c_Q, *p_Q = 0;39593960if( _Qmat.needed() )3961{3962_Qmat.create(4, 4, rtype);3963p_Q = &(c_Q = cvMat(Q = _Qmat.getMat()));3964}39653966CvMat *p_distCoeffs1 = distCoeffs1.empty() ? NULL : &c_distCoeffs1;3967CvMat *p_distCoeffs2 = distCoeffs2.empty() ? NULL : &c_distCoeffs2;3968cvStereoRectify( &c_cameraMatrix1, &c_cameraMatrix2, p_distCoeffs1, p_distCoeffs2,3969cvSize(imageSize), &c_R, &c_T, &c_R1, &c_R2, &c_P1, &c_P2, p_Q, flags, alpha,3970cvSize(newImageSize), (CvRect*)validPixROI1, (CvRect*)validPixROI2);3971}39723973bool cv::stereoRectifyUncalibrated( InputArray _points1, InputArray _points2,3974InputArray _Fmat, Size imgSize,3975OutputArray _Hmat1, OutputArray _Hmat2, double threshold )3976{3977CV_INSTRUMENT_REGION();39783979int rtype = CV_64F;3980_Hmat1.create(3, 3, rtype);3981_Hmat2.create(3, 3, rtype);3982Mat F = _Fmat.getMat();3983Mat points1 = _points1.getMat(), points2 = _points2.getMat();3984CvMat c_pt1 = cvMat(points1), c_pt2 = cvMat(points2);3985Mat H1 = _Hmat1.getMat(), H2 = _Hmat2.getMat();3986CvMat c_F, *p_F=0, c_H1 = cvMat(H1), c_H2 = cvMat(H2);3987if( F.size() == Size(3, 3) )3988p_F = &(c_F = cvMat(F));3989return cvStereoRectifyUncalibrated(&c_pt1, &c_pt2, p_F, cvSize(imgSize), &c_H1, &c_H2, threshold) > 0;3990}39913992cv::Mat cv::getOptimalNewCameraMatrix( InputArray _cameraMatrix,3993InputArray _distCoeffs,3994Size imgSize, double alpha, Size newImgSize,3995Rect* validPixROI, bool centerPrincipalPoint )3996{3997CV_INSTRUMENT_REGION();39983999Mat cameraMatrix = _cameraMatrix.getMat(), distCoeffs = _distCoeffs.getMat();4000CvMat c_cameraMatrix = cvMat(cameraMatrix), c_distCoeffs = cvMat(distCoeffs);40014002Mat newCameraMatrix(3, 3, CV_MAT_TYPE(c_cameraMatrix.type));4003CvMat c_newCameraMatrix = cvMat(newCameraMatrix);40044005cvGetOptimalNewCameraMatrix(&c_cameraMatrix, &c_distCoeffs, cvSize(imgSize),4006alpha, &c_newCameraMatrix,4007cvSize(newImgSize), (CvRect*)validPixROI, (int)centerPrincipalPoint);4008return newCameraMatrix;4009}401040114012cv::Vec3d cv::RQDecomp3x3( InputArray _Mmat,4013OutputArray _Rmat,4014OutputArray _Qmat,4015OutputArray _Qx,4016OutputArray _Qy,4017OutputArray _Qz )4018{4019CV_INSTRUMENT_REGION();40204021Mat M = _Mmat.getMat();4022_Rmat.create(3, 3, M.type());4023_Qmat.create(3, 3, M.type());4024Mat Rmat = _Rmat.getMat();4025Mat Qmat = _Qmat.getMat();4026Vec3d eulerAngles;40274028CvMat matM = cvMat(M), matR = cvMat(Rmat), matQ = cvMat(Qmat);4029#define CV_RQDecomp3x3_PARAM(name) \4030Mat name; \4031CvMat c_ ## name, *p ## name = NULL; \4032if( _ ## name.needed() ) \4033{ \4034_ ## name.create(3, 3, M.type()); \4035name = _ ## name.getMat(); \4036c_ ## name = cvMat(name); p ## name = &c_ ## name; \4037}40384039CV_RQDecomp3x3_PARAM(Qx);4040CV_RQDecomp3x3_PARAM(Qy);4041CV_RQDecomp3x3_PARAM(Qz);4042#undef CV_RQDecomp3x3_PARAM4043cvRQDecomp3x3(&matM, &matR, &matQ, pQx, pQy, pQz, (CvPoint3D64f*)&eulerAngles[0]);4044return eulerAngles;4045}404640474048void cv::decomposeProjectionMatrix( InputArray _projMatrix, OutputArray _cameraMatrix,4049OutputArray _rotMatrix, OutputArray _transVect,4050OutputArray _rotMatrixX, OutputArray _rotMatrixY,4051OutputArray _rotMatrixZ, OutputArray _eulerAngles )4052{4053CV_INSTRUMENT_REGION();40544055Mat projMatrix = _projMatrix.getMat();4056int type = projMatrix.type();4057_cameraMatrix.create(3, 3, type);4058_rotMatrix.create(3, 3, type);4059_transVect.create(4, 1, type);4060Mat cameraMatrix = _cameraMatrix.getMat();4061Mat rotMatrix = _rotMatrix.getMat();4062Mat transVect = _transVect.getMat();4063CvMat c_projMatrix = cvMat(projMatrix), c_cameraMatrix = cvMat(cameraMatrix);4064CvMat c_rotMatrix = cvMat(rotMatrix), c_transVect = cvMat(transVect);4065CvPoint3D64f *p_eulerAngles = 0;40664067#define CV_decomposeProjectionMatrix_PARAM(name) \4068Mat name; \4069CvMat c_ ## name, *p_ ## name = NULL; \4070if( _ ## name.needed() ) \4071{ \4072_ ## name.create(3, 3, type); \4073name = _ ## name.getMat(); \4074c_ ## name = cvMat(name); p_ ## name = &c_ ## name; \4075}40764077CV_decomposeProjectionMatrix_PARAM(rotMatrixX);4078CV_decomposeProjectionMatrix_PARAM(rotMatrixY);4079CV_decomposeProjectionMatrix_PARAM(rotMatrixZ);4080#undef CV_decomposeProjectionMatrix_PARAM40814082if( _eulerAngles.needed() )4083{4084_eulerAngles.create(3, 1, CV_64F, -1, true);4085p_eulerAngles = _eulerAngles.getMat().ptr<CvPoint3D64f>();4086}40874088cvDecomposeProjectionMatrix(&c_projMatrix, &c_cameraMatrix, &c_rotMatrix,4089&c_transVect, p_rotMatrixX, p_rotMatrixY,4090p_rotMatrixZ, p_eulerAngles);4091}409240934094namespace cv4095{40964097static void adjust3rdMatrix(InputArrayOfArrays _imgpt1_0,4098InputArrayOfArrays _imgpt3_0,4099const Mat& cameraMatrix1, const Mat& distCoeffs1,4100const Mat& cameraMatrix3, const Mat& distCoeffs3,4101const Mat& R1, const Mat& R3, const Mat& P1, Mat& P3 )4102{4103size_t n1 = _imgpt1_0.total(), n3 = _imgpt3_0.total();4104std::vector<Point2f> imgpt1, imgpt3;41054106for( int i = 0; i < (int)std::min(n1, n3); i++ )4107{4108Mat pt1 = _imgpt1_0.getMat(i), pt3 = _imgpt3_0.getMat(i);4109int ni1 = pt1.checkVector(2, CV_32F), ni3 = pt3.checkVector(2, CV_32F);4110CV_Assert( ni1 > 0 && ni1 == ni3 );4111const Point2f* pt1data = pt1.ptr<Point2f>();4112const Point2f* pt3data = pt3.ptr<Point2f>();4113std::copy(pt1data, pt1data + ni1, std::back_inserter(imgpt1));4114std::copy(pt3data, pt3data + ni3, std::back_inserter(imgpt3));4115}41164117undistortPoints(imgpt1, imgpt1, cameraMatrix1, distCoeffs1, R1, P1);4118undistortPoints(imgpt3, imgpt3, cameraMatrix3, distCoeffs3, R3, P3);41194120double y1_ = 0, y2_ = 0, y1y1_ = 0, y1y2_ = 0;4121size_t n = imgpt1.size();41224123for( size_t i = 0; i < n; i++ )4124{4125double y1 = imgpt3[i].y, y2 = imgpt1[i].y;41264127y1_ += y1; y2_ += y2;4128y1y1_ += y1*y1; y1y2_ += y1*y2;4129}41304131y1_ /= n;4132y2_ /= n;4133y1y1_ /= n;4134y1y2_ /= n;41354136double a = (y1y2_ - y1_*y2_)/(y1y1_ - y1_*y1_);4137double b = y2_ - a*y1_;41384139P3.at<double>(0,0) *= a;4140P3.at<double>(1,1) *= a;4141P3.at<double>(0,2) = P3.at<double>(0,2)*a;4142P3.at<double>(1,2) = P3.at<double>(1,2)*a + b;4143P3.at<double>(0,3) *= a;4144P3.at<double>(1,3) *= a;4145}41464147}41484149float cv::rectify3Collinear( InputArray _cameraMatrix1, InputArray _distCoeffs1,4150InputArray _cameraMatrix2, InputArray _distCoeffs2,4151InputArray _cameraMatrix3, InputArray _distCoeffs3,4152InputArrayOfArrays _imgpt1,4153InputArrayOfArrays _imgpt3,4154Size imageSize, InputArray _Rmat12, InputArray _Tmat12,4155InputArray _Rmat13, InputArray _Tmat13,4156OutputArray _Rmat1, OutputArray _Rmat2, OutputArray _Rmat3,4157OutputArray _Pmat1, OutputArray _Pmat2, OutputArray _Pmat3,4158OutputArray _Qmat,4159double alpha, Size newImgSize,4160Rect* roi1, Rect* roi2, int flags )4161{4162// first, rectify the 1-2 stereo pair4163stereoRectify( _cameraMatrix1, _distCoeffs1, _cameraMatrix2, _distCoeffs2,4164imageSize, _Rmat12, _Tmat12, _Rmat1, _Rmat2, _Pmat1, _Pmat2, _Qmat,4165flags, alpha, newImgSize, roi1, roi2 );41664167Mat R12 = _Rmat12.getMat(), R13 = _Rmat13.getMat(), T12 = _Tmat12.getMat(), T13 = _Tmat13.getMat();41684169_Rmat3.create(3, 3, CV_64F);4170_Pmat3.create(3, 4, CV_64F);41714172Mat P1 = _Pmat1.getMat(), P2 = _Pmat2.getMat();4173Mat R3 = _Rmat3.getMat(), P3 = _Pmat3.getMat();41744175// recompute rectification transforms for cameras 1 & 2.4176Mat om, r_r, r_r13;41774178if( R13.size() != Size(3,3) )4179Rodrigues(R13, r_r13);4180else4181R13.copyTo(r_r13);41824183if( R12.size() == Size(3,3) )4184Rodrigues(R12, om);4185else4186R12.copyTo(om);41874188om *= -0.5;4189Rodrigues(om, r_r); // rotate cameras to same orientation by averaging4190Mat_<double> t12 = r_r * T12;41914192int idx = fabs(t12(0,0)) > fabs(t12(1,0)) ? 0 : 1;4193double c = t12(idx,0), nt = norm(t12, CV_L2);4194CV_Assert(fabs(nt) > 0);4195Mat_<double> uu = Mat_<double>::zeros(3,1);4196uu(idx, 0) = c > 0 ? 1 : -1;41974198// calculate global Z rotation4199Mat_<double> ww = t12.cross(uu), wR;4200double nw = norm(ww, CV_L2);4201CV_Assert(fabs(nw) > 0);4202ww *= acos(fabs(c)/nt)/nw;4203Rodrigues(ww, wR);42044205// now rotate camera 3 to make its optical axis parallel to cameras 1 and 2.4206R3 = wR*r_r.t()*r_r13.t();4207Mat_<double> t13 = R3 * T13;42084209P2.copyTo(P3);4210Mat t = P3.col(3);4211t13.copyTo(t);4212P3.at<double>(0,3) *= P3.at<double>(0,0);4213P3.at<double>(1,3) *= P3.at<double>(1,1);42144215if( !_imgpt1.empty() && !_imgpt3.empty() )4216adjust3rdMatrix(_imgpt1, _imgpt3, _cameraMatrix1.getMat(), _distCoeffs1.getMat(),4217_cameraMatrix3.getMat(), _distCoeffs3.getMat(), _Rmat1.getMat(), R3, P1, P3);42184219return (float)((P3.at<double>(idx,3)/P3.at<double>(idx,idx))/4220(P2.at<double>(idx,3)/P2.at<double>(idx,idx)));4221}422242234224/* End of file. */422542264227