diff --git a/modules/calib3d/src/_modelest.h b/modules/calib3d/src/calib3d_init.cpp similarity index 51% rename from modules/calib3d/src/_modelest.h rename to modules/calib3d/src/calib3d_init.cpp index a467e1cc02..06303bd985 100644 --- a/modules/calib3d/src/_modelest.h +++ b/modules/calib3d/src/calib3d_init.cpp @@ -7,10 +7,11 @@ // copy or use the software. // // -// Intel License Agreement +// License Agreement // For Open Source Computer Vision Library // -// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -23,7 +24,7 @@ // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // -// * The name of Intel Corporation may not be used to endorse or promote products +// * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and @@ -39,44 +40,27 @@ // //M*/ +#include "precomp.hpp" -#ifndef _CV_MODEL_EST_H_ -#define _CV_MODEL_EST_H_ +using namespace cv; -#include "opencv2/calib3d/calib3d.hpp" +////////////////////////////////////////////////////////////////////////////////////////////////////////// -class CV_EXPORTS CvModelEstimator2 -{ -public: - CvModelEstimator2(int _modelPoints, CvSize _modelSize, int _maxBasicSolutions); - virtual ~CvModelEstimator2(); - virtual int runKernel( const CvMat* m1, const CvMat* m2, CvMat* model )=0; - virtual bool runLMeDS( const CvMat* m1, const CvMat* m2, CvMat* model, - CvMat* mask, double confidence=0.99, int maxIters=2000 ); - virtual bool runRANSAC( const CvMat* m1, const CvMat* m2, CvMat* model, - CvMat* mask, double threshold, - double confidence=0.99, int maxIters=2000 ); - virtual bool refine( const CvMat*, const CvMat*, CvMat*, int ) { return true; } - virtual void setSeed( int64 seed ); +////////////////////////////////////////////////////////////////////////////////////////////////////////// + -protected: - virtual void computeReprojError( const CvMat* m1, const CvMat* m2, - const CvMat* model, CvMat* error ) = 0; - virtual int findInliers( const CvMat* m1, const CvMat* m2, - const CvMat* model, CvMat* error, - CvMat* mask, double threshold ); - virtual bool getSubset( const CvMat* m1, const CvMat* m2, - CvMat* ms1, CvMat* ms2, int maxAttempts=1000 ); - virtual bool checkSubset( const CvMat* ms1, int count ); - virtual bool isMinimalSetConsistent( const CvMat* /*m1*/, const CvMat* /*m2*/ ) { return true; }; - CvRNG rng; - int modelPoints; - CvSize modelSize; - int maxBasicSolutions; - bool checkPartialSubsets; -}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////// -#endif // _CV_MODEL_EST_H_ +#if 0 +bool cv::initModule_calib3d(void) +{ + bool all = true; + all &= !RANSACPointSetRegistrator_info_auto.name().empty(); + all &= !LMeDSPointSetRegistrator_info_auto.name().empty(); + all &= !LMSolverImpl_info_auto.name().empty(); + return all; +} +#endif diff --git a/modules/calib3d/src/calibration.cpp b/modules/calib3d/src/calibration.cpp index 61b68ccb24..e36c1e5ede 100644 --- a/modules/calib3d/src/calibration.cpp +++ b/modules/calib3d/src/calibration.cpp @@ -55,247 +55,6 @@ using namespace cv; -CvLevMarq::CvLevMarq() -{ - mask = prevParam = param = J = err = JtJ = JtJN = JtErr = JtJV = JtJW = Ptr(); - lambdaLg10 = 0; state = DONE; - criteria = cvTermCriteria(0,0,0); - iters = 0; - completeSymmFlag = false; -} - -CvLevMarq::CvLevMarq( int nparams, int nerrs, CvTermCriteria criteria0, bool _completeSymmFlag ) -{ - mask = prevParam = param = J = err = JtJ = JtJN = JtErr = JtJV = JtJW = Ptr(); - init(nparams, nerrs, criteria0, _completeSymmFlag); -} - -void CvLevMarq::clear() -{ - mask.release(); - prevParam.release(); - param.release(); - J.release(); - err.release(); - JtJ.release(); - JtJN.release(); - JtErr.release(); - JtJV.release(); - JtJW.release(); -} - -CvLevMarq::~CvLevMarq() -{ - clear(); -} - -void CvLevMarq::init( int nparams, int nerrs, CvTermCriteria criteria0, bool _completeSymmFlag ) -{ - if( !param || param->rows != nparams || nerrs != (err ? err->rows : 0) ) - clear(); - mask = cvCreateMat( nparams, 1, CV_8U ); - cvSet(mask, cvScalarAll(1)); - prevParam = cvCreateMat( nparams, 1, CV_64F ); - param = cvCreateMat( nparams, 1, CV_64F ); - JtJ = cvCreateMat( nparams, nparams, CV_64F ); - JtJN = cvCreateMat( nparams, nparams, CV_64F ); - JtJV = cvCreateMat( nparams, nparams, CV_64F ); - JtJW = cvCreateMat( nparams, 1, CV_64F ); - JtErr = cvCreateMat( nparams, 1, CV_64F ); - if( nerrs > 0 ) - { - J = cvCreateMat( nerrs, nparams, CV_64F ); - err = cvCreateMat( nerrs, 1, CV_64F ); - } - prevErrNorm = DBL_MAX; - lambdaLg10 = -3; - criteria = criteria0; - if( criteria.type & CV_TERMCRIT_ITER ) - criteria.max_iter = MIN(MAX(criteria.max_iter,1),1000); - else - criteria.max_iter = 30; - if( criteria.type & CV_TERMCRIT_EPS ) - criteria.epsilon = MAX(criteria.epsilon, 0); - else - criteria.epsilon = DBL_EPSILON; - state = STARTED; - iters = 0; - completeSymmFlag = _completeSymmFlag; -} - -bool CvLevMarq::update( const CvMat*& _param, CvMat*& matJ, CvMat*& _err ) -{ - double change; - - matJ = _err = 0; - - assert( !err.empty() ); - if( state == DONE ) - { - _param = param; - return false; - } - - if( state == STARTED ) - { - _param = param; - cvZero( J ); - cvZero( err ); - matJ = J; - _err = err; - state = CALC_J; - return true; - } - - if( state == CALC_J ) - { - cvMulTransposed( J, JtJ, 1 ); - cvGEMM( J, err, 1, 0, 0, JtErr, CV_GEMM_A_T ); - cvCopy( param, prevParam ); - step(); - if( iters == 0 ) - prevErrNorm = cvNorm(err, 0, CV_L2); - _param = param; - cvZero( err ); - _err = err; - state = CHECK_ERR; - return true; - } - - assert( state == CHECK_ERR ); - errNorm = cvNorm( err, 0, CV_L2 ); - if( errNorm > prevErrNorm ) - { - if( ++lambdaLg10 <= 16 ) - { - step(); - _param = param; - cvZero( err ); - _err = err; - state = CHECK_ERR; - return true; - } - } - - lambdaLg10 = MAX(lambdaLg10-1, -16); - if( ++iters >= criteria.max_iter || - (change = cvNorm(param, prevParam, CV_RELATIVE_L2)) < criteria.epsilon ) - { - _param = param; - state = DONE; - return true; - } - - prevErrNorm = errNorm; - _param = param; - cvZero(J); - matJ = J; - _err = err; - state = CALC_J; - return true; -} - - -bool CvLevMarq::updateAlt( const CvMat*& _param, CvMat*& _JtJ, CvMat*& _JtErr, double*& _errNorm ) -{ - double change; - - CV_Assert( err.empty() ); - if( state == DONE ) - { - _param = param; - return false; - } - - if( state == STARTED ) - { - _param = param; - cvZero( JtJ ); - cvZero( JtErr ); - errNorm = 0; - _JtJ = JtJ; - _JtErr = JtErr; - _errNorm = &errNorm; - state = CALC_J; - return true; - } - - if( state == CALC_J ) - { - cvCopy( param, prevParam ); - step(); - _param = param; - prevErrNorm = errNorm; - errNorm = 0; - _errNorm = &errNorm; - state = CHECK_ERR; - return true; - } - - assert( state == CHECK_ERR ); - if( errNorm > prevErrNorm ) - { - if( ++lambdaLg10 <= 16 ) - { - step(); - _param = param; - errNorm = 0; - _errNorm = &errNorm; - state = CHECK_ERR; - return true; - } - } - - lambdaLg10 = MAX(lambdaLg10-1, -16); - if( ++iters >= criteria.max_iter || - (change = cvNorm(param, prevParam, CV_RELATIVE_L2)) < criteria.epsilon ) - { - _param = param; - state = DONE; - return false; - } - - prevErrNorm = errNorm; - cvZero( JtJ ); - cvZero( JtErr ); - _param = param; - _JtJ = JtJ; - _JtErr = JtErr; - state = CALC_J; - return true; -} - -void CvLevMarq::step() -{ - const double LOG10 = log(10.); - double lambda = exp(lambdaLg10*LOG10); - int i, j, nparams = param->rows; - - for( i = 0; i < nparams; i++ ) - if( mask->data.ptr[i] == 0 ) - { - double *row = JtJ->data.db + i*nparams, *col = JtJ->data.db + i; - for( j = 0; j < nparams; j++ ) - row[j] = col[j*nparams] = 0; - JtErr->data.db[i] = 0; - } - - if( !err ) - cvCompleteSymm( JtJ, completeSymmFlag ); -#if 1 - cvCopy( JtJ, JtJN ); - for( i = 0; i < nparams; i++ ) - JtJN->data.db[(nparams+1)*i] *= 1. + lambda; -#else - cvSetIdentity(JtJN, cvRealScalar(lambda)); - cvAdd( JtJ, JtJN, JtJN ); -#endif - cvSVD( JtJN, JtJW, 0, JtJV, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T ); - cvSVBkSb( JtJW, JtJV, JtJV, JtErr, param, CV_SVD_U_T + CV_SVD_V_T ); - for( i = 0; i < nparams; i++ ) - param->data.db[i] = prevParam->data.db[i] - (mask->data.ptr[i] ? param->data.db[i] : 0); -} - // reimplementation of dAB.m CV_IMPL void cvCalcMatMulDeriv( const CvMat* A, const CvMat* B, CvMat* dABdA, CvMat* dABdB ) { diff --git a/modules/calib3d/src/circlesgrid.cpp b/modules/calib3d/src/circlesgrid.cpp index 3bd46200d1..93a535482a 100644 --- a/modules/calib3d/src/circlesgrid.cpp +++ b/modules/calib3d/src/circlesgrid.cpp @@ -402,14 +402,16 @@ void CirclesGridClusterFinder::parsePatternPoints(const std::vector else idealPt = Point2f(j*squareSize, i*squareSize); - std::vector query = Mat(idealPt); + Mat query(1, 2, CV_32F, &idealPt); int knn = 1; - std::vector indices(knn); - std::vector dists(knn); + int indicesbuf = 0; + float distsbuf = 0.f; + Mat indices(1, knn, CV_32S, &indicesbuf); + Mat dists(1, knn, CV_32F, &distsbuf); flannIndex.knnSearch(query, indices, dists, knn, flann::SearchParams()); - centers.push_back(patternPoints.at(indices[0])); + centers.push_back(patternPoints.at(indicesbuf)); - if(dists[0] > maxRectifiedDistance) + if(distsbuf > maxRectifiedDistance) { #ifdef DEBUG_CIRCLES cout << "Pattern not detected: too large rectified distance" << endl; diff --git a/modules/calib3d/src/compat_ptsetreg.cpp b/modules/calib3d/src/compat_ptsetreg.cpp new file mode 100644 index 0000000000..dca0d0dabe --- /dev/null +++ b/modules/calib3d/src/compat_ptsetreg.cpp @@ -0,0 +1,430 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +/************************************************************************************\ + Some backward compatibility stuff, to be moved to legacy or compat module +\************************************************************************************/ + +using cv::Ptr; + +////////////////// Levenberg-Marquardt engine (the old variant) //////////////////////// + +CvLevMarq::CvLevMarq() +{ + mask = prevParam = param = J = err = JtJ = JtJN = JtErr = JtJV = JtJW = Ptr(); + lambdaLg10 = 0; state = DONE; + criteria = cvTermCriteria(0,0,0); + iters = 0; + completeSymmFlag = false; +} + +CvLevMarq::CvLevMarq( int nparams, int nerrs, CvTermCriteria criteria0, bool _completeSymmFlag ) +{ + mask = prevParam = param = J = err = JtJ = JtJN = JtErr = JtJV = JtJW = Ptr(); + init(nparams, nerrs, criteria0, _completeSymmFlag); +} + +void CvLevMarq::clear() +{ + mask.release(); + prevParam.release(); + param.release(); + J.release(); + err.release(); + JtJ.release(); + JtJN.release(); + JtErr.release(); + JtJV.release(); + JtJW.release(); +} + +CvLevMarq::~CvLevMarq() +{ + clear(); +} + +void CvLevMarq::init( int nparams, int nerrs, CvTermCriteria criteria0, bool _completeSymmFlag ) +{ + if( !param || param->rows != nparams || nerrs != (err ? err->rows : 0) ) + clear(); + mask = cvCreateMat( nparams, 1, CV_8U ); + cvSet(mask, cvScalarAll(1)); + prevParam = cvCreateMat( nparams, 1, CV_64F ); + param = cvCreateMat( nparams, 1, CV_64F ); + JtJ = cvCreateMat( nparams, nparams, CV_64F ); + JtJN = cvCreateMat( nparams, nparams, CV_64F ); + JtJV = cvCreateMat( nparams, nparams, CV_64F ); + JtJW = cvCreateMat( nparams, 1, CV_64F ); + JtErr = cvCreateMat( nparams, 1, CV_64F ); + if( nerrs > 0 ) + { + J = cvCreateMat( nerrs, nparams, CV_64F ); + err = cvCreateMat( nerrs, 1, CV_64F ); + } + prevErrNorm = DBL_MAX; + lambdaLg10 = -3; + criteria = criteria0; + if( criteria.type & CV_TERMCRIT_ITER ) + criteria.max_iter = MIN(MAX(criteria.max_iter,1),1000); + else + criteria.max_iter = 30; + if( criteria.type & CV_TERMCRIT_EPS ) + criteria.epsilon = MAX(criteria.epsilon, 0); + else + criteria.epsilon = DBL_EPSILON; + state = STARTED; + iters = 0; + completeSymmFlag = _completeSymmFlag; +} + +bool CvLevMarq::update( const CvMat*& _param, CvMat*& matJ, CvMat*& _err ) +{ + double change; + + matJ = _err = 0; + + assert( !err.empty() ); + if( state == DONE ) + { + _param = param; + return false; + } + + if( state == STARTED ) + { + _param = param; + cvZero( J ); + cvZero( err ); + matJ = J; + _err = err; + state = CALC_J; + return true; + } + + if( state == CALC_J ) + { + cvMulTransposed( J, JtJ, 1 ); + cvGEMM( J, err, 1, 0, 0, JtErr, CV_GEMM_A_T ); + cvCopy( param, prevParam ); + step(); + if( iters == 0 ) + prevErrNorm = cvNorm(err, 0, CV_L2); + _param = param; + cvZero( err ); + _err = err; + state = CHECK_ERR; + return true; + } + + assert( state == CHECK_ERR ); + errNorm = cvNorm( err, 0, CV_L2 ); + if( errNorm > prevErrNorm ) + { + if( ++lambdaLg10 <= 16 ) + { + step(); + _param = param; + cvZero( err ); + _err = err; + state = CHECK_ERR; + return true; + } + } + + lambdaLg10 = MAX(lambdaLg10-1, -16); + if( ++iters >= criteria.max_iter || + (change = cvNorm(param, prevParam, CV_RELATIVE_L2)) < criteria.epsilon ) + { + _param = param; + state = DONE; + return true; + } + + prevErrNorm = errNorm; + _param = param; + cvZero(J); + matJ = J; + _err = err; + state = CALC_J; + return true; +} + + +bool CvLevMarq::updateAlt( const CvMat*& _param, CvMat*& _JtJ, CvMat*& _JtErr, double*& _errNorm ) +{ + double change; + + CV_Assert( err.empty() ); + if( state == DONE ) + { + _param = param; + return false; + } + + if( state == STARTED ) + { + _param = param; + cvZero( JtJ ); + cvZero( JtErr ); + errNorm = 0; + _JtJ = JtJ; + _JtErr = JtErr; + _errNorm = &errNorm; + state = CALC_J; + return true; + } + + if( state == CALC_J ) + { + cvCopy( param, prevParam ); + step(); + _param = param; + prevErrNorm = errNorm; + errNorm = 0; + _errNorm = &errNorm; + state = CHECK_ERR; + return true; + } + + assert( state == CHECK_ERR ); + if( errNorm > prevErrNorm ) + { + if( ++lambdaLg10 <= 16 ) + { + step(); + _param = param; + errNorm = 0; + _errNorm = &errNorm; + state = CHECK_ERR; + return true; + } + } + + lambdaLg10 = MAX(lambdaLg10-1, -16); + if( ++iters >= criteria.max_iter || + (change = cvNorm(param, prevParam, CV_RELATIVE_L2)) < criteria.epsilon ) + { + _param = param; + state = DONE; + return false; + } + + prevErrNorm = errNorm; + cvZero( JtJ ); + cvZero( JtErr ); + _param = param; + _JtJ = JtJ; + _JtErr = JtErr; + state = CALC_J; + return true; +} + +void CvLevMarq::step() +{ + const double LOG10 = log(10.); + double lambda = exp(lambdaLg10*LOG10); + int i, j, nparams = param->rows; + + for( i = 0; i < nparams; i++ ) + if( mask->data.ptr[i] == 0 ) + { + double *row = JtJ->data.db + i*nparams, *col = JtJ->data.db + i; + for( j = 0; j < nparams; j++ ) + row[j] = col[j*nparams] = 0; + JtErr->data.db[i] = 0; + } + + if( !err ) + cvCompleteSymm( JtJ, completeSymmFlag ); +#if 1 + cvCopy( JtJ, JtJN ); + for( i = 0; i < nparams; i++ ) + JtJN->data.db[(nparams+1)*i] *= 1. + lambda; +#else + cvSetIdentity(JtJN, cvRealScalar(lambda)); + cvAdd( JtJ, JtJN, JtJN ); +#endif + cvSVD( JtJN, JtJW, 0, JtJV, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T ); + cvSVBkSb( JtJW, JtJV, JtJV, JtErr, param, CV_SVD_U_T + CV_SVD_V_T ); + for( i = 0; i < nparams; i++ ) + param->data.db[i] = prevParam->data.db[i] - (mask->data.ptr[i] ? param->data.db[i] : 0); +} + + +CV_IMPL int cvRANSACUpdateNumIters( double p, double ep, int modelPoints, int maxIters ) +{ + return cv::RANSACUpdateNumIters(p, ep, modelPoints, maxIters); +} + + +CV_IMPL int cvFindHomography( const CvMat* _src, const CvMat* _dst, CvMat* __H, int method, + double ransacReprojThreshold, CvMat* _mask ) +{ + cv::Mat src = cv::cvarrToMat(_src), dst = cv::cvarrToMat(_dst); + + if( src.channels() == 1 && (src.rows == 2 || src.rows == 3) && src.cols > 3 ) + cv::transpose(src, src); + if( dst.channels() == 1 && (dst.rows == 2 || dst.rows == 3) && dst.cols > 3 ) + cv::transpose(dst, dst); + + const cv::Mat H = cv::cvarrToMat(__H), mask = cv::cvarrToMat(_mask); + cv::Mat H0 = cv::findHomography(src, dst, method, ransacReprojThreshold, + _mask ? cv::_OutputArray(mask) : cv::_OutputArray()); + + if( H0.empty() ) + { + cv::Mat Hz = cv::cvarrToMat(__H); + Hz.setTo(cv::Scalar::all(0)); + return 0; + } + H0.convertTo(H, H.type()); + return 1; +} + + +CV_IMPL int cvFindFundamentalMat( const CvMat* points1, const CvMat* points2, + CvMat* fmatrix, int method, + double param1, double param2, CvMat* _mask ) +{ + cv::Mat m1 = cv::cvarrToMat(points1), m2 = cv::cvarrToMat(points2); + + if( m1.channels() == 1 && (m1.rows == 2 || m1.rows == 3) && m1.cols > 3 ) + cv::transpose(m1, m1); + if( m2.channels() == 1 && (m2.rows == 2 || m2.rows == 3) && m2.cols > 3 ) + cv::transpose(m2, m2); + + const cv::Mat FM = cv::cvarrToMat(fmatrix), mask = cv::cvarrToMat(_mask); + cv::Mat FM0 = cv::findFundamentalMat(m1, m2, method, param1, param2, + _mask ? cv::_OutputArray(mask) : cv::_OutputArray()); + + if( FM0.empty() ) + { + cv::Mat FM0z = cv::cvarrToMat(fmatrix); + FM0z.setTo(cv::Scalar::all(0)); + return 0; + } + + CV_Assert( FM0.cols == 3 && FM0.rows % 3 == 0 && FM.cols == 3 && FM.rows % 3 == 0 && FM.channels() == 1 ); + cv::Mat FM1 = FM.rowRange(0, MIN(FM0.rows, FM.rows)); + FM0.rowRange(0, FM1.rows).convertTo(FM1, FM1.type()); + return FM1.rows / 3; +} + + +CV_IMPL void cvComputeCorrespondEpilines( const CvMat* points, int pointImageID, + const CvMat* fmatrix, CvMat* _lines ) +{ + cv::Mat pt = cv::cvarrToMat(points), fm = cv::cvarrToMat(fmatrix); + cv::Mat lines = cv::cvarrToMat(_lines); + const cv::Mat lines0 = lines; + + if( pt.channels() == 1 && (pt.rows == 2 || pt.rows == 3) && pt.cols > 3 ) + cv::transpose(pt, pt); + + cv::computeCorrespondEpilines(pt, pointImageID, fm, lines); + + bool tflag = lines0.channels() == 1 && lines0.rows == 3 && lines0.cols > 3; + lines = lines.reshape(lines0.channels(), (tflag ? lines0.cols : lines0.rows)); + + if( tflag ) + { + CV_Assert( lines.rows == lines0.cols && lines.cols == lines0.rows ); + if( lines0.type() == lines.type() ) + transpose( lines, lines0 ); + else + { + transpose( lines, lines ); + lines.convertTo( lines0, lines0.type() ); + } + } + else + { + CV_Assert( lines.size() == lines0.size() ); + if( lines.data != lines0.data ) + lines.convertTo(lines0, lines0.type()); + } +} + + +CV_IMPL void cvConvertPointsHomogeneous( const CvMat* _src, CvMat* _dst ) +{ + cv::Mat src = cv::cvarrToMat(_src), dst = cv::cvarrToMat(_dst); + const cv::Mat dst0 = dst; + + int d0 = src.channels() > 1 ? src.channels() : MIN(src.cols, src.rows); + + if( src.channels() == 1 && src.cols > d0 ) + cv::transpose(src, src); + + int d1 = dst.channels() > 1 ? dst.channels() : MIN(dst.cols, dst.rows); + + if( d0 == d1 ) + src.copyTo(dst); + else if( d0 < d1 ) + cv::convertPointsToHomogeneous(src, dst); + else + cv::convertPointsFromHomogeneous(src, dst); + + bool tflag = dst0.channels() == 1 && dst0.cols > d1; + dst = dst.reshape(dst0.channels(), (tflag ? dst0.cols : dst0.rows)); + + if( tflag ) + { + CV_Assert( dst.rows == dst0.cols && dst.cols == dst0.rows ); + if( dst0.type() == dst.type() ) + transpose( dst, dst0 ); + else + { + transpose( dst, dst ); + dst.convertTo( dst0, dst0.type() ); + } + } + else + { + CV_Assert( dst.size() == dst0.size() ); + if( dst.data != dst0.data ) + dst.convertTo(dst0, dst0.type()); + } +} + diff --git a/modules/calib3d/src/five-point.cpp b/modules/calib3d/src/five-point.cpp index 3c93d7b3ae..57f941e381 100644 --- a/modules/calib3d/src/five-point.cpp +++ b/modules/calib3d/src/five-point.cpp @@ -1,755 +1,731 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ #include "precomp.hpp" -#include "_modelest.h" #include -using namespace cv; +namespace cv +{ -class CvEMEstimator : public CvModelEstimator2 +class EMEstimatorCallback : public PointSetRegistrator::Callback { public: - CvEMEstimator(); - virtual int runKernel( const CvMat* m1, const CvMat* m2, CvMat* model ); - virtual int run5Point( const CvMat* _q1, const CvMat* _q2, CvMat* _ematrix ); -protected: - bool reliable( const CvMat* m1, const CvMat* m2, const CvMat* model ); - virtual void calibrated_fivepoint_helper( double *eet, double* at ); - virtual void computeReprojError( const CvMat* m1, const CvMat* m2, - const CvMat* model, CvMat* error ); -}; + int runKernel( InputArray _m1, InputArray _m2, OutputArray _model ) const + { + Mat q1 = _m1.getMat(), q2 = _m2.getMat(); + Mat Q1 = q1.reshape(1, (int)q1.total()); + Mat Q2 = q2.reshape(1, (int)q2.total()); + int n = Q1.rows; + Mat Q(n, 9, CV_64F); + Q.col(0) = Q1.col(0).mul( Q2.col(0) ); + Q.col(1) = Q1.col(1).mul( Q2.col(0) ); + Q.col(2) = Q2.col(0) * 1.0; + Q.col(3) = Q1.col(0).mul( Q2.col(1) ); + Q.col(4) = Q1.col(1).mul( Q2.col(1) ); + Q.col(5) = Q2.col(1) * 1.0; + Q.col(6) = Q1.col(0) * 1.0; + Q.col(7) = Q1.col(1) * 1.0; + Q.col(8) = 1.0; + Mat U, W, Vt; + SVD::compute(Q, W, U, Vt, SVD::MODIFY_A | SVD::FULL_UV); -// Input should be a vector of n 2D points or a Nx2 matrix -Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, double focal, Point2d pp, - int method, double prob, double threshold, OutputArray _mask) -{ - Mat points1, points2; - _points1.getMat().copyTo(points1); - _points2.getMat().copyTo(points2); + Mat EE = Mat(Vt.t()).colRange(5, 9) * 1.0; + Mat AA(20, 10, CV_64F); + EE = EE.t(); + calibrated_fivepoint_helper((double*)EE.data, (double*)AA.data); + AA = AA.t(); + EE = EE.t(); - int npoints = points1.checkVector(2); - CV_Assert( npoints >= 5 && points2.checkVector(2) == npoints && - points1.type() == points2.type()); + Mat A(10, 20, CV_64F); + int perm[20] = {0, 3, 1, 2, 4, 10, 6, 12, 5, 11, 7, 13, 16, 8, 14, 17, 9, 15, 18, 19}; + for (int i = 0; i < 20; i++) + A.col(i) = AA.col(perm[i]) * 1.0; - if (points1.channels() > 1) - { - points1 = points1.reshape(1, npoints); - points2 = points2.reshape(1, npoints); - } + A = A.colRange(0, 10).inv() * A.colRange(10, 20); + double b[3 * 13]; + Mat B(3, 13, CV_64F, b); + for (int i = 0; i < 3; i++) + { + Mat arow1 = A.row(i * 2 + 4) * 1.0; + Mat arow2 = A.row(i * 2 + 5) * 1.0; + Mat row1(1, 13, CV_64F, Scalar(0.0)); + Mat row2(1, 13, CV_64F, Scalar(0.0)); - points1.convertTo(points1, CV_64F); - points2.convertTo(points2, CV_64F); + row1.colRange(1, 4) = arow1.colRange(0, 3) * 1.0; + row1.colRange(5, 8) = arow1.colRange(3, 6) * 1.0; + row1.colRange(9, 13) = arow1.colRange(6, 10) * 1.0; - points1.col(0) = (points1.col(0) - pp.x) / focal; - points2.col(0) = (points2.col(0) - pp.x) / focal; - points1.col(1) = (points1.col(1) - pp.y) / focal; - points2.col(1) = (points2.col(1) - pp.y) / focal; + row2.colRange(0, 3) = arow2.colRange(0, 3) * 1.0; + row2.colRange(4, 7) = arow2.colRange(3, 6) * 1.0; + row2.colRange(8, 12) = arow2.colRange(6, 10) * 1.0; - // Reshape data to fit opencv ransac function - points1 = points1.reshape(2, 1); - points2 = points2.reshape(2, 1); + B.row(i) = row1 - row2; + } - Mat E(3, 3, CV_64F); - CvEMEstimator estimator; + double c[11]; + Mat coeffs(1, 11, CV_64F, c); + c[10] = (b[0]*b[17]*b[34]+b[26]*b[4]*b[21]-b[26]*b[17]*b[8]-b[13]*b[4]*b[34]-b[0]*b[21]*b[30]+b[13]*b[30]*b[8]); + c[9] = (b[26]*b[4]*b[22]+b[14]*b[30]*b[8]+b[13]*b[31]*b[8]+b[1]*b[17]*b[34]-b[13]*b[5]*b[34]+b[26]*b[5]*b[21]-b[0]*b[21]*b[31]-b[26]*b[17]*b[9]-b[1]*b[21]*b[30]+b[27]*b[4]*b[21]+b[0]*b[17]*b[35]-b[0]*b[22]*b[30]+b[13]*b[30]*b[9]+b[0]*b[18]*b[34]-b[27]*b[17]*b[8]-b[14]*b[4]*b[34]-b[13]*b[4]*b[35]-b[26]*b[18]*b[8]); + c[8] = (b[14]*b[30]*b[9]+b[14]*b[31]*b[8]+b[13]*b[31]*b[9]-b[13]*b[4]*b[36]-b[13]*b[5]*b[35]+b[15]*b[30]*b[8]-b[13]*b[6]*b[34]+b[13]*b[30]*b[10]+b[13]*b[32]*b[8]-b[14]*b[4]*b[35]-b[14]*b[5]*b[34]+b[26]*b[4]*b[23]+b[26]*b[5]*b[22]+b[26]*b[6]*b[21]-b[26]*b[17]*b[10]-b[15]*b[4]*b[34]-b[26]*b[18]*b[9]-b[26]*b[19]*b[8]+b[27]*b[4]*b[22]+b[27]*b[5]*b[21]-b[27]*b[17]*b[9]-b[27]*b[18]*b[8]-b[1]*b[21]*b[31]-b[0]*b[23]*b[30]-b[0]*b[21]*b[32]+b[28]*b[4]*b[21]-b[28]*b[17]*b[8]+b[2]*b[17]*b[34]+b[0]*b[18]*b[35]-b[0]*b[22]*b[31]+b[0]*b[17]*b[36]+b[0]*b[19]*b[34]-b[1]*b[22]*b[30]+b[1]*b[18]*b[34]+b[1]*b[17]*b[35]-b[2]*b[21]*b[30]); + c[7] = (b[14]*b[30]*b[10]+b[14]*b[32]*b[8]-b[3]*b[21]*b[30]+b[3]*b[17]*b[34]+b[13]*b[32]*b[9]+b[13]*b[33]*b[8]-b[13]*b[4]*b[37]-b[13]*b[5]*b[36]+b[15]*b[30]*b[9]+b[15]*b[31]*b[8]-b[16]*b[4]*b[34]-b[13]*b[6]*b[35]-b[13]*b[7]*b[34]+b[13]*b[30]*b[11]+b[13]*b[31]*b[10]+b[14]*b[31]*b[9]-b[14]*b[4]*b[36]-b[14]*b[5]*b[35]-b[14]*b[6]*b[34]+b[16]*b[30]*b[8]-b[26]*b[20]*b[8]+b[26]*b[4]*b[24]+b[26]*b[5]*b[23]+b[26]*b[6]*b[22]+b[26]*b[7]*b[21]-b[26]*b[17]*b[11]-b[15]*b[4]*b[35]-b[15]*b[5]*b[34]-b[26]*b[18]*b[10]-b[26]*b[19]*b[9]+b[27]*b[4]*b[23]+b[27]*b[5]*b[22]+b[27]*b[6]*b[21]-b[27]*b[17]*b[10]-b[27]*b[18]*b[9]-b[27]*b[19]*b[8]+b[0]*b[17]*b[37]-b[0]*b[23]*b[31]-b[0]*b[24]*b[30]-b[0]*b[21]*b[33]-b[29]*b[17]*b[8]+b[28]*b[4]*b[22]+b[28]*b[5]*b[21]-b[28]*b[17]*b[9]-b[28]*b[18]*b[8]+b[29]*b[4]*b[21]+b[1]*b[19]*b[34]-b[2]*b[21]*b[31]+b[0]*b[20]*b[34]+b[0]*b[19]*b[35]+b[0]*b[18]*b[36]-b[0]*b[22]*b[32]-b[1]*b[23]*b[30]-b[1]*b[21]*b[32]+b[1]*b[18]*b[35]-b[1]*b[22]*b[31]-b[2]*b[22]*b[30]+b[2]*b[17]*b[35]+b[1]*b[17]*b[36]+b[2]*b[18]*b[34]); + c[6] = (-b[14]*b[6]*b[35]-b[14]*b[7]*b[34]-b[3]*b[22]*b[30]-b[3]*b[21]*b[31]+b[3]*b[17]*b[35]+b[3]*b[18]*b[34]+b[13]*b[32]*b[10]+b[13]*b[33]*b[9]-b[13]*b[4]*b[38]-b[13]*b[5]*b[37]-b[15]*b[6]*b[34]+b[15]*b[30]*b[10]+b[15]*b[32]*b[8]-b[16]*b[4]*b[35]-b[13]*b[6]*b[36]-b[13]*b[7]*b[35]+b[13]*b[31]*b[11]+b[13]*b[30]*b[12]+b[14]*b[32]*b[9]+b[14]*b[33]*b[8]-b[14]*b[4]*b[37]-b[14]*b[5]*b[36]+b[16]*b[30]*b[9]+b[16]*b[31]*b[8]-b[26]*b[20]*b[9]+b[26]*b[4]*b[25]+b[26]*b[5]*b[24]+b[26]*b[6]*b[23]+b[26]*b[7]*b[22]-b[26]*b[17]*b[12]+b[14]*b[30]*b[11]+b[14]*b[31]*b[10]+b[15]*b[31]*b[9]-b[15]*b[4]*b[36]-b[15]*b[5]*b[35]-b[26]*b[18]*b[11]-b[26]*b[19]*b[10]-b[27]*b[20]*b[8]+b[27]*b[4]*b[24]+b[27]*b[5]*b[23]+b[27]*b[6]*b[22]+b[27]*b[7]*b[21]-b[27]*b[17]*b[11]-b[27]*b[18]*b[10]-b[27]*b[19]*b[9]-b[16]*b[5]*b[34]-b[29]*b[17]*b[9]-b[29]*b[18]*b[8]+b[28]*b[4]*b[23]+b[28]*b[5]*b[22]+b[28]*b[6]*b[21]-b[28]*b[17]*b[10]-b[28]*b[18]*b[9]-b[28]*b[19]*b[8]+b[29]*b[4]*b[22]+b[29]*b[5]*b[21]-b[2]*b[23]*b[30]+b[2]*b[18]*b[35]-b[1]*b[22]*b[32]-b[2]*b[21]*b[32]+b[2]*b[19]*b[34]+b[0]*b[19]*b[36]-b[0]*b[22]*b[33]+b[0]*b[20]*b[35]-b[0]*b[23]*b[32]-b[0]*b[25]*b[30]+b[0]*b[17]*b[38]+b[0]*b[18]*b[37]-b[0]*b[24]*b[31]+b[1]*b[17]*b[37]-b[1]*b[23]*b[31]-b[1]*b[24]*b[30]-b[1]*b[21]*b[33]+b[1]*b[20]*b[34]+b[1]*b[19]*b[35]+b[1]*b[18]*b[36]+b[2]*b[17]*b[36]-b[2]*b[22]*b[31]); + c[5] = (-b[14]*b[6]*b[36]-b[14]*b[7]*b[35]+b[14]*b[31]*b[11]-b[3]*b[23]*b[30]-b[3]*b[21]*b[32]+b[3]*b[18]*b[35]-b[3]*b[22]*b[31]+b[3]*b[17]*b[36]+b[3]*b[19]*b[34]+b[13]*b[32]*b[11]+b[13]*b[33]*b[10]-b[13]*b[5]*b[38]-b[15]*b[6]*b[35]-b[15]*b[7]*b[34]+b[15]*b[30]*b[11]+b[15]*b[31]*b[10]+b[16]*b[31]*b[9]-b[13]*b[6]*b[37]-b[13]*b[7]*b[36]+b[13]*b[31]*b[12]+b[14]*b[32]*b[10]+b[14]*b[33]*b[9]-b[14]*b[4]*b[38]-b[14]*b[5]*b[37]-b[16]*b[6]*b[34]+b[16]*b[30]*b[10]+b[16]*b[32]*b[8]-b[26]*b[20]*b[10]+b[26]*b[5]*b[25]+b[26]*b[6]*b[24]+b[26]*b[7]*b[23]+b[14]*b[30]*b[12]+b[15]*b[32]*b[9]+b[15]*b[33]*b[8]-b[15]*b[4]*b[37]-b[15]*b[5]*b[36]+b[29]*b[5]*b[22]+b[29]*b[6]*b[21]-b[26]*b[18]*b[12]-b[26]*b[19]*b[11]-b[27]*b[20]*b[9]+b[27]*b[4]*b[25]+b[27]*b[5]*b[24]+b[27]*b[6]*b[23]+b[27]*b[7]*b[22]-b[27]*b[17]*b[12]-b[27]*b[18]*b[11]-b[27]*b[19]*b[10]-b[28]*b[20]*b[8]-b[16]*b[4]*b[36]-b[16]*b[5]*b[35]-b[29]*b[17]*b[10]-b[29]*b[18]*b[9]-b[29]*b[19]*b[8]+b[28]*b[4]*b[24]+b[28]*b[5]*b[23]+b[28]*b[6]*b[22]+b[28]*b[7]*b[21]-b[28]*b[17]*b[11]-b[28]*b[18]*b[10]-b[28]*b[19]*b[9]+b[29]*b[4]*b[23]-b[2]*b[22]*b[32]-b[2]*b[21]*b[33]-b[1]*b[24]*b[31]+b[0]*b[18]*b[38]-b[0]*b[24]*b[32]+b[0]*b[19]*b[37]+b[0]*b[20]*b[36]-b[0]*b[25]*b[31]-b[0]*b[23]*b[33]+b[1]*b[19]*b[36]-b[1]*b[22]*b[33]+b[1]*b[20]*b[35]+b[2]*b[19]*b[35]-b[2]*b[24]*b[30]-b[2]*b[23]*b[31]+b[2]*b[20]*b[34]+b[2]*b[17]*b[37]-b[1]*b[25]*b[30]+b[1]*b[18]*b[37]+b[1]*b[17]*b[38]-b[1]*b[23]*b[32]+b[2]*b[18]*b[36]); + c[4] = (-b[14]*b[6]*b[37]-b[14]*b[7]*b[36]+b[14]*b[31]*b[12]+b[3]*b[17]*b[37]-b[3]*b[23]*b[31]-b[3]*b[24]*b[30]-b[3]*b[21]*b[33]+b[3]*b[20]*b[34]+b[3]*b[19]*b[35]+b[3]*b[18]*b[36]-b[3]*b[22]*b[32]+b[13]*b[32]*b[12]+b[13]*b[33]*b[11]-b[15]*b[6]*b[36]-b[15]*b[7]*b[35]+b[15]*b[31]*b[11]+b[15]*b[30]*b[12]+b[16]*b[32]*b[9]+b[16]*b[33]*b[8]-b[13]*b[6]*b[38]-b[13]*b[7]*b[37]+b[14]*b[32]*b[11]+b[14]*b[33]*b[10]-b[14]*b[5]*b[38]-b[16]*b[6]*b[35]-b[16]*b[7]*b[34]+b[16]*b[30]*b[11]+b[16]*b[31]*b[10]-b[26]*b[19]*b[12]-b[26]*b[20]*b[11]+b[26]*b[6]*b[25]+b[26]*b[7]*b[24]+b[15]*b[32]*b[10]+b[15]*b[33]*b[9]-b[15]*b[4]*b[38]-b[15]*b[5]*b[37]+b[29]*b[5]*b[23]+b[29]*b[6]*b[22]+b[29]*b[7]*b[21]-b[27]*b[20]*b[10]+b[27]*b[5]*b[25]+b[27]*b[6]*b[24]+b[27]*b[7]*b[23]-b[27]*b[18]*b[12]-b[27]*b[19]*b[11]-b[28]*b[20]*b[9]-b[16]*b[4]*b[37]-b[16]*b[5]*b[36]+b[0]*b[19]*b[38]-b[0]*b[24]*b[33]+b[0]*b[20]*b[37]-b[29]*b[17]*b[11]-b[29]*b[18]*b[10]-b[29]*b[19]*b[9]+b[28]*b[4]*b[25]+b[28]*b[5]*b[24]+b[28]*b[6]*b[23]+b[28]*b[7]*b[22]-b[28]*b[17]*b[12]-b[28]*b[18]*b[11]-b[28]*b[19]*b[10]-b[29]*b[20]*b[8]+b[29]*b[4]*b[24]+b[2]*b[18]*b[37]-b[0]*b[25]*b[32]+b[1]*b[18]*b[38]-b[1]*b[24]*b[32]+b[1]*b[19]*b[37]+b[1]*b[20]*b[36]-b[1]*b[25]*b[31]+b[2]*b[17]*b[38]+b[2]*b[19]*b[36]-b[2]*b[24]*b[31]-b[2]*b[22]*b[33]-b[2]*b[23]*b[32]+b[2]*b[20]*b[35]-b[1]*b[23]*b[33]-b[2]*b[25]*b[30]); + c[3] = (-b[14]*b[6]*b[38]-b[14]*b[7]*b[37]+b[3]*b[19]*b[36]-b[3]*b[22]*b[33]+b[3]*b[20]*b[35]-b[3]*b[23]*b[32]-b[3]*b[25]*b[30]+b[3]*b[17]*b[38]+b[3]*b[18]*b[37]-b[3]*b[24]*b[31]-b[15]*b[6]*b[37]-b[15]*b[7]*b[36]+b[15]*b[31]*b[12]+b[16]*b[32]*b[10]+b[16]*b[33]*b[9]+b[13]*b[33]*b[12]-b[13]*b[7]*b[38]+b[14]*b[32]*b[12]+b[14]*b[33]*b[11]-b[16]*b[6]*b[36]-b[16]*b[7]*b[35]+b[16]*b[31]*b[11]+b[16]*b[30]*b[12]+b[15]*b[32]*b[11]+b[15]*b[33]*b[10]-b[15]*b[5]*b[38]+b[29]*b[5]*b[24]+b[29]*b[6]*b[23]-b[26]*b[20]*b[12]+b[26]*b[7]*b[25]-b[27]*b[19]*b[12]-b[27]*b[20]*b[11]+b[27]*b[6]*b[25]+b[27]*b[7]*b[24]-b[28]*b[20]*b[10]-b[16]*b[4]*b[38]-b[16]*b[5]*b[37]+b[29]*b[7]*b[22]-b[29]*b[17]*b[12]-b[29]*b[18]*b[11]-b[29]*b[19]*b[10]+b[28]*b[5]*b[25]+b[28]*b[6]*b[24]+b[28]*b[7]*b[23]-b[28]*b[18]*b[12]-b[28]*b[19]*b[11]-b[29]*b[20]*b[9]+b[29]*b[4]*b[25]-b[2]*b[24]*b[32]+b[0]*b[20]*b[38]-b[0]*b[25]*b[33]+b[1]*b[19]*b[38]-b[1]*b[24]*b[33]+b[1]*b[20]*b[37]-b[2]*b[25]*b[31]+b[2]*b[20]*b[36]-b[1]*b[25]*b[32]+b[2]*b[19]*b[37]+b[2]*b[18]*b[38]-b[2]*b[23]*b[33]); + c[2] = (b[3]*b[18]*b[38]-b[3]*b[24]*b[32]+b[3]*b[19]*b[37]+b[3]*b[20]*b[36]-b[3]*b[25]*b[31]-b[3]*b[23]*b[33]-b[15]*b[6]*b[38]-b[15]*b[7]*b[37]+b[16]*b[32]*b[11]+b[16]*b[33]*b[10]-b[16]*b[5]*b[38]-b[16]*b[6]*b[37]-b[16]*b[7]*b[36]+b[16]*b[31]*b[12]+b[14]*b[33]*b[12]-b[14]*b[7]*b[38]+b[15]*b[32]*b[12]+b[15]*b[33]*b[11]+b[29]*b[5]*b[25]+b[29]*b[6]*b[24]-b[27]*b[20]*b[12]+b[27]*b[7]*b[25]-b[28]*b[19]*b[12]-b[28]*b[20]*b[11]+b[29]*b[7]*b[23]-b[29]*b[18]*b[12]-b[29]*b[19]*b[11]+b[28]*b[6]*b[25]+b[28]*b[7]*b[24]-b[29]*b[20]*b[10]+b[2]*b[19]*b[38]-b[1]*b[25]*b[33]+b[2]*b[20]*b[37]-b[2]*b[24]*b[33]-b[2]*b[25]*b[32]+b[1]*b[20]*b[38]); + c[1] = (b[29]*b[7]*b[24]-b[29]*b[20]*b[11]+b[2]*b[20]*b[38]-b[2]*b[25]*b[33]-b[28]*b[20]*b[12]+b[28]*b[7]*b[25]-b[29]*b[19]*b[12]-b[3]*b[24]*b[33]+b[15]*b[33]*b[12]+b[3]*b[19]*b[38]-b[16]*b[6]*b[38]+b[3]*b[20]*b[37]+b[16]*b[32]*b[12]+b[29]*b[6]*b[25]-b[16]*b[7]*b[37]-b[3]*b[25]*b[32]-b[15]*b[7]*b[38]+b[16]*b[33]*b[11]); + c[0] = -b[29]*b[20]*b[12]+b[29]*b[7]*b[25]+b[16]*b[33]*b[12]-b[16]*b[7]*b[38]+b[3]*b[20]*b[38]-b[3]*b[25]*b[33]; + + std::vector > roots; + solvePoly(coeffs, roots); + + std::vector xs, ys, zs; + int count = 0; + + Mat ematrix(10*3, 3, CV_64F); + double* e = ematrix.ptr(); + for (size_t i = 0; i < roots.size(); i++) + { + if (fabs(roots[i].imag()) > 1e-10) continue; + double z1 = roots[i].real(); + double z2 = z1 * z1; + double z3 = z2 * z1; + double z4 = z3 * z1; + + double bz[3][3]; + for (int j = 0; j < 3; j++) + { + const double * br = b + j * 13; + bz[j][0] = br[0] * z3 + br[1] * z2 + br[2] * z1 + br[3]; + bz[j][1] = br[4] * z3 + br[5] * z2 + br[6] * z1 + br[7]; + bz[j][2] = br[8] * z4 + br[9] * z3 + br[10] * z2 + br[11] * z1 + br[12]; + } + + Mat Bz(3, 3, CV_64F, bz); + cv::Mat xy1; + SVD::solveZ(Bz, xy1); + + if (fabs(xy1.at(2)) < 1e-10) continue; + xs.push_back(xy1.at(0) / xy1.at(2)); + ys.push_back(xy1.at(1) / xy1.at(2)); + zs.push_back(z1); + + cv::Mat Evec = EE.col(0) * xs.back() + EE.col(1) * ys.back() + EE.col(2) * zs.back() + EE.col(3); + Evec /= norm(Evec); + + memcpy(e + count * 9, Evec.data, 9 * sizeof(double)); + count++; + } - CvMat p1 = points1; - CvMat p2 = points2; - CvMat _E = E; - CvMat* tempMask = cvCreateMat(1, npoints, CV_8U); + ematrix.rowRange(0, count*3).copyTo(_model); + return count; + } - assert(npoints >= 5); - threshold /= focal; - int count = 1; - if (npoints == 5) +protected: + void calibrated_fivepoint_helper( double *EE, double* A ) const { - E.create(3 * 10, 3, CV_64F); - _E = E; - count = estimator.runKernel(&p1, &p2, &_E); - E = E.rowRange(0, 3 * count) * 1.0; - Mat(tempMask).setTo(true); + double e00,e01,e02,e03,e04,e05,e06,e07,e08; + double e10,e11,e12,e13,e14,e15,e16,e17,e18; + double e20,e21,e22,e23,e24,e25,e26,e27,e28; + double e30,e31,e32,e33,e34,e35,e36,e37,e38; + + double e002,e012,e022,e032,e042,e052,e062,e072,e082; + double e102,e112,e122,e132,e142,e152,e162,e172,e182; + double e202,e212,e222,e232,e242,e252,e262,e272,e282; + double e302,e312,e322,e332,e342,e352,e362,e372,e382; + + double e003,e013,e023,e033,e043,e053,e063,e073,e083; + double e103,e113,e123,e133,e143,e153,e163,e173,e183; + double e203,e213,e223,e233,e243,e253,e263,e273,e283; + double e303,e313,e323,e333,e343,e353,e363,e373,e383; + e00 = EE[0*9 + 0 ]; + e10 = EE[1*9 + 0 ]; + e20 = EE[2*9 + 0 ]; + e30 = EE[3*9 + 0 ]; + e01 = EE[0*9 + 1 ]; + e11 = EE[1*9 + 1 ]; + e21 = EE[2*9 + 1 ]; + e31 = EE[3*9 + 1 ]; + e02 = EE[0*9 + 2 ]; + e12 = EE[1*9 + 2 ]; + e22 = EE[2*9 + 2 ]; + e32 = EE[3*9 + 2 ]; + e03 = EE[0*9 + 3 ]; + e13 = EE[1*9 + 3 ]; + e23 = EE[2*9 + 3 ]; + e33 = EE[3*9 + 3 ]; + e04 = EE[0*9 + 4 ]; + e14 = EE[1*9 + 4 ]; + e24 = EE[2*9 + 4 ]; + e34 = EE[3*9 + 4 ]; + e05 = EE[0*9 + 5 ]; + e15 = EE[1*9 + 5 ]; + e25 = EE[2*9 + 5 ]; + e35 = EE[3*9 + 5 ]; + e06 = EE[0*9 + 6 ]; + e16 = EE[1*9 + 6 ]; + e26 = EE[2*9 + 6 ]; + e36 = EE[3*9 + 6 ]; + e07 = EE[0*9 + 7 ]; + e17 = EE[1*9 + 7 ]; + e27 = EE[2*9 + 7 ]; + e37 = EE[3*9 + 7 ]; + e08 = EE[0*9 + 8 ]; + e18 = EE[1*9 + 8 ]; + e28 = EE[2*9 + 8 ]; + e38 = EE[3*9 + 8 ]; + + + e002 =e00*e00; + e102 =e10*e10; + e202 =e20*e20; + e302 =e30*e30; + e012 =e01*e01; + e112 =e11*e11; + e212 =e21*e21; + e312 =e31*e31; + e022 =e02*e02; + e122 =e12*e12; + e222 =e22*e22; + e322 =e32*e32; + e032 =e03*e03; + e132 =e13*e13; + e232 =e23*e23; + e332 =e33*e33; + e042 =e04*e04; + e142 =e14*e14; + e242 =e24*e24; + e342 =e34*e34; + e052 =e05*e05; + e152 =e15*e15; + e252 =e25*e25; + e352 =e35*e35; + e062 =e06*e06; + e162 =e16*e16; + e262 =e26*e26; + e362 =e36*e36; + e072 =e07*e07; + e172 =e17*e17; + e272 =e27*e27; + e372 =e37*e37; + e082 =e08*e08; + e182 =e18*e18; + e282 =e28*e28; + e382 =e38*e38; + + e003 =e00*e00*e00; + e103 =e10*e10*e10; + e203 =e20*e20*e20; + e303 =e30*e30*e30; + e013 =e01*e01*e01; + e113 =e11*e11*e11; + e213 =e21*e21*e21; + e313 =e31*e31*e31; + e023 =e02*e02*e02; + e123 =e12*e12*e12; + e223 =e22*e22*e22; + e323 =e32*e32*e32; + e033 =e03*e03*e03; + e133 =e13*e13*e13; + e233 =e23*e23*e23; + e333 =e33*e33*e33; + e043 =e04*e04*e04; + e143 =e14*e14*e14; + e243 =e24*e24*e24; + e343 =e34*e34*e34; + e053 =e05*e05*e05; + e153 =e15*e15*e15; + e253 =e25*e25*e25; + e353 =e35*e35*e35; + e063 =e06*e06*e06; + e163 =e16*e16*e16; + e263 =e26*e26*e26; + e363 =e36*e36*e36; + e073 =e07*e07*e07; + e173 =e17*e17*e17; + e273 =e27*e27*e27; + e373 =e37*e37*e37; + e083 =e08*e08*e08; + e183 =e18*e18*e18; + e283 =e28*e28*e28; + e383 =e38*e38*e38; + + + A[0 + 10*0]=0.5*e003+0.5*e00*e012+0.5*e00*e022+0.5*e00*e032+e03*e01*e04+e03*e02*e05+0.5*e00*e062+e06*e01*e07+e06*e02*e08-0.5*e00*e042-0.5*e00*e052-0.5*e00*e072-0.5*e00*e082; + A[0 + 10*1]=e00*e11*e01+e00*e12*e02+e03*e00*e13+e03*e11*e04+e03*e01*e14+e03*e12*e05+e03*e02*e15+e13*e01*e04+e13*e02*e05+e06*e00*e16+1.5*e10*e002+0.5*e10*e012+0.5*e10*e022+0.5*e10*e062-0.5*e10*e042-0.5*e10*e052-0.5*e10*e072+0.5*e10*e032+e06*e11*e07+e06*e01*e17+e06*e12*e08+e06*e02*e18+e16*e01*e07+e16*e02*e08-e00*e14*e04-e00*e17*e07-e00*e15*e05-e00*e18*e08-0.5*e10*e082; + A[0 + 10*2]=e16*e02*e18+e03*e12*e15+e10*e11*e01+e10*e12*e02+e03*e10*e13+e03*e11*e14+e13*e11*e04+e13*e01*e14+e13*e12*e05+e13*e02*e15+e06*e10*e16+e06*e12*e18+e06*e11*e17+e16*e11*e07+e16*e01*e17+e16*e12*e08-e10*e14*e04-e10*e17*e07-e10*e15*e05-e10*e18*e08+1.5*e00*e102+0.5*e00*e122+0.5*e00*e112+0.5*e00*e132+0.5*e00*e162-0.5*e00*e152-0.5*e00*e172-0.5*e00*e182-0.5*e00*e142; + A[0 + 10*3]=0.5*e103+0.5*e10*e122+0.5*e10*e112+0.5*e10*e132+e13*e12*e15+e13*e11*e14+0.5*e10*e162+e16*e12*e18+e16*e11*e17-0.5*e10*e152-0.5*e10*e172-0.5*e10*e182-0.5*e10*e142; + A[0 + 10*4]=-e00*e28*e08-e00*e25*e05-e00*e27*e07-e00*e24*e04+e26*e02*e08+e26*e01*e07+e06*e02*e28+e06*e22*e08+e06*e01*e27+e06*e21*e07+e23*e02*e05+e23*e01*e04+e03*e02*e25+e03*e22*e05+e03*e01*e24+e03*e21*e04+e00*e22*e02+e00*e21*e01-0.5*e20*e082-0.5*e20*e052-0.5*e20*e072-0.5*e20*e042+e06*e00*e26+0.5*e20*e062+e03*e00*e23+0.5*e20*e022+1.5*e20*e002+0.5*e20*e032+0.5*e20*e012; + A[0 + 10*5]=-e10*e24*e04-e10*e27*e07-e10*e25*e05-e10*e28*e08-e20*e14*e04-e20*e17*e07-e20*e15*e05-e20*e18*e08-e00*e24*e14-e00*e25*e15-e00*e27*e17-e00*e28*e18+e06*e21*e17+e06*e22*e18+e06*e12*e28+e16*e00*e26+e16*e21*e07+e16*e01*e27+e16*e22*e08+e16*e02*e28+e26*e11*e07+e26*e01*e17+e26*e12*e08+e26*e02*e18+e06*e11*e27+e23*e11*e04+e23*e01*e14+e23*e12*e05+e23*e02*e15+e06*e20*e16+e06*e10*e26+e03*e21*e14+e03*e22*e15+e03*e12*e25+e13*e00*e23+e13*e21*e04+e13*e01*e24+e13*e22*e05+e13*e02*e25+e03*e11*e24+e03*e20*e13+e03*e10*e23+e00*e21*e11+3*e00*e20*e10+e00*e22*e12+e20*e12*e02+e20*e11*e01+e10*e22*e02+e10*e21*e01; + A[0 + 10*6]=-0.5*e20*e152+e26*e11*e17-e10*e24*e14-e10*e25*e15-e10*e27*e17-e10*e28*e18+0.5*e20*e162+e13*e10*e23+e13*e22*e15+e23*e12*e15+e23*e11*e14+e16*e10*e26+e16*e21*e17+e16*e11*e27+e16*e22*e18+e16*e12*e28+e26*e12*e18+e13*e12*e25+0.5*e20*e132+1.5*e20*e102+0.5*e20*e122+0.5*e20*e112+e10*e21*e11+e10*e22*e12+e13*e11*e24-0.5*e20*e172-0.5*e20*e182-0.5*e20*e142+e13*e21*e14; + A[0 + 10*7]=-e20*e25*e05-e20*e28*e08-0.5*e00*e272-0.5*e00*e282-0.5*e00*e242+0.5*e00*e262-0.5*e00*e252+e06*e20*e26+0.5*e00*e232+e06*e22*e28+e06*e21*e27+e26*e21*e07+e26*e01*e27+e26*e22*e08+e26*e02*e28-e20*e24*e04-e20*e27*e07+e03*e20*e23+e03*e22*e25+e03*e21*e24+e23*e21*e04+e23*e01*e24+e23*e22*e05+e23*e02*e25+e20*e21*e01+e20*e22*e02+1.5*e00*e202+0.5*e00*e222+0.5*e00*e212; + A[0 + 10*8]=e23*e21*e14+e23*e11*e24+e23*e22*e15+e23*e12*e25+e16*e20*e26+e16*e22*e28+e16*e21*e27+e26*e21*e17+e26*e11*e27+e26*e22*e18+e26*e12*e28+1.5*e10*e202+0.5*e10*e222+0.5*e10*e212+0.5*e10*e232+e20*e21*e11+e20*e22*e12+e13*e20*e23+e13*e22*e25+e13*e21*e24-e20*e24*e14-e20*e25*e15-e20*e27*e17-e20*e28*e18-0.5*e10*e272-0.5*e10*e282-0.5*e10*e242-0.5*e10*e252+0.5*e10*e262; + A[0 + 10*9]=0.5*e203+0.5*e20*e222+0.5*e20*e212+0.5*e20*e232+e23*e22*e25+e23*e21*e24+0.5*e20*e262+e26*e22*e28+e26*e21*e27-0.5*e20*e252-0.5*e20*e272-0.5*e20*e282-0.5*e20*e242; + A[0 + 10*10]=e06*e32*e08-0.5*e30*e082-0.5*e30*e042-0.5*e30*e052-0.5*e30*e072+0.5*e30*e012+0.5*e30*e022+0.5*e30*e032+0.5*e30*e062+1.5*e30*e002+e00*e31*e01+e00*e32*e02+e03*e31*e04+e03*e01*e34+e03*e32*e05+e03*e02*e35+e33*e01*e04+e33*e02*e05+e06*e00*e36+e06*e31*e07+e06*e01*e37+e06*e02*e38+e36*e01*e07+e36*e02*e08-e00*e34*e04-e00*e37*e07-e00*e35*e05-e00*e38*e08+e03*e00*e33; + A[0 + 10*11]=e06*e30*e16+e03*e30*e13+e16*e31*e07+e06*e10*e36-e10*e37*e07+3*e00*e30*e10+e00*e32*e12-e00*e38*e18-e10*e34*e04-e10*e35*e05-e10*e38*e08-e30*e14*e04-e30*e17*e07-e30*e15*e05-e30*e18*e08+e00*e31*e11+e10*e31*e01+e10*e32*e02+e30*e11*e01+e30*e12*e02+e03*e10*e33-e00*e34*e14-e00*e35*e15-e00*e37*e17+e03*e31*e14+e03*e11*e34+e03*e32*e15+e03*e12*e35+e13*e00*e33+e13*e31*e04+e13*e01*e34+e13*e32*e05+e13*e02*e35+e33*e11*e04+e33*e01*e14+e33*e12*e05+e33*e02*e15+e06*e31*e17+e06*e11*e37+e06*e32*e18+e06*e12*e38+e16*e00*e36+e16*e01*e37+e16*e32*e08+e16*e02*e38+e36*e11*e07+e36*e01*e17+e36*e12*e08+e36*e02*e18; + A[0 + 10*12]=e13*e10*e33+e33*e11*e14+e16*e10*e36+e16*e31*e17+e16*e11*e37+e16*e32*e18+e16*e12*e38+e36*e12*e18+e36*e11*e17-e10*e34*e14-e10*e35*e15-e10*e37*e17-e10*e38*e18+e10*e31*e11+e10*e32*e12+e13*e31*e14+e13*e11*e34+e13*e32*e15+e13*e12*e35+e33*e12*e15+1.5*e30*e102+0.5*e30*e122+0.5*e30*e112+0.5*e30*e132+0.5*e30*e162-0.5*e30*e152-0.5*e30*e172-0.5*e30*e182-0.5*e30*e142; + A[0 + 10*13]=e00*e32*e22+3*e00*e30*e20+e00*e31*e21+e20*e31*e01+e20*e32*e02+e30*e21*e01+e30*e22*e02+e03*e20*e33+e03*e32*e25+e03*e22*e35+e03*e31*e24+e03*e21*e34+e23*e00*e33+e23*e31*e04+e23*e01*e34+e23*e32*e05+e23*e02*e35+e33*e21*e04+e33*e01*e24+e33*e22*e05+e33*e02*e25+e06*e30*e26+e06*e20*e36+e06*e32*e28+e06*e22*e38+e06*e31*e27+e06*e21*e37+e26*e00*e36+e26*e31*e07+e03*e30*e23+e26*e01*e37+e26*e32*e08+e26*e02*e38+e36*e21*e07+e36*e01*e27+e36*e22*e08+e36*e02*e28-e00*e35*e25-e00*e37*e27-e00*e38*e28-e00*e34*e24-e20*e34*e04-e20*e37*e07-e20*e35*e05-e20*e38*e08-e30*e24*e04-e30*e27*e07-e30*e25*e05-e30*e28*e08; + A[0 + 10*14]=e16*e30*e26+e13*e21*e34+3*e10*e30*e20+e10*e32*e22+e10*e31*e21+e20*e31*e11+e20*e32*e12+e30*e21*e11+e30*e22*e12+e13*e30*e23+e13*e20*e33+e13*e32*e25+e13*e22*e35+e13*e31*e24+e23*e10*e33+e23*e31*e14+e23*e11*e34+e23*e32*e15+e23*e12*e35+e33*e21*e14+e33*e11*e24+e33*e22*e15+e33*e12*e25+e16*e20*e36+e16*e32*e28+e16*e22*e38+e16*e31*e27+e16*e21*e37+e26*e10*e36+e26*e31*e17+e26*e11*e37+e26*e32*e18+e26*e12*e38+e36*e21*e17+e36*e11*e27+e36*e22*e18+e36*e12*e28-e10*e35*e25-e10*e37*e27-e10*e38*e28-e10*e34*e24-e20*e34*e14-e20*e35*e15-e20*e37*e17-e20*e38*e18-e30*e24*e14-e30*e25*e15-e30*e27*e17-e30*e28*e18; + A[0 + 10*15]=-e20*e34*e24+0.5*e30*e262-0.5*e30*e252-0.5*e30*e272-0.5*e30*e282-0.5*e30*e242+1.5*e30*e202+0.5*e30*e222+0.5*e30*e212+0.5*e30*e232+e20*e32*e22+e20*e31*e21+e23*e20*e33+e23*e32*e25+e23*e22*e35+e23*e31*e24+e23*e21*e34+e33*e22*e25+e33*e21*e24+e26*e20*e36+e26*e32*e28+e26*e22*e38+e26*e31*e27+e26*e21*e37+e36*e22*e28+e36*e21*e27-e20*e35*e25-e20*e37*e27-e20*e38*e28; + A[0 + 10*16]=0.5*e00*e322+e30*e32*e02+e30*e31*e01+1.5*e00*e302+0.5*e00*e312+e03*e32*e35+e33*e31*e04+e33*e01*e34+e33*e32*e05+e33*e02*e35+e06*e30*e36+e06*e31*e37+e06*e32*e38+e36*e31*e07+e36*e01*e37+e36*e32*e08+e36*e02*e38-e30*e34*e04-e30*e37*e07-e30*e35*e05-e30*e38*e08+0.5*e00*e332+0.5*e00*e362-0.5*e00*e382-0.5*e00*e352-0.5*e00*e342-0.5*e00*e372+e03*e30*e33+e03*e31*e34; + A[0 + 10*17]=0.5*e10*e362-0.5*e10*e382-0.5*e10*e352-0.5*e10*e342-0.5*e10*e372+e36*e31*e17+e36*e11*e37+e36*e32*e18+e36*e12*e38-e30*e34*e14-e30*e35*e15-e30*e37*e17-e30*e38*e18+1.5*e10*e302+0.5*e10*e312+0.5*e10*e322+0.5*e10*e332+e30*e31*e11+e30*e32*e12+e13*e30*e33+e13*e31*e34+e13*e32*e35+e33*e31*e14+e33*e11*e34+e33*e32*e15+e33*e12*e35+e16*e30*e36+e16*e31*e37+e16*e32*e38; + A[0 + 10*18]=e33*e31*e24+e33*e21*e34+e26*e30*e36+e26*e31*e37+e26*e32*e38+e36*e32*e28+e36*e22*e38+e36*e31*e27+e36*e21*e37-e30*e35*e25-e30*e37*e27-e30*e38*e28-e30*e34*e24+e33*e22*e35+1.5*e20*e302+0.5*e20*e312+0.5*e20*e322+0.5*e20*e332+0.5*e20*e362-0.5*e20*e382-0.5*e20*e352-0.5*e20*e342-0.5*e20*e372+e30*e32*e22+e30*e31*e21+e23*e30*e33+e23*e31*e34+e23*e32*e35+e33*e32*e25; + A[0 + 10*19]=0.5*e303+0.5*e30*e312+0.5*e30*e322+0.5*e30*e332+e33*e31*e34+e33*e32*e35+0.5*e30*e362+e36*e31*e37+e36*e32*e38-0.5*e30*e382-0.5*e30*e352-0.5*e30*e342-0.5*e30*e372; + A[1 + 10*0]=e00*e01*e04+0.5*e002*e03+e00*e02*e05+0.5*e033+0.5*e03*e042+0.5*e03*e052+0.5*e03*e062+e06*e04*e07+e06*e05*e08-0.5*e03*e012-0.5*e03*e072-0.5*e03*e022-0.5*e03*e082; + A[1 + 10*1]=e03*e14*e04+e10*e01*e04+e16*e05*e08+e00*e10*e03+e00*e11*e04+e00*e01*e14+e00*e12*e05+e00*e02*e15+e10*e02*e05+e03*e15*e05+e06*e03*e16+e06*e14*e07+e06*e04*e17+e06*e15*e08+e06*e05*e18+0.5*e002*e13+1.5*e13*e032+0.5*e13*e042+0.5*e13*e052+0.5*e13*e062-0.5*e13*e012-0.5*e13*e072-0.5*e13*e022-0.5*e13*e082+e16*e04*e07-e03*e12*e02-e03*e11*e01-e03*e17*e07-e03*e18*e08; + A[1 + 10*2]=-e13*e11*e01+e00*e10*e13+e00*e12*e15+e00*e11*e14+e10*e11*e04+e10*e01*e14+e10*e12*e05+e10*e02*e15+e13*e14*e04+e13*e15*e05+e06*e13*e16+e06*e15*e18+e06*e14*e17+e16*e14*e07+e16*e04*e17+e16*e15*e08+e16*e05*e18-e13*e12*e02-e13*e17*e07-e13*e18*e08+0.5*e102*e03+1.5*e03*e132+0.5*e03*e152+0.5*e03*e142+0.5*e03*e162-0.5*e03*e112-0.5*e03*e172-0.5*e03*e122-0.5*e03*e182; + A[1 + 10*3]=0.5*e102*e13+e10*e11*e14+e10*e12*e15+0.5*e133+0.5*e13*e152+0.5*e13*e142+0.5*e13*e162+e16*e15*e18+e16*e14*e17-0.5*e13*e112-0.5*e13*e122-0.5*e13*e172-0.5*e13*e182; + A[1 + 10*4]=-e03*e28*e08-e03*e27*e07-e03*e21*e01-e03*e22*e02+e26*e05*e08+e26*e04*e07+e06*e05*e28+e06*e25*e08+e06*e04*e27+e06*e24*e07+e03*e25*e05+e03*e24*e04+e20*e02*e05+e20*e01*e04+e00*e02*e25+e00*e22*e05+e00*e01*e24+e00*e21*e04+e00*e20*e03-0.5*e23*e072-0.5*e23*e082-0.5*e23*e022-0.5*e23*e012+e06*e03*e26+0.5*e23*e052+0.5*e23*e062+1.5*e23*e032+0.5*e23*e042+0.5*e002*e23; + A[1 + 10*5]=e00*e21*e14+e00*e11*e24+e00*e10*e23+e00*e22*e15+e00*e12*e25+e20*e12*e05+e20*e01*e14+e20*e11*e04+e00*e20*e13+e10*e02*e25+e10*e22*e05+e10*e01*e24+e10*e21*e04+e10*e20*e03+e23*e15*e05+e23*e14*e04+e13*e25*e05+e13*e24*e04+e03*e24*e14+e03*e25*e15+3*e03*e23*e13+e20*e02*e15+e16*e03*e26+e06*e14*e27-e23*e18*e08+e06*e24*e17+e06*e15*e28+e06*e25*e18+e06*e13*e26+e06*e23*e16+e26*e04*e17+e26*e14*e07+e16*e05*e28+e16*e25*e08+e16*e04*e27+e16*e24*e07-e03*e22*e12-e03*e21*e11+e26*e05*e18+e26*e15*e08-e03*e27*e17-e03*e28*e18-e13*e22*e02-e13*e28*e08-e13*e27*e07-e13*e21*e01-e23*e17*e07-e23*e11*e01-e23*e12*e02; + A[1 + 10*6]=-0.5*e23*e182-0.5*e23*e172-0.5*e23*e112-0.5*e23*e122-e13*e22*e12-e13*e27*e17-e13*e28*e18+e26*e15*e18+e26*e14*e17-e13*e21*e11+e20*e12*e15+e13*e25*e15+e13*e24*e14+e16*e13*e26+e16*e25*e18+e16*e15*e28+e16*e24*e17+e16*e14*e27+1.5*e23*e132+0.5*e23*e152+0.5*e23*e142+0.5*e23*e162+e10*e20*e13+e10*e21*e14+e10*e11*e24+e10*e22*e15+e10*e12*e25+e20*e11*e14+0.5*e102*e23; + A[1 + 10*7]=e26*e04*e27+e00*e22*e25-e23*e28*e08+0.5*e03*e262-0.5*e03*e212-0.5*e03*e272-0.5*e03*e222-0.5*e03*e282+e23*e24*e04+e23*e25*e05+0.5*e202*e03+e06*e23*e26+e06*e24*e27+e06*e25*e28+e26*e24*e07+e26*e25*e08+e26*e05*e28-e23*e22*e02-e23*e21*e01-e23*e27*e07+e00*e20*e23+e00*e21*e24+e20*e21*e04+e20*e01*e24+e20*e22*e05+e20*e02*e25+1.5*e03*e232+0.5*e03*e242+0.5*e03*e252; + A[1 + 10*8]=e20*e11*e24-0.5*e13*e212-0.5*e13*e272-0.5*e13*e222-0.5*e13*e282-e23*e27*e17-e23*e28*e18+e26*e25*e18+e26*e24*e17+e26*e14*e27-e23*e21*e11-e23*e22*e12+e26*e15*e28+e23*e25*e15+e23*e24*e14+e16*e23*e26+e16*e24*e27+e16*e25*e28+0.5*e13*e262+e20*e21*e14+e20*e22*e15+e20*e12*e25+0.5*e13*e242+0.5*e13*e252+0.5*e202*e13+1.5*e13*e232+e10*e20*e23+e10*e22*e25+e10*e21*e24; + A[1 + 10*9]=0.5*e202*e23+e20*e22*e25+e20*e21*e24+0.5*e233+0.5*e23*e242+0.5*e23*e252+0.5*e23*e262+e26*e24*e27+e26*e25*e28-0.5*e23*e212-0.5*e23*e272-0.5*e23*e222-0.5*e23*e282; + A[1 + 10*10]=e00*e30*e03+0.5*e33*e062-0.5*e33*e012-0.5*e33*e022-0.5*e33*e072+e03*e35*e05+e06*e03*e36+e06*e34*e07+e06*e04*e37+e06*e35*e08+e06*e05*e38+e36*e04*e07+e36*e05*e08-e03*e32*e02-e03*e31*e01-e03*e37*e07+e00*e31*e04+e00*e01*e34+e00*e32*e05+e00*e02*e35+e30*e01*e04+e30*e02*e05+e03*e34*e04-e03*e38*e08+0.5*e002*e33+1.5*e33*e032+0.5*e33*e042+0.5*e33*e052-0.5*e33*e082; + A[1 + 10*11]=e06*e35*e18+e06*e33*e16+e00*e30*e13+e00*e10*e33+e00*e31*e14+e00*e11*e34+e00*e32*e15+e00*e12*e35+e10*e30*e03-e33*e17*e07-e33*e18*e08+e10*e31*e04+e10*e01*e34+e10*e32*e05+e10*e02*e35+e30*e11*e04+e30*e01*e14+e30*e12*e05+e30*e02*e15+3*e03*e33*e13+e03*e35*e15+e03*e34*e14+e13*e34*e04+e13*e35*e05+e33*e14*e04+e33*e15*e05+e06*e13*e36+e06*e15*e38+e06*e34*e17+e06*e14*e37+e16*e03*e36+e16*e34*e07+e16*e04*e37+e16*e35*e08+e16*e05*e38+e36*e14*e07+e36*e04*e17+e36*e15*e08+e36*e05*e18-e03*e31*e11-e03*e32*e12-e03*e37*e17-e03*e38*e18-e13*e32*e02-e13*e31*e01-e13*e37*e07-e13*e38*e08-e33*e12*e02-e33*e11*e01; + A[1 + 10*12]=e16*e13*e36+e10*e11*e34+0.5*e33*e152+0.5*e33*e142+0.5*e33*e162-0.5*e33*e112-0.5*e33*e122-0.5*e33*e172-0.5*e33*e182+0.5*e102*e33+1.5*e33*e132+e10*e30*e13+e10*e31*e14+e10*e32*e15+e10*e12*e35+e30*e11*e14+e30*e12*e15+e13*e35*e15+e13*e34*e14+e16*e35*e18+e16*e15*e38+e16*e34*e17+e16*e14*e37+e36*e15*e18+e36*e14*e17-e13*e31*e11-e13*e32*e12-e13*e37*e17-e13*e38*e18; + A[1 + 10*13]=e06*e35*e28+e36*e04*e27+e00*e20*e33+e00*e30*e23+3*e03*e33*e23+e03*e34*e24+e03*e35*e25+e23*e34*e04+e23*e35*e05+e33*e24*e04+e33*e25*e05+e06*e33*e26+e06*e23*e36+e06*e34*e27+e06*e24*e37+e06*e25*e38+e26*e03*e36+e26*e34*e07+e26*e04*e37+e26*e35*e08+e26*e05*e38+e36*e24*e07+e36*e25*e08+e36*e05*e28-e03*e31*e21-e03*e37*e27-e03*e32*e22-e03*e38*e28-e23*e32*e02-e23*e31*e01-e23*e37*e07-e23*e38*e08-e33*e22*e02-e33*e21*e01-e33*e27*e07-e33*e28*e08+e00*e32*e25+e00*e22*e35+e00*e31*e24+e00*e21*e34+e20*e30*e03+e20*e31*e04+e20*e01*e34+e20*e32*e05+e20*e02*e35+e30*e21*e04+e30*e01*e24+e30*e22*e05+e30*e02*e25; + A[1 + 10*14]=e10*e30*e23+e10*e20*e33+e10*e22*e35+e10*e32*e25+e10*e31*e24+e10*e21*e34+e20*e30*e13+e20*e31*e14+e20*e11*e34+e20*e32*e15+e20*e12*e35+e30*e21*e14+e30*e11*e24+e30*e22*e15+e30*e12*e25+3*e13*e33*e23+e13*e34*e24+e13*e35*e25+e23*e35*e15+e23*e34*e14+e33*e25*e15+e33*e24*e14+e16*e33*e26+e16*e23*e36+e16*e34*e27+e16*e24*e37+e16*e35*e28+e16*e25*e38+e26*e13*e36+e26*e35*e18+e26*e15*e38+e26*e34*e17+e26*e14*e37+e36*e25*e18+e36*e15*e28+e36*e24*e17+e36*e14*e27-e13*e31*e21-e13*e37*e27-e13*e32*e22-e13*e38*e28-e23*e31*e11-e23*e32*e12-e23*e37*e17-e23*e38*e18-e33*e21*e11-e33*e22*e12-e33*e27*e17-e33*e28*e18; + A[1 + 10*15]=-0.5*e33*e212-0.5*e33*e272-0.5*e33*e222-0.5*e33*e282+e26*e23*e36+e20*e30*e23+e20*e32*e25+e20*e22*e35+e20*e31*e24+e20*e21*e34+e30*e22*e25+e30*e21*e24+e23*e34*e24+e23*e35*e25+e26*e34*e27+e26*e24*e37+e26*e35*e28+e26*e25*e38+e36*e24*e27+e36*e25*e28-e23*e31*e21-e23*e37*e27-e23*e32*e22-e23*e38*e28+0.5*e202*e33+1.5*e33*e232+0.5*e33*e242+0.5*e33*e252+0.5*e33*e262; + A[1 + 10*16]=e33*e35*e05+e30*e32*e05+0.5*e03*e362+0.5*e302*e03+1.5*e03*e332+0.5*e03*e352+0.5*e03*e342+e00*e30*e33+e00*e31*e34+e00*e32*e35+e30*e31*e04+e30*e01*e34+e30*e02*e35+e33*e34*e04+e06*e33*e36+e06*e35*e38+e06*e34*e37+e36*e34*e07+e36*e04*e37+e36*e35*e08+e36*e05*e38-e33*e32*e02-e33*e31*e01-e33*e37*e07-e33*e38*e08-0.5*e03*e322-0.5*e03*e382-0.5*e03*e312-0.5*e03*e372; + A[1 + 10*17]=-e33*e31*e11-e33*e32*e12-e33*e38*e18+e30*e11*e34+e30*e32*e15+e30*e12*e35+e33*e35*e15+e33*e34*e14+e16*e33*e36+e16*e35*e38+e16*e34*e37+e36*e35*e18+e36*e15*e38+e36*e34*e17+e36*e14*e37-e33*e37*e17+0.5*e302*e13+1.5*e13*e332+0.5*e13*e352+0.5*e13*e342+0.5*e13*e362-0.5*e13*e322-0.5*e13*e382-0.5*e13*e312-0.5*e13*e372+e10*e30*e33+e10*e31*e34+e10*e32*e35+e30*e31*e14; + A[1 + 10*18]=e36*e25*e38+0.5*e302*e23+1.5*e23*e332+0.5*e23*e352+0.5*e23*e342+0.5*e23*e362-0.5*e23*e322-0.5*e23*e382-0.5*e23*e312-0.5*e23*e372+e20*e30*e33+e20*e31*e34+e20*e32*e35+e30*e32*e25+e30*e22*e35+e30*e31*e24+e30*e21*e34+e33*e34*e24+e33*e35*e25+e26*e33*e36+e26*e35*e38+e26*e34*e37+e36*e34*e27+e36*e24*e37+e36*e35*e28-e33*e31*e21-e33*e37*e27-e33*e32*e22-e33*e38*e28; + A[1 + 10*19]=0.5*e302*e33+e30*e31*e34+e30*e32*e35+0.5*e333+0.5*e33*e352+0.5*e33*e342+0.5*e33*e362+e36*e35*e38+e36*e34*e37-0.5*e33*e322-0.5*e33*e382-0.5*e33*e312-0.5*e33*e372; + A[2 + 10*0]=0.5*e002*e06+e00*e01*e07+e00*e02*e08+0.5*e032*e06+e03*e04*e07+e03*e05*e08+0.5*e063+0.5*e06*e072+0.5*e06*e082-0.5*e06*e012-0.5*e06*e022-0.5*e06*e042-0.5*e06*e052; + A[2 + 10*1]=e00*e10*e06+0.5*e002*e16+0.5*e032*e16+1.5*e16*e062+0.5*e16*e072+0.5*e16*e082-0.5*e16*e012-0.5*e16*e022-0.5*e16*e042-0.5*e16*e052+e00*e11*e07+e00*e01*e17+e00*e12*e08+e00*e02*e18+e10*e01*e07+e10*e02*e08+e03*e13*e06+e03*e14*e07+e03*e04*e17+e03*e15*e08+e03*e05*e18+e13*e04*e07+e13*e05*e08+e06*e17*e07+e06*e18*e08-e06*e12*e02-e06*e11*e01-e06*e14*e04-e06*e15*e05; + A[2 + 10*2]=e13*e14*e07+0.5*e102*e06+e00*e10*e16+e00*e12*e18+e00*e11*e17+e10*e11*e07+e10*e01*e17+e10*e12*e08+e10*e02*e18+e03*e13*e16+e03*e15*e18+e03*e14*e17+e13*e04*e17+e13*e15*e08+e13*e05*e18+e16*e17*e07+e16*e18*e08-e16*e12*e02-e16*e11*e01-e16*e14*e04-e16*e15*e05+0.5*e132*e06+1.5*e06*e162+0.5*e06*e182+0.5*e06*e172-0.5*e06*e112-0.5*e06*e122-0.5*e06*e142-0.5*e06*e152; + A[2 + 10*3]=0.5*e102*e16+e10*e12*e18+e10*e11*e17+0.5*e132*e16+e13*e15*e18+e13*e14*e17+0.5*e163+0.5*e16*e182+0.5*e16*e172-0.5*e16*e112-0.5*e16*e122-0.5*e16*e142-0.5*e16*e152; + A[2 + 10*4]=e06*e27*e07+e23*e05*e08+e23*e04*e07+e03*e05*e28+e03*e25*e08+e03*e04*e27+e03*e24*e07+e20*e02*e08+e20*e01*e07+e00*e02*e28+e00*e22*e08+e00*e01*e27+e00*e21*e07+e00*e20*e06-e06*e25*e05-e06*e24*e04-e06*e21*e01-e06*e22*e02+e06*e28*e08-0.5*e26*e042-0.5*e26*e052-0.5*e26*e012-0.5*e26*e022+0.5*e26*e082+0.5*e26*e072+1.5*e26*e062+0.5*e002*e26+e03*e23*e06+0.5*e032*e26; + A[2 + 10*5]=e13*e05*e28+e00*e12*e28+e13*e25*e08+e13*e04*e27+e13*e24*e07+e13*e23*e06+e03*e14*e27+e03*e24*e17+e03*e15*e28+e03*e25*e18+e03*e13*e26+e03*e23*e16+e20*e02*e18+e20*e12*e08+e20*e01*e17+e20*e11*e07+e00*e21*e17+e10*e02*e28+e10*e22*e08+e10*e01*e27+e10*e21*e07+e10*e20*e06+e00*e11*e27-e26*e15*e05-e26*e14*e04-e26*e11*e01-e26*e12*e02-e16*e25*e05-e16*e24*e04-e16*e21*e01-e16*e22*e02-e06*e24*e14-e06*e22*e12-e06*e21*e11-e06*e25*e15+e00*e20*e16+e00*e22*e18+e00*e10*e26+e26*e18*e08+e26*e17*e07+e16*e28*e08+e16*e27*e07+e06*e27*e17+e06*e28*e18+3*e06*e26*e16+e23*e05*e18+e23*e15*e08+e23*e04*e17+e23*e14*e07; + A[2 + 10*6]=e10*e22*e18+0.5*e26*e182+0.5*e26*e172+e16*e28*e18+e16*e27*e17-e16*e25*e15-e16*e21*e11-e16*e22*e12+1.5*e26*e162+e13*e15*e28+e13*e24*e17+e13*e14*e27+e23*e15*e18+e23*e14*e17+e10*e12*e28+e10*e21*e17+e10*e11*e27+e20*e12*e18+e20*e11*e17+e13*e23*e16+e13*e25*e18+e10*e20*e16+0.5*e102*e26-0.5*e26*e122-0.5*e26*e142-0.5*e26*e152-e16*e24*e14-0.5*e26*e112+0.5*e132*e26; + A[2 + 10*7]=-0.5*e06*e212-0.5*e06*e252-0.5*e06*e242+0.5*e06*e272+0.5*e06*e282-0.5*e06*e222+e20*e02*e28+e03*e23*e26+e03*e24*e27+e03*e25*e28+e23*e24*e07+e23*e04*e27+e23*e25*e08+e23*e05*e28+e26*e28*e08-e26*e22*e02-e26*e21*e01-e26*e24*e04-e26*e25*e05+e26*e27*e07+e00*e20*e26+e00*e21*e27+e00*e22*e28+e20*e21*e07+e20*e01*e27+e20*e22*e08+0.5*e202*e06+0.5*e232*e06+1.5*e06*e262; + A[2 + 10*8]=-e26*e24*e14-0.5*e16*e212-0.5*e16*e252-0.5*e16*e242-e26*e25*e15-0.5*e16*e222-e26*e21*e11+e26*e28*e18+e26*e27*e17-e26*e22*e12+e23*e15*e28+e23*e24*e17+e23*e14*e27+0.5*e232*e16+1.5*e16*e262+0.5*e16*e272+0.5*e16*e282+e10*e20*e26+e10*e21*e27+e10*e22*e28+e20*e22*e18+e20*e12*e28+e20*e21*e17+e20*e11*e27+e13*e23*e26+e13*e24*e27+e13*e25*e28+e23*e25*e18+0.5*e202*e16; + A[2 + 10*9]=0.5*e202*e26+e20*e21*e27+e20*e22*e28+0.5*e232*e26+e23*e24*e27+e23*e25*e28+0.5*e263+0.5*e26*e272+0.5*e26*e282-0.5*e26*e222-0.5*e26*e212-0.5*e26*e252-0.5*e26*e242; + A[2 + 10*10]=e03*e34*e07+0.5*e032*e36+1.5*e36*e062+e03*e33*e06+e00*e31*e07+e00*e01*e37+e00*e32*e08+e00*e02*e38+e30*e01*e07+e30*e02*e08+e03*e04*e37+e03*e35*e08+e03*e05*e38+0.5*e002*e36-0.5*e36*e022-0.5*e36*e042-0.5*e36*e052+0.5*e36*e072+0.5*e36*e082-0.5*e36*e012+e33*e04*e07+e33*e05*e08+e06*e37*e07+e06*e38*e08-e06*e32*e02-e06*e31*e01-e06*e34*e04-e06*e35*e05+e00*e30*e06; + A[2 + 10*11]=e13*e33*e06+e13*e34*e07+e13*e04*e37+e13*e35*e08+e13*e05*e38+e33*e14*e07+e33*e04*e17+e33*e15*e08+e33*e05*e18+3*e06*e36*e16+e06*e38*e18+e06*e37*e17+e16*e37*e07+e16*e38*e08+e36*e17*e07+e36*e18*e08-e06*e35*e15-e06*e31*e11-e06*e32*e12+e00*e31*e17+e00*e11*e37+e10*e30*e06+e10*e31*e07+e10*e01*e37+e10*e32*e08+e10*e02*e38+e30*e11*e07+e30*e01*e17+e30*e12*e08+e30*e02*e18+e03*e33*e16+e03*e13*e36+e03*e35*e18+e03*e15*e38+e03*e34*e17+e03*e14*e37+e00*e30*e16+e00*e12*e38-e06*e34*e14-e16*e32*e02-e16*e31*e01-e16*e34*e04-e16*e35*e05-e36*e12*e02-e36*e11*e01-e36*e14*e04-e36*e15*e05+e00*e10*e36+e00*e32*e18; + A[2 + 10*12]=0.5*e36*e182+0.5*e36*e172-0.5*e36*e112-0.5*e36*e122-0.5*e36*e142-0.5*e36*e152+0.5*e102*e36+0.5*e132*e36+1.5*e36*e162+e10*e30*e16+e10*e32*e18+e10*e12*e38+e10*e31*e17+e10*e11*e37+e30*e12*e18+e30*e11*e17+e13*e33*e16+e13*e35*e18+e13*e15*e38+e13*e34*e17+e13*e14*e37+e33*e15*e18+e33*e14*e17+e16*e38*e18+e16*e37*e17-e16*e35*e15-e16*e31*e11-e16*e32*e12-e16*e34*e14; + A[2 + 10*13]=e00*e20*e36+e00*e31*e27+e00*e21*e37+e00*e32*e28+e00*e22*e38+e20*e30*e06+e20*e31*e07+e20*e01*e37+e20*e32*e08+e20*e02*e38+e30*e21*e07+e30*e01*e27+e30*e22*e08+e30*e02*e28+e03*e33*e26+e03*e23*e36+e03*e34*e27+e03*e24*e37+e03*e35*e28-e26*e31*e01-e26*e35*e05-e36*e22*e02-e36*e21*e01-e36*e24*e04-e36*e25*e05-e26*e34*e04+e03*e25*e38+e23*e34*e07+e23*e04*e37+e23*e35*e08+e23*e05*e38+e33*e24*e07+e33*e04*e27+e33*e25*e08+e33*e05*e28+3*e06*e36*e26+e06*e37*e27+e06*e38*e28+e26*e37*e07+e26*e38*e08+e36*e27*e07+e36*e28*e08-e06*e32*e22-e06*e31*e21-e06*e35*e25-e06*e34*e24-e26*e32*e02+e00*e30*e26+e23*e33*e06; + A[2 + 10*14]=e10*e30*e26+e10*e20*e36+e10*e31*e27+e10*e21*e37+e10*e32*e28+e10*e22*e38+e20*e30*e16+e20*e32*e18+e20*e12*e38+e20*e31*e17+e20*e11*e37+e30*e22*e18+e30*e12*e28+e30*e21*e17+e30*e11*e27+e13*e33*e26+e13*e23*e36+e13*e34*e27+e13*e24*e37+e13*e35*e28+e13*e25*e38+e23*e33*e16+e23*e35*e18+e23*e15*e38+e23*e34*e17+e23*e14*e37+e33*e25*e18+e33*e15*e28+e33*e24*e17+e33*e14*e27+3*e16*e36*e26+e16*e37*e27+e16*e38*e28+e26*e38*e18+e26*e37*e17+e36*e28*e18+e36*e27*e17-e16*e32*e22-e16*e31*e21-e16*e35*e25-e16*e34*e24-e26*e35*e15-e26*e31*e11-e26*e32*e12-e26*e34*e14-e36*e25*e15-e36*e21*e11-e36*e22*e12-e36*e24*e14; + A[2 + 10*15]=e33*e25*e28+e20*e30*e26+e20*e32*e28+e20*e31*e27+e20*e21*e37+e20*e22*e38+e30*e21*e27+e30*e22*e28+e23*e33*e26+e23*e34*e27+e23*e24*e37+e23*e35*e28+e23*e25*e38+e33*e24*e27+e26*e37*e27+e26*e38*e28-e26*e32*e22-e26*e31*e21-e26*e35*e25-e26*e34*e24+0.5*e202*e36+0.5*e232*e36+1.5*e36*e262+0.5*e36*e272+0.5*e36*e282-0.5*e36*e222-0.5*e36*e212-0.5*e36*e252-0.5*e36*e242; + A[2 + 10*16]=e00*e30*e36+e00*e32*e38+e00*e31*e37+e30*e31*e07+e30*e01*e37+e30*e32*e08+e30*e02*e38+e03*e33*e36-0.5*e06*e342+e03*e35*e38+e33*e34*e07+e33*e04*e37+e33*e35*e08+e33*e05*e38+e36*e37*e07+e36*e38*e08-e36*e32*e02-e36*e31*e01-e36*e34*e04-e36*e35*e05+e03*e34*e37+0.5*e302*e06+0.5*e332*e06+1.5*e06*e362+0.5*e06*e382+0.5*e06*e372-0.5*e06*e352-0.5*e06*e312-0.5*e06*e322; + A[2 + 10*17]=-e36*e35*e15+e10*e30*e36+0.5*e302*e16+0.5*e332*e16+1.5*e16*e362+0.5*e16*e382+0.5*e16*e372-0.5*e16*e352-0.5*e16*e312-0.5*e16*e322-0.5*e16*e342+e10*e32*e38+e10*e31*e37+e30*e32*e18+e30*e12*e38+e30*e31*e17+e30*e11*e37+e13*e33*e36+e13*e35*e38+e13*e34*e37+e33*e35*e18+e33*e15*e38+e33*e34*e17+e33*e14*e37+e36*e38*e18+e36*e37*e17-e36*e31*e11-e36*e32*e12-e36*e34*e14; + A[2 + 10*18]=-e36*e35*e25+e30*e32*e28+0.5*e302*e26+0.5*e332*e26+1.5*e26*e362+0.5*e26*e382+0.5*e26*e372-0.5*e26*e352-0.5*e26*e312-0.5*e26*e322-0.5*e26*e342+e20*e30*e36+e20*e32*e38+e20*e31*e37+e30*e31*e27+e30*e21*e37+e30*e22*e38+e23*e33*e36+e23*e35*e38+e23*e34*e37+e33*e34*e27+e33*e24*e37+e33*e35*e28+e33*e25*e38+e36*e37*e27+e36*e38*e28-e36*e32*e22-e36*e31*e21-e36*e34*e24; + A[2 + 10*19]=0.5*e302*e36+e30*e32*e38+e30*e31*e37+0.5*e332*e36+e33*e35*e38+e33*e34*e37+0.5*e363+0.5*e36*e382+0.5*e36*e372-0.5*e36*e352-0.5*e36*e312-0.5*e36*e322-0.5*e36*e342; + A[3 + 10*0]=0.5*e01*e002+0.5*e013+0.5*e01*e022+e04*e00*e03+0.5*e01*e042+e04*e02*e05+e07*e00*e06+0.5*e01*e072+e07*e02*e08-0.5*e01*e032-0.5*e01*e052-0.5*e01*e062-0.5*e01*e082; + A[3 + 10*1]=1.5*e11*e012+0.5*e11*e002+0.5*e11*e022+0.5*e11*e042+0.5*e11*e072-0.5*e11*e032-0.5*e11*e052-0.5*e11*e062-0.5*e11*e082+e01*e10*e00+e01*e12*e02+e04*e10*e03+e04*e00*e13+e04*e01*e14+e04*e12*e05+e04*e02*e15+e14*e00*e03+e14*e02*e05+e07*e10*e06+e07*e00*e16+e07*e01*e17+e07*e12*e08+e07*e02*e18+e17*e00*e06+e17*e02*e08-e01*e13*e03-e01*e16*e06-e01*e15*e05-e01*e18*e08; + A[3 + 10*2]=e17*e02*e18+e14*e10*e03+e11*e12*e02-e11*e18*e08+0.5*e01*e102+0.5*e01*e122+1.5*e01*e112+0.5*e01*e142+0.5*e01*e172-0.5*e01*e132-0.5*e01*e152-0.5*e01*e162-0.5*e01*e182+e11*e10*e00+e04*e10*e13+e04*e12*e15+e04*e11*e14+e14*e00*e13+e14*e12*e05+e14*e02*e15+e07*e10*e16+e07*e12*e18+e07*e11*e17+e17*e10*e06+e17*e00*e16+e17*e12*e08-e11*e13*e03-e11*e16*e06-e11*e15*e05; + A[3 + 10*3]=0.5*e11*e102+0.5*e11*e122+0.5*e113+e14*e10*e13+e14*e12*e15+0.5*e11*e142+e17*e10*e16+e17*e12*e18+0.5*e11*e172-0.5*e11*e132-0.5*e11*e152-0.5*e11*e162-0.5*e11*e182; + A[3 + 10*4]=-e01*e25*e05-e01*e26*e06-e01*e23*e03+e27*e02*e08+e27*e00*e06+e07*e02*e28+e07*e22*e08+e07*e01*e27+e07*e00*e26+e24*e02*e05+e24*e00*e03+e04*e02*e25+e04*e22*e05+e04*e01*e24+e04*e00*e23+e04*e20*e03+e01*e22*e02+e01*e20*e00-e01*e28*e08+e07*e20*e06+0.5*e21*e072+0.5*e21*e042+0.5*e21*e022+0.5*e21*e002+1.5*e21*e012-0.5*e21*e082-0.5*e21*e052-0.5*e21*e062-0.5*e21*e032; + A[3 + 10*5]=e11*e20*e00+e07*e20*e16+3*e01*e21*e11+e01*e22*e12-e21*e18*e08-e21*e15*e05-e21*e16*e06-e21*e13*e03-e11*e28*e08-e11*e25*e05-e11*e26*e06-e11*e23*e03-e01*e28*e18-e01*e23*e13-e01*e25*e15-e01*e26*e16+e27*e02*e18+e27*e12*e08+e27*e00*e16+e27*e10*e06+e17*e02*e28+e17*e22*e08+e17*e01*e27+e17*e00*e26+e17*e20*e06+e07*e11*e27+e07*e21*e17+e07*e12*e28+e07*e22*e18+e07*e10*e26+e24*e02*e15+e24*e12*e05+e24*e00*e13+e24*e10*e03+e14*e02*e25+e14*e22*e05+e14*e01*e24+e14*e00*e23+e14*e20*e03+e04*e11*e24+e04*e21*e14+e04*e12*e25+e04*e22*e15+e21*e12*e02+e04*e20*e13+e01*e20*e10+e11*e22*e02+e21*e10*e00+e04*e10*e23; + A[3 + 10*6]=1.5*e21*e112+0.5*e21*e102+0.5*e21*e122+e11*e20*e10+e11*e22*e12+e14*e10*e23+e14*e22*e15+e14*e12*e25-0.5*e21*e162-0.5*e21*e152-0.5*e21*e132-0.5*e21*e182+e27*e12*e18-e11*e26*e16-e11*e25*e15-e11*e23*e13-e11*e28*e18+e17*e20*e16+e17*e10*e26+e17*e22*e18+e17*e12*e28+e17*e11*e27+e27*e10*e16+0.5*e21*e172+e14*e11*e24+e24*e10*e13+e24*e12*e15+0.5*e21*e142+e14*e20*e13; + A[3 + 10*7]=-0.5*e01*e262-0.5*e01*e282-0.5*e01*e252-0.5*e01*e232+0.5*e01*e272+e27*e22*e08+e27*e02*e28-e21*e23*e03-e21*e26*e06-e21*e25*e05-e21*e28*e08+e04*e22*e25+e24*e20*e03+e24*e00*e23+e24*e22*e05+e24*e02*e25+e07*e20*e26+e07*e21*e27+e07*e22*e28+e27*e20*e06+e27*e00*e26+e21*e20*e00+e21*e22*e02+e04*e20*e23+e04*e21*e24+0.5*e01*e222+0.5*e01*e242+1.5*e01*e212+0.5*e01*e202; + A[3 + 10*8]=-0.5*e11*e282-0.5*e11*e252-e21*e26*e16+e27*e12*e28-e21*e25*e15-e21*e23*e13-e21*e28*e18+e17*e20*e26+e17*e21*e27+e17*e22*e28+e27*e20*e16+e27*e10*e26+e27*e22*e18+0.5*e11*e242+0.5*e11*e272-0.5*e11*e232-0.5*e11*e262+0.5*e11*e202+1.5*e11*e212+0.5*e11*e222+e21*e20*e10+e14*e20*e23+e14*e21*e24+e14*e22*e25+e24*e20*e13+e24*e10*e23+e24*e22*e15+e24*e12*e25+e21*e22*e12; + A[3 + 10*9]=0.5*e21*e202+0.5*e213+0.5*e21*e222+e24*e20*e23+0.5*e21*e242+e24*e22*e25+e27*e20*e26+0.5*e21*e272+e27*e22*e28-0.5*e21*e232-0.5*e21*e262-0.5*e21*e282-0.5*e21*e252; + A[3 + 10*10]=-0.5*e31*e032-0.5*e31*e052-0.5*e31*e062-0.5*e31*e082+e07*e30*e06+e07*e00*e36+e07*e01*e37+e07*e32*e08+e07*e02*e38+e37*e00*e06+e37*e02*e08-e01*e33*e03-e01*e36*e06-e01*e35*e05-e01*e38*e08+0.5*e31*e072+e04*e30*e03+e04*e00*e33+e04*e01*e34+e04*e32*e05+e04*e02*e35+e34*e00*e03+e34*e02*e05+0.5*e31*e002+0.5*e31*e022+0.5*e31*e042+e01*e30*e00+e01*e32*e02+1.5*e31*e012; + A[3 + 10*11]=e34*e12*e05+e34*e02*e15+e07*e10*e36+e07*e32*e18+e07*e12*e38+e07*e31*e17+e07*e11*e37+e17*e30*e06+e17*e00*e36+e17*e01*e37+e17*e32*e08+e17*e02*e38+e37*e10*e06+e37*e00*e16+e37*e12*e08+e37*e02*e18-e01*e36*e16-e01*e35*e15-e01*e33*e13-e01*e38*e18-e11*e33*e03-e11*e36*e06-e11*e35*e05+e01*e30*e10+e01*e32*e12+3*e01*e31*e11+e11*e30*e00+e11*e32*e02+e31*e10*e00+e31*e12*e02+e04*e30*e13+e04*e10*e33+e04*e32*e15+e04*e12*e35+e04*e31*e14+e04*e11*e34+e14*e30*e03+e14*e00*e33+e14*e01*e34+e14*e32*e05+e14*e02*e35+e34*e10*e03+e34*e00*e13+e07*e30*e16-e11*e38*e08-e31*e13*e03-e31*e16*e06-e31*e15*e05-e31*e18*e08; + A[3 + 10*12]=-e11*e33*e13-e11*e38*e18+0.5*e31*e142+0.5*e31*e172-0.5*e31*e162-0.5*e31*e152-0.5*e31*e132-0.5*e31*e182+0.5*e31*e122+0.5*e31*e102+e11*e30*e10+e11*e32*e12+e14*e30*e13+e14*e10*e33+e14*e32*e15+e14*e12*e35+e14*e11*e34+e34*e10*e13+e34*e12*e15+e17*e30*e16+e17*e10*e36+e17*e32*e18+e17*e12*e38+e17*e11*e37+e37*e10*e16+e37*e12*e18-e11*e36*e16-e11*e35*e15+1.5*e31*e112; + A[3 + 10*13]=-e21*e35*e05+e07*e32*e28+e01*e30*e20-e21*e33*e03-e21*e36*e06-e21*e38*e08-e31*e23*e03-e31*e26*e06-e31*e25*e05-e31*e28*e08+3*e01*e31*e21+e01*e32*e22+e21*e30*e00+e21*e32*e02+e31*e20*e00+e31*e22*e02+e04*e30*e23+e04*e20*e33+e04*e31*e24+e04*e21*e34+e04*e32*e25+e04*e22*e35+e24*e30*e03+e24*e00*e33+e24*e01*e34+e24*e32*e05+e24*e02*e35+e34*e20*e03+e34*e00*e23+e34*e22*e05+e34*e02*e25+e07*e30*e26+e07*e20*e36+e07*e31*e27+e07*e21*e37+e07*e22*e38+e27*e30*e06+e27*e00*e36+e27*e01*e37+e27*e32*e08+e27*e02*e38+e37*e00*e26+e37*e22*e08+e37*e02*e28-e01*e33*e23-e01*e36*e26-e01*e38*e28-e01*e35*e25+e37*e20*e06; + A[3 + 10*14]=e11*e32*e22+e34*e12*e25+e11*e30*e20+3*e11*e31*e21+e21*e30*e10+e21*e32*e12+e34*e10*e23+e34*e22*e15+e17*e30*e26+e17*e20*e36+e17*e31*e27+e17*e21*e37+e17*e32*e28+e17*e22*e38+e27*e30*e16+e27*e10*e36+e27*e32*e18+e27*e12*e38+e27*e11*e37+e37*e20*e16+e37*e10*e26+e37*e22*e18+e37*e12*e28-e11*e33*e23-e11*e36*e26-e11*e38*e28-e11*e35*e25-e21*e36*e16-e21*e35*e15-e21*e33*e13-e21*e38*e18-e31*e26*e16-e31*e25*e15-e31*e23*e13-e31*e28*e18+e31*e20*e10+e31*e22*e12+e14*e30*e23+e14*e20*e33+e14*e31*e24+e14*e21*e34+e14*e32*e25+e14*e22*e35+e24*e30*e13+e24*e10*e33+e24*e32*e15+e24*e12*e35+e24*e11*e34+e34*e20*e13; + A[3 + 10*15]=-e21*e36*e26+e37*e22*e28-e21*e33*e23-e21*e38*e28-e21*e35*e25+0.5*e31*e222+0.5*e31*e242+0.5*e31*e272-0.5*e31*e232-0.5*e31*e262-0.5*e31*e282-0.5*e31*e252+e21*e30*e20+e21*e32*e22+e24*e30*e23+e24*e20*e33+e24*e21*e34+e24*e32*e25+e24*e22*e35+e34*e20*e23+e34*e22*e25+e27*e30*e26+e27*e20*e36+e27*e21*e37+e27*e32*e28+e27*e22*e38+e37*e20*e26+1.5*e31*e212+0.5*e31*e202; + A[3 + 10*16]=e04*e32*e35+0.5*e01*e372-0.5*e01*e352-0.5*e01*e362-0.5*e01*e332-0.5*e01*e382+e04*e31*e34+e34*e30*e03+e34*e00*e33+e34*e32*e05+e34*e02*e35+e07*e30*e36+e07*e32*e38+e07*e31*e37+e37*e30*e06+e37*e00*e36+e37*e32*e08+e04*e30*e33+e37*e02*e38-e31*e33*e03-e31*e36*e06-e31*e35*e05-e31*e38*e08+0.5*e01*e302+0.5*e01*e322+1.5*e01*e312+0.5*e01*e342+e31*e30*e00+e31*e32*e02; + A[3 + 10*17]=e31*e32*e12+e14*e30*e33+e14*e32*e35+e14*e31*e34+e34*e30*e13+e34*e10*e33+e34*e32*e15+e34*e12*e35+e17*e30*e36+e17*e32*e38+e17*e31*e37+e37*e30*e16+e37*e10*e36+e37*e32*e18+e37*e12*e38-e31*e36*e16-e31*e35*e15+0.5*e11*e302+0.5*e11*e322+1.5*e11*e312-e31*e33*e13-e31*e38*e18+0.5*e11*e342+0.5*e11*e372+e31*e30*e10-0.5*e11*e352-0.5*e11*e362-0.5*e11*e332-0.5*e11*e382; + A[3 + 10*18]=e34*e32*e25+0.5*e21*e342+0.5*e21*e372-0.5*e21*e352-0.5*e21*e362-0.5*e21*e332-0.5*e21*e382+0.5*e21*e302+0.5*e21*e322+1.5*e21*e312+e31*e30*e20+e31*e32*e22+e24*e30*e33+e24*e32*e35+e24*e31*e34+e34*e30*e23+e34*e20*e33+e34*e22*e35+e27*e30*e36+e27*e32*e38+e27*e31*e37+e37*e30*e26+e37*e20*e36+e37*e32*e28+e37*e22*e38-e31*e33*e23-e31*e36*e26-e31*e38*e28-e31*e35*e25; + A[3 + 10*19]=0.5*e31*e302+0.5*e31*e322+0.5*e313+e34*e30*e33+e34*e32*e35+0.5*e31*e342+e37*e30*e36+e37*e32*e38+0.5*e31*e372-0.5*e31*e352-0.5*e31*e362-0.5*e31*e332-0.5*e31*e382; + A[4 + 10*0]=e01*e00*e03+0.5*e012*e04+e01*e02*e05+0.5*e04*e032+0.5*e043+0.5*e04*e052+e07*e03*e06+0.5*e04*e072+e07*e05*e08-0.5*e04*e002-0.5*e04*e022-0.5*e04*e062-0.5*e04*e082; + A[4 + 10*1]=e07*e13*e06+e01*e10*e03-0.5*e14*e002-0.5*e14*e022-0.5*e14*e062-0.5*e14*e082+e01*e00*e13+e01*e11*e04+e01*e12*e05+e01*e02*e15+e11*e00*e03+e11*e02*e05+e04*e13*e03+e04*e15*e05+e07*e03*e16+e07*e04*e17+e07*e15*e08+e07*e05*e18+e17*e03*e06+e17*e05*e08-e04*e10*e00-e04*e12*e02-e04*e16*e06-e04*e18*e08+0.5*e012*e14+1.5*e14*e042+0.5*e14*e032+0.5*e14*e052+0.5*e14*e072; + A[4 + 10*2]=e11*e10*e03+0.5*e112*e04+0.5*e04*e132+0.5*e04*e152+1.5*e04*e142+0.5*e04*e172-0.5*e04*e102-0.5*e04*e162-0.5*e04*e122-0.5*e04*e182+e01*e10*e13+e01*e12*e15+e01*e11*e14+e11*e00*e13+e11*e12*e05+e11*e02*e15+e14*e13*e03+e14*e15*e05+e07*e13*e16+e07*e15*e18+e07*e14*e17+e17*e13*e06+e17*e03*e16+e17*e15*e08+e17*e05*e18-e14*e10*e00-e14*e12*e02-e14*e16*e06-e14*e18*e08; + A[4 + 10*3]=e11*e10*e13+e11*e12*e15+0.5*e112*e14+0.5*e14*e132+0.5*e14*e152+0.5*e143+e17*e13*e16+e17*e15*e18+0.5*e14*e172-0.5*e14*e102-0.5*e14*e162-0.5*e14*e122-0.5*e14*e182; + A[4 + 10*4]=-e04*e28*e08-e04*e26*e06-e04*e22*e02-e04*e20*e00+e27*e05*e08+e27*e03*e06+e07*e05*e28+e07*e25*e08+e07*e04*e27+e07*e03*e26+e07*e23*e06+e04*e25*e05+e04*e23*e03+e21*e02*e05+e21*e00*e03+e01*e02*e25+e01*e22*e05+e01*e21*e04+e01*e00*e23+e01*e20*e03+0.5*e012*e24+0.5*e24*e072+0.5*e24*e052+0.5*e24*e032+1.5*e24*e042-0.5*e24*e022-0.5*e24*e002-0.5*e24*e082-0.5*e24*e062; + A[4 + 10*5]=e11*e02*e25+e11*e22*e05+e11*e21*e04-e24*e18*e08-e24*e16*e06-e24*e12*e02-e14*e28*e08-e14*e26*e06-e14*e22*e02-e14*e20*e00-e04*e28*e18-e04*e22*e12-e04*e26*e16-e04*e20*e10+e27*e05*e18+e27*e15*e08+e27*e03*e16+e27*e13*e06+e17*e05*e28+e17*e25*e08+e17*e04*e27+e17*e03*e26+e17*e23*e06+e07*e14*e27+e07*e24*e17+e07*e15*e28+e07*e25*e18+e07*e13*e26+e07*e23*e16+e24*e15*e05+e24*e13*e03+e14*e25*e05+e14*e23*e03+3*e04*e24*e14+e04*e25*e15+e04*e23*e13+e21*e02*e15+e21*e12*e05+e21*e00*e13+e21*e10*e03-e24*e10*e00+e01*e20*e13+e01*e10*e23+e01*e22*e15+e01*e12*e25+e01*e11*e24+e11*e20*e03+e11*e00*e23+e01*e21*e14; + A[4 + 10*6]=e11*e12*e25-0.5*e24*e182-0.5*e24*e102-0.5*e24*e162-0.5*e24*e122+e27*e13*e16+e27*e15*e18-e14*e20*e10-e14*e26*e16-e14*e22*e12-e14*e28*e18+e17*e15*e28+e17*e14*e27+1.5*e24*e142+0.5*e24*e132+0.5*e24*e152+0.5*e112*e24+0.5*e24*e172+e11*e21*e14+e11*e22*e15+e11*e10*e23+e11*e20*e13+e21*e10*e13+e21*e12*e15+e17*e13*e26+e17*e23*e16+e14*e25*e15+e14*e23*e13+e17*e25*e18; + A[4 + 10*7]=e27*e03*e26+e27*e25*e08+e27*e05*e28-e24*e20*e00-e24*e22*e02-e24*e26*e06-e24*e28*e08+0.5*e04*e232+1.5*e04*e242+0.5*e04*e252+0.5*e04*e272-0.5*e04*e202-0.5*e04*e222-0.5*e04*e262-0.5*e04*e282+e24*e23*e03+e24*e25*e05+e07*e23*e26+e07*e24*e27+e07*e25*e28+e27*e23*e06+e21*e20*e03+e21*e00*e23+e21*e22*e05+e21*e02*e25+0.5*e212*e04+e01*e20*e23+e01*e21*e24+e01*e22*e25; + A[4 + 10*8]=-e24*e22*e12-e24*e28*e18+0.5*e14*e272-0.5*e14*e202-0.5*e14*e222-0.5*e14*e262-0.5*e14*e282+e17*e23*e26+e17*e24*e27+e17*e25*e28+e27*e23*e16+e27*e13*e26+e27*e25*e18+e27*e15*e28-e24*e20*e10-e24*e26*e16+0.5*e14*e232+1.5*e14*e242+0.5*e14*e252+e21*e10*e23+e21*e22*e15+e21*e12*e25+e24*e23*e13+e24*e25*e15+e21*e20*e13+0.5*e212*e14+e11*e20*e23+e11*e22*e25+e11*e21*e24; + A[4 + 10*9]=e21*e20*e23+0.5*e212*e24+e21*e22*e25+0.5*e24*e232+0.5*e243+0.5*e24*e252+e27*e23*e26+0.5*e24*e272+e27*e25*e28-0.5*e24*e202-0.5*e24*e222-0.5*e24*e262-0.5*e24*e282; + A[4 + 10*10]=-e04*e38*e08-e04*e32*e02-e04*e36*e06-0.5*e34*e002-0.5*e34*e022-0.5*e34*e062-0.5*e34*e082+e37*e03*e06+e37*e05*e08-e04*e30*e00+0.5*e34*e032+0.5*e34*e052+0.5*e34*e072+1.5*e34*e042+e01*e30*e03+e01*e00*e33+e01*e31*e04+e01*e32*e05+e01*e02*e35+e31*e00*e03+e31*e02*e05+e04*e33*e03+e04*e35*e05+e07*e03*e36+e07*e04*e37+e07*e35*e08+e07*e05*e38+0.5*e012*e34+e07*e33*e06; + A[4 + 10*11]=e07*e13*e36+e01*e12*e35-e04*e30*e10+e17*e04*e37+e17*e35*e08+e17*e05*e38+e37*e13*e06+e37*e03*e16+e37*e15*e08+e37*e05*e18-e04*e36*e16+e17*e33*e06+e04*e33*e13+e04*e35*e15+3*e04*e34*e14+e14*e33*e03+e14*e35*e05+e34*e13*e03+e34*e15*e05+e07*e33*e16+e07*e35*e18+e07*e15*e38+e07*e34*e17+e07*e14*e37+e17*e03*e36+e31*e10*e03+e01*e30*e13+e01*e10*e33+e01*e32*e15+e01*e31*e14+e01*e11*e34+e11*e30*e03+e11*e00*e33+e11*e31*e04+e11*e32*e05+e11*e02*e35+e31*e00*e13+e31*e12*e05+e31*e02*e15-e34*e12*e02-e34*e16*e06-e34*e18*e08-e14*e32*e02-e14*e36*e06-e14*e38*e08-e34*e10*e00-e04*e32*e12-e04*e38*e18-e14*e30*e00; + A[4 + 10*12]=e11*e32*e15-0.5*e34*e102-0.5*e34*e162-0.5*e34*e122-0.5*e34*e182+e37*e13*e16+0.5*e112*e34+1.5*e34*e142+0.5*e34*e132+0.5*e34*e152+0.5*e34*e172+e11*e30*e13+e11*e10*e33+e11*e12*e35+e11*e31*e14+e31*e10*e13+e31*e12*e15+e14*e33*e13+e14*e35*e15+e17*e33*e16+e17*e13*e36+e17*e35*e18+e17*e15*e38+e17*e14*e37+e37*e15*e18-e14*e30*e10-e14*e36*e16-e14*e32*e12-e14*e38*e18; + A[4 + 10*13]=e01*e22*e35-e04*e30*e20-e04*e32*e22+e01*e31*e24+e01*e21*e34+e01*e32*e25+e21*e30*e03+e21*e00*e33+e21*e31*e04+e21*e32*e05+e21*e02*e35+e31*e20*e03+e31*e00*e23+e31*e22*e05+e31*e02*e25+e04*e33*e23+3*e04*e34*e24+e04*e35*e25+e24*e33*e03+e37*e05*e28-e04*e36*e26-e04*e38*e28-e24*e30*e00-e24*e32*e02-e24*e36*e06-e24*e38*e08+e24*e35*e05+e34*e23*e03+e34*e25*e05+e07*e33*e26+e07*e23*e36+e07*e34*e27+e07*e24*e37+e07*e35*e28+e07*e25*e38+e27*e33*e06+e27*e03*e36+e27*e04*e37+e27*e35*e08+e27*e05*e38+e37*e23*e06+e37*e03*e26+e37*e25*e08-e34*e20*e00-e34*e22*e02-e34*e26*e06-e34*e28*e08+e01*e30*e23+e01*e20*e33; + A[4 + 10*14]=e21*e10*e33+e11*e30*e23+e11*e20*e33+e11*e31*e24+e11*e21*e34+e11*e32*e25+e11*e22*e35+e21*e30*e13+e21*e32*e15+e21*e12*e35+e21*e31*e14+e31*e20*e13+e31*e10*e23+e31*e22*e15+e31*e12*e25+e14*e33*e23+3*e14*e34*e24+e14*e35*e25+e24*e33*e13+e24*e35*e15+e34*e23*e13+e34*e25*e15+e17*e33*e26+e17*e23*e36+e17*e34*e27+e17*e24*e37+e17*e35*e28+e17*e25*e38+e27*e33*e16+e27*e13*e36+e27*e35*e18+e27*e15*e38+e27*e14*e37+e37*e23*e16+e37*e13*e26+e37*e25*e18+e37*e15*e28-e34*e28*e18-e34*e22*e12-e14*e32*e22-e14*e36*e26-e14*e38*e28-e24*e30*e10-e24*e36*e16-e24*e32*e12-e24*e38*e18-e34*e20*e10-e34*e26*e16-e14*e30*e20; + A[4 + 10*15]=-0.5*e34*e202-0.5*e34*e222-0.5*e34*e262-0.5*e34*e282+e37*e25*e28-e24*e32*e22-e24*e36*e26-e24*e38*e28-e24*e30*e20+0.5*e212*e34+1.5*e34*e242+0.5*e34*e232+0.5*e34*e252+0.5*e34*e272+e21*e30*e23+e21*e20*e33+e21*e31*e24+e21*e32*e25+e21*e22*e35+e31*e20*e23+e31*e22*e25+e24*e33*e23+e24*e35*e25+e27*e33*e26+e27*e23*e36+e27*e24*e37+e27*e35*e28+e27*e25*e38+e37*e23*e26; + A[4 + 10*16]=e37*e33*e06+e01*e30*e33+e01*e31*e34+e31*e30*e03+e31*e02*e35+e34*e33*e03+e34*e35*e05+e07*e33*e36+e07*e35*e38+e07*e34*e37+e37*e03*e36+e37*e35*e08+e37*e05*e38-e34*e32*e02-e34*e36*e06-e34*e38*e08+e31*e32*e05+e31*e00*e33+0.5*e312*e04+0.5*e04*e332+0.5*e04*e352+1.5*e04*e342+0.5*e04*e372+e01*e32*e35-0.5*e04*e302-0.5*e04*e322-0.5*e04*e362-0.5*e04*e382-e34*e30*e00; + A[4 + 10*17]=0.5*e14*e372-0.5*e14*e302-0.5*e14*e322-0.5*e14*e362-0.5*e14*e382+0.5*e312*e14+0.5*e14*e332+0.5*e14*e352+1.5*e14*e342+e11*e30*e33+e11*e32*e35+e11*e31*e34+e31*e30*e13+e31*e10*e33+e31*e32*e15+e31*e12*e35+e34*e33*e13+e34*e35*e15+e17*e33*e36+e17*e35*e38+e17*e34*e37+e37*e33*e16+e37*e13*e36+e37*e35*e18+e37*e15*e38-e34*e30*e10-e34*e36*e16-e34*e32*e12-e34*e38*e18; + A[4 + 10*18]=-e34*e32*e22-e34*e36*e26-e34*e38*e28+0.5*e24*e332+0.5*e24*e352+1.5*e24*e342+0.5*e24*e372-0.5*e24*e302-0.5*e24*e322-0.5*e24*e362-0.5*e24*e382+e21*e30*e33+0.5*e312*e24+e21*e32*e35+e21*e31*e34+e31*e30*e23+e31*e20*e33+e31*e32*e25+e31*e22*e35+e34*e33*e23+e34*e35*e25+e27*e33*e36+e27*e35*e38+e27*e34*e37+e37*e33*e26+e37*e23*e36+e37*e35*e28+e37*e25*e38-e34*e30*e20; + A[4 + 10*19]=e31*e30*e33+e31*e32*e35+0.5*e312*e34+0.5*e34*e332+0.5*e34*e352+0.5*e343+e37*e33*e36+e37*e35*e38+0.5*e34*e372-0.5*e34*e302-0.5*e34*e322-0.5*e34*e362-0.5*e34*e382; + A[5 + 10*0]=e01*e00*e06+0.5*e012*e07+e01*e02*e08+e04*e03*e06+0.5*e042*e07+e04*e05*e08+0.5*e07*e062+0.5*e073+0.5*e07*e082-0.5*e07*e002-0.5*e07*e022-0.5*e07*e032-0.5*e07*e052; + A[5 + 10*1]=e04*e13*e06+0.5*e042*e17+1.5*e17*e072+0.5*e17*e062+0.5*e17*e082-0.5*e17*e002-0.5*e17*e022-0.5*e17*e032-0.5*e17*e052+e01*e10*e06+e07*e16*e06+e07*e18*e08-e07*e10*e00-e07*e12*e02-e07*e13*e03-e07*e15*e05+e01*e00*e16+e01*e11*e07+e01*e12*e08+e01*e02*e18+e11*e00*e06+e11*e02*e08+e04*e03*e16+e04*e14*e07+e04*e15*e08+e04*e05*e18+e14*e03*e06+e14*e05*e08+0.5*e012*e17; + A[5 + 10*2]=-e17*e10*e00+0.5*e112*e07+0.5*e142*e07+0.5*e07*e162+0.5*e07*e182+1.5*e07*e172-0.5*e07*e102-0.5*e07*e152-0.5*e07*e132-0.5*e07*e122+e01*e10*e16+e01*e12*e18+e01*e11*e17+e11*e10*e06+e11*e00*e16+e11*e12*e08+e11*e02*e18+e04*e13*e16+e04*e15*e18+e04*e14*e17+e14*e13*e06+e14*e03*e16+e14*e15*e08+e14*e05*e18+e17*e16*e06+e17*e18*e08-e17*e12*e02-e17*e13*e03-e17*e15*e05; + A[5 + 10*3]=e11*e10*e16+e11*e12*e18+0.5*e112*e17+e14*e13*e16+e14*e15*e18+0.5*e142*e17+0.5*e17*e162+0.5*e17*e182+0.5*e173-0.5*e17*e102-0.5*e17*e152-0.5*e17*e132-0.5*e17*e122; + A[5 + 10*4]=e01*e22*e08+e07*e28*e08-e07*e20*e00-e07*e23*e03-e07*e22*e02-e07*e25*e05+0.5*e012*e27+0.5*e042*e27+1.5*e27*e072+0.5*e27*e062+0.5*e27*e082-0.5*e27*e002-0.5*e27*e022-0.5*e27*e032-0.5*e27*e052+e07*e26*e06+e01*e20*e06+e01*e00*e26+e01*e21*e07+e01*e02*e28+e21*e00*e06+e21*e02*e08+e04*e23*e06+e04*e03*e26+e04*e24*e07+e04*e25*e08+e04*e05*e28+e24*e03*e06+e24*e05*e08; + A[5 + 10*5]=e14*e24*e07+e14*e03*e26+e14*e23*e06+e04*e14*e27+e04*e24*e17+e04*e15*e28+e04*e25*e18+e04*e13*e26+e04*e23*e16+e21*e02*e18+e21*e12*e08-e27*e15*e05-e27*e13*e03-e27*e12*e02-e27*e10*e00-e17*e25*e05-e17*e23*e03-e17*e22*e02-e17*e20*e00-e07*e22*e12-e07*e23*e13-e07*e25*e15-e07*e20*e10+e27*e18*e08+e27*e16*e06+e17*e28*e08+e17*e26*e06+3*e07*e27*e17+e07*e28*e18+e07*e26*e16+e24*e05*e18+e24*e15*e08+e24*e03*e16+e24*e13*e06+e14*e05*e28+e14*e25*e08+e01*e12*e28+e01*e20*e16+e01*e10*e26+e01*e22*e18+e01*e21*e17+e11*e20*e06+e01*e11*e27+e21*e00*e16+e21*e10*e06+e11*e21*e07+e11*e22*e08+e11*e02*e28+e11*e00*e26; + A[5 + 10*6]=-0.5*e27*e102-0.5*e27*e152-0.5*e27*e132-0.5*e27*e122+0.5*e142*e27+1.5*e27*e172+0.5*e27*e162+0.5*e27*e182+0.5*e112*e27+e11*e22*e18+e11*e10*e26+e11*e20*e16-e17*e22*e12-e17*e23*e13-e17*e25*e15-e17*e20*e10+e17*e28*e18+e17*e26*e16+e24*e15*e18+e24*e13*e16+e14*e24*e17+e14*e15*e28+e14*e25*e18+e14*e13*e26+e14*e23*e16+e21*e12*e18+e21*e10*e16+e11*e21*e17+e11*e12*e28; + A[5 + 10*7]=-0.5*e07*e252+e27*e26*e06+e27*e28*e08-e27*e20*e00-e27*e22*e02-e27*e23*e03-e27*e25*e05+1.5*e07*e272+0.5*e07*e282+e01*e22*e28+e21*e20*e06+e21*e00*e26+e21*e22*e08+e21*e02*e28+e04*e23*e26+e04*e24*e27+e04*e25*e28+e24*e23*e06+e24*e03*e26+e24*e25*e08+e24*e05*e28+0.5*e212*e07+0.5*e242*e07+0.5*e07*e262+e01*e20*e26+e01*e21*e27-0.5*e07*e202-0.5*e07*e232-0.5*e07*e222; + A[5 + 10*8]=-e27*e25*e15-e27*e23*e13-e27*e22*e12-0.5*e17*e252-0.5*e17*e202-0.5*e17*e222-0.5*e17*e232+0.5*e17*e262+1.5*e17*e272+0.5*e17*e282+e24*e23*e16+e24*e13*e26+e24*e25*e18+e24*e15*e28+e27*e26*e16+e27*e28*e18-e27*e20*e10+e14*e24*e27+e14*e25*e28+0.5*e212*e17+0.5*e242*e17+e11*e20*e26+e11*e21*e27+e11*e22*e28+e21*e20*e16+e21*e10*e26+e21*e22*e18+e21*e12*e28+e14*e23*e26; + A[5 + 10*9]=e21*e20*e26+0.5*e212*e27+e21*e22*e28+e24*e23*e26+0.5*e242*e27+e24*e25*e28+0.5*e27*e262+0.5*e273+0.5*e27*e282-0.5*e27*e202-0.5*e27*e222-0.5*e27*e232-0.5*e27*e252; + A[5 + 10*10]=e04*e05*e38+e01*e30*e06-0.5*e37*e002-0.5*e37*e022-0.5*e37*e032-0.5*e37*e052-e07*e32*e02-e07*e35*e05-e07*e33*e03+e07*e36*e06+e07*e38*e08-e07*e30*e00+1.5*e37*e072+0.5*e37*e062+0.5*e37*e082+e01*e02*e38+e31*e00*e06+e31*e02*e08+e04*e33*e06+e04*e03*e36+e04*e34*e07+e04*e35*e08+e34*e03*e06+e34*e05*e08+0.5*e012*e37+0.5*e042*e37+e01*e00*e36+e01*e31*e07+e01*e32*e08; + A[5 + 10*11]=e14*e33*e06+e11*e30*e06+e11*e00*e36+e11*e31*e07+e31*e10*e06+e11*e32*e08+e11*e02*e38+e31*e00*e16+e31*e12*e08+e31*e02*e18+e04*e33*e16+e04*e13*e36+e04*e35*e18+e04*e15*e38+e01*e10*e36+e01*e32*e18+e01*e12*e38+e01*e31*e17+e01*e11*e37+e01*e30*e16-e17*e35*e05-e37*e10*e00-e37*e12*e02-e37*e13*e03-e37*e15*e05+e37*e18*e08-e07*e30*e10-e07*e35*e15-e07*e33*e13-e07*e32*e12-e17*e30*e00-e17*e32*e02-e17*e33*e03+e07*e38*e18+3*e07*e37*e17+e17*e36*e06+e17*e38*e08+e37*e16*e06+e04*e34*e17+e04*e14*e37+e14*e03*e36+e14*e34*e07+e14*e35*e08+e14*e05*e38+e34*e13*e06+e34*e03*e16+e34*e15*e08+e34*e05*e18+e07*e36*e16; + A[5 + 10*12]=e11*e32*e18-0.5*e37*e102-0.5*e37*e152-0.5*e37*e132-0.5*e37*e122+0.5*e112*e37+0.5*e142*e37+1.5*e37*e172+0.5*e37*e162+0.5*e37*e182+e11*e10*e36+e11*e12*e38+e11*e31*e17+e31*e10*e16+e31*e12*e18+e14*e33*e16+e14*e13*e36+e14*e35*e18+e14*e15*e38+e14*e34*e17+e34*e13*e16+e34*e15*e18+e17*e36*e16+e17*e38*e18-e17*e30*e10-e17*e35*e15-e17*e33*e13-e17*e32*e12+e11*e30*e16; + A[5 + 10*13]=e01*e20*e36+e01*e31*e27+e01*e21*e37+e01*e32*e28+e01*e22*e38+e21*e30*e06+e21*e00*e36+e21*e31*e07+e21*e32*e08+e21*e02*e38+e01*e30*e26+e31*e20*e06+e31*e00*e26+e31*e22*e08+e31*e02*e28+e04*e33*e26+e04*e23*e36+e04*e34*e27+e04*e24*e37+e04*e35*e28+e04*e25*e38+e24*e33*e06+e24*e03*e36+e24*e34*e07+e24*e35*e08+e24*e05*e38+e34*e23*e06+e34*e03*e26+e34*e25*e08+e34*e05*e28+e07*e36*e26+3*e07*e37*e27+e07*e38*e28+e27*e36*e06+e27*e38*e08+e37*e26*e06+e37*e28*e08-e07*e30*e20-e07*e32*e22-e07*e33*e23-e07*e35*e25-e27*e30*e00-e27*e32*e02-e27*e33*e03-e27*e35*e05-e37*e20*e00-e37*e22*e02-e37*e23*e03-e37*e25*e05; + A[5 + 10*14]=e11*e30*e26+e11*e20*e36+e11*e31*e27+e11*e21*e37+e11*e32*e28+e11*e22*e38+e21*e10*e36+e21*e32*e18+e21*e12*e38+e21*e31*e17+e31*e20*e16+e31*e10*e26+e31*e22*e18+e31*e12*e28+e14*e33*e26+e14*e23*e36+e14*e34*e27+e14*e24*e37+e14*e35*e28+e14*e25*e38+e24*e33*e16+e24*e13*e36+e24*e35*e18+e24*e15*e38+e24*e34*e17+e34*e23*e16+e34*e13*e26+e34*e25*e18+e34*e15*e28+e17*e36*e26+3*e17*e37*e27+e17*e38*e28+e27*e36*e16+e27*e38*e18+e37*e26*e16+e37*e28*e18-e17*e30*e20-e17*e32*e22-e17*e33*e23-e17*e35*e25-e27*e30*e10-e27*e35*e15-e27*e33*e13-e27*e32*e12-e37*e20*e10-e37*e25*e15-e37*e23*e13-e37*e22*e12+e21*e30*e16; + A[5 + 10*15]=e21*e20*e36+e21*e31*e27+e21*e32*e28+e21*e22*e38+e31*e22*e28+e24*e33*e26+e24*e23*e36+e24*e34*e27+e24*e35*e28+e24*e25*e38+e34*e23*e26+e34*e25*e28+e27*e36*e26+e27*e38*e28-e27*e30*e20-e27*e32*e22-e27*e33*e23-e27*e35*e25+0.5*e242*e37+1.5*e37*e272+0.5*e37*e262+0.5*e37*e282+e31*e20*e26+e21*e30*e26+0.5*e212*e37-0.5*e37*e202-0.5*e37*e222-0.5*e37*e232-0.5*e37*e252; + A[5 + 10*16]=e01*e30*e36+e01*e32*e38+e01*e31*e37+e31*e30*e06+e31*e00*e36+e31*e32*e08+e31*e02*e38+e04*e33*e36+e04*e35*e38+e04*e34*e37+e34*e33*e06+e34*e03*e36+e34*e35*e08+e34*e05*e38+e37*e36*e06+e37*e38*e08-e37*e30*e00-e37*e32*e02-e37*e33*e03-e37*e35*e05+0.5*e312*e07+0.5*e342*e07+0.5*e07*e362+0.5*e07*e382+1.5*e07*e372-0.5*e07*e302-0.5*e07*e352-0.5*e07*e322-0.5*e07*e332; + A[5 + 10*17]=0.5*e312*e17+0.5*e342*e17+0.5*e17*e362+0.5*e17*e382+1.5*e17*e372-0.5*e17*e302-0.5*e17*e352-0.5*e17*e322-0.5*e17*e332-e37*e32*e12-e37*e33*e13+e11*e30*e36+e11*e32*e38+e11*e31*e37+e31*e30*e16+e31*e10*e36+e31*e32*e18+e31*e12*e38+e14*e33*e36+e14*e35*e38+e14*e34*e37+e34*e33*e16+e34*e13*e36+e34*e35*e18+e34*e15*e38+e37*e36*e16+e37*e38*e18-e37*e30*e10-e37*e35*e15; + A[5 + 10*18]=e21*e31*e37-0.5*e27*e332+e21*e30*e36+e21*e32*e38+e31*e30*e26+e31*e20*e36+e31*e32*e28+e31*e22*e38+e24*e33*e36+e24*e35*e38+e24*e34*e37+e34*e33*e26+e34*e23*e36+e34*e35*e28+e34*e25*e38+e37*e36*e26+e37*e38*e28-e37*e30*e20-e37*e32*e22-e37*e33*e23-e37*e35*e25+0.5*e312*e27+0.5*e342*e27+0.5*e27*e362+0.5*e27*e382+1.5*e27*e372-0.5*e27*e302-0.5*e27*e352-0.5*e27*e322; + A[5 + 10*19]=e31*e30*e36+e31*e32*e38+0.5*e312*e37+e34*e33*e36+e34*e35*e38+0.5*e342*e37+0.5*e37*e362+0.5*e37*e382+0.5*e373-0.5*e37*e302-0.5*e37*e352-0.5*e37*e322-0.5*e37*e332; + A[6 + 10*0]=0.5*e02*e002+0.5*e02*e012+0.5*e023+e05*e00*e03+e05*e01*e04+0.5*e02*e052+e08*e00*e06+e08*e01*e07+0.5*e02*e082-0.5*e02*e032-0.5*e02*e042-0.5*e02*e062-0.5*e02*e072; + A[6 + 10*1]=-0.5*e12*e042-0.5*e12*e062-0.5*e12*e072+0.5*e12*e082-0.5*e12*e032+1.5*e12*e022+0.5*e12*e002+0.5*e12*e012+0.5*e12*e052+e02*e10*e00+e02*e11*e01+e05*e10*e03+e05*e00*e13+e05*e11*e04+e05*e01*e14+e05*e02*e15+e15*e00*e03+e15*e01*e04+e08*e10*e06+e08*e00*e16+e08*e11*e07+e08*e01*e17+e08*e02*e18+e18*e00*e06+e18*e01*e07-e02*e13*e03-e02*e14*e04-e02*e16*e06-e02*e17*e07; + A[6 + 10*2]=0.5*e02*e102+1.5*e02*e122+0.5*e02*e112+0.5*e02*e152+0.5*e02*e182-0.5*e02*e162-0.5*e02*e172-0.5*e02*e132-0.5*e02*e142+e12*e10*e00+e12*e11*e01+e05*e10*e13+e05*e12*e15+e05*e11*e14+e15*e10*e03+e15*e00*e13+e15*e11*e04+e15*e01*e14+e08*e10*e16+e08*e12*e18+e08*e11*e17+e18*e10*e06+e18*e00*e16+e18*e11*e07+e18*e01*e17-e12*e13*e03-e12*e14*e04-e12*e16*e06-e12*e17*e07; + A[6 + 10*3]=0.5*e12*e102+0.5*e123+0.5*e12*e112+e15*e10*e13+0.5*e12*e152+e15*e11*e14+e18*e10*e16+0.5*e12*e182+e18*e11*e17-0.5*e12*e162-0.5*e12*e172-0.5*e12*e132-0.5*e12*e142; + A[6 + 10*4]=-0.5*e22*e032-0.5*e22*e042-0.5*e22*e062-0.5*e22*e072+0.5*e22*e082+1.5*e22*e022+0.5*e22*e002+0.5*e22*e012+0.5*e22*e052+e02*e20*e00+e02*e21*e01+e05*e20*e03+e05*e00*e23+e05*e21*e04+e05*e01*e24+e05*e02*e25+e25*e00*e03+e25*e01*e04+e08*e20*e06+e08*e00*e26+e08*e21*e07+e08*e01*e27+e08*e02*e28+e28*e00*e06+e28*e01*e07-e02*e27*e07-e02*e23*e03-e02*e24*e04-e02*e26*e06; + A[6 + 10*5]=-e22*e17*e07-e22*e16*e06-e22*e14*e04-e22*e13*e03-e12*e26*e06-e12*e24*e04-e12*e23*e03-e12*e27*e07-e02*e24*e14-e02*e23*e13-e02*e27*e17-e02*e26*e16+e28*e01*e17+e28*e11*e07+e28*e00*e16+e28*e10*e06+e18*e02*e28+e18*e01*e27+e18*e21*e07+e18*e00*e26+e18*e20*e06+e08*e11*e27+e08*e21*e17+e08*e12*e28+e08*e22*e18+e08*e10*e26+e25*e01*e14+e25*e11*e04+e25*e00*e13+e25*e10*e03+e15*e01*e24+e02*e21*e11+e12*e21*e01+e15*e02*e25+e15*e21*e04+e05*e22*e15+e05*e11*e24+e15*e20*e03+e15*e00*e23+e05*e10*e23+e05*e12*e25+e05*e21*e14+e22*e10*e00+e22*e11*e01+e02*e20*e10+3*e02*e22*e12+e12*e20*e00+e08*e20*e16+e05*e20*e13; + A[6 + 10*6]=-e12*e24*e14-e12*e23*e13-e12*e27*e17-e12*e26*e16+e28*e11*e17+e28*e10*e16+e18*e11*e27+e18*e21*e17+e18*e12*e28+e18*e10*e26+e18*e20*e16+e25*e11*e14+e25*e10*e13+e15*e11*e24+e15*e21*e14+e15*e12*e25+e15*e10*e23+e15*e20*e13+e12*e21*e11+0.5*e22*e182+0.5*e22*e152+1.5*e22*e122+0.5*e22*e102+e12*e20*e10+0.5*e22*e112-0.5*e22*e172-0.5*e22*e132-0.5*e22*e142-0.5*e22*e162; + A[6 + 10*7]=0.5*e02*e282+e28*e01*e27-e22*e27*e07-e22*e23*e03-e22*e24*e04-e22*e26*e06+0.5*e02*e252+e05*e20*e23+e05*e22*e25+e25*e20*e03+e25*e00*e23+e25*e21*e04+e25*e01*e24+e08*e20*e26+e08*e21*e27+e08*e22*e28+e28*e20*e06+e28*e00*e26+e28*e21*e07+e05*e21*e24+0.5*e02*e202+0.5*e02*e212+1.5*e02*e222+e22*e20*e00+e22*e21*e01-0.5*e02*e272-0.5*e02*e242-0.5*e02*e232-0.5*e02*e262; + A[6 + 10*8]=-e22*e27*e17-e22*e23*e13-e22*e24*e14-0.5*e12*e232-0.5*e12*e262-0.5*e12*e242-0.5*e12*e272+0.5*e12*e282+e18*e21*e27+e28*e20*e16+e28*e10*e26+e28*e21*e17+e28*e11*e27-e22*e26*e16+e18*e22*e28+0.5*e12*e252+0.5*e12*e202+0.5*e12*e212+1.5*e12*e222+e22*e20*e10+e15*e20*e23+e15*e21*e24+e15*e22*e25+e25*e20*e13+e25*e10*e23+e25*e21*e14+e25*e11*e24+e18*e20*e26+e22*e21*e11; + A[6 + 10*9]=0.5*e22*e202+0.5*e22*e212+0.5*e223+e25*e20*e23+e25*e21*e24+0.5*e22*e252+e28*e20*e26+e28*e21*e27+0.5*e22*e282-0.5*e22*e232-0.5*e22*e262-0.5*e22*e242-0.5*e22*e272; + A[6 + 10*10]=e08*e31*e07-0.5*e32*e032-e02*e33*e03-e02*e34*e04-e02*e36*e06-0.5*e32*e042-0.5*e32*e062-0.5*e32*e072+e38*e01*e07+e38*e00*e06-e02*e37*e07+e05*e31*e04+e05*e01*e34+e05*e02*e35+e35*e01*e04+e35*e00*e03+e08*e30*e06+e08*e00*e36+e08*e01*e37+e08*e02*e38+0.5*e32*e052+e02*e30*e00+e02*e31*e01+e05*e30*e03+e05*e00*e33+1.5*e32*e022+0.5*e32*e012+0.5*e32*e002+0.5*e32*e082; + A[6 + 10*11]=e05*e32*e15+e32*e11*e01+e38*e10*e06+e08*e12*e38-e32*e14*e04-e32*e16*e06-e32*e17*e07-e12*e36*e06-e32*e13*e03-e02*e34*e14-e12*e37*e07-e12*e33*e03-e12*e34*e04-e02*e37*e17-e02*e33*e13+e38*e01*e17-e02*e36*e16+e18*e01*e37+e18*e02*e38+e38*e00*e16+e38*e11*e07+e08*e30*e16+e08*e10*e36+e08*e32*e18+e08*e31*e17+e08*e11*e37+e18*e30*e06+e18*e00*e36+e18*e31*e07+e35*e10*e03+e35*e00*e13+e35*e11*e04+e35*e01*e14+e15*e02*e35+e05*e10*e33+e05*e12*e35+e05*e31*e14+e05*e11*e34+e15*e30*e03+e15*e00*e33+e15*e31*e04+e15*e01*e34+e05*e30*e13+e02*e30*e10+e02*e31*e11+3*e02*e32*e12+e12*e30*e00+e12*e31*e01+e32*e10*e00; + A[6 + 10*12]=0.5*e32*e102+0.5*e32*e112+e12*e30*e10+1.5*e32*e122+e12*e31*e11+e15*e30*e13+e15*e10*e33+e15*e12*e35+e15*e31*e14+e15*e11*e34+e35*e10*e13-0.5*e32*e162-0.5*e32*e172-0.5*e32*e132-0.5*e32*e142-e12*e37*e17-e12*e33*e13-e12*e34*e14+0.5*e32*e182+0.5*e32*e152+e35*e11*e14+e18*e30*e16+e18*e10*e36+e18*e12*e38+e18*e31*e17+e18*e11*e37+e38*e10*e16+e38*e11*e17-e12*e36*e16; + A[6 + 10*13]=3*e02*e32*e22+e05*e31*e24+e08*e22*e38+e02*e31*e21+e22*e30*e00+e22*e31*e01+e32*e20*e00+e32*e21*e01+e05*e30*e23+e05*e20*e33+e05*e21*e34-e22*e37*e07-e22*e33*e03-e22*e34*e04-e22*e36*e06-e32*e27*e07-e32*e23*e03-e32*e24*e04-e32*e26*e06+e05*e32*e25+e25*e30*e03+e25*e00*e33+e25*e31*e04+e25*e01*e34+e25*e02*e35+e35*e20*e03+e35*e00*e23+e35*e21*e04+e35*e01*e24+e08*e30*e26+e08*e20*e36+e08*e31*e27+e08*e21*e37+e08*e32*e28+e28*e30*e06+e28*e00*e36+e28*e31*e07+e28*e01*e37+e28*e02*e38+e38*e20*e06+e38*e00*e26+e38*e21*e07+e38*e01*e27-e02*e33*e23-e02*e36*e26-e02*e34*e24-e02*e37*e27+e05*e22*e35+e02*e30*e20; + A[6 + 10*14]=e18*e22*e38+e12*e31*e21+3*e12*e32*e22+e22*e30*e10+e22*e31*e11+e32*e20*e10+e32*e21*e11+e15*e30*e23+e15*e20*e33+e15*e31*e24+e15*e21*e34+e15*e32*e25+e15*e22*e35+e25*e30*e13+e25*e10*e33+e25*e12*e35+e25*e31*e14+e25*e11*e34+e35*e20*e13+e35*e10*e23+e35*e21*e14+e35*e11*e24+e18*e30*e26+e18*e20*e36+e18*e31*e27+e18*e21*e37+e18*e32*e28+e28*e30*e16+e28*e10*e36+e28*e12*e38+e28*e31*e17+e28*e11*e37+e38*e20*e16+e38*e10*e26+e12*e30*e20-e22*e37*e17-e22*e33*e13-e22*e34*e14-e32*e26*e16-e32*e27*e17-e32*e23*e13-e32*e24*e14-e22*e36*e16+e38*e21*e17+e38*e11*e27-e12*e33*e23-e12*e36*e26-e12*e34*e24-e12*e37*e27; + A[6 + 10*15]=e25*e30*e23+e22*e30*e20+e22*e31*e21+e25*e20*e33+e25*e31*e24+e25*e21*e34+e25*e22*e35+e35*e20*e23+e35*e21*e24+e28*e30*e26+e28*e20*e36+e28*e31*e27+e28*e21*e37+e28*e22*e38+e38*e20*e26+e38*e21*e27-e22*e33*e23-e22*e36*e26-e22*e34*e24-e22*e37*e27+0.5*e32*e212+0.5*e32*e252+1.5*e32*e222+0.5*e32*e202+0.5*e32*e282-0.5*e32*e232-0.5*e32*e262-0.5*e32*e242-0.5*e32*e272; + A[6 + 10*16]=0.5*e02*e302+1.5*e02*e322+0.5*e02*e312+0.5*e02*e352+0.5*e02*e382-0.5*e02*e342-0.5*e02*e362-0.5*e02*e332-0.5*e02*e372+e38*e30*e06+e32*e30*e00+e32*e31*e01+e05*e30*e33+e05*e32*e35+e05*e31*e34+e35*e30*e03+e35*e00*e33+e35*e31*e04+e35*e01*e34+e08*e30*e36+e08*e32*e38+e08*e31*e37+e38*e00*e36+e38*e31*e07+e38*e01*e37-e32*e37*e07-e32*e33*e03-e32*e34*e04-e32*e36*e06; + A[6 + 10*17]=e32*e30*e10+e32*e31*e11+e15*e30*e33+e15*e32*e35+e15*e31*e34+e35*e30*e13+e35*e10*e33+e35*e31*e14+e35*e11*e34+e18*e30*e36+e18*e32*e38+e18*e31*e37+e38*e30*e16+e38*e10*e36+e38*e31*e17+e38*e11*e37-e32*e36*e16-e32*e37*e17-e32*e33*e13-e32*e34*e14+0.5*e12*e382-0.5*e12*e342-0.5*e12*e362-0.5*e12*e332-0.5*e12*e372+0.5*e12*e352+1.5*e12*e322+0.5*e12*e312+0.5*e12*e302; + A[6 + 10*18]=0.5*e22*e302+0.5*e22*e312+0.5*e22*e352+0.5*e22*e382-0.5*e22*e342-0.5*e22*e362-0.5*e22*e332-0.5*e22*e372+1.5*e22*e322+e32*e30*e20+e32*e31*e21+e25*e30*e33+e25*e32*e35+e25*e31*e34+e35*e30*e23+e35*e20*e33+e35*e31*e24+e35*e21*e34+e28*e30*e36+e28*e32*e38+e28*e31*e37+e38*e30*e26+e38*e20*e36+e38*e31*e27+e38*e21*e37-e32*e33*e23-e32*e36*e26-e32*e34*e24-e32*e37*e27; + A[6 + 10*19]=0.5*e32*e302+0.5*e323+0.5*e32*e312+e35*e30*e33+0.5*e32*e352+e35*e31*e34+e38*e30*e36+0.5*e32*e382+e38*e31*e37-0.5*e32*e342-0.5*e32*e362-0.5*e32*e332-0.5*e32*e372; + A[7 + 10*0]=e02*e01*e04+e02*e00*e03+0.5*e022*e05+0.5*e05*e032+0.5*e05*e042+0.5*e053+e08*e03*e06+e08*e04*e07+0.5*e05*e082-0.5*e05*e002-0.5*e05*e062-0.5*e05*e012-0.5*e05*e072; + A[7 + 10*1]=e08*e13*e06+e02*e10*e03+e02*e00*e13+e02*e11*e04+e02*e01*e14+e02*e12*e05+e12*e01*e04+e12*e00*e03+e05*e13*e03+e05*e14*e04+e08*e03*e16+e08*e14*e07+e08*e04*e17+e08*e05*e18+e18*e03*e06+e18*e04*e07-e05*e10*e00-e05*e11*e01-e05*e16*e06-e05*e17*e07+0.5*e022*e15+1.5*e15*e052+0.5*e15*e032+0.5*e15*e042+0.5*e15*e082-0.5*e15*e002-0.5*e15*e062-0.5*e15*e012-0.5*e15*e072; + A[7 + 10*2]=0.5*e122*e05+0.5*e05*e132+1.5*e05*e152+0.5*e05*e142+0.5*e05*e182-0.5*e05*e102-0.5*e05*e162-0.5*e05*e112-0.5*e05*e172+e02*e10*e13+e02*e12*e15+e02*e11*e14+e12*e10*e03+e12*e00*e13+e12*e11*e04+e12*e01*e14+e15*e13*e03+e15*e14*e04+e08*e13*e16+e08*e15*e18+e08*e14*e17+e18*e13*e06+e18*e03*e16+e18*e14*e07+e18*e04*e17-e15*e11*e01-e15*e16*e06-e15*e17*e07-e15*e10*e00; + A[7 + 10*3]=e12*e10*e13+0.5*e122*e15+e12*e11*e14+0.5*e15*e132+0.5*e153+0.5*e15*e142+e18*e13*e16+0.5*e15*e182+e18*e14*e17-0.5*e15*e102-0.5*e15*e162-0.5*e15*e112-0.5*e15*e172; + A[7 + 10*4]=0.5*e25*e082-0.5*e25*e002-0.5*e25*e062-0.5*e25*e012-0.5*e25*e072+e02*e20*e03+e02*e00*e23+e02*e21*e04+e02*e01*e24+e02*e22*e05+e22*e01*e04+e22*e00*e03+e05*e23*e03+e05*e24*e04+e08*e23*e06+e08*e03*e26+e08*e24*e07+e08*e04*e27+e08*e05*e28+e28*e03*e06+e28*e04*e07-e05*e20*e00-e05*e27*e07-e05*e21*e01-e05*e26*e06+0.5*e022*e25+1.5*e25*e052+0.5*e25*e032+0.5*e25*e042; + A[7 + 10*5]=-e25*e17*e07-e25*e16*e06-e25*e11*e01-e25*e10*e00-e15*e26*e06-e15*e21*e01-e15*e27*e07-e15*e20*e00-e05*e27*e17-e05*e21*e11-e05*e26*e16-e05*e20*e10+e28*e04*e17+e28*e14*e07+e28*e03*e16+e28*e13*e06+e18*e05*e28+e18*e04*e27+e18*e24*e07+e18*e03*e26+e18*e23*e06+e08*e14*e27+e08*e24*e17+e08*e15*e28+e08*e25*e18+e08*e13*e26+e08*e23*e16+e25*e14*e04+e25*e13*e03+e15*e24*e04+e15*e23*e03+e05*e24*e14+3*e05*e25*e15+e05*e23*e13+e22*e01*e14+e22*e11*e04+e22*e00*e13+e22*e10*e03+e12*e22*e05+e12*e01*e24+e12*e21*e04+e12*e00*e23+e12*e20*e03+e02*e11*e24+e02*e21*e14+e02*e12*e25+e02*e22*e15+e02*e10*e23+e02*e20*e13; + A[7 + 10*6]=-e15*e27*e17-e15*e21*e11-e15*e26*e16+e28*e14*e17+e28*e13*e16+e18*e14*e27+e18*e24*e17+e18*e15*e28+e18*e13*e26+e15*e24*e14+e15*e23*e13+e22*e11*e14+e22*e10*e13+e12*e11*e24+e12*e21*e14+e12*e22*e15+e12*e10*e23+e18*e23*e16+0.5*e25*e142+0.5*e25*e182+1.5*e25*e152+0.5*e25*e132+0.5*e122*e25+e12*e20*e13-0.5*e25*e172-0.5*e25*e162-0.5*e25*e112-0.5*e25*e102-e15*e20*e10; + A[7 + 10*7]=e28*e24*e07-0.5*e05*e272-0.5*e05*e262-0.5*e05*e212+0.5*e05*e282-0.5*e05*e202+e28*e23*e06+e08*e23*e26+e08*e25*e28+e08*e24*e27+e28*e03*e26+e28*e04*e27-e25*e27*e07-e25*e21*e01-e25*e26*e06+e02*e20*e23+e02*e22*e25+e02*e21*e24+e22*e20*e03+e22*e00*e23+e22*e21*e04+e22*e01*e24+e25*e23*e03+e25*e24*e04+0.5*e222*e05+0.5*e05*e232+1.5*e05*e252+0.5*e05*e242-e25*e20*e00; + A[7 + 10*8]=-0.5*e15*e202-0.5*e15*e262-0.5*e15*e212-0.5*e15*e272+e18*e23*e26+e18*e25*e28+e18*e24*e27+e28*e23*e16+e28*e13*e26+e28*e24*e17+e28*e14*e27-e25*e20*e10-e25*e26*e16-e25*e21*e11-e25*e27*e17+0.5*e15*e282+0.5*e15*e232+1.5*e15*e252+0.5*e15*e242+0.5*e222*e15+e12*e21*e24+e22*e20*e13+e22*e10*e23+e22*e21*e14+e22*e11*e24+e25*e23*e13+e25*e24*e14+e12*e20*e23+e12*e22*e25; + A[7 + 10*9]=e22*e20*e23+0.5*e222*e25+e22*e21*e24+0.5*e25*e232+0.5*e253+0.5*e25*e242+e28*e23*e26+0.5*e25*e282+e28*e24*e27-0.5*e25*e202-0.5*e25*e262-0.5*e25*e212-0.5*e25*e272; + A[7 + 10*10]=-0.5*e35*e062-0.5*e35*e012-0.5*e35*e072-e05*e30*e00-e05*e31*e01-e05*e36*e06-e05*e37*e07-0.5*e35*e002+0.5*e35*e082+e05*e34*e04+e08*e33*e06+e08*e03*e36+e08*e34*e07+e08*e04*e37+e08*e05*e38+e38*e04*e07+e38*e03*e06+0.5*e022*e35+1.5*e35*e052+0.5*e35*e042+0.5*e35*e032+e02*e30*e03+e02*e00*e33+e02*e31*e04+e02*e01*e34+e02*e32*e05+e32*e01*e04+e32*e00*e03+e05*e33*e03; + A[7 + 10*11]=e08*e33*e16-e35*e16*e06-e35*e17*e07-e15*e30*e00-e15*e37*e07-e15*e31*e01-e15*e36*e06-e35*e10*e00-e35*e11*e01-e05*e37*e17-e05*e31*e11+e38*e04*e17-e05*e30*e10-e05*e36*e16+e18*e33*e06+e18*e03*e36+e18*e34*e07+e18*e04*e37+e18*e05*e38+e38*e13*e06+e38*e03*e16+e38*e14*e07+e35*e14*e04+e08*e13*e36+e08*e35*e18+e08*e15*e38+e08*e34*e17+e08*e14*e37+e35*e13*e03+e05*e33*e13+3*e05*e35*e15+e05*e34*e14+e15*e33*e03+e15*e34*e04+e12*e01*e34+e12*e32*e05+e32*e10*e03+e32*e00*e13+e32*e11*e04+e32*e01*e14+e12*e30*e03+e02*e30*e13+e02*e32*e15+e02*e10*e33+e02*e12*e35+e12*e00*e33+e02*e31*e14+e02*e11*e34+e12*e31*e04; + A[7 + 10*12]=-0.5*e35*e162-0.5*e35*e172-e15*e36*e16-e15*e31*e11-e15*e37*e17-0.5*e35*e102-0.5*e35*e112-e15*e30*e10+e18*e13*e36+e18*e15*e38+e18*e34*e17+e18*e14*e37+e38*e13*e16+e38*e14*e17+e18*e33*e16+1.5*e35*e152+0.5*e35*e132+0.5*e35*e142+0.5*e35*e182+0.5*e122*e35+e32*e10*e13+e32*e11*e14+e15*e33*e13+e15*e34*e14+e12*e10*e33+e12*e32*e15+e12*e31*e14+e12*e11*e34+e12*e30*e13; + A[7 + 10*13]=e05*e33*e23+3*e05*e35*e25+e05*e34*e24+e25*e33*e03+e25*e34*e04+e35*e23*e03+e35*e24*e04+e08*e33*e26+e08*e23*e36+e08*e35*e28+e02*e20*e33+e02*e32*e25+e02*e22*e35+e02*e31*e24+e02*e21*e34+e22*e30*e03+e22*e00*e33+e22*e31*e04+e22*e01*e34+e22*e32*e05+e32*e20*e03+e32*e00*e23+e32*e21*e04+e32*e01*e24+e02*e30*e23-e35*e27*e07-e35*e21*e01-e35*e26*e06+e08*e25*e38+e08*e34*e27+e08*e24*e37+e28*e33*e06+e28*e03*e36+e28*e34*e07+e28*e04*e37+e28*e05*e38+e38*e23*e06+e38*e03*e26+e38*e24*e07+e38*e04*e27-e05*e30*e20-e05*e36*e26-e05*e31*e21-e05*e37*e27-e25*e30*e00-e25*e37*e07-e25*e31*e01-e25*e36*e06-e35*e20*e00; + A[7 + 10*14]=e12*e21*e34+e18*e25*e38+e12*e30*e23+e12*e20*e33+e12*e32*e25+e12*e22*e35+e12*e31*e24+e22*e30*e13+e22*e10*e33+e22*e32*e15+e22*e31*e14+e22*e11*e34+e32*e20*e13+e32*e10*e23+e32*e21*e14-e25*e30*e10-e25*e36*e16-e25*e31*e11-e25*e37*e17-e35*e20*e10-e35*e26*e16-e35*e21*e11-e35*e27*e17+e15*e33*e23+3*e15*e35*e25+e15*e34*e24+e25*e33*e13+e25*e34*e14+e35*e23*e13+e35*e24*e14+e18*e33*e26+e18*e23*e36+e18*e35*e28+e18*e34*e27+e18*e24*e37+e28*e33*e16+e28*e13*e36+e28*e15*e38+e28*e34*e17+e28*e14*e37+e38*e23*e16+e38*e13*e26+e38*e24*e17+e38*e14*e27-e15*e30*e20-e15*e36*e26-e15*e31*e21-e15*e37*e27+e32*e11*e24; + A[7 + 10*15]=-0.5*e35*e202-0.5*e35*e262-0.5*e35*e212-0.5*e35*e272+e25*e34*e24+e28*e23*e36+e28*e25*e38+e28*e34*e27+e28*e24*e37+e38*e23*e26+e38*e24*e27-e25*e30*e20-e25*e36*e26-e25*e31*e21-e25*e37*e27+e25*e33*e23+0.5*e222*e35+1.5*e35*e252+0.5*e35*e232+0.5*e35*e242+0.5*e35*e282+e22*e30*e23+e22*e20*e33+e22*e32*e25+e22*e31*e24+e22*e21*e34+e32*e20*e23+e32*e21*e24+e28*e33*e26; + A[7 + 10*16]=-e35*e30*e00-e35*e31*e01-e35*e36*e06-e35*e37*e07+0.5*e322*e05+0.5*e05*e332+0.5*e05*e342+1.5*e05*e352+0.5*e05*e382-0.5*e05*e302-0.5*e05*e362-0.5*e05*e312-0.5*e05*e372+e02*e30*e33+e02*e31*e34+e02*e32*e35+e32*e30*e03+e32*e00*e33+e32*e31*e04+e32*e01*e34+e35*e33*e03+e35*e34*e04+e08*e33*e36+e08*e34*e37+e08*e35*e38+e38*e33*e06+e38*e03*e36+e38*e34*e07+e38*e04*e37; + A[7 + 10*17]=-e35*e30*e10+e12*e32*e35-0.5*e15*e362-0.5*e15*e312-0.5*e15*e372-e35*e36*e16+0.5*e322*e15+0.5*e15*e332+0.5*e15*e342+1.5*e15*e352+0.5*e15*e382-0.5*e15*e302+e12*e30*e33+e12*e31*e34+e32*e30*e13+e32*e10*e33+e32*e31*e14+e32*e11*e34+e35*e33*e13+e35*e34*e14+e18*e33*e36+e18*e34*e37+e18*e35*e38+e38*e33*e16+e38*e13*e36+e38*e34*e17+e38*e14*e37-e35*e31*e11-e35*e37*e17; + A[7 + 10*18]=-0.5*e25*e302-0.5*e25*e362-0.5*e25*e312-0.5*e25*e372+0.5*e322*e25+0.5*e25*e332+0.5*e25*e342+1.5*e25*e352+0.5*e25*e382+e22*e30*e33+e22*e31*e34+e22*e32*e35+e32*e30*e23+e32*e20*e33+e32*e31*e24+e32*e21*e34+e35*e33*e23+e35*e34*e24+e28*e33*e36+e28*e34*e37+e28*e35*e38+e38*e33*e26+e38*e23*e36+e38*e34*e27+e38*e24*e37-e35*e30*e20-e35*e36*e26-e35*e31*e21-e35*e37*e27; + A[7 + 10*19]=e32*e30*e33+e32*e31*e34+0.5*e322*e35+0.5*e35*e332+0.5*e35*e342+0.5*e353+e38*e33*e36+e38*e34*e37+0.5*e35*e382-0.5*e35*e302-0.5*e35*e362-0.5*e35*e312-0.5*e35*e372; + A[8 + 10*0]=e02*e00*e06+e02*e01*e07+0.5*e022*e08+e05*e04*e07+e05*e03*e06+0.5*e052*e08+0.5*e08*e062+0.5*e08*e072+0.5*e083-0.5*e08*e042-0.5*e08*e002-0.5*e08*e012-0.5*e08*e032; + A[8 + 10*1]=e02*e10*e06+e02*e00*e16+e02*e11*e07+e02*e01*e17+e02*e12*e08+e12*e00*e06+e12*e01*e07+e05*e13*e06+e05*e03*e16+e05*e14*e07+e05*e04*e17+e05*e15*e08+e15*e04*e07+e15*e03*e06+e08*e16*e06+e08*e17*e07-e08*e10*e00-e08*e11*e01-e08*e13*e03-e08*e14*e04+0.5*e022*e18+0.5*e052*e18+1.5*e18*e082+0.5*e18*e062+0.5*e18*e072-0.5*e18*e042-0.5*e18*e002-0.5*e18*e012-0.5*e18*e032; + A[8 + 10*2]=e12*e01*e17+0.5*e152*e08+0.5*e08*e162+1.5*e08*e182+0.5*e08*e172-0.5*e08*e102-0.5*e08*e112-0.5*e08*e132-0.5*e08*e142+e05*e13*e16+e05*e14*e17+e05*e15*e18+e15*e13*e06+e15*e03*e16+e15*e14*e07+e15*e04*e17+e18*e16*e06+e18*e17*e07-e18*e10*e00-e18*e11*e01-e18*e13*e03-e18*e14*e04+0.5*e122*e08+e02*e10*e16+e02*e12*e18+e02*e11*e17+e12*e10*e06+e12*e00*e16+e12*e11*e07; + A[8 + 10*3]=e12*e10*e16+0.5*e122*e18+e12*e11*e17+e15*e13*e16+e15*e14*e17+0.5*e152*e18+0.5*e18*e162+0.5*e183+0.5*e18*e172-0.5*e18*e102-0.5*e18*e112-0.5*e18*e132-0.5*e18*e142; + A[8 + 10*4]=-e08*e20*e00+e08*e27*e07-e08*e21*e01-e08*e23*e03-e08*e24*e04+e02*e20*e06+e02*e00*e26+e02*e21*e07+e02*e01*e27+e02*e22*e08+e22*e00*e06+e22*e01*e07+e05*e23*e06+e05*e03*e26+e05*e24*e07+e05*e04*e27+e05*e25*e08+e25*e04*e07+e25*e03*e06+e08*e26*e06+0.5*e022*e28+0.5*e052*e28+1.5*e28*e082+0.5*e28*e062+0.5*e28*e072-0.5*e28*e042-0.5*e28*e002-0.5*e28*e012-0.5*e28*e032; + A[8 + 10*5]=e22*e10*e06+e22*e11*e07+e22*e01*e17+e05*e23*e16+e05*e13*e26+e05*e25*e18+e05*e15*e28+e05*e24*e17+e05*e14*e27+e15*e23*e06+e15*e03*e26+e15*e24*e07+e15*e04*e27+e15*e25*e08+e25*e13*e06+e25*e03*e16+e25*e14*e07+e25*e04*e17+e08*e26*e16+3*e08*e28*e18+e08*e27*e17+e18*e26*e06+e18*e27*e07+e22*e00*e16+e28*e16*e06+e28*e17*e07-e08*e20*e10-e08*e21*e11-e08*e23*e13-e08*e24*e14-e18*e20*e00-e18*e21*e01-e18*e23*e03-e18*e24*e04-e28*e10*e00-e28*e11*e01-e28*e13*e03-e28*e14*e04+e02*e20*e16+e02*e10*e26+e02*e22*e18+e02*e12*e28+e02*e21*e17+e02*e11*e27+e12*e20*e06+e12*e00*e26+e12*e21*e07+e12*e01*e27+e12*e22*e08; + A[8 + 10*6]=-e18*e24*e14-e18*e21*e11-e18*e23*e13-e18*e20*e10+e18*e27*e17+e18*e26*e16+e25*e14*e17+e25*e13*e16+e15*e25*e18+e15*e14*e27+e15*e24*e17+e15*e13*e26+e15*e23*e16+e22*e11*e17+e22*e10*e16+e12*e11*e27+e12*e21*e17+e12*e22*e18+e12*e10*e26+e12*e20*e16+0.5*e28*e162+0.5*e28*e172+1.5*e28*e182+0.5*e152*e28-0.5*e28*e142-0.5*e28*e112-0.5*e28*e132-0.5*e28*e102+0.5*e122*e28; + A[8 + 10*7]=-e28*e24*e04-e28*e21*e01-e28*e23*e03-e28*e20*e00+e28*e27*e07+e28*e26*e06+e25*e04*e27+e25*e24*e07+e25*e03*e26+e05*e24*e27+e05*e25*e28+e05*e23*e26+e22*e01*e27+e22*e21*e07+e22*e00*e26+e22*e20*e06+e02*e22*e28+e02*e20*e26+e02*e21*e27+0.5*e222*e08-0.5*e08*e242-0.5*e08*e212-0.5*e08*e232-0.5*e08*e202+0.5*e08*e262+0.5*e08*e272+1.5*e08*e282+0.5*e252*e08+e25*e23*e06; + A[8 + 10*8]=e25*e24*e17+e25*e14*e27+e28*e26*e16+e28*e27*e17-e28*e21*e11-e28*e24*e14+e12*e22*e28+e22*e10*e26+e22*e21*e17+e22*e11*e27+e15*e23*e26+e15*e25*e28+e15*e24*e27+e25*e23*e16+e25*e13*e26+e22*e20*e16+0.5*e222*e18+0.5*e252*e18+0.5*e18*e262+0.5*e18*e272+e12*e20*e26+e12*e21*e27-e28*e20*e10-0.5*e18*e232-0.5*e18*e242-e28*e23*e13-0.5*e18*e212+1.5*e18*e282-0.5*e18*e202; + A[8 + 10*9]=e22*e20*e26+e22*e21*e27+0.5*e222*e28+e25*e23*e26+0.5*e252*e28+e25*e24*e27+0.5*e28*e262+0.5*e28*e272+0.5*e283-0.5*e28*e202-0.5*e28*e212-0.5*e28*e232-0.5*e28*e242; + A[8 + 10*10]=-e08*e30*e00-0.5*e38*e042-0.5*e38*e002-0.5*e38*e012-0.5*e38*e032+1.5*e38*e082+0.5*e38*e062+0.5*e38*e072+e32*e01*e07+e05*e33*e06+e05*e03*e36+e05*e34*e07+e05*e04*e37+e05*e35*e08+e35*e04*e07+e35*e03*e06+e08*e36*e06+e08*e37*e07+0.5*e052*e38+e32*e00*e06+e02*e30*e06+e02*e00*e36+e02*e31*e07+e02*e01*e37+e02*e32*e08+0.5*e022*e38-e08*e33*e03-e08*e31*e01-e08*e34*e04; + A[8 + 10*11]=-e38*e11*e01-e38*e14*e04-e38*e10*e00-e38*e13*e03-e18*e30*e00-e18*e33*e03-e18*e31*e01-e18*e34*e04-e08*e30*e10-e08*e33*e13-e08*e31*e11-e08*e34*e14+3*e08*e38*e18+e08*e37*e17+e18*e36*e06+e18*e37*e07+e38*e16*e06+e38*e17*e07+e15*e35*e08+e35*e13*e06+e35*e03*e16+e35*e14*e07+e35*e04*e17+e08*e36*e16+e05*e35*e18+e05*e15*e38+e15*e33*e06+e15*e03*e36+e15*e34*e07+e15*e04*e37+e05*e14*e37+e12*e30*e06+e12*e31*e07+e12*e01*e37+e12*e00*e36+e12*e32*e08+e32*e10*e06+e32*e00*e16+e32*e11*e07+e32*e01*e17+e05*e33*e16+e05*e13*e36+e05*e34*e17+e02*e30*e16+e02*e10*e36+e02*e32*e18+e02*e12*e38+e02*e31*e17+e02*e11*e37; + A[8 + 10*12]=e12*e30*e16+e12*e10*e36+e12*e32*e18+e12*e31*e17+e12*e11*e37+e32*e10*e16+e32*e11*e17+e15*e33*e16+e15*e13*e36-0.5*e38*e102-0.5*e38*e112-0.5*e38*e132-0.5*e38*e142+0.5*e38*e162+0.5*e38*e172+e15*e34*e17+e15*e14*e37+e15*e35*e18+e35*e13*e16+e35*e14*e17+e18*e36*e16+e18*e37*e17-e18*e30*e10-e18*e33*e13-e18*e31*e11-e18*e34*e14+0.5*e122*e38+0.5*e152*e38+1.5*e38*e182; + A[8 + 10*13]=e22*e30*e06-e28*e34*e04+e05*e35*e28+e02*e22*e38+e22*e00*e36+e22*e31*e07+e22*e01*e37+e02*e32*e28+e02*e21*e37-e38*e20*e00-e28*e31*e01-e38*e23*e03-e38*e21*e01-e38*e24*e04-e28*e30*e00-e08*e30*e20-e08*e31*e21-e08*e33*e23-e08*e34*e24-e28*e33*e03+e35*e24*e07+e35*e04*e27+e08*e36*e26+e08*e37*e27+3*e08*e38*e28+e28*e36*e06+e28*e37*e07+e38*e26*e06+e38*e27*e07+e25*e04*e37+e25*e35*e08+e35*e23*e06+e35*e03*e26+e05*e23*e36+e05*e25*e38+e05*e34*e27+e05*e24*e37+e25*e33*e06+e25*e03*e36+e25*e34*e07+e05*e33*e26+e32*e21*e07+e32*e01*e27+e22*e32*e08+e32*e20*e06+e32*e00*e26+e02*e30*e26+e02*e20*e36+e02*e31*e27; + A[8 + 10*14]=e35*e13*e26-e38*e21*e11-e38*e24*e14+e35*e24*e17+e35*e14*e27+e18*e36*e26+e18*e37*e27+3*e18*e38*e28+e28*e36*e16+e28*e37*e17+e38*e26*e16+e38*e27*e17-e18*e30*e20-e18*e31*e21-e18*e33*e23-e18*e34*e24-e28*e30*e10-e28*e33*e13-e28*e31*e11-e28*e34*e14-e38*e20*e10-e38*e23*e13+e35*e23*e16+e12*e20*e36+e12*e30*e26+e12*e31*e27+e12*e21*e37+e12*e32*e28+e12*e22*e38+e22*e30*e16+e22*e10*e36+e22*e32*e18+e22*e31*e17+e22*e11*e37+e32*e20*e16+e32*e10*e26+e32*e21*e17+e32*e11*e27+e15*e33*e26+e15*e23*e36+e15*e35*e28+e15*e25*e38+e15*e34*e27+e15*e24*e37+e25*e33*e16+e25*e13*e36+e25*e34*e17+e25*e14*e37+e25*e35*e18; + A[8 + 10*15]=-e28*e30*e20+e22*e30*e26+e22*e20*e36+e22*e31*e27+e22*e21*e37+e22*e32*e28+e32*e20*e26+e32*e21*e27+e25*e33*e26+e25*e23*e36+e25*e35*e28+e25*e34*e27+e25*e24*e37+e35*e23*e26+e35*e24*e27+e28*e36*e26+e28*e37*e27-e28*e31*e21-e28*e33*e23-e28*e34*e24-0.5*e38*e242+0.5*e252*e38+1.5*e38*e282+0.5*e38*e262+0.5*e38*e272-0.5*e38*e202-0.5*e38*e212-0.5*e38*e232+0.5*e222*e38; + A[8 + 10*16]=-0.5*e08*e312-0.5*e08*e342+0.5*e352*e08+0.5*e08*e362+1.5*e08*e382+0.5*e08*e372-0.5*e08*e302-0.5*e08*e332+e02*e30*e36+e02*e32*e38+e02*e31*e37+e32*e30*e06+e32*e00*e36+e32*e31*e07+e32*e01*e37+e05*e33*e36+e05*e34*e37+e05*e35*e38+e35*e33*e06+e35*e03*e36+e35*e34*e07+e35*e04*e37+0.5*e322*e08+e38*e36*e06+e38*e37*e07-e38*e30*e00-e38*e33*e03-e38*e31*e01-e38*e34*e04; + A[8 + 10*17]=-e38*e30*e10+e38*e36*e16+e38*e37*e17-e38*e33*e13-e38*e31*e11-e38*e34*e14+0.5*e18*e362+e12*e30*e36+e12*e32*e38+e12*e31*e37+e32*e30*e16+e32*e10*e36+e32*e31*e17+e32*e11*e37+e15*e33*e36+e15*e34*e37+e15*e35*e38+e35*e33*e16+e35*e13*e36+e35*e34*e17+e35*e14*e37+0.5*e322*e18+0.5*e352*e18+1.5*e18*e382+0.5*e18*e372-0.5*e18*e302-0.5*e18*e332-0.5*e18*e312-0.5*e18*e342; + A[8 + 10*18]=-e38*e30*e20+e25*e35*e38+e22*e30*e36+e22*e32*e38+e22*e31*e37+e32*e30*e26+e32*e20*e36+e32*e31*e27+e32*e21*e37+e25*e33*e36+e25*e34*e37+e35*e33*e26+e35*e23*e36+e35*e34*e27+e35*e24*e37+e38*e36*e26+e38*e37*e27-e38*e31*e21-e38*e33*e23-e38*e34*e24-0.5*e28*e332-0.5*e28*e312-0.5*e28*e342+0.5*e322*e28+0.5*e352*e28+0.5*e28*e362+1.5*e28*e382+0.5*e28*e372-0.5*e28*e302; + A[8 + 10*19]=e32*e30*e36+0.5*e322*e38+e32*e31*e37+e35*e33*e36+e35*e34*e37+0.5*e352*e38+0.5*e38*e362+0.5*e383+0.5*e38*e372-0.5*e38*e302-0.5*e38*e332-0.5*e38*e312-0.5*e38*e342; + A[9 + 10*0]=e00*e04*e08-e00*e05*e07+e03*e02*e07-e03*e01*e08-e06*e02*e04+e06*e01*e05; + A[9 + 10*1]=e06*e01*e15-e16*e02*e04+e16*e01*e05+e03*e02*e17-e13*e01*e08+e06*e11*e05+e13*e02*e07+e00*e04*e18+e00*e14*e08-e00*e05*e17-e10*e05*e07-e00*e15*e07-e06*e12*e04-e06*e02*e14-e03*e01*e18-e03*e11*e08+e10*e04*e08+e03*e12*e07; + A[9 + 10*2]=-e13*e01*e18-e13*e11*e08+e13*e12*e07+e13*e02*e17+e03*e12*e17-e10*e15*e07+e10*e04*e18+e10*e14*e08-e10*e05*e17-e00*e15*e17+e00*e14*e18+e16*e01*e15+e06*e11*e15-e06*e12*e14-e16*e12*e04-e16*e02*e14+e16*e11*e05-e03*e11*e18; + A[9 + 10*3]=e10*e14*e18-e10*e15*e17-e13*e11*e18+e13*e12*e17+e16*e11*e15-e16*e12*e14; + A[9 + 10*4]=-e20*e05*e07+e03*e22*e07+e06*e21*e05+e06*e01*e25-e23*e01*e08+e23*e02*e07+e00*e24*e08-e00*e25*e07-e00*e05*e27+e00*e04*e28-e06*e22*e04-e06*e02*e24-e03*e21*e08-e03*e01*e28-e26*e02*e04+e26*e01*e05+e03*e02*e27+e20*e04*e08; + A[9 + 10*5]=e23*e12*e07-e26*e02*e14+e16*e21*e05-e23*e11*e08+e10*e24*e08-e20*e05*e17+e26*e11*e05+e26*e01*e15+e10*e04*e28+e00*e24*e18-e00*e15*e27+e03*e22*e17-e13*e01*e28+e23*e02*e17+e16*e01*e25+e20*e04*e18+e06*e11*e25+e13*e02*e27-e23*e01*e18-e20*e15*e07-e10*e25*e07+e13*e22*e07-e06*e22*e14-e26*e12*e04-e03*e11*e28-e03*e21*e18-e16*e22*e04-e16*e02*e24-e06*e12*e24+e06*e21*e15+e00*e14*e28-e00*e25*e17+e20*e14*e08-e13*e21*e08-e10*e05*e27+e03*e12*e27; + A[9 + 10*6]=-e13*e11*e28+e13*e12*e27+e13*e22*e17+e16*e11*e25+e10*e14*e28-e13*e21*e18-e23*e11*e18+e23*e12*e17+e20*e14*e18-e20*e15*e17+e26*e11*e15-e10*e15*e27-e10*e25*e17-e16*e22*e14-e16*e12*e24+e16*e21*e15-e26*e12*e14+e10*e24*e18; + A[9 + 10*7]=e26*e21*e05+e26*e01*e25+e20*e04*e28+e20*e24*e08-e20*e25*e07+e23*e22*e07+e03*e22*e27-e03*e21*e28-e26*e22*e04-e20*e05*e27-e00*e25*e27+e06*e21*e25-e06*e22*e24+e00*e24*e28-e26*e02*e24-e23*e21*e08-e23*e01*e28+e23*e02*e27; + A[9 + 10*8]=-e10*e25*e27+e10*e24*e28-e20*e15*e27-e20*e25*e17+e20*e14*e28+e20*e24*e18+e26*e11*e25+e23*e22*e17-e23*e11*e28+e23*e12*e27-e23*e21*e18-e13*e21*e28+e13*e22*e27-e26*e12*e24+e26*e21*e15-e16*e22*e24+e16*e21*e25-e26*e22*e14; + A[9 + 10*9]=-e20*e25*e27+e20*e24*e28-e23*e21*e28+e23*e22*e27-e26*e22*e24+e26*e21*e25; + A[9 + 10*10]=e03*e02*e37-e03*e31*e08-e03*e01*e38+e03*e32*e07-e00*e35*e07+e30*e04*e08+e06*e31*e05-e36*e02*e04+e36*e01*e05-e06*e32*e04-e06*e02*e34+e06*e01*e35+e00*e04*e38-e00*e05*e37+e33*e02*e07-e33*e01*e08-e30*e05*e07+e00*e34*e08; + A[9 + 10*11]=-e36*e12*e04+e30*e04*e18-e30*e15*e07-e36*e02*e14-e30*e05*e17+e30*e14*e08-e00*e35*e17-e00*e15*e37+e33*e02*e17-e06*e32*e14-e06*e12*e34-e16*e32*e04+e06*e31*e15+e06*e11*e35+e00*e34*e18-e10*e35*e07-e33*e11*e08-e33*e01*e18+e16*e01*e35-e16*e02*e34+e16*e31*e05-e03*e31*e18-e03*e11*e38+e03*e32*e17+e13*e02*e37-e13*e31*e08-e13*e01*e38+e10*e34*e08+e00*e14*e38+e36*e11*e05+e36*e01*e15+e03*e12*e37-e10*e05*e37+e10*e04*e38+e33*e12*e07+e13*e32*e07; + A[9 + 10*12]=-e36*e12*e14-e30*e15*e17+e13*e32*e17-e13*e31*e18-e33*e11*e18+e33*e12*e17+e10*e14*e38+e30*e14*e18-e13*e11*e38+e13*e12*e37-e10*e35*e17+e10*e34*e18-e16*e12*e34-e16*e32*e14+e16*e11*e35+e16*e31*e15+e36*e11*e15-e10*e15*e37; + A[9 + 10*13]=-e06*e22*e34-e06*e32*e24-e00*e25*e37-e00*e35*e27+e23*e02*e37+e00*e24*e38-e23*e01*e38-e03*e31*e28-e33*e01*e28+e03*e22*e37+e03*e32*e27+e33*e02*e27-e03*e21*e38-e26*e32*e04-e33*e21*e08+e36*e01*e25+e36*e21*e05-e20*e05*e37+e20*e04*e38+e30*e04*e28-e20*e35*e07+e33*e22*e07+e30*e24*e08-e30*e25*e07-e23*e31*e08+e23*e32*e07+e00*e34*e28+e06*e21*e35+e06*e31*e25-e36*e02*e24+e26*e01*e35-e36*e22*e04+e26*e31*e05-e26*e02*e34+e20*e34*e08-e30*e05*e27; + A[9 + 10*14]=e33*e22*e17+e33*e12*e27+e16*e21*e35-e16*e22*e34-e16*e32*e24+e23*e32*e17-e23*e11*e38-e23*e31*e18+e23*e12*e37-e13*e21*e38-e13*e31*e28+e13*e22*e37+e36*e21*e15-e36*e12*e24+e36*e11*e25-e26*e12*e34-e20*e35*e17+e20*e14*e38+e20*e34*e18+e30*e24*e18-e30*e15*e27-e30*e25*e17+e30*e14*e28-e33*e21*e18+e10*e34*e28+e10*e24*e38-e10*e35*e27-e10*e25*e37-e20*e15*e37-e26*e32*e14+e26*e11*e35+e26*e31*e15-e36*e22*e14+e13*e32*e27+e16*e31*e25-e33*e11*e28; + A[9 + 10*15]=-e20*e35*e27-e20*e25*e37+e20*e34*e28+e20*e24*e38+e30*e24*e28-e30*e25*e27+e23*e32*e27+e23*e22*e37-e23*e31*e28-e23*e21*e38+e33*e22*e27-e26*e22*e34-e26*e32*e24+e26*e21*e35+e26*e31*e25-e36*e22*e24+e36*e21*e25-e33*e21*e28; + A[9 + 10*16]=-e33*e01*e38-e03*e31*e38+e00*e34*e38+e33*e32*e07+e03*e32*e37+e06*e31*e35-e00*e35*e37-e36*e32*e04-e06*e32*e34-e36*e02*e34+e36*e01*e35+e36*e31*e05+e30*e04*e38+e30*e34*e08-e33*e31*e08+e33*e02*e37-e30*e05*e37-e30*e35*e07; + A[9 + 10*17]=-e33*e31*e18-e33*e11*e38+e10*e34*e38+e30*e14*e38-e10*e35*e37-e30*e15*e37-e13*e31*e38+e13*e32*e37-e30*e35*e17+e33*e12*e37+e30*e34*e18+e33*e32*e17+e16*e31*e35-e16*e32*e34-e36*e12*e34-e36*e32*e14+e36*e11*e35+e36*e31*e15; + A[9 + 10*18]=-e20*e35*e37+e20*e34*e38+e30*e24*e38-e30*e35*e27-e30*e25*e37+e30*e34*e28+e23*e32*e37-e23*e31*e38-e33*e21*e38-e33*e31*e28+e33*e22*e37+e33*e32*e27+e26*e31*e35-e26*e32*e34-e36*e22*e34-e36*e32*e24+e36*e21*e35+e36*e31*e25; + A[9 + 10*19]=-e33*e31*e38-e30*e35*e37+e36*e31*e35+e33*e32*e37+e30*e34*e38-e36*e32*e34; } - else if (method == CV_RANSAC) - { - estimator.runRANSAC(&p1, &p2, &_E, tempMask, threshold, prob); - } - else + + void computeError( InputArray _m1, InputArray _m2, InputArray _model, OutputArray _err ) const + { + Mat X1 = _m1.getMat(), X2 = _m2.getMat(), model = _model.getMat(); + const Point2d* x1ptr = X1.ptr(); + const Point2d* x2ptr = X2.ptr(); + int n = X1.checkVector(2); + Matx33d E(model.ptr()); + + _err.create(n, 1, CV_32F); + Mat err = _err.getMat(); + + for (int i = 0; i < n; i++) + { + Vec3d x1(x1ptr[i].x, x1ptr[i].y, 1.); + Vec3d x2(x2ptr[i].x, x2ptr[i].y, 1.); + Vec3d Ex1 = E * x1; + Vec3d Etx2 = E.t() * x2; + double x2tEx1 = x2.dot(Ex1); + + double a = Ex1[0] * Ex1[0]; + double b = Ex1[1] * Ex1[1]; + double c = Etx2[0] * Etx2[0]; + double d = Etx2[1] * Etx2[1]; + + err.at(i) = (float)(x2tEx1 * x2tEx1 / (a + b + c + d)); + } + } +}; + +} + +// Input should be a vector of n 2D points or a Nx2 matrix +cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, double focal, Point2d pp, + int method, double prob, double threshold, OutputArray _mask) +{ + Mat points1, points2; + _points1.getMat().convertTo(points1, CV_64F); + _points2.getMat().convertTo(points2, CV_64F); + + int npoints = points1.checkVector(2); + CV_Assert( npoints >= 5 && points2.checkVector(2) == npoints && + points1.type() == points2.type()); + + if( points1.channels() > 1 ) { - estimator.runLMeDS(&p1, &p2, &_E, tempMask, prob); + points1 = points1.reshape(1, npoints); + points2 = points2.reshape(1, npoints); } - if (_mask.needed()) + + double ifocal = focal != 0 ? 1./focal : 1.; + for( int i = 0; i < npoints; i++ ) { - _mask.create(1, npoints, CV_8U, -1, true); - Mat mask = _mask.getMat(); - Mat(tempMask).copyTo(mask); + points1.at(i, 0) = (points1.at(i, 0) - pp.x)*ifocal; + points1.at(i, 1) = (points1.at(i, 1) - pp.y)*ifocal; + points2.at(i, 0) = (points2.at(i, 0) - pp.x)*ifocal; + points2.at(i, 1) = (points2.at(i, 1) - pp.y)*ifocal; } + // Reshape data to fit opencv ransac function + points1 = points1.reshape(2, npoints); + points2 = points2.reshape(2, npoints); + + threshold /= focal; - return E; + Mat E; + if( method == CV_RANSAC ) + createRANSACPointSetRegistrator(new EMEstimatorCallback, 5, threshold, prob)->run(points1, points2, E, _mask); + else + createLMeDSPointSetRegistrator(new EMEstimatorCallback, 5, prob)->run(points1, points2, E, _mask); + return E; } -int cv::recoverPose( InputArray E, InputArray _points1, InputArray _points2, OutputArray _R, OutputArray _t, - double focal, Point2d pp, - InputOutputArray _mask) +int cv::recoverPose( InputArray E, InputArray _points1, InputArray _points2, OutputArray _R, + OutputArray _t, double focal, Point2d pp, InputOutputArray _mask) { - Mat points1, points2; - _points1.getMat().copyTo(points1); - _points2.getMat().copyTo(points2); - + Mat points1, points2; + _points1.getMat().copyTo(points1); + _points2.getMat().copyTo(points2); + int npoints = points1.checkVector(2); CV_Assert( npoints >= 0 && points2.checkVector(2) == npoints && points1.type() == points2.type()); if (points1.channels() > 1) { - points1 = points1.reshape(1, npoints); - points2 = points2.reshape(1, npoints); + points1 = points1.reshape(1, npoints); + points2 = points2.reshape(1, npoints); } - points1.convertTo(points1, CV_64F); - points2.convertTo(points2, CV_64F); - - points1.col(0) = (points1.col(0) - pp.x) / focal; - points2.col(0) = (points2.col(0) - pp.x) / focal; - points1.col(1) = (points1.col(1) - pp.y) / focal; - points2.col(1) = (points2.col(1) - pp.y) / focal; - - points1 = points1.t(); - points2 = points2.t(); - - Mat R1, R2, t; - decomposeEssentialMat(E, R1, R2, t); - Mat P0 = Mat::eye(3, 4, R1.type()); - Mat P1(3, 4, R1.type()), P2(3, 4, R1.type()), P3(3, 4, R1.type()), P4(3, 4, R1.type()); - P1(Range::all(), Range(0, 3)) = R1 * 1.0; P1.col(3) = t * 1.0; - P2(Range::all(), Range(0, 3)) = R2 * 1.0; P2.col(3) = t * 1.0; - P3(Range::all(), Range(0, 3)) = R1 * 1.0; P3.col(3) = -t * 1.0; - P4(Range::all(), Range(0, 3)) = R2 * 1.0; P4.col(3) = -t * 1.0; - - // Do the cheirality check. + points1.convertTo(points1, CV_64F); + points2.convertTo(points2, CV_64F); + + points1.col(0) = (points1.col(0) - pp.x) / focal; + points2.col(0) = (points2.col(0) - pp.x) / focal; + points1.col(1) = (points1.col(1) - pp.y) / focal; + points2.col(1) = (points2.col(1) - pp.y) / focal; + + points1 = points1.t(); + points2 = points2.t(); + + Mat R1, R2, t; + decomposeEssentialMat(E, R1, R2, t); + Mat P0 = Mat::eye(3, 4, R1.type()); + Mat P1(3, 4, R1.type()), P2(3, 4, R1.type()), P3(3, 4, R1.type()), P4(3, 4, R1.type()); + P1(Range::all(), Range(0, 3)) = R1 * 1.0; P1.col(3) = t * 1.0; + P2(Range::all(), Range(0, 3)) = R2 * 1.0; P2.col(3) = t * 1.0; + P3(Range::all(), Range(0, 3)) = R1 * 1.0; P3.col(3) = -t * 1.0; + P4(Range::all(), Range(0, 3)) = R2 * 1.0; P4.col(3) = -t * 1.0; + + // Do the cheirality check. // Notice here a threshold dist is used to filter - // out far away points (i.e. infinite points) since - // there depth may vary between postive and negtive. - double dist = 50.0; - Mat Q; - triangulatePoints(P0, P1, points1, points2, Q); - Mat mask1 = Q.row(2).mul(Q.row(3)) > 0; - Q.row(0) /= Q.row(3); - Q.row(1) /= Q.row(3); - Q.row(2) /= Q.row(3); - Q.row(3) /= Q.row(3); - mask1 = (Q.row(2) < dist) & mask1; - Q = P1 * Q; - mask1 = (Q.row(2) > 0) & mask1; - mask1 = (Q.row(2) < dist) & mask1; - - triangulatePoints(P0, P2, points1, points2, Q); - Mat mask2 = Q.row(2).mul(Q.row(3)) > 0; - Q.row(0) /= Q.row(3); - Q.row(1) /= Q.row(3); - Q.row(2) /= Q.row(3); - Q.row(3) /= Q.row(3); - mask2 = (Q.row(2) < dist) & mask2; - Q = P2 * Q; - mask2 = (Q.row(2) > 0) & mask2; - mask2 = (Q.row(2) < dist) & mask2; - - triangulatePoints(P0, P3, points1, points2, Q); - Mat mask3 = Q.row(2).mul(Q.row(3)) > 0; - Q.row(0) /= Q.row(3); - Q.row(1) /= Q.row(3); - Q.row(2) /= Q.row(3); - Q.row(3) /= Q.row(3); - mask3 = (Q.row(2) < dist) & mask3; - Q = P3 * Q; - mask3 = (Q.row(2) > 0) & mask3; - mask3 = (Q.row(2) < dist) & mask3; - - triangulatePoints(P0, P4, points1, points2, Q); - Mat mask4 = Q.row(2).mul(Q.row(3)) > 0; - Q.row(0) /= Q.row(3); - Q.row(1) /= Q.row(3); - Q.row(2) /= Q.row(3); - Q.row(3) /= Q.row(3); - mask4 = (Q.row(2) < dist) & mask4; - Q = P4 * Q; - mask4 = (Q.row(2) > 0) & mask4; - mask4 = (Q.row(2) < dist) & mask4; - - // If _mask is given, then use it to filter outliers. + // out far away points (i.e. infinite points) since + // there depth may vary between postive and negtive. + double dist = 50.0; + Mat Q; + triangulatePoints(P0, P1, points1, points2, Q); + Mat mask1 = Q.row(2).mul(Q.row(3)) > 0; + Q.row(0) /= Q.row(3); + Q.row(1) /= Q.row(3); + Q.row(2) /= Q.row(3); + Q.row(3) /= Q.row(3); + mask1 = (Q.row(2) < dist) & mask1; + Q = P1 * Q; + mask1 = (Q.row(2) > 0) & mask1; + mask1 = (Q.row(2) < dist) & mask1; + + triangulatePoints(P0, P2, points1, points2, Q); + Mat mask2 = Q.row(2).mul(Q.row(3)) > 0; + Q.row(0) /= Q.row(3); + Q.row(1) /= Q.row(3); + Q.row(2) /= Q.row(3); + Q.row(3) /= Q.row(3); + mask2 = (Q.row(2) < dist) & mask2; + Q = P2 * Q; + mask2 = (Q.row(2) > 0) & mask2; + mask2 = (Q.row(2) < dist) & mask2; + + triangulatePoints(P0, P3, points1, points2, Q); + Mat mask3 = Q.row(2).mul(Q.row(3)) > 0; + Q.row(0) /= Q.row(3); + Q.row(1) /= Q.row(3); + Q.row(2) /= Q.row(3); + Q.row(3) /= Q.row(3); + mask3 = (Q.row(2) < dist) & mask3; + Q = P3 * Q; + mask3 = (Q.row(2) > 0) & mask3; + mask3 = (Q.row(2) < dist) & mask3; + + triangulatePoints(P0, P4, points1, points2, Q); + Mat mask4 = Q.row(2).mul(Q.row(3)) > 0; + Q.row(0) /= Q.row(3); + Q.row(1) /= Q.row(3); + Q.row(2) /= Q.row(3); + Q.row(3) /= Q.row(3); + mask4 = (Q.row(2) < dist) & mask4; + Q = P4 * Q; + mask4 = (Q.row(2) > 0) & mask4; + mask4 = (Q.row(2) < dist) & mask4; + + // If _mask is given, then use it to filter outliers. if (_mask.needed()) { - _mask.create(1, npoints, CV_8U, -1, true); - Mat mask = _mask.getMat(); - bitwise_and(mask, mask1, mask1); - bitwise_and(mask, mask2, mask2); - bitwise_and(mask, mask3, mask3); - bitwise_and(mask, mask4, mask4); + _mask.create(1, npoints, CV_8U, -1, true); + Mat mask = _mask.getMat(); + bitwise_and(mask, mask1, mask1); + bitwise_and(mask, mask2, mask2); + bitwise_and(mask, mask3, mask3); + bitwise_and(mask, mask4, mask4); } - CV_Assert(_R.needed() && _t.needed()); - _R.create(3, 3, R1.type()); - _t.create(3, 1, t.type()); + CV_Assert(_R.needed() && _t.needed()); + _R.create(3, 3, R1.type()); + _t.create(3, 1, t.type()); - int good1 = countNonZero(mask1); - int good2 = countNonZero(mask2); - int good3 = countNonZero(mask3); - int good4 = countNonZero(mask4); + int good1 = countNonZero(mask1); + int good2 = countNonZero(mask2); + int good3 = countNonZero(mask3); + int good4 = countNonZero(mask4); if (good1 >= good2 && good1 >= good3 && good1 >= good4) { - R1.copyTo(_R.getMat()); - t.copyTo(_t.getMat()); - if (_mask.needed()) mask1.copyTo(_mask.getMat()); - return good1; + R1.copyTo(_R); + t.copyTo(_t); + if (_mask.needed()) mask1.copyTo(_mask); + return good1; } else if (good2 >= good1 && good2 >= good3 && good2 >= good4) { - R2.copyTo(_R.getMat()); - t.copyTo(_t.getMat()); - if (_mask.needed()) mask2.copyTo(_mask.getMat()); - return good2; + R2.copyTo(_R); + t.copyTo(_t); + if (_mask.needed()) mask2.copyTo(_mask); + return good2; } else if (good3 >= good1 && good3 >= good2 && good3 >= good4) { - t = -t; - R1.copyTo(_R.getMat()); - t.copyTo(_t.getMat()); - if (_mask.needed()) mask3.copyTo(_mask.getMat()); - return good3; + t = -t; + R1.copyTo(_R); + t.copyTo(_t); + if (_mask.needed()) mask3.copyTo(_mask); + return good3; } - else + else { - t = -t; - R2.copyTo(_R.getMat()); - t.copyTo(_t.getMat()); - if (_mask.needed()) mask4.copyTo(_mask.getMat()); - return good4; + t = -t; + R2.copyTo(_R); + t.copyTo(_t); + if (_mask.needed()) mask4.copyTo(_mask); + return good4; } - -} - - - -void cv::decomposeEssentialMat( InputArray _E, OutputArray _R1, OutputArray _R2, OutputArray _t ) -{ - Mat E; - _E.getMat().copyTo(E); - E = E.reshape(1, 3); - - assert(E.cols == 3 && E.rows == 3); - - Mat D, U, Vt; - SVD::compute(E, D, U, Vt); - - if (determinant(U) < 0) U = -U; - if (determinant(Vt) < 0) Vt = -Vt; - - Mat W = (Mat_(3, 3) << 0, 1, 0, -1, 0, 0, 0, 0, 1); - W.convertTo(W, E.type()); - - Mat R1, R2, t; - R1 = U * W * Vt; - R2 = U * W.t() * Vt; - t = U.col(2) * 1.0; - - _R1.create(3, 3, E.type()); - _R2.create(3, 3, E.type()); - _t.create(3, 1, E.type()); - R1.copyTo(_R1.getMat()); - R2.copyTo(_R2.getMat()); - t.copyTo(_t.getMat()); - } -CvEMEstimator::CvEMEstimator() -: CvModelEstimator2( 5, cvSize(3,3), 10 ) -{ -} - -int CvEMEstimator::runKernel( const CvMat* m1, const CvMat* m2, CvMat* model ) +void cv::decomposeEssentialMat( InputArray _E, OutputArray _R1, OutputArray _R2, OutputArray _t ) { - return run5Point(m1, m2, model); + Mat E = _E.getMat().reshape(1, 3); + CV_Assert(E.cols == 3 && E.rows == 3); + + Mat D, U, Vt; + SVD::compute(E, D, U, Vt); + + if (determinant(U) < 0) U *= -1.; + if (determinant(Vt) < 0) Vt *= -1.; + + Mat W = (Mat_(3, 3) << 0, 1, 0, -1, 0, 0, 0, 0, 1); + W.convertTo(W, E.type()); + + Mat R1, R2, t; + R1 = U * W * Vt; + R2 = U * W.t() * Vt; + t = U.col(2) * 1.0; + + R1.copyTo(_R1); + R2.copyTo(_R2); + t.copyTo(_t); } - -// Notice to keep compatibility with opencv ransac, q1 and q2 have -// to be of 1 row x n col x 2 channel. -int CvEMEstimator::run5Point( const CvMat* q1, const CvMat* q2, CvMat* ematrix ) -{ - Mat Q1 = Mat(q1).reshape(1, q1->cols); - Mat Q2 = Mat(q2).reshape(1, q2->cols); - - int n = Q1.rows; - Mat Q(n, 9, CV_64F); - Q.col(0) = Q1.col(0).mul( Q2.col(0) ); - Q.col(1) = Q1.col(1).mul( Q2.col(0) ); - Q.col(2) = Q2.col(0) * 1.0; - Q.col(3) = Q1.col(0).mul( Q2.col(1) ); - Q.col(4) = Q1.col(1).mul( Q2.col(1) ); - Q.col(5) = Q2.col(1) * 1.0; - Q.col(6) = Q1.col(0) * 1.0; - Q.col(7) = Q1.col(1) * 1.0; - Q.col(8) = 1.0; - - Mat U, W, Vt; - SVD::compute(Q, W, U, Vt, SVD::MODIFY_A | SVD::FULL_UV); - - Mat EE = Mat(Vt.t()).colRange(5, 9) * 1.0; - Mat AA(20, 10, CV_64F); - EE = EE.t(); - calibrated_fivepoint_helper((double*)EE.data, (double*)AA.data); - AA = AA.t(); - EE = EE.t(); - - Mat A(10, 20, CV_64F); - int perm[20] = {0, 3, 1, 2, 4, 10, 6, 12, 5, 11, 7, 13, 16, 8, 14, 17, 9, 15, 18, 19}; - for (int i = 0; i < 20; i++) - A.col(i) = AA.col(perm[i]) * 1.0; - - - A = A.colRange(0, 10).inv() * A.colRange(10, 20); - - double b[3 * 13]; - Mat B(3, 13, CV_64F, b); - for (int i = 0; i < 3; i++) - { - Mat arow1 = A.row(i * 2 + 4) * 1.0; - Mat arow2 = A.row(i * 2 + 5) * 1.0; - Mat row1(1, 13, CV_64F, Scalar(0.0)); - Mat row2(1, 13, CV_64F, Scalar(0.0)); - - row1.colRange(1, 4) = arow1.colRange(0, 3) * 1.0; - row1.colRange(5, 8) = arow1.colRange(3, 6) * 1.0; - row1.colRange(9, 13) = arow1.colRange(6, 10) * 1.0; - - row2.colRange(0, 3) = arow2.colRange(0, 3) * 1.0; - row2.colRange(4, 7) = arow2.colRange(3, 6) * 1.0; - row2.colRange(8, 12) = arow2.colRange(6, 10) * 1.0; - - B.row(i) = row1 - row2; - } - - double c[11]; - Mat coeffs(1, 11, CV_64F, c); - c[10] = (b[0]*b[17]*b[34]+b[26]*b[4]*b[21]-b[26]*b[17]*b[8]-b[13]*b[4]*b[34]-b[0]*b[21]*b[30]+b[13]*b[30]*b[8]); - c[9] = (b[26]*b[4]*b[22]+b[14]*b[30]*b[8]+b[13]*b[31]*b[8]+b[1]*b[17]*b[34]-b[13]*b[5]*b[34]+b[26]*b[5]*b[21]-b[0]*b[21]*b[31]-b[26]*b[17]*b[9]-b[1]*b[21]*b[30]+b[27]*b[4]*b[21]+b[0]*b[17]*b[35]-b[0]*b[22]*b[30]+b[13]*b[30]*b[9]+b[0]*b[18]*b[34]-b[27]*b[17]*b[8]-b[14]*b[4]*b[34]-b[13]*b[4]*b[35]-b[26]*b[18]*b[8]); - c[8] = (b[14]*b[30]*b[9]+b[14]*b[31]*b[8]+b[13]*b[31]*b[9]-b[13]*b[4]*b[36]-b[13]*b[5]*b[35]+b[15]*b[30]*b[8]-b[13]*b[6]*b[34]+b[13]*b[30]*b[10]+b[13]*b[32]*b[8]-b[14]*b[4]*b[35]-b[14]*b[5]*b[34]+b[26]*b[4]*b[23]+b[26]*b[5]*b[22]+b[26]*b[6]*b[21]-b[26]*b[17]*b[10]-b[15]*b[4]*b[34]-b[26]*b[18]*b[9]-b[26]*b[19]*b[8]+b[27]*b[4]*b[22]+b[27]*b[5]*b[21]-b[27]*b[17]*b[9]-b[27]*b[18]*b[8]-b[1]*b[21]*b[31]-b[0]*b[23]*b[30]-b[0]*b[21]*b[32]+b[28]*b[4]*b[21]-b[28]*b[17]*b[8]+b[2]*b[17]*b[34]+b[0]*b[18]*b[35]-b[0]*b[22]*b[31]+b[0]*b[17]*b[36]+b[0]*b[19]*b[34]-b[1]*b[22]*b[30]+b[1]*b[18]*b[34]+b[1]*b[17]*b[35]-b[2]*b[21]*b[30]); - c[7] = (b[14]*b[30]*b[10]+b[14]*b[32]*b[8]-b[3]*b[21]*b[30]+b[3]*b[17]*b[34]+b[13]*b[32]*b[9]+b[13]*b[33]*b[8]-b[13]*b[4]*b[37]-b[13]*b[5]*b[36]+b[15]*b[30]*b[9]+b[15]*b[31]*b[8]-b[16]*b[4]*b[34]-b[13]*b[6]*b[35]-b[13]*b[7]*b[34]+b[13]*b[30]*b[11]+b[13]*b[31]*b[10]+b[14]*b[31]*b[9]-b[14]*b[4]*b[36]-b[14]*b[5]*b[35]-b[14]*b[6]*b[34]+b[16]*b[30]*b[8]-b[26]*b[20]*b[8]+b[26]*b[4]*b[24]+b[26]*b[5]*b[23]+b[26]*b[6]*b[22]+b[26]*b[7]*b[21]-b[26]*b[17]*b[11]-b[15]*b[4]*b[35]-b[15]*b[5]*b[34]-b[26]*b[18]*b[10]-b[26]*b[19]*b[9]+b[27]*b[4]*b[23]+b[27]*b[5]*b[22]+b[27]*b[6]*b[21]-b[27]*b[17]*b[10]-b[27]*b[18]*b[9]-b[27]*b[19]*b[8]+b[0]*b[17]*b[37]-b[0]*b[23]*b[31]-b[0]*b[24]*b[30]-b[0]*b[21]*b[33]-b[29]*b[17]*b[8]+b[28]*b[4]*b[22]+b[28]*b[5]*b[21]-b[28]*b[17]*b[9]-b[28]*b[18]*b[8]+b[29]*b[4]*b[21]+b[1]*b[19]*b[34]-b[2]*b[21]*b[31]+b[0]*b[20]*b[34]+b[0]*b[19]*b[35]+b[0]*b[18]*b[36]-b[0]*b[22]*b[32]-b[1]*b[23]*b[30]-b[1]*b[21]*b[32]+b[1]*b[18]*b[35]-b[1]*b[22]*b[31]-b[2]*b[22]*b[30]+b[2]*b[17]*b[35]+b[1]*b[17]*b[36]+b[2]*b[18]*b[34]); - c[6] = (-b[14]*b[6]*b[35]-b[14]*b[7]*b[34]-b[3]*b[22]*b[30]-b[3]*b[21]*b[31]+b[3]*b[17]*b[35]+b[3]*b[18]*b[34]+b[13]*b[32]*b[10]+b[13]*b[33]*b[9]-b[13]*b[4]*b[38]-b[13]*b[5]*b[37]-b[15]*b[6]*b[34]+b[15]*b[30]*b[10]+b[15]*b[32]*b[8]-b[16]*b[4]*b[35]-b[13]*b[6]*b[36]-b[13]*b[7]*b[35]+b[13]*b[31]*b[11]+b[13]*b[30]*b[12]+b[14]*b[32]*b[9]+b[14]*b[33]*b[8]-b[14]*b[4]*b[37]-b[14]*b[5]*b[36]+b[16]*b[30]*b[9]+b[16]*b[31]*b[8]-b[26]*b[20]*b[9]+b[26]*b[4]*b[25]+b[26]*b[5]*b[24]+b[26]*b[6]*b[23]+b[26]*b[7]*b[22]-b[26]*b[17]*b[12]+b[14]*b[30]*b[11]+b[14]*b[31]*b[10]+b[15]*b[31]*b[9]-b[15]*b[4]*b[36]-b[15]*b[5]*b[35]-b[26]*b[18]*b[11]-b[26]*b[19]*b[10]-b[27]*b[20]*b[8]+b[27]*b[4]*b[24]+b[27]*b[5]*b[23]+b[27]*b[6]*b[22]+b[27]*b[7]*b[21]-b[27]*b[17]*b[11]-b[27]*b[18]*b[10]-b[27]*b[19]*b[9]-b[16]*b[5]*b[34]-b[29]*b[17]*b[9]-b[29]*b[18]*b[8]+b[28]*b[4]*b[23]+b[28]*b[5]*b[22]+b[28]*b[6]*b[21]-b[28]*b[17]*b[10]-b[28]*b[18]*b[9]-b[28]*b[19]*b[8]+b[29]*b[4]*b[22]+b[29]*b[5]*b[21]-b[2]*b[23]*b[30]+b[2]*b[18]*b[35]-b[1]*b[22]*b[32]-b[2]*b[21]*b[32]+b[2]*b[19]*b[34]+b[0]*b[19]*b[36]-b[0]*b[22]*b[33]+b[0]*b[20]*b[35]-b[0]*b[23]*b[32]-b[0]*b[25]*b[30]+b[0]*b[17]*b[38]+b[0]*b[18]*b[37]-b[0]*b[24]*b[31]+b[1]*b[17]*b[37]-b[1]*b[23]*b[31]-b[1]*b[24]*b[30]-b[1]*b[21]*b[33]+b[1]*b[20]*b[34]+b[1]*b[19]*b[35]+b[1]*b[18]*b[36]+b[2]*b[17]*b[36]-b[2]*b[22]*b[31]); - c[5] = (-b[14]*b[6]*b[36]-b[14]*b[7]*b[35]+b[14]*b[31]*b[11]-b[3]*b[23]*b[30]-b[3]*b[21]*b[32]+b[3]*b[18]*b[35]-b[3]*b[22]*b[31]+b[3]*b[17]*b[36]+b[3]*b[19]*b[34]+b[13]*b[32]*b[11]+b[13]*b[33]*b[10]-b[13]*b[5]*b[38]-b[15]*b[6]*b[35]-b[15]*b[7]*b[34]+b[15]*b[30]*b[11]+b[15]*b[31]*b[10]+b[16]*b[31]*b[9]-b[13]*b[6]*b[37]-b[13]*b[7]*b[36]+b[13]*b[31]*b[12]+b[14]*b[32]*b[10]+b[14]*b[33]*b[9]-b[14]*b[4]*b[38]-b[14]*b[5]*b[37]-b[16]*b[6]*b[34]+b[16]*b[30]*b[10]+b[16]*b[32]*b[8]-b[26]*b[20]*b[10]+b[26]*b[5]*b[25]+b[26]*b[6]*b[24]+b[26]*b[7]*b[23]+b[14]*b[30]*b[12]+b[15]*b[32]*b[9]+b[15]*b[33]*b[8]-b[15]*b[4]*b[37]-b[15]*b[5]*b[36]+b[29]*b[5]*b[22]+b[29]*b[6]*b[21]-b[26]*b[18]*b[12]-b[26]*b[19]*b[11]-b[27]*b[20]*b[9]+b[27]*b[4]*b[25]+b[27]*b[5]*b[24]+b[27]*b[6]*b[23]+b[27]*b[7]*b[22]-b[27]*b[17]*b[12]-b[27]*b[18]*b[11]-b[27]*b[19]*b[10]-b[28]*b[20]*b[8]-b[16]*b[4]*b[36]-b[16]*b[5]*b[35]-b[29]*b[17]*b[10]-b[29]*b[18]*b[9]-b[29]*b[19]*b[8]+b[28]*b[4]*b[24]+b[28]*b[5]*b[23]+b[28]*b[6]*b[22]+b[28]*b[7]*b[21]-b[28]*b[17]*b[11]-b[28]*b[18]*b[10]-b[28]*b[19]*b[9]+b[29]*b[4]*b[23]-b[2]*b[22]*b[32]-b[2]*b[21]*b[33]-b[1]*b[24]*b[31]+b[0]*b[18]*b[38]-b[0]*b[24]*b[32]+b[0]*b[19]*b[37]+b[0]*b[20]*b[36]-b[0]*b[25]*b[31]-b[0]*b[23]*b[33]+b[1]*b[19]*b[36]-b[1]*b[22]*b[33]+b[1]*b[20]*b[35]+b[2]*b[19]*b[35]-b[2]*b[24]*b[30]-b[2]*b[23]*b[31]+b[2]*b[20]*b[34]+b[2]*b[17]*b[37]-b[1]*b[25]*b[30]+b[1]*b[18]*b[37]+b[1]*b[17]*b[38]-b[1]*b[23]*b[32]+b[2]*b[18]*b[36]); - c[4] = (-b[14]*b[6]*b[37]-b[14]*b[7]*b[36]+b[14]*b[31]*b[12]+b[3]*b[17]*b[37]-b[3]*b[23]*b[31]-b[3]*b[24]*b[30]-b[3]*b[21]*b[33]+b[3]*b[20]*b[34]+b[3]*b[19]*b[35]+b[3]*b[18]*b[36]-b[3]*b[22]*b[32]+b[13]*b[32]*b[12]+b[13]*b[33]*b[11]-b[15]*b[6]*b[36]-b[15]*b[7]*b[35]+b[15]*b[31]*b[11]+b[15]*b[30]*b[12]+b[16]*b[32]*b[9]+b[16]*b[33]*b[8]-b[13]*b[6]*b[38]-b[13]*b[7]*b[37]+b[14]*b[32]*b[11]+b[14]*b[33]*b[10]-b[14]*b[5]*b[38]-b[16]*b[6]*b[35]-b[16]*b[7]*b[34]+b[16]*b[30]*b[11]+b[16]*b[31]*b[10]-b[26]*b[19]*b[12]-b[26]*b[20]*b[11]+b[26]*b[6]*b[25]+b[26]*b[7]*b[24]+b[15]*b[32]*b[10]+b[15]*b[33]*b[9]-b[15]*b[4]*b[38]-b[15]*b[5]*b[37]+b[29]*b[5]*b[23]+b[29]*b[6]*b[22]+b[29]*b[7]*b[21]-b[27]*b[20]*b[10]+b[27]*b[5]*b[25]+b[27]*b[6]*b[24]+b[27]*b[7]*b[23]-b[27]*b[18]*b[12]-b[27]*b[19]*b[11]-b[28]*b[20]*b[9]-b[16]*b[4]*b[37]-b[16]*b[5]*b[36]+b[0]*b[19]*b[38]-b[0]*b[24]*b[33]+b[0]*b[20]*b[37]-b[29]*b[17]*b[11]-b[29]*b[18]*b[10]-b[29]*b[19]*b[9]+b[28]*b[4]*b[25]+b[28]*b[5]*b[24]+b[28]*b[6]*b[23]+b[28]*b[7]*b[22]-b[28]*b[17]*b[12]-b[28]*b[18]*b[11]-b[28]*b[19]*b[10]-b[29]*b[20]*b[8]+b[29]*b[4]*b[24]+b[2]*b[18]*b[37]-b[0]*b[25]*b[32]+b[1]*b[18]*b[38]-b[1]*b[24]*b[32]+b[1]*b[19]*b[37]+b[1]*b[20]*b[36]-b[1]*b[25]*b[31]+b[2]*b[17]*b[38]+b[2]*b[19]*b[36]-b[2]*b[24]*b[31]-b[2]*b[22]*b[33]-b[2]*b[23]*b[32]+b[2]*b[20]*b[35]-b[1]*b[23]*b[33]-b[2]*b[25]*b[30]); - c[3] = (-b[14]*b[6]*b[38]-b[14]*b[7]*b[37]+b[3]*b[19]*b[36]-b[3]*b[22]*b[33]+b[3]*b[20]*b[35]-b[3]*b[23]*b[32]-b[3]*b[25]*b[30]+b[3]*b[17]*b[38]+b[3]*b[18]*b[37]-b[3]*b[24]*b[31]-b[15]*b[6]*b[37]-b[15]*b[7]*b[36]+b[15]*b[31]*b[12]+b[16]*b[32]*b[10]+b[16]*b[33]*b[9]+b[13]*b[33]*b[12]-b[13]*b[7]*b[38]+b[14]*b[32]*b[12]+b[14]*b[33]*b[11]-b[16]*b[6]*b[36]-b[16]*b[7]*b[35]+b[16]*b[31]*b[11]+b[16]*b[30]*b[12]+b[15]*b[32]*b[11]+b[15]*b[33]*b[10]-b[15]*b[5]*b[38]+b[29]*b[5]*b[24]+b[29]*b[6]*b[23]-b[26]*b[20]*b[12]+b[26]*b[7]*b[25]-b[27]*b[19]*b[12]-b[27]*b[20]*b[11]+b[27]*b[6]*b[25]+b[27]*b[7]*b[24]-b[28]*b[20]*b[10]-b[16]*b[4]*b[38]-b[16]*b[5]*b[37]+b[29]*b[7]*b[22]-b[29]*b[17]*b[12]-b[29]*b[18]*b[11]-b[29]*b[19]*b[10]+b[28]*b[5]*b[25]+b[28]*b[6]*b[24]+b[28]*b[7]*b[23]-b[28]*b[18]*b[12]-b[28]*b[19]*b[11]-b[29]*b[20]*b[9]+b[29]*b[4]*b[25]-b[2]*b[24]*b[32]+b[0]*b[20]*b[38]-b[0]*b[25]*b[33]+b[1]*b[19]*b[38]-b[1]*b[24]*b[33]+b[1]*b[20]*b[37]-b[2]*b[25]*b[31]+b[2]*b[20]*b[36]-b[1]*b[25]*b[32]+b[2]*b[19]*b[37]+b[2]*b[18]*b[38]-b[2]*b[23]*b[33]); - c[2] = (b[3]*b[18]*b[38]-b[3]*b[24]*b[32]+b[3]*b[19]*b[37]+b[3]*b[20]*b[36]-b[3]*b[25]*b[31]-b[3]*b[23]*b[33]-b[15]*b[6]*b[38]-b[15]*b[7]*b[37]+b[16]*b[32]*b[11]+b[16]*b[33]*b[10]-b[16]*b[5]*b[38]-b[16]*b[6]*b[37]-b[16]*b[7]*b[36]+b[16]*b[31]*b[12]+b[14]*b[33]*b[12]-b[14]*b[7]*b[38]+b[15]*b[32]*b[12]+b[15]*b[33]*b[11]+b[29]*b[5]*b[25]+b[29]*b[6]*b[24]-b[27]*b[20]*b[12]+b[27]*b[7]*b[25]-b[28]*b[19]*b[12]-b[28]*b[20]*b[11]+b[29]*b[7]*b[23]-b[29]*b[18]*b[12]-b[29]*b[19]*b[11]+b[28]*b[6]*b[25]+b[28]*b[7]*b[24]-b[29]*b[20]*b[10]+b[2]*b[19]*b[38]-b[1]*b[25]*b[33]+b[2]*b[20]*b[37]-b[2]*b[24]*b[33]-b[2]*b[25]*b[32]+b[1]*b[20]*b[38]); - c[1] = (b[29]*b[7]*b[24]-b[29]*b[20]*b[11]+b[2]*b[20]*b[38]-b[2]*b[25]*b[33]-b[28]*b[20]*b[12]+b[28]*b[7]*b[25]-b[29]*b[19]*b[12]-b[3]*b[24]*b[33]+b[15]*b[33]*b[12]+b[3]*b[19]*b[38]-b[16]*b[6]*b[38]+b[3]*b[20]*b[37]+b[16]*b[32]*b[12]+b[29]*b[6]*b[25]-b[16]*b[7]*b[37]-b[3]*b[25]*b[32]-b[15]*b[7]*b[38]+b[16]*b[33]*b[11]); - c[0] = -b[29]*b[20]*b[12]+b[29]*b[7]*b[25]+b[16]*b[33]*b[12]-b[16]*b[7]*b[38]+b[3]*b[20]*b[38]-b[3]*b[25]*b[33]; - - std::vector > roots; - solvePoly(coeffs, roots); - - std::vector xs, ys, zs; - int count = 0; - double * e = ematrix->data.db; - for (size_t i = 0; i < roots.size(); i++) - { - if (fabs(roots[i].imag()) > 1e-10) continue; - double z1 = roots[i].real(); - double z2 = z1 * z1; - double z3 = z2 * z1; - double z4 = z3 * z1; - - double bz[3][3]; - for (int j = 0; j < 3; j++) - { - const double * br = b + j * 13; - bz[j][0] = br[0] * z3 + br[1] * z2 + br[2] * z1 + br[3]; - bz[j][1] = br[4] * z3 + br[5] * z2 + br[6] * z1 + br[7]; - bz[j][2] = br[8] * z4 + br[9] * z3 + br[10] * z2 + br[11] * z1 + br[12]; - } - - Mat Bz(3, 3, CV_64F, bz); - cv::Mat xy1; - SVD::solveZ(Bz, xy1); - - if (fabs(xy1.at(2)) < 1e-10) continue; - xs.push_back(xy1.at(0) / xy1.at(2)); - ys.push_back(xy1.at(1) / xy1.at(2)); - zs.push_back(z1); - - cv::Mat Evec = EE.col(0) * xs.back() + EE.col(1) * ys.back() + EE.col(2) * zs.back() + EE.col(3); - Evec /= norm(Evec); - - memcpy(e + count * 9, Evec.data, 9 * sizeof(double)); - count++; - } - return count; - -} - -// Same as the runKernel (run5Point), m1 and m2 should be -// 1 row x n col x 2 channels. -// And also, error has to be of CV_32FC1. -void CvEMEstimator::computeReprojError( const CvMat* m1, const CvMat* m2, - const CvMat* model, CvMat* error ) -{ - Mat X1(m1), X2(m2); - int n = X1.cols; - X1 = X1.reshape(1, n); - X2 = X2.reshape(1, n); - - X1.convertTo(X1, CV_64F); - X2.convertTo(X2, CV_64F); - - Mat E(model); - for (int i = 0; i < n; i++) - { - Mat x1 = (Mat_(3, 1) << X1.at(i, 0), X1.at(i, 1), 1.0); - Mat x2 = (Mat_(3, 1) << X2.at(i, 0), X2.at(i, 1), 1.0); - double x2tEx1 = x2.dot(E * x1); - Mat Ex1 = E * x1; - Mat Etx2 = E * x2; - double a = Ex1.at(0) * Ex1.at(0); - double b = Ex1.at(1) * Ex1.at(1); - double c = Etx2.at(0) * Etx2.at(0); - double d = Etx2.at(0) * Etx2.at(0); - - error->data.fl[i] = (float)(x2tEx1 * x2tEx1 / (a + b + c + d)); - } - -} - -void CvEMEstimator::calibrated_fivepoint_helper( double *EE, double* A ) -{ - double e00,e01,e02,e03,e04,e05,e06,e07,e08; - double e10,e11,e12,e13,e14,e15,e16,e17,e18; - double e20,e21,e22,e23,e24,e25,e26,e27,e28; - double e30,e31,e32,e33,e34,e35,e36,e37,e38; - - double e002,e012,e022,e032,e042,e052,e062,e072,e082; - double e102,e112,e122,e132,e142,e152,e162,e172,e182; - double e202,e212,e222,e232,e242,e252,e262,e272,e282; - double e302,e312,e322,e332,e342,e352,e362,e372,e382; - - double e003,e013,e023,e033,e043,e053,e063,e073,e083; - double e103,e113,e123,e133,e143,e153,e163,e173,e183; - double e203,e213,e223,e233,e243,e253,e263,e273,e283; - double e303,e313,e323,e333,e343,e353,e363,e373,e383; - e00 = EE[0*9 + 0 ]; - e10 = EE[1*9 + 0 ]; - e20 = EE[2*9 + 0 ]; - e30 = EE[3*9 + 0 ]; - e01 = EE[0*9 + 1 ]; - e11 = EE[1*9 + 1 ]; - e21 = EE[2*9 + 1 ]; - e31 = EE[3*9 + 1 ]; - e02 = EE[0*9 + 2 ]; - e12 = EE[1*9 + 2 ]; - e22 = EE[2*9 + 2 ]; - e32 = EE[3*9 + 2 ]; - e03 = EE[0*9 + 3 ]; - e13 = EE[1*9 + 3 ]; - e23 = EE[2*9 + 3 ]; - e33 = EE[3*9 + 3 ]; - e04 = EE[0*9 + 4 ]; - e14 = EE[1*9 + 4 ]; - e24 = EE[2*9 + 4 ]; - e34 = EE[3*9 + 4 ]; - e05 = EE[0*9 + 5 ]; - e15 = EE[1*9 + 5 ]; - e25 = EE[2*9 + 5 ]; - e35 = EE[3*9 + 5 ]; - e06 = EE[0*9 + 6 ]; - e16 = EE[1*9 + 6 ]; - e26 = EE[2*9 + 6 ]; - e36 = EE[3*9 + 6 ]; - e07 = EE[0*9 + 7 ]; - e17 = EE[1*9 + 7 ]; - e27 = EE[2*9 + 7 ]; - e37 = EE[3*9 + 7 ]; - e08 = EE[0*9 + 8 ]; - e18 = EE[1*9 + 8 ]; - e28 = EE[2*9 + 8 ]; - e38 = EE[3*9 + 8 ]; - - - e002 =e00*e00; - e102 =e10*e10; - e202 =e20*e20; - e302 =e30*e30; - e012 =e01*e01; - e112 =e11*e11; - e212 =e21*e21; - e312 =e31*e31; - e022 =e02*e02; - e122 =e12*e12; - e222 =e22*e22; - e322 =e32*e32; - e032 =e03*e03; - e132 =e13*e13; - e232 =e23*e23; - e332 =e33*e33; - e042 =e04*e04; - e142 =e14*e14; - e242 =e24*e24; - e342 =e34*e34; - e052 =e05*e05; - e152 =e15*e15; - e252 =e25*e25; - e352 =e35*e35; - e062 =e06*e06; - e162 =e16*e16; - e262 =e26*e26; - e362 =e36*e36; - e072 =e07*e07; - e172 =e17*e17; - e272 =e27*e27; - e372 =e37*e37; - e082 =e08*e08; - e182 =e18*e18; - e282 =e28*e28; - e382 =e38*e38; - - e003 =e00*e00*e00; - e103 =e10*e10*e10; - e203 =e20*e20*e20; - e303 =e30*e30*e30; - e013 =e01*e01*e01; - e113 =e11*e11*e11; - e213 =e21*e21*e21; - e313 =e31*e31*e31; - e023 =e02*e02*e02; - e123 =e12*e12*e12; - e223 =e22*e22*e22; - e323 =e32*e32*e32; - e033 =e03*e03*e03; - e133 =e13*e13*e13; - e233 =e23*e23*e23; - e333 =e33*e33*e33; - e043 =e04*e04*e04; - e143 =e14*e14*e14; - e243 =e24*e24*e24; - e343 =e34*e34*e34; - e053 =e05*e05*e05; - e153 =e15*e15*e15; - e253 =e25*e25*e25; - e353 =e35*e35*e35; - e063 =e06*e06*e06; - e163 =e16*e16*e16; - e263 =e26*e26*e26; - e363 =e36*e36*e36; - e073 =e07*e07*e07; - e173 =e17*e17*e17; - e273 =e27*e27*e27; - e373 =e37*e37*e37; - e083 =e08*e08*e08; - e183 =e18*e18*e18; - e283 =e28*e28*e28; - e383 =e38*e38*e38; - - - A[0 + 10*0]=0.5*e003+0.5*e00*e012+0.5*e00*e022+0.5*e00*e032+e03*e01*e04+e03*e02*e05+0.5*e00*e062+e06*e01*e07+e06*e02*e08-0.5*e00*e042-0.5*e00*e052-0.5*e00*e072-0.5*e00*e082; - A[0 + 10*1]=e00*e11*e01+e00*e12*e02+e03*e00*e13+e03*e11*e04+e03*e01*e14+e03*e12*e05+e03*e02*e15+e13*e01*e04+e13*e02*e05+e06*e00*e16+1.5*e10*e002+0.5*e10*e012+0.5*e10*e022+0.5*e10*e062-0.5*e10*e042-0.5*e10*e052-0.5*e10*e072+0.5*e10*e032+e06*e11*e07+e06*e01*e17+e06*e12*e08+e06*e02*e18+e16*e01*e07+e16*e02*e08-e00*e14*e04-e00*e17*e07-e00*e15*e05-e00*e18*e08-0.5*e10*e082; - A[0 + 10*2]=e16*e02*e18+e03*e12*e15+e10*e11*e01+e10*e12*e02+e03*e10*e13+e03*e11*e14+e13*e11*e04+e13*e01*e14+e13*e12*e05+e13*e02*e15+e06*e10*e16+e06*e12*e18+e06*e11*e17+e16*e11*e07+e16*e01*e17+e16*e12*e08-e10*e14*e04-e10*e17*e07-e10*e15*e05-e10*e18*e08+1.5*e00*e102+0.5*e00*e122+0.5*e00*e112+0.5*e00*e132+0.5*e00*e162-0.5*e00*e152-0.5*e00*e172-0.5*e00*e182-0.5*e00*e142; - A[0 + 10*3]=0.5*e103+0.5*e10*e122+0.5*e10*e112+0.5*e10*e132+e13*e12*e15+e13*e11*e14+0.5*e10*e162+e16*e12*e18+e16*e11*e17-0.5*e10*e152-0.5*e10*e172-0.5*e10*e182-0.5*e10*e142; - A[0 + 10*4]=-e00*e28*e08-e00*e25*e05-e00*e27*e07-e00*e24*e04+e26*e02*e08+e26*e01*e07+e06*e02*e28+e06*e22*e08+e06*e01*e27+e06*e21*e07+e23*e02*e05+e23*e01*e04+e03*e02*e25+e03*e22*e05+e03*e01*e24+e03*e21*e04+e00*e22*e02+e00*e21*e01-0.5*e20*e082-0.5*e20*e052-0.5*e20*e072-0.5*e20*e042+e06*e00*e26+0.5*e20*e062+e03*e00*e23+0.5*e20*e022+1.5*e20*e002+0.5*e20*e032+0.5*e20*e012; - A[0 + 10*5]=-e10*e24*e04-e10*e27*e07-e10*e25*e05-e10*e28*e08-e20*e14*e04-e20*e17*e07-e20*e15*e05-e20*e18*e08-e00*e24*e14-e00*e25*e15-e00*e27*e17-e00*e28*e18+e06*e21*e17+e06*e22*e18+e06*e12*e28+e16*e00*e26+e16*e21*e07+e16*e01*e27+e16*e22*e08+e16*e02*e28+e26*e11*e07+e26*e01*e17+e26*e12*e08+e26*e02*e18+e06*e11*e27+e23*e11*e04+e23*e01*e14+e23*e12*e05+e23*e02*e15+e06*e20*e16+e06*e10*e26+e03*e21*e14+e03*e22*e15+e03*e12*e25+e13*e00*e23+e13*e21*e04+e13*e01*e24+e13*e22*e05+e13*e02*e25+e03*e11*e24+e03*e20*e13+e03*e10*e23+e00*e21*e11+3*e00*e20*e10+e00*e22*e12+e20*e12*e02+e20*e11*e01+e10*e22*e02+e10*e21*e01; - A[0 + 10*6]=-0.5*e20*e152+e26*e11*e17-e10*e24*e14-e10*e25*e15-e10*e27*e17-e10*e28*e18+0.5*e20*e162+e13*e10*e23+e13*e22*e15+e23*e12*e15+e23*e11*e14+e16*e10*e26+e16*e21*e17+e16*e11*e27+e16*e22*e18+e16*e12*e28+e26*e12*e18+e13*e12*e25+0.5*e20*e132+1.5*e20*e102+0.5*e20*e122+0.5*e20*e112+e10*e21*e11+e10*e22*e12+e13*e11*e24-0.5*e20*e172-0.5*e20*e182-0.5*e20*e142+e13*e21*e14; - A[0 + 10*7]=-e20*e25*e05-e20*e28*e08-0.5*e00*e272-0.5*e00*e282-0.5*e00*e242+0.5*e00*e262-0.5*e00*e252+e06*e20*e26+0.5*e00*e232+e06*e22*e28+e06*e21*e27+e26*e21*e07+e26*e01*e27+e26*e22*e08+e26*e02*e28-e20*e24*e04-e20*e27*e07+e03*e20*e23+e03*e22*e25+e03*e21*e24+e23*e21*e04+e23*e01*e24+e23*e22*e05+e23*e02*e25+e20*e21*e01+e20*e22*e02+1.5*e00*e202+0.5*e00*e222+0.5*e00*e212; - A[0 + 10*8]=e23*e21*e14+e23*e11*e24+e23*e22*e15+e23*e12*e25+e16*e20*e26+e16*e22*e28+e16*e21*e27+e26*e21*e17+e26*e11*e27+e26*e22*e18+e26*e12*e28+1.5*e10*e202+0.5*e10*e222+0.5*e10*e212+0.5*e10*e232+e20*e21*e11+e20*e22*e12+e13*e20*e23+e13*e22*e25+e13*e21*e24-e20*e24*e14-e20*e25*e15-e20*e27*e17-e20*e28*e18-0.5*e10*e272-0.5*e10*e282-0.5*e10*e242-0.5*e10*e252+0.5*e10*e262; - A[0 + 10*9]=0.5*e203+0.5*e20*e222+0.5*e20*e212+0.5*e20*e232+e23*e22*e25+e23*e21*e24+0.5*e20*e262+e26*e22*e28+e26*e21*e27-0.5*e20*e252-0.5*e20*e272-0.5*e20*e282-0.5*e20*e242; - A[0 + 10*10]=e06*e32*e08-0.5*e30*e082-0.5*e30*e042-0.5*e30*e052-0.5*e30*e072+0.5*e30*e012+0.5*e30*e022+0.5*e30*e032+0.5*e30*e062+1.5*e30*e002+e00*e31*e01+e00*e32*e02+e03*e31*e04+e03*e01*e34+e03*e32*e05+e03*e02*e35+e33*e01*e04+e33*e02*e05+e06*e00*e36+e06*e31*e07+e06*e01*e37+e06*e02*e38+e36*e01*e07+e36*e02*e08-e00*e34*e04-e00*e37*e07-e00*e35*e05-e00*e38*e08+e03*e00*e33; - A[0 + 10*11]=e06*e30*e16+e03*e30*e13+e16*e31*e07+e06*e10*e36-e10*e37*e07+3*e00*e30*e10+e00*e32*e12-e00*e38*e18-e10*e34*e04-e10*e35*e05-e10*e38*e08-e30*e14*e04-e30*e17*e07-e30*e15*e05-e30*e18*e08+e00*e31*e11+e10*e31*e01+e10*e32*e02+e30*e11*e01+e30*e12*e02+e03*e10*e33-e00*e34*e14-e00*e35*e15-e00*e37*e17+e03*e31*e14+e03*e11*e34+e03*e32*e15+e03*e12*e35+e13*e00*e33+e13*e31*e04+e13*e01*e34+e13*e32*e05+e13*e02*e35+e33*e11*e04+e33*e01*e14+e33*e12*e05+e33*e02*e15+e06*e31*e17+e06*e11*e37+e06*e32*e18+e06*e12*e38+e16*e00*e36+e16*e01*e37+e16*e32*e08+e16*e02*e38+e36*e11*e07+e36*e01*e17+e36*e12*e08+e36*e02*e18; - A[0 + 10*12]=e13*e10*e33+e33*e11*e14+e16*e10*e36+e16*e31*e17+e16*e11*e37+e16*e32*e18+e16*e12*e38+e36*e12*e18+e36*e11*e17-e10*e34*e14-e10*e35*e15-e10*e37*e17-e10*e38*e18+e10*e31*e11+e10*e32*e12+e13*e31*e14+e13*e11*e34+e13*e32*e15+e13*e12*e35+e33*e12*e15+1.5*e30*e102+0.5*e30*e122+0.5*e30*e112+0.5*e30*e132+0.5*e30*e162-0.5*e30*e152-0.5*e30*e172-0.5*e30*e182-0.5*e30*e142; - A[0 + 10*13]=e00*e32*e22+3*e00*e30*e20+e00*e31*e21+e20*e31*e01+e20*e32*e02+e30*e21*e01+e30*e22*e02+e03*e20*e33+e03*e32*e25+e03*e22*e35+e03*e31*e24+e03*e21*e34+e23*e00*e33+e23*e31*e04+e23*e01*e34+e23*e32*e05+e23*e02*e35+e33*e21*e04+e33*e01*e24+e33*e22*e05+e33*e02*e25+e06*e30*e26+e06*e20*e36+e06*e32*e28+e06*e22*e38+e06*e31*e27+e06*e21*e37+e26*e00*e36+e26*e31*e07+e03*e30*e23+e26*e01*e37+e26*e32*e08+e26*e02*e38+e36*e21*e07+e36*e01*e27+e36*e22*e08+e36*e02*e28-e00*e35*e25-e00*e37*e27-e00*e38*e28-e00*e34*e24-e20*e34*e04-e20*e37*e07-e20*e35*e05-e20*e38*e08-e30*e24*e04-e30*e27*e07-e30*e25*e05-e30*e28*e08; - A[0 + 10*14]=e16*e30*e26+e13*e21*e34+3*e10*e30*e20+e10*e32*e22+e10*e31*e21+e20*e31*e11+e20*e32*e12+e30*e21*e11+e30*e22*e12+e13*e30*e23+e13*e20*e33+e13*e32*e25+e13*e22*e35+e13*e31*e24+e23*e10*e33+e23*e31*e14+e23*e11*e34+e23*e32*e15+e23*e12*e35+e33*e21*e14+e33*e11*e24+e33*e22*e15+e33*e12*e25+e16*e20*e36+e16*e32*e28+e16*e22*e38+e16*e31*e27+e16*e21*e37+e26*e10*e36+e26*e31*e17+e26*e11*e37+e26*e32*e18+e26*e12*e38+e36*e21*e17+e36*e11*e27+e36*e22*e18+e36*e12*e28-e10*e35*e25-e10*e37*e27-e10*e38*e28-e10*e34*e24-e20*e34*e14-e20*e35*e15-e20*e37*e17-e20*e38*e18-e30*e24*e14-e30*e25*e15-e30*e27*e17-e30*e28*e18; - A[0 + 10*15]=-e20*e34*e24+0.5*e30*e262-0.5*e30*e252-0.5*e30*e272-0.5*e30*e282-0.5*e30*e242+1.5*e30*e202+0.5*e30*e222+0.5*e30*e212+0.5*e30*e232+e20*e32*e22+e20*e31*e21+e23*e20*e33+e23*e32*e25+e23*e22*e35+e23*e31*e24+e23*e21*e34+e33*e22*e25+e33*e21*e24+e26*e20*e36+e26*e32*e28+e26*e22*e38+e26*e31*e27+e26*e21*e37+e36*e22*e28+e36*e21*e27-e20*e35*e25-e20*e37*e27-e20*e38*e28; - A[0 + 10*16]=0.5*e00*e322+e30*e32*e02+e30*e31*e01+1.5*e00*e302+0.5*e00*e312+e03*e32*e35+e33*e31*e04+e33*e01*e34+e33*e32*e05+e33*e02*e35+e06*e30*e36+e06*e31*e37+e06*e32*e38+e36*e31*e07+e36*e01*e37+e36*e32*e08+e36*e02*e38-e30*e34*e04-e30*e37*e07-e30*e35*e05-e30*e38*e08+0.5*e00*e332+0.5*e00*e362-0.5*e00*e382-0.5*e00*e352-0.5*e00*e342-0.5*e00*e372+e03*e30*e33+e03*e31*e34; - A[0 + 10*17]=0.5*e10*e362-0.5*e10*e382-0.5*e10*e352-0.5*e10*e342-0.5*e10*e372+e36*e31*e17+e36*e11*e37+e36*e32*e18+e36*e12*e38-e30*e34*e14-e30*e35*e15-e30*e37*e17-e30*e38*e18+1.5*e10*e302+0.5*e10*e312+0.5*e10*e322+0.5*e10*e332+e30*e31*e11+e30*e32*e12+e13*e30*e33+e13*e31*e34+e13*e32*e35+e33*e31*e14+e33*e11*e34+e33*e32*e15+e33*e12*e35+e16*e30*e36+e16*e31*e37+e16*e32*e38; - A[0 + 10*18]=e33*e31*e24+e33*e21*e34+e26*e30*e36+e26*e31*e37+e26*e32*e38+e36*e32*e28+e36*e22*e38+e36*e31*e27+e36*e21*e37-e30*e35*e25-e30*e37*e27-e30*e38*e28-e30*e34*e24+e33*e22*e35+1.5*e20*e302+0.5*e20*e312+0.5*e20*e322+0.5*e20*e332+0.5*e20*e362-0.5*e20*e382-0.5*e20*e352-0.5*e20*e342-0.5*e20*e372+e30*e32*e22+e30*e31*e21+e23*e30*e33+e23*e31*e34+e23*e32*e35+e33*e32*e25; - A[0 + 10*19]=0.5*e303+0.5*e30*e312+0.5*e30*e322+0.5*e30*e332+e33*e31*e34+e33*e32*e35+0.5*e30*e362+e36*e31*e37+e36*e32*e38-0.5*e30*e382-0.5*e30*e352-0.5*e30*e342-0.5*e30*e372; - A[1 + 10*0]=e00*e01*e04+0.5*e002*e03+e00*e02*e05+0.5*e033+0.5*e03*e042+0.5*e03*e052+0.5*e03*e062+e06*e04*e07+e06*e05*e08-0.5*e03*e012-0.5*e03*e072-0.5*e03*e022-0.5*e03*e082; - A[1 + 10*1]=e03*e14*e04+e10*e01*e04+e16*e05*e08+e00*e10*e03+e00*e11*e04+e00*e01*e14+e00*e12*e05+e00*e02*e15+e10*e02*e05+e03*e15*e05+e06*e03*e16+e06*e14*e07+e06*e04*e17+e06*e15*e08+e06*e05*e18+0.5*e002*e13+1.5*e13*e032+0.5*e13*e042+0.5*e13*e052+0.5*e13*e062-0.5*e13*e012-0.5*e13*e072-0.5*e13*e022-0.5*e13*e082+e16*e04*e07-e03*e12*e02-e03*e11*e01-e03*e17*e07-e03*e18*e08; - A[1 + 10*2]=-e13*e11*e01+e00*e10*e13+e00*e12*e15+e00*e11*e14+e10*e11*e04+e10*e01*e14+e10*e12*e05+e10*e02*e15+e13*e14*e04+e13*e15*e05+e06*e13*e16+e06*e15*e18+e06*e14*e17+e16*e14*e07+e16*e04*e17+e16*e15*e08+e16*e05*e18-e13*e12*e02-e13*e17*e07-e13*e18*e08+0.5*e102*e03+1.5*e03*e132+0.5*e03*e152+0.5*e03*e142+0.5*e03*e162-0.5*e03*e112-0.5*e03*e172-0.5*e03*e122-0.5*e03*e182; - A[1 + 10*3]=0.5*e102*e13+e10*e11*e14+e10*e12*e15+0.5*e133+0.5*e13*e152+0.5*e13*e142+0.5*e13*e162+e16*e15*e18+e16*e14*e17-0.5*e13*e112-0.5*e13*e122-0.5*e13*e172-0.5*e13*e182; - A[1 + 10*4]=-e03*e28*e08-e03*e27*e07-e03*e21*e01-e03*e22*e02+e26*e05*e08+e26*e04*e07+e06*e05*e28+e06*e25*e08+e06*e04*e27+e06*e24*e07+e03*e25*e05+e03*e24*e04+e20*e02*e05+e20*e01*e04+e00*e02*e25+e00*e22*e05+e00*e01*e24+e00*e21*e04+e00*e20*e03-0.5*e23*e072-0.5*e23*e082-0.5*e23*e022-0.5*e23*e012+e06*e03*e26+0.5*e23*e052+0.5*e23*e062+1.5*e23*e032+0.5*e23*e042+0.5*e002*e23; - A[1 + 10*5]=e00*e21*e14+e00*e11*e24+e00*e10*e23+e00*e22*e15+e00*e12*e25+e20*e12*e05+e20*e01*e14+e20*e11*e04+e00*e20*e13+e10*e02*e25+e10*e22*e05+e10*e01*e24+e10*e21*e04+e10*e20*e03+e23*e15*e05+e23*e14*e04+e13*e25*e05+e13*e24*e04+e03*e24*e14+e03*e25*e15+3*e03*e23*e13+e20*e02*e15+e16*e03*e26+e06*e14*e27-e23*e18*e08+e06*e24*e17+e06*e15*e28+e06*e25*e18+e06*e13*e26+e06*e23*e16+e26*e04*e17+e26*e14*e07+e16*e05*e28+e16*e25*e08+e16*e04*e27+e16*e24*e07-e03*e22*e12-e03*e21*e11+e26*e05*e18+e26*e15*e08-e03*e27*e17-e03*e28*e18-e13*e22*e02-e13*e28*e08-e13*e27*e07-e13*e21*e01-e23*e17*e07-e23*e11*e01-e23*e12*e02; - A[1 + 10*6]=-0.5*e23*e182-0.5*e23*e172-0.5*e23*e112-0.5*e23*e122-e13*e22*e12-e13*e27*e17-e13*e28*e18+e26*e15*e18+e26*e14*e17-e13*e21*e11+e20*e12*e15+e13*e25*e15+e13*e24*e14+e16*e13*e26+e16*e25*e18+e16*e15*e28+e16*e24*e17+e16*e14*e27+1.5*e23*e132+0.5*e23*e152+0.5*e23*e142+0.5*e23*e162+e10*e20*e13+e10*e21*e14+e10*e11*e24+e10*e22*e15+e10*e12*e25+e20*e11*e14+0.5*e102*e23; - A[1 + 10*7]=e26*e04*e27+e00*e22*e25-e23*e28*e08+0.5*e03*e262-0.5*e03*e212-0.5*e03*e272-0.5*e03*e222-0.5*e03*e282+e23*e24*e04+e23*e25*e05+0.5*e202*e03+e06*e23*e26+e06*e24*e27+e06*e25*e28+e26*e24*e07+e26*e25*e08+e26*e05*e28-e23*e22*e02-e23*e21*e01-e23*e27*e07+e00*e20*e23+e00*e21*e24+e20*e21*e04+e20*e01*e24+e20*e22*e05+e20*e02*e25+1.5*e03*e232+0.5*e03*e242+0.5*e03*e252; - A[1 + 10*8]=e20*e11*e24-0.5*e13*e212-0.5*e13*e272-0.5*e13*e222-0.5*e13*e282-e23*e27*e17-e23*e28*e18+e26*e25*e18+e26*e24*e17+e26*e14*e27-e23*e21*e11-e23*e22*e12+e26*e15*e28+e23*e25*e15+e23*e24*e14+e16*e23*e26+e16*e24*e27+e16*e25*e28+0.5*e13*e262+e20*e21*e14+e20*e22*e15+e20*e12*e25+0.5*e13*e242+0.5*e13*e252+0.5*e202*e13+1.5*e13*e232+e10*e20*e23+e10*e22*e25+e10*e21*e24; - A[1 + 10*9]=0.5*e202*e23+e20*e22*e25+e20*e21*e24+0.5*e233+0.5*e23*e242+0.5*e23*e252+0.5*e23*e262+e26*e24*e27+e26*e25*e28-0.5*e23*e212-0.5*e23*e272-0.5*e23*e222-0.5*e23*e282; - A[1 + 10*10]=e00*e30*e03+0.5*e33*e062-0.5*e33*e012-0.5*e33*e022-0.5*e33*e072+e03*e35*e05+e06*e03*e36+e06*e34*e07+e06*e04*e37+e06*e35*e08+e06*e05*e38+e36*e04*e07+e36*e05*e08-e03*e32*e02-e03*e31*e01-e03*e37*e07+e00*e31*e04+e00*e01*e34+e00*e32*e05+e00*e02*e35+e30*e01*e04+e30*e02*e05+e03*e34*e04-e03*e38*e08+0.5*e002*e33+1.5*e33*e032+0.5*e33*e042+0.5*e33*e052-0.5*e33*e082; - A[1 + 10*11]=e06*e35*e18+e06*e33*e16+e00*e30*e13+e00*e10*e33+e00*e31*e14+e00*e11*e34+e00*e32*e15+e00*e12*e35+e10*e30*e03-e33*e17*e07-e33*e18*e08+e10*e31*e04+e10*e01*e34+e10*e32*e05+e10*e02*e35+e30*e11*e04+e30*e01*e14+e30*e12*e05+e30*e02*e15+3*e03*e33*e13+e03*e35*e15+e03*e34*e14+e13*e34*e04+e13*e35*e05+e33*e14*e04+e33*e15*e05+e06*e13*e36+e06*e15*e38+e06*e34*e17+e06*e14*e37+e16*e03*e36+e16*e34*e07+e16*e04*e37+e16*e35*e08+e16*e05*e38+e36*e14*e07+e36*e04*e17+e36*e15*e08+e36*e05*e18-e03*e31*e11-e03*e32*e12-e03*e37*e17-e03*e38*e18-e13*e32*e02-e13*e31*e01-e13*e37*e07-e13*e38*e08-e33*e12*e02-e33*e11*e01; - A[1 + 10*12]=e16*e13*e36+e10*e11*e34+0.5*e33*e152+0.5*e33*e142+0.5*e33*e162-0.5*e33*e112-0.5*e33*e122-0.5*e33*e172-0.5*e33*e182+0.5*e102*e33+1.5*e33*e132+e10*e30*e13+e10*e31*e14+e10*e32*e15+e10*e12*e35+e30*e11*e14+e30*e12*e15+e13*e35*e15+e13*e34*e14+e16*e35*e18+e16*e15*e38+e16*e34*e17+e16*e14*e37+e36*e15*e18+e36*e14*e17-e13*e31*e11-e13*e32*e12-e13*e37*e17-e13*e38*e18; - A[1 + 10*13]=e06*e35*e28+e36*e04*e27+e00*e20*e33+e00*e30*e23+3*e03*e33*e23+e03*e34*e24+e03*e35*e25+e23*e34*e04+e23*e35*e05+e33*e24*e04+e33*e25*e05+e06*e33*e26+e06*e23*e36+e06*e34*e27+e06*e24*e37+e06*e25*e38+e26*e03*e36+e26*e34*e07+e26*e04*e37+e26*e35*e08+e26*e05*e38+e36*e24*e07+e36*e25*e08+e36*e05*e28-e03*e31*e21-e03*e37*e27-e03*e32*e22-e03*e38*e28-e23*e32*e02-e23*e31*e01-e23*e37*e07-e23*e38*e08-e33*e22*e02-e33*e21*e01-e33*e27*e07-e33*e28*e08+e00*e32*e25+e00*e22*e35+e00*e31*e24+e00*e21*e34+e20*e30*e03+e20*e31*e04+e20*e01*e34+e20*e32*e05+e20*e02*e35+e30*e21*e04+e30*e01*e24+e30*e22*e05+e30*e02*e25; - A[1 + 10*14]=e10*e30*e23+e10*e20*e33+e10*e22*e35+e10*e32*e25+e10*e31*e24+e10*e21*e34+e20*e30*e13+e20*e31*e14+e20*e11*e34+e20*e32*e15+e20*e12*e35+e30*e21*e14+e30*e11*e24+e30*e22*e15+e30*e12*e25+3*e13*e33*e23+e13*e34*e24+e13*e35*e25+e23*e35*e15+e23*e34*e14+e33*e25*e15+e33*e24*e14+e16*e33*e26+e16*e23*e36+e16*e34*e27+e16*e24*e37+e16*e35*e28+e16*e25*e38+e26*e13*e36+e26*e35*e18+e26*e15*e38+e26*e34*e17+e26*e14*e37+e36*e25*e18+e36*e15*e28+e36*e24*e17+e36*e14*e27-e13*e31*e21-e13*e37*e27-e13*e32*e22-e13*e38*e28-e23*e31*e11-e23*e32*e12-e23*e37*e17-e23*e38*e18-e33*e21*e11-e33*e22*e12-e33*e27*e17-e33*e28*e18; - A[1 + 10*15]=-0.5*e33*e212-0.5*e33*e272-0.5*e33*e222-0.5*e33*e282+e26*e23*e36+e20*e30*e23+e20*e32*e25+e20*e22*e35+e20*e31*e24+e20*e21*e34+e30*e22*e25+e30*e21*e24+e23*e34*e24+e23*e35*e25+e26*e34*e27+e26*e24*e37+e26*e35*e28+e26*e25*e38+e36*e24*e27+e36*e25*e28-e23*e31*e21-e23*e37*e27-e23*e32*e22-e23*e38*e28+0.5*e202*e33+1.5*e33*e232+0.5*e33*e242+0.5*e33*e252+0.5*e33*e262; - A[1 + 10*16]=e33*e35*e05+e30*e32*e05+0.5*e03*e362+0.5*e302*e03+1.5*e03*e332+0.5*e03*e352+0.5*e03*e342+e00*e30*e33+e00*e31*e34+e00*e32*e35+e30*e31*e04+e30*e01*e34+e30*e02*e35+e33*e34*e04+e06*e33*e36+e06*e35*e38+e06*e34*e37+e36*e34*e07+e36*e04*e37+e36*e35*e08+e36*e05*e38-e33*e32*e02-e33*e31*e01-e33*e37*e07-e33*e38*e08-0.5*e03*e322-0.5*e03*e382-0.5*e03*e312-0.5*e03*e372; - A[1 + 10*17]=-e33*e31*e11-e33*e32*e12-e33*e38*e18+e30*e11*e34+e30*e32*e15+e30*e12*e35+e33*e35*e15+e33*e34*e14+e16*e33*e36+e16*e35*e38+e16*e34*e37+e36*e35*e18+e36*e15*e38+e36*e34*e17+e36*e14*e37-e33*e37*e17+0.5*e302*e13+1.5*e13*e332+0.5*e13*e352+0.5*e13*e342+0.5*e13*e362-0.5*e13*e322-0.5*e13*e382-0.5*e13*e312-0.5*e13*e372+e10*e30*e33+e10*e31*e34+e10*e32*e35+e30*e31*e14; - A[1 + 10*18]=e36*e25*e38+0.5*e302*e23+1.5*e23*e332+0.5*e23*e352+0.5*e23*e342+0.5*e23*e362-0.5*e23*e322-0.5*e23*e382-0.5*e23*e312-0.5*e23*e372+e20*e30*e33+e20*e31*e34+e20*e32*e35+e30*e32*e25+e30*e22*e35+e30*e31*e24+e30*e21*e34+e33*e34*e24+e33*e35*e25+e26*e33*e36+e26*e35*e38+e26*e34*e37+e36*e34*e27+e36*e24*e37+e36*e35*e28-e33*e31*e21-e33*e37*e27-e33*e32*e22-e33*e38*e28; - A[1 + 10*19]=0.5*e302*e33+e30*e31*e34+e30*e32*e35+0.5*e333+0.5*e33*e352+0.5*e33*e342+0.5*e33*e362+e36*e35*e38+e36*e34*e37-0.5*e33*e322-0.5*e33*e382-0.5*e33*e312-0.5*e33*e372; - A[2 + 10*0]=0.5*e002*e06+e00*e01*e07+e00*e02*e08+0.5*e032*e06+e03*e04*e07+e03*e05*e08+0.5*e063+0.5*e06*e072+0.5*e06*e082-0.5*e06*e012-0.5*e06*e022-0.5*e06*e042-0.5*e06*e052; - A[2 + 10*1]=e00*e10*e06+0.5*e002*e16+0.5*e032*e16+1.5*e16*e062+0.5*e16*e072+0.5*e16*e082-0.5*e16*e012-0.5*e16*e022-0.5*e16*e042-0.5*e16*e052+e00*e11*e07+e00*e01*e17+e00*e12*e08+e00*e02*e18+e10*e01*e07+e10*e02*e08+e03*e13*e06+e03*e14*e07+e03*e04*e17+e03*e15*e08+e03*e05*e18+e13*e04*e07+e13*e05*e08+e06*e17*e07+e06*e18*e08-e06*e12*e02-e06*e11*e01-e06*e14*e04-e06*e15*e05; - A[2 + 10*2]=e13*e14*e07+0.5*e102*e06+e00*e10*e16+e00*e12*e18+e00*e11*e17+e10*e11*e07+e10*e01*e17+e10*e12*e08+e10*e02*e18+e03*e13*e16+e03*e15*e18+e03*e14*e17+e13*e04*e17+e13*e15*e08+e13*e05*e18+e16*e17*e07+e16*e18*e08-e16*e12*e02-e16*e11*e01-e16*e14*e04-e16*e15*e05+0.5*e132*e06+1.5*e06*e162+0.5*e06*e182+0.5*e06*e172-0.5*e06*e112-0.5*e06*e122-0.5*e06*e142-0.5*e06*e152; - A[2 + 10*3]=0.5*e102*e16+e10*e12*e18+e10*e11*e17+0.5*e132*e16+e13*e15*e18+e13*e14*e17+0.5*e163+0.5*e16*e182+0.5*e16*e172-0.5*e16*e112-0.5*e16*e122-0.5*e16*e142-0.5*e16*e152; - A[2 + 10*4]=e06*e27*e07+e23*e05*e08+e23*e04*e07+e03*e05*e28+e03*e25*e08+e03*e04*e27+e03*e24*e07+e20*e02*e08+e20*e01*e07+e00*e02*e28+e00*e22*e08+e00*e01*e27+e00*e21*e07+e00*e20*e06-e06*e25*e05-e06*e24*e04-e06*e21*e01-e06*e22*e02+e06*e28*e08-0.5*e26*e042-0.5*e26*e052-0.5*e26*e012-0.5*e26*e022+0.5*e26*e082+0.5*e26*e072+1.5*e26*e062+0.5*e002*e26+e03*e23*e06+0.5*e032*e26; - A[2 + 10*5]=e13*e05*e28+e00*e12*e28+e13*e25*e08+e13*e04*e27+e13*e24*e07+e13*e23*e06+e03*e14*e27+e03*e24*e17+e03*e15*e28+e03*e25*e18+e03*e13*e26+e03*e23*e16+e20*e02*e18+e20*e12*e08+e20*e01*e17+e20*e11*e07+e00*e21*e17+e10*e02*e28+e10*e22*e08+e10*e01*e27+e10*e21*e07+e10*e20*e06+e00*e11*e27-e26*e15*e05-e26*e14*e04-e26*e11*e01-e26*e12*e02-e16*e25*e05-e16*e24*e04-e16*e21*e01-e16*e22*e02-e06*e24*e14-e06*e22*e12-e06*e21*e11-e06*e25*e15+e00*e20*e16+e00*e22*e18+e00*e10*e26+e26*e18*e08+e26*e17*e07+e16*e28*e08+e16*e27*e07+e06*e27*e17+e06*e28*e18+3*e06*e26*e16+e23*e05*e18+e23*e15*e08+e23*e04*e17+e23*e14*e07; - A[2 + 10*6]=e10*e22*e18+0.5*e26*e182+0.5*e26*e172+e16*e28*e18+e16*e27*e17-e16*e25*e15-e16*e21*e11-e16*e22*e12+1.5*e26*e162+e13*e15*e28+e13*e24*e17+e13*e14*e27+e23*e15*e18+e23*e14*e17+e10*e12*e28+e10*e21*e17+e10*e11*e27+e20*e12*e18+e20*e11*e17+e13*e23*e16+e13*e25*e18+e10*e20*e16+0.5*e102*e26-0.5*e26*e122-0.5*e26*e142-0.5*e26*e152-e16*e24*e14-0.5*e26*e112+0.5*e132*e26; - A[2 + 10*7]=-0.5*e06*e212-0.5*e06*e252-0.5*e06*e242+0.5*e06*e272+0.5*e06*e282-0.5*e06*e222+e20*e02*e28+e03*e23*e26+e03*e24*e27+e03*e25*e28+e23*e24*e07+e23*e04*e27+e23*e25*e08+e23*e05*e28+e26*e28*e08-e26*e22*e02-e26*e21*e01-e26*e24*e04-e26*e25*e05+e26*e27*e07+e00*e20*e26+e00*e21*e27+e00*e22*e28+e20*e21*e07+e20*e01*e27+e20*e22*e08+0.5*e202*e06+0.5*e232*e06+1.5*e06*e262; - A[2 + 10*8]=-e26*e24*e14-0.5*e16*e212-0.5*e16*e252-0.5*e16*e242-e26*e25*e15-0.5*e16*e222-e26*e21*e11+e26*e28*e18+e26*e27*e17-e26*e22*e12+e23*e15*e28+e23*e24*e17+e23*e14*e27+0.5*e232*e16+1.5*e16*e262+0.5*e16*e272+0.5*e16*e282+e10*e20*e26+e10*e21*e27+e10*e22*e28+e20*e22*e18+e20*e12*e28+e20*e21*e17+e20*e11*e27+e13*e23*e26+e13*e24*e27+e13*e25*e28+e23*e25*e18+0.5*e202*e16; - A[2 + 10*9]=0.5*e202*e26+e20*e21*e27+e20*e22*e28+0.5*e232*e26+e23*e24*e27+e23*e25*e28+0.5*e263+0.5*e26*e272+0.5*e26*e282-0.5*e26*e222-0.5*e26*e212-0.5*e26*e252-0.5*e26*e242; - A[2 + 10*10]=e03*e34*e07+0.5*e032*e36+1.5*e36*e062+e03*e33*e06+e00*e31*e07+e00*e01*e37+e00*e32*e08+e00*e02*e38+e30*e01*e07+e30*e02*e08+e03*e04*e37+e03*e35*e08+e03*e05*e38+0.5*e002*e36-0.5*e36*e022-0.5*e36*e042-0.5*e36*e052+0.5*e36*e072+0.5*e36*e082-0.5*e36*e012+e33*e04*e07+e33*e05*e08+e06*e37*e07+e06*e38*e08-e06*e32*e02-e06*e31*e01-e06*e34*e04-e06*e35*e05+e00*e30*e06; - A[2 + 10*11]=e13*e33*e06+e13*e34*e07+e13*e04*e37+e13*e35*e08+e13*e05*e38+e33*e14*e07+e33*e04*e17+e33*e15*e08+e33*e05*e18+3*e06*e36*e16+e06*e38*e18+e06*e37*e17+e16*e37*e07+e16*e38*e08+e36*e17*e07+e36*e18*e08-e06*e35*e15-e06*e31*e11-e06*e32*e12+e00*e31*e17+e00*e11*e37+e10*e30*e06+e10*e31*e07+e10*e01*e37+e10*e32*e08+e10*e02*e38+e30*e11*e07+e30*e01*e17+e30*e12*e08+e30*e02*e18+e03*e33*e16+e03*e13*e36+e03*e35*e18+e03*e15*e38+e03*e34*e17+e03*e14*e37+e00*e30*e16+e00*e12*e38-e06*e34*e14-e16*e32*e02-e16*e31*e01-e16*e34*e04-e16*e35*e05-e36*e12*e02-e36*e11*e01-e36*e14*e04-e36*e15*e05+e00*e10*e36+e00*e32*e18; - A[2 + 10*12]=0.5*e36*e182+0.5*e36*e172-0.5*e36*e112-0.5*e36*e122-0.5*e36*e142-0.5*e36*e152+0.5*e102*e36+0.5*e132*e36+1.5*e36*e162+e10*e30*e16+e10*e32*e18+e10*e12*e38+e10*e31*e17+e10*e11*e37+e30*e12*e18+e30*e11*e17+e13*e33*e16+e13*e35*e18+e13*e15*e38+e13*e34*e17+e13*e14*e37+e33*e15*e18+e33*e14*e17+e16*e38*e18+e16*e37*e17-e16*e35*e15-e16*e31*e11-e16*e32*e12-e16*e34*e14; - A[2 + 10*13]=e00*e20*e36+e00*e31*e27+e00*e21*e37+e00*e32*e28+e00*e22*e38+e20*e30*e06+e20*e31*e07+e20*e01*e37+e20*e32*e08+e20*e02*e38+e30*e21*e07+e30*e01*e27+e30*e22*e08+e30*e02*e28+e03*e33*e26+e03*e23*e36+e03*e34*e27+e03*e24*e37+e03*e35*e28-e26*e31*e01-e26*e35*e05-e36*e22*e02-e36*e21*e01-e36*e24*e04-e36*e25*e05-e26*e34*e04+e03*e25*e38+e23*e34*e07+e23*e04*e37+e23*e35*e08+e23*e05*e38+e33*e24*e07+e33*e04*e27+e33*e25*e08+e33*e05*e28+3*e06*e36*e26+e06*e37*e27+e06*e38*e28+e26*e37*e07+e26*e38*e08+e36*e27*e07+e36*e28*e08-e06*e32*e22-e06*e31*e21-e06*e35*e25-e06*e34*e24-e26*e32*e02+e00*e30*e26+e23*e33*e06; - A[2 + 10*14]=e10*e30*e26+e10*e20*e36+e10*e31*e27+e10*e21*e37+e10*e32*e28+e10*e22*e38+e20*e30*e16+e20*e32*e18+e20*e12*e38+e20*e31*e17+e20*e11*e37+e30*e22*e18+e30*e12*e28+e30*e21*e17+e30*e11*e27+e13*e33*e26+e13*e23*e36+e13*e34*e27+e13*e24*e37+e13*e35*e28+e13*e25*e38+e23*e33*e16+e23*e35*e18+e23*e15*e38+e23*e34*e17+e23*e14*e37+e33*e25*e18+e33*e15*e28+e33*e24*e17+e33*e14*e27+3*e16*e36*e26+e16*e37*e27+e16*e38*e28+e26*e38*e18+e26*e37*e17+e36*e28*e18+e36*e27*e17-e16*e32*e22-e16*e31*e21-e16*e35*e25-e16*e34*e24-e26*e35*e15-e26*e31*e11-e26*e32*e12-e26*e34*e14-e36*e25*e15-e36*e21*e11-e36*e22*e12-e36*e24*e14; - A[2 + 10*15]=e33*e25*e28+e20*e30*e26+e20*e32*e28+e20*e31*e27+e20*e21*e37+e20*e22*e38+e30*e21*e27+e30*e22*e28+e23*e33*e26+e23*e34*e27+e23*e24*e37+e23*e35*e28+e23*e25*e38+e33*e24*e27+e26*e37*e27+e26*e38*e28-e26*e32*e22-e26*e31*e21-e26*e35*e25-e26*e34*e24+0.5*e202*e36+0.5*e232*e36+1.5*e36*e262+0.5*e36*e272+0.5*e36*e282-0.5*e36*e222-0.5*e36*e212-0.5*e36*e252-0.5*e36*e242; - A[2 + 10*16]=e00*e30*e36+e00*e32*e38+e00*e31*e37+e30*e31*e07+e30*e01*e37+e30*e32*e08+e30*e02*e38+e03*e33*e36-0.5*e06*e342+e03*e35*e38+e33*e34*e07+e33*e04*e37+e33*e35*e08+e33*e05*e38+e36*e37*e07+e36*e38*e08-e36*e32*e02-e36*e31*e01-e36*e34*e04-e36*e35*e05+e03*e34*e37+0.5*e302*e06+0.5*e332*e06+1.5*e06*e362+0.5*e06*e382+0.5*e06*e372-0.5*e06*e352-0.5*e06*e312-0.5*e06*e322; - A[2 + 10*17]=-e36*e35*e15+e10*e30*e36+0.5*e302*e16+0.5*e332*e16+1.5*e16*e362+0.5*e16*e382+0.5*e16*e372-0.5*e16*e352-0.5*e16*e312-0.5*e16*e322-0.5*e16*e342+e10*e32*e38+e10*e31*e37+e30*e32*e18+e30*e12*e38+e30*e31*e17+e30*e11*e37+e13*e33*e36+e13*e35*e38+e13*e34*e37+e33*e35*e18+e33*e15*e38+e33*e34*e17+e33*e14*e37+e36*e38*e18+e36*e37*e17-e36*e31*e11-e36*e32*e12-e36*e34*e14; - A[2 + 10*18]=-e36*e35*e25+e30*e32*e28+0.5*e302*e26+0.5*e332*e26+1.5*e26*e362+0.5*e26*e382+0.5*e26*e372-0.5*e26*e352-0.5*e26*e312-0.5*e26*e322-0.5*e26*e342+e20*e30*e36+e20*e32*e38+e20*e31*e37+e30*e31*e27+e30*e21*e37+e30*e22*e38+e23*e33*e36+e23*e35*e38+e23*e34*e37+e33*e34*e27+e33*e24*e37+e33*e35*e28+e33*e25*e38+e36*e37*e27+e36*e38*e28-e36*e32*e22-e36*e31*e21-e36*e34*e24; - A[2 + 10*19]=0.5*e302*e36+e30*e32*e38+e30*e31*e37+0.5*e332*e36+e33*e35*e38+e33*e34*e37+0.5*e363+0.5*e36*e382+0.5*e36*e372-0.5*e36*e352-0.5*e36*e312-0.5*e36*e322-0.5*e36*e342; - A[3 + 10*0]=0.5*e01*e002+0.5*e013+0.5*e01*e022+e04*e00*e03+0.5*e01*e042+e04*e02*e05+e07*e00*e06+0.5*e01*e072+e07*e02*e08-0.5*e01*e032-0.5*e01*e052-0.5*e01*e062-0.5*e01*e082; - A[3 + 10*1]=1.5*e11*e012+0.5*e11*e002+0.5*e11*e022+0.5*e11*e042+0.5*e11*e072-0.5*e11*e032-0.5*e11*e052-0.5*e11*e062-0.5*e11*e082+e01*e10*e00+e01*e12*e02+e04*e10*e03+e04*e00*e13+e04*e01*e14+e04*e12*e05+e04*e02*e15+e14*e00*e03+e14*e02*e05+e07*e10*e06+e07*e00*e16+e07*e01*e17+e07*e12*e08+e07*e02*e18+e17*e00*e06+e17*e02*e08-e01*e13*e03-e01*e16*e06-e01*e15*e05-e01*e18*e08; - A[3 + 10*2]=e17*e02*e18+e14*e10*e03+e11*e12*e02-e11*e18*e08+0.5*e01*e102+0.5*e01*e122+1.5*e01*e112+0.5*e01*e142+0.5*e01*e172-0.5*e01*e132-0.5*e01*e152-0.5*e01*e162-0.5*e01*e182+e11*e10*e00+e04*e10*e13+e04*e12*e15+e04*e11*e14+e14*e00*e13+e14*e12*e05+e14*e02*e15+e07*e10*e16+e07*e12*e18+e07*e11*e17+e17*e10*e06+e17*e00*e16+e17*e12*e08-e11*e13*e03-e11*e16*e06-e11*e15*e05; - A[3 + 10*3]=0.5*e11*e102+0.5*e11*e122+0.5*e113+e14*e10*e13+e14*e12*e15+0.5*e11*e142+e17*e10*e16+e17*e12*e18+0.5*e11*e172-0.5*e11*e132-0.5*e11*e152-0.5*e11*e162-0.5*e11*e182; - A[3 + 10*4]=-e01*e25*e05-e01*e26*e06-e01*e23*e03+e27*e02*e08+e27*e00*e06+e07*e02*e28+e07*e22*e08+e07*e01*e27+e07*e00*e26+e24*e02*e05+e24*e00*e03+e04*e02*e25+e04*e22*e05+e04*e01*e24+e04*e00*e23+e04*e20*e03+e01*e22*e02+e01*e20*e00-e01*e28*e08+e07*e20*e06+0.5*e21*e072+0.5*e21*e042+0.5*e21*e022+0.5*e21*e002+1.5*e21*e012-0.5*e21*e082-0.5*e21*e052-0.5*e21*e062-0.5*e21*e032; - A[3 + 10*5]=e11*e20*e00+e07*e20*e16+3*e01*e21*e11+e01*e22*e12-e21*e18*e08-e21*e15*e05-e21*e16*e06-e21*e13*e03-e11*e28*e08-e11*e25*e05-e11*e26*e06-e11*e23*e03-e01*e28*e18-e01*e23*e13-e01*e25*e15-e01*e26*e16+e27*e02*e18+e27*e12*e08+e27*e00*e16+e27*e10*e06+e17*e02*e28+e17*e22*e08+e17*e01*e27+e17*e00*e26+e17*e20*e06+e07*e11*e27+e07*e21*e17+e07*e12*e28+e07*e22*e18+e07*e10*e26+e24*e02*e15+e24*e12*e05+e24*e00*e13+e24*e10*e03+e14*e02*e25+e14*e22*e05+e14*e01*e24+e14*e00*e23+e14*e20*e03+e04*e11*e24+e04*e21*e14+e04*e12*e25+e04*e22*e15+e21*e12*e02+e04*e20*e13+e01*e20*e10+e11*e22*e02+e21*e10*e00+e04*e10*e23; - A[3 + 10*6]=1.5*e21*e112+0.5*e21*e102+0.5*e21*e122+e11*e20*e10+e11*e22*e12+e14*e10*e23+e14*e22*e15+e14*e12*e25-0.5*e21*e162-0.5*e21*e152-0.5*e21*e132-0.5*e21*e182+e27*e12*e18-e11*e26*e16-e11*e25*e15-e11*e23*e13-e11*e28*e18+e17*e20*e16+e17*e10*e26+e17*e22*e18+e17*e12*e28+e17*e11*e27+e27*e10*e16+0.5*e21*e172+e14*e11*e24+e24*e10*e13+e24*e12*e15+0.5*e21*e142+e14*e20*e13; - A[3 + 10*7]=-0.5*e01*e262-0.5*e01*e282-0.5*e01*e252-0.5*e01*e232+0.5*e01*e272+e27*e22*e08+e27*e02*e28-e21*e23*e03-e21*e26*e06-e21*e25*e05-e21*e28*e08+e04*e22*e25+e24*e20*e03+e24*e00*e23+e24*e22*e05+e24*e02*e25+e07*e20*e26+e07*e21*e27+e07*e22*e28+e27*e20*e06+e27*e00*e26+e21*e20*e00+e21*e22*e02+e04*e20*e23+e04*e21*e24+0.5*e01*e222+0.5*e01*e242+1.5*e01*e212+0.5*e01*e202; - A[3 + 10*8]=-0.5*e11*e282-0.5*e11*e252-e21*e26*e16+e27*e12*e28-e21*e25*e15-e21*e23*e13-e21*e28*e18+e17*e20*e26+e17*e21*e27+e17*e22*e28+e27*e20*e16+e27*e10*e26+e27*e22*e18+0.5*e11*e242+0.5*e11*e272-0.5*e11*e232-0.5*e11*e262+0.5*e11*e202+1.5*e11*e212+0.5*e11*e222+e21*e20*e10+e14*e20*e23+e14*e21*e24+e14*e22*e25+e24*e20*e13+e24*e10*e23+e24*e22*e15+e24*e12*e25+e21*e22*e12; - A[3 + 10*9]=0.5*e21*e202+0.5*e213+0.5*e21*e222+e24*e20*e23+0.5*e21*e242+e24*e22*e25+e27*e20*e26+0.5*e21*e272+e27*e22*e28-0.5*e21*e232-0.5*e21*e262-0.5*e21*e282-0.5*e21*e252; - A[3 + 10*10]=-0.5*e31*e032-0.5*e31*e052-0.5*e31*e062-0.5*e31*e082+e07*e30*e06+e07*e00*e36+e07*e01*e37+e07*e32*e08+e07*e02*e38+e37*e00*e06+e37*e02*e08-e01*e33*e03-e01*e36*e06-e01*e35*e05-e01*e38*e08+0.5*e31*e072+e04*e30*e03+e04*e00*e33+e04*e01*e34+e04*e32*e05+e04*e02*e35+e34*e00*e03+e34*e02*e05+0.5*e31*e002+0.5*e31*e022+0.5*e31*e042+e01*e30*e00+e01*e32*e02+1.5*e31*e012; - A[3 + 10*11]=e34*e12*e05+e34*e02*e15+e07*e10*e36+e07*e32*e18+e07*e12*e38+e07*e31*e17+e07*e11*e37+e17*e30*e06+e17*e00*e36+e17*e01*e37+e17*e32*e08+e17*e02*e38+e37*e10*e06+e37*e00*e16+e37*e12*e08+e37*e02*e18-e01*e36*e16-e01*e35*e15-e01*e33*e13-e01*e38*e18-e11*e33*e03-e11*e36*e06-e11*e35*e05+e01*e30*e10+e01*e32*e12+3*e01*e31*e11+e11*e30*e00+e11*e32*e02+e31*e10*e00+e31*e12*e02+e04*e30*e13+e04*e10*e33+e04*e32*e15+e04*e12*e35+e04*e31*e14+e04*e11*e34+e14*e30*e03+e14*e00*e33+e14*e01*e34+e14*e32*e05+e14*e02*e35+e34*e10*e03+e34*e00*e13+e07*e30*e16-e11*e38*e08-e31*e13*e03-e31*e16*e06-e31*e15*e05-e31*e18*e08; - A[3 + 10*12]=-e11*e33*e13-e11*e38*e18+0.5*e31*e142+0.5*e31*e172-0.5*e31*e162-0.5*e31*e152-0.5*e31*e132-0.5*e31*e182+0.5*e31*e122+0.5*e31*e102+e11*e30*e10+e11*e32*e12+e14*e30*e13+e14*e10*e33+e14*e32*e15+e14*e12*e35+e14*e11*e34+e34*e10*e13+e34*e12*e15+e17*e30*e16+e17*e10*e36+e17*e32*e18+e17*e12*e38+e17*e11*e37+e37*e10*e16+e37*e12*e18-e11*e36*e16-e11*e35*e15+1.5*e31*e112; - A[3 + 10*13]=-e21*e35*e05+e07*e32*e28+e01*e30*e20-e21*e33*e03-e21*e36*e06-e21*e38*e08-e31*e23*e03-e31*e26*e06-e31*e25*e05-e31*e28*e08+3*e01*e31*e21+e01*e32*e22+e21*e30*e00+e21*e32*e02+e31*e20*e00+e31*e22*e02+e04*e30*e23+e04*e20*e33+e04*e31*e24+e04*e21*e34+e04*e32*e25+e04*e22*e35+e24*e30*e03+e24*e00*e33+e24*e01*e34+e24*e32*e05+e24*e02*e35+e34*e20*e03+e34*e00*e23+e34*e22*e05+e34*e02*e25+e07*e30*e26+e07*e20*e36+e07*e31*e27+e07*e21*e37+e07*e22*e38+e27*e30*e06+e27*e00*e36+e27*e01*e37+e27*e32*e08+e27*e02*e38+e37*e00*e26+e37*e22*e08+e37*e02*e28-e01*e33*e23-e01*e36*e26-e01*e38*e28-e01*e35*e25+e37*e20*e06; - A[3 + 10*14]=e11*e32*e22+e34*e12*e25+e11*e30*e20+3*e11*e31*e21+e21*e30*e10+e21*e32*e12+e34*e10*e23+e34*e22*e15+e17*e30*e26+e17*e20*e36+e17*e31*e27+e17*e21*e37+e17*e32*e28+e17*e22*e38+e27*e30*e16+e27*e10*e36+e27*e32*e18+e27*e12*e38+e27*e11*e37+e37*e20*e16+e37*e10*e26+e37*e22*e18+e37*e12*e28-e11*e33*e23-e11*e36*e26-e11*e38*e28-e11*e35*e25-e21*e36*e16-e21*e35*e15-e21*e33*e13-e21*e38*e18-e31*e26*e16-e31*e25*e15-e31*e23*e13-e31*e28*e18+e31*e20*e10+e31*e22*e12+e14*e30*e23+e14*e20*e33+e14*e31*e24+e14*e21*e34+e14*e32*e25+e14*e22*e35+e24*e30*e13+e24*e10*e33+e24*e32*e15+e24*e12*e35+e24*e11*e34+e34*e20*e13; - A[3 + 10*15]=-e21*e36*e26+e37*e22*e28-e21*e33*e23-e21*e38*e28-e21*e35*e25+0.5*e31*e222+0.5*e31*e242+0.5*e31*e272-0.5*e31*e232-0.5*e31*e262-0.5*e31*e282-0.5*e31*e252+e21*e30*e20+e21*e32*e22+e24*e30*e23+e24*e20*e33+e24*e21*e34+e24*e32*e25+e24*e22*e35+e34*e20*e23+e34*e22*e25+e27*e30*e26+e27*e20*e36+e27*e21*e37+e27*e32*e28+e27*e22*e38+e37*e20*e26+1.5*e31*e212+0.5*e31*e202; - A[3 + 10*16]=e04*e32*e35+0.5*e01*e372-0.5*e01*e352-0.5*e01*e362-0.5*e01*e332-0.5*e01*e382+e04*e31*e34+e34*e30*e03+e34*e00*e33+e34*e32*e05+e34*e02*e35+e07*e30*e36+e07*e32*e38+e07*e31*e37+e37*e30*e06+e37*e00*e36+e37*e32*e08+e04*e30*e33+e37*e02*e38-e31*e33*e03-e31*e36*e06-e31*e35*e05-e31*e38*e08+0.5*e01*e302+0.5*e01*e322+1.5*e01*e312+0.5*e01*e342+e31*e30*e00+e31*e32*e02; - A[3 + 10*17]=e31*e32*e12+e14*e30*e33+e14*e32*e35+e14*e31*e34+e34*e30*e13+e34*e10*e33+e34*e32*e15+e34*e12*e35+e17*e30*e36+e17*e32*e38+e17*e31*e37+e37*e30*e16+e37*e10*e36+e37*e32*e18+e37*e12*e38-e31*e36*e16-e31*e35*e15+0.5*e11*e302+0.5*e11*e322+1.5*e11*e312-e31*e33*e13-e31*e38*e18+0.5*e11*e342+0.5*e11*e372+e31*e30*e10-0.5*e11*e352-0.5*e11*e362-0.5*e11*e332-0.5*e11*e382; - A[3 + 10*18]=e34*e32*e25+0.5*e21*e342+0.5*e21*e372-0.5*e21*e352-0.5*e21*e362-0.5*e21*e332-0.5*e21*e382+0.5*e21*e302+0.5*e21*e322+1.5*e21*e312+e31*e30*e20+e31*e32*e22+e24*e30*e33+e24*e32*e35+e24*e31*e34+e34*e30*e23+e34*e20*e33+e34*e22*e35+e27*e30*e36+e27*e32*e38+e27*e31*e37+e37*e30*e26+e37*e20*e36+e37*e32*e28+e37*e22*e38-e31*e33*e23-e31*e36*e26-e31*e38*e28-e31*e35*e25; - A[3 + 10*19]=0.5*e31*e302+0.5*e31*e322+0.5*e313+e34*e30*e33+e34*e32*e35+0.5*e31*e342+e37*e30*e36+e37*e32*e38+0.5*e31*e372-0.5*e31*e352-0.5*e31*e362-0.5*e31*e332-0.5*e31*e382; - A[4 + 10*0]=e01*e00*e03+0.5*e012*e04+e01*e02*e05+0.5*e04*e032+0.5*e043+0.5*e04*e052+e07*e03*e06+0.5*e04*e072+e07*e05*e08-0.5*e04*e002-0.5*e04*e022-0.5*e04*e062-0.5*e04*e082; - A[4 + 10*1]=e07*e13*e06+e01*e10*e03-0.5*e14*e002-0.5*e14*e022-0.5*e14*e062-0.5*e14*e082+e01*e00*e13+e01*e11*e04+e01*e12*e05+e01*e02*e15+e11*e00*e03+e11*e02*e05+e04*e13*e03+e04*e15*e05+e07*e03*e16+e07*e04*e17+e07*e15*e08+e07*e05*e18+e17*e03*e06+e17*e05*e08-e04*e10*e00-e04*e12*e02-e04*e16*e06-e04*e18*e08+0.5*e012*e14+1.5*e14*e042+0.5*e14*e032+0.5*e14*e052+0.5*e14*e072; - A[4 + 10*2]=e11*e10*e03+0.5*e112*e04+0.5*e04*e132+0.5*e04*e152+1.5*e04*e142+0.5*e04*e172-0.5*e04*e102-0.5*e04*e162-0.5*e04*e122-0.5*e04*e182+e01*e10*e13+e01*e12*e15+e01*e11*e14+e11*e00*e13+e11*e12*e05+e11*e02*e15+e14*e13*e03+e14*e15*e05+e07*e13*e16+e07*e15*e18+e07*e14*e17+e17*e13*e06+e17*e03*e16+e17*e15*e08+e17*e05*e18-e14*e10*e00-e14*e12*e02-e14*e16*e06-e14*e18*e08; - A[4 + 10*3]=e11*e10*e13+e11*e12*e15+0.5*e112*e14+0.5*e14*e132+0.5*e14*e152+0.5*e143+e17*e13*e16+e17*e15*e18+0.5*e14*e172-0.5*e14*e102-0.5*e14*e162-0.5*e14*e122-0.5*e14*e182; - A[4 + 10*4]=-e04*e28*e08-e04*e26*e06-e04*e22*e02-e04*e20*e00+e27*e05*e08+e27*e03*e06+e07*e05*e28+e07*e25*e08+e07*e04*e27+e07*e03*e26+e07*e23*e06+e04*e25*e05+e04*e23*e03+e21*e02*e05+e21*e00*e03+e01*e02*e25+e01*e22*e05+e01*e21*e04+e01*e00*e23+e01*e20*e03+0.5*e012*e24+0.5*e24*e072+0.5*e24*e052+0.5*e24*e032+1.5*e24*e042-0.5*e24*e022-0.5*e24*e002-0.5*e24*e082-0.5*e24*e062; - A[4 + 10*5]=e11*e02*e25+e11*e22*e05+e11*e21*e04-e24*e18*e08-e24*e16*e06-e24*e12*e02-e14*e28*e08-e14*e26*e06-e14*e22*e02-e14*e20*e00-e04*e28*e18-e04*e22*e12-e04*e26*e16-e04*e20*e10+e27*e05*e18+e27*e15*e08+e27*e03*e16+e27*e13*e06+e17*e05*e28+e17*e25*e08+e17*e04*e27+e17*e03*e26+e17*e23*e06+e07*e14*e27+e07*e24*e17+e07*e15*e28+e07*e25*e18+e07*e13*e26+e07*e23*e16+e24*e15*e05+e24*e13*e03+e14*e25*e05+e14*e23*e03+3*e04*e24*e14+e04*e25*e15+e04*e23*e13+e21*e02*e15+e21*e12*e05+e21*e00*e13+e21*e10*e03-e24*e10*e00+e01*e20*e13+e01*e10*e23+e01*e22*e15+e01*e12*e25+e01*e11*e24+e11*e20*e03+e11*e00*e23+e01*e21*e14; - A[4 + 10*6]=e11*e12*e25-0.5*e24*e182-0.5*e24*e102-0.5*e24*e162-0.5*e24*e122+e27*e13*e16+e27*e15*e18-e14*e20*e10-e14*e26*e16-e14*e22*e12-e14*e28*e18+e17*e15*e28+e17*e14*e27+1.5*e24*e142+0.5*e24*e132+0.5*e24*e152+0.5*e112*e24+0.5*e24*e172+e11*e21*e14+e11*e22*e15+e11*e10*e23+e11*e20*e13+e21*e10*e13+e21*e12*e15+e17*e13*e26+e17*e23*e16+e14*e25*e15+e14*e23*e13+e17*e25*e18; - A[4 + 10*7]=e27*e03*e26+e27*e25*e08+e27*e05*e28-e24*e20*e00-e24*e22*e02-e24*e26*e06-e24*e28*e08+0.5*e04*e232+1.5*e04*e242+0.5*e04*e252+0.5*e04*e272-0.5*e04*e202-0.5*e04*e222-0.5*e04*e262-0.5*e04*e282+e24*e23*e03+e24*e25*e05+e07*e23*e26+e07*e24*e27+e07*e25*e28+e27*e23*e06+e21*e20*e03+e21*e00*e23+e21*e22*e05+e21*e02*e25+0.5*e212*e04+e01*e20*e23+e01*e21*e24+e01*e22*e25; - A[4 + 10*8]=-e24*e22*e12-e24*e28*e18+0.5*e14*e272-0.5*e14*e202-0.5*e14*e222-0.5*e14*e262-0.5*e14*e282+e17*e23*e26+e17*e24*e27+e17*e25*e28+e27*e23*e16+e27*e13*e26+e27*e25*e18+e27*e15*e28-e24*e20*e10-e24*e26*e16+0.5*e14*e232+1.5*e14*e242+0.5*e14*e252+e21*e10*e23+e21*e22*e15+e21*e12*e25+e24*e23*e13+e24*e25*e15+e21*e20*e13+0.5*e212*e14+e11*e20*e23+e11*e22*e25+e11*e21*e24; - A[4 + 10*9]=e21*e20*e23+0.5*e212*e24+e21*e22*e25+0.5*e24*e232+0.5*e243+0.5*e24*e252+e27*e23*e26+0.5*e24*e272+e27*e25*e28-0.5*e24*e202-0.5*e24*e222-0.5*e24*e262-0.5*e24*e282; - A[4 + 10*10]=-e04*e38*e08-e04*e32*e02-e04*e36*e06-0.5*e34*e002-0.5*e34*e022-0.5*e34*e062-0.5*e34*e082+e37*e03*e06+e37*e05*e08-e04*e30*e00+0.5*e34*e032+0.5*e34*e052+0.5*e34*e072+1.5*e34*e042+e01*e30*e03+e01*e00*e33+e01*e31*e04+e01*e32*e05+e01*e02*e35+e31*e00*e03+e31*e02*e05+e04*e33*e03+e04*e35*e05+e07*e03*e36+e07*e04*e37+e07*e35*e08+e07*e05*e38+0.5*e012*e34+e07*e33*e06; - A[4 + 10*11]=e07*e13*e36+e01*e12*e35-e04*e30*e10+e17*e04*e37+e17*e35*e08+e17*e05*e38+e37*e13*e06+e37*e03*e16+e37*e15*e08+e37*e05*e18-e04*e36*e16+e17*e33*e06+e04*e33*e13+e04*e35*e15+3*e04*e34*e14+e14*e33*e03+e14*e35*e05+e34*e13*e03+e34*e15*e05+e07*e33*e16+e07*e35*e18+e07*e15*e38+e07*e34*e17+e07*e14*e37+e17*e03*e36+e31*e10*e03+e01*e30*e13+e01*e10*e33+e01*e32*e15+e01*e31*e14+e01*e11*e34+e11*e30*e03+e11*e00*e33+e11*e31*e04+e11*e32*e05+e11*e02*e35+e31*e00*e13+e31*e12*e05+e31*e02*e15-e34*e12*e02-e34*e16*e06-e34*e18*e08-e14*e32*e02-e14*e36*e06-e14*e38*e08-e34*e10*e00-e04*e32*e12-e04*e38*e18-e14*e30*e00; - A[4 + 10*12]=e11*e32*e15-0.5*e34*e102-0.5*e34*e162-0.5*e34*e122-0.5*e34*e182+e37*e13*e16+0.5*e112*e34+1.5*e34*e142+0.5*e34*e132+0.5*e34*e152+0.5*e34*e172+e11*e30*e13+e11*e10*e33+e11*e12*e35+e11*e31*e14+e31*e10*e13+e31*e12*e15+e14*e33*e13+e14*e35*e15+e17*e33*e16+e17*e13*e36+e17*e35*e18+e17*e15*e38+e17*e14*e37+e37*e15*e18-e14*e30*e10-e14*e36*e16-e14*e32*e12-e14*e38*e18; - A[4 + 10*13]=e01*e22*e35-e04*e30*e20-e04*e32*e22+e01*e31*e24+e01*e21*e34+e01*e32*e25+e21*e30*e03+e21*e00*e33+e21*e31*e04+e21*e32*e05+e21*e02*e35+e31*e20*e03+e31*e00*e23+e31*e22*e05+e31*e02*e25+e04*e33*e23+3*e04*e34*e24+e04*e35*e25+e24*e33*e03+e37*e05*e28-e04*e36*e26-e04*e38*e28-e24*e30*e00-e24*e32*e02-e24*e36*e06-e24*e38*e08+e24*e35*e05+e34*e23*e03+e34*e25*e05+e07*e33*e26+e07*e23*e36+e07*e34*e27+e07*e24*e37+e07*e35*e28+e07*e25*e38+e27*e33*e06+e27*e03*e36+e27*e04*e37+e27*e35*e08+e27*e05*e38+e37*e23*e06+e37*e03*e26+e37*e25*e08-e34*e20*e00-e34*e22*e02-e34*e26*e06-e34*e28*e08+e01*e30*e23+e01*e20*e33; - A[4 + 10*14]=e21*e10*e33+e11*e30*e23+e11*e20*e33+e11*e31*e24+e11*e21*e34+e11*e32*e25+e11*e22*e35+e21*e30*e13+e21*e32*e15+e21*e12*e35+e21*e31*e14+e31*e20*e13+e31*e10*e23+e31*e22*e15+e31*e12*e25+e14*e33*e23+3*e14*e34*e24+e14*e35*e25+e24*e33*e13+e24*e35*e15+e34*e23*e13+e34*e25*e15+e17*e33*e26+e17*e23*e36+e17*e34*e27+e17*e24*e37+e17*e35*e28+e17*e25*e38+e27*e33*e16+e27*e13*e36+e27*e35*e18+e27*e15*e38+e27*e14*e37+e37*e23*e16+e37*e13*e26+e37*e25*e18+e37*e15*e28-e34*e28*e18-e34*e22*e12-e14*e32*e22-e14*e36*e26-e14*e38*e28-e24*e30*e10-e24*e36*e16-e24*e32*e12-e24*e38*e18-e34*e20*e10-e34*e26*e16-e14*e30*e20; - A[4 + 10*15]=-0.5*e34*e202-0.5*e34*e222-0.5*e34*e262-0.5*e34*e282+e37*e25*e28-e24*e32*e22-e24*e36*e26-e24*e38*e28-e24*e30*e20+0.5*e212*e34+1.5*e34*e242+0.5*e34*e232+0.5*e34*e252+0.5*e34*e272+e21*e30*e23+e21*e20*e33+e21*e31*e24+e21*e32*e25+e21*e22*e35+e31*e20*e23+e31*e22*e25+e24*e33*e23+e24*e35*e25+e27*e33*e26+e27*e23*e36+e27*e24*e37+e27*e35*e28+e27*e25*e38+e37*e23*e26; - A[4 + 10*16]=e37*e33*e06+e01*e30*e33+e01*e31*e34+e31*e30*e03+e31*e02*e35+e34*e33*e03+e34*e35*e05+e07*e33*e36+e07*e35*e38+e07*e34*e37+e37*e03*e36+e37*e35*e08+e37*e05*e38-e34*e32*e02-e34*e36*e06-e34*e38*e08+e31*e32*e05+e31*e00*e33+0.5*e312*e04+0.5*e04*e332+0.5*e04*e352+1.5*e04*e342+0.5*e04*e372+e01*e32*e35-0.5*e04*e302-0.5*e04*e322-0.5*e04*e362-0.5*e04*e382-e34*e30*e00; - A[4 + 10*17]=0.5*e14*e372-0.5*e14*e302-0.5*e14*e322-0.5*e14*e362-0.5*e14*e382+0.5*e312*e14+0.5*e14*e332+0.5*e14*e352+1.5*e14*e342+e11*e30*e33+e11*e32*e35+e11*e31*e34+e31*e30*e13+e31*e10*e33+e31*e32*e15+e31*e12*e35+e34*e33*e13+e34*e35*e15+e17*e33*e36+e17*e35*e38+e17*e34*e37+e37*e33*e16+e37*e13*e36+e37*e35*e18+e37*e15*e38-e34*e30*e10-e34*e36*e16-e34*e32*e12-e34*e38*e18; - A[4 + 10*18]=-e34*e32*e22-e34*e36*e26-e34*e38*e28+0.5*e24*e332+0.5*e24*e352+1.5*e24*e342+0.5*e24*e372-0.5*e24*e302-0.5*e24*e322-0.5*e24*e362-0.5*e24*e382+e21*e30*e33+0.5*e312*e24+e21*e32*e35+e21*e31*e34+e31*e30*e23+e31*e20*e33+e31*e32*e25+e31*e22*e35+e34*e33*e23+e34*e35*e25+e27*e33*e36+e27*e35*e38+e27*e34*e37+e37*e33*e26+e37*e23*e36+e37*e35*e28+e37*e25*e38-e34*e30*e20; - A[4 + 10*19]=e31*e30*e33+e31*e32*e35+0.5*e312*e34+0.5*e34*e332+0.5*e34*e352+0.5*e343+e37*e33*e36+e37*e35*e38+0.5*e34*e372-0.5*e34*e302-0.5*e34*e322-0.5*e34*e362-0.5*e34*e382; - A[5 + 10*0]=e01*e00*e06+0.5*e012*e07+e01*e02*e08+e04*e03*e06+0.5*e042*e07+e04*e05*e08+0.5*e07*e062+0.5*e073+0.5*e07*e082-0.5*e07*e002-0.5*e07*e022-0.5*e07*e032-0.5*e07*e052; - A[5 + 10*1]=e04*e13*e06+0.5*e042*e17+1.5*e17*e072+0.5*e17*e062+0.5*e17*e082-0.5*e17*e002-0.5*e17*e022-0.5*e17*e032-0.5*e17*e052+e01*e10*e06+e07*e16*e06+e07*e18*e08-e07*e10*e00-e07*e12*e02-e07*e13*e03-e07*e15*e05+e01*e00*e16+e01*e11*e07+e01*e12*e08+e01*e02*e18+e11*e00*e06+e11*e02*e08+e04*e03*e16+e04*e14*e07+e04*e15*e08+e04*e05*e18+e14*e03*e06+e14*e05*e08+0.5*e012*e17; - A[5 + 10*2]=-e17*e10*e00+0.5*e112*e07+0.5*e142*e07+0.5*e07*e162+0.5*e07*e182+1.5*e07*e172-0.5*e07*e102-0.5*e07*e152-0.5*e07*e132-0.5*e07*e122+e01*e10*e16+e01*e12*e18+e01*e11*e17+e11*e10*e06+e11*e00*e16+e11*e12*e08+e11*e02*e18+e04*e13*e16+e04*e15*e18+e04*e14*e17+e14*e13*e06+e14*e03*e16+e14*e15*e08+e14*e05*e18+e17*e16*e06+e17*e18*e08-e17*e12*e02-e17*e13*e03-e17*e15*e05; - A[5 + 10*3]=e11*e10*e16+e11*e12*e18+0.5*e112*e17+e14*e13*e16+e14*e15*e18+0.5*e142*e17+0.5*e17*e162+0.5*e17*e182+0.5*e173-0.5*e17*e102-0.5*e17*e152-0.5*e17*e132-0.5*e17*e122; - A[5 + 10*4]=e01*e22*e08+e07*e28*e08-e07*e20*e00-e07*e23*e03-e07*e22*e02-e07*e25*e05+0.5*e012*e27+0.5*e042*e27+1.5*e27*e072+0.5*e27*e062+0.5*e27*e082-0.5*e27*e002-0.5*e27*e022-0.5*e27*e032-0.5*e27*e052+e07*e26*e06+e01*e20*e06+e01*e00*e26+e01*e21*e07+e01*e02*e28+e21*e00*e06+e21*e02*e08+e04*e23*e06+e04*e03*e26+e04*e24*e07+e04*e25*e08+e04*e05*e28+e24*e03*e06+e24*e05*e08; - A[5 + 10*5]=e14*e24*e07+e14*e03*e26+e14*e23*e06+e04*e14*e27+e04*e24*e17+e04*e15*e28+e04*e25*e18+e04*e13*e26+e04*e23*e16+e21*e02*e18+e21*e12*e08-e27*e15*e05-e27*e13*e03-e27*e12*e02-e27*e10*e00-e17*e25*e05-e17*e23*e03-e17*e22*e02-e17*e20*e00-e07*e22*e12-e07*e23*e13-e07*e25*e15-e07*e20*e10+e27*e18*e08+e27*e16*e06+e17*e28*e08+e17*e26*e06+3*e07*e27*e17+e07*e28*e18+e07*e26*e16+e24*e05*e18+e24*e15*e08+e24*e03*e16+e24*e13*e06+e14*e05*e28+e14*e25*e08+e01*e12*e28+e01*e20*e16+e01*e10*e26+e01*e22*e18+e01*e21*e17+e11*e20*e06+e01*e11*e27+e21*e00*e16+e21*e10*e06+e11*e21*e07+e11*e22*e08+e11*e02*e28+e11*e00*e26; - A[5 + 10*6]=-0.5*e27*e102-0.5*e27*e152-0.5*e27*e132-0.5*e27*e122+0.5*e142*e27+1.5*e27*e172+0.5*e27*e162+0.5*e27*e182+0.5*e112*e27+e11*e22*e18+e11*e10*e26+e11*e20*e16-e17*e22*e12-e17*e23*e13-e17*e25*e15-e17*e20*e10+e17*e28*e18+e17*e26*e16+e24*e15*e18+e24*e13*e16+e14*e24*e17+e14*e15*e28+e14*e25*e18+e14*e13*e26+e14*e23*e16+e21*e12*e18+e21*e10*e16+e11*e21*e17+e11*e12*e28; - A[5 + 10*7]=-0.5*e07*e252+e27*e26*e06+e27*e28*e08-e27*e20*e00-e27*e22*e02-e27*e23*e03-e27*e25*e05+1.5*e07*e272+0.5*e07*e282+e01*e22*e28+e21*e20*e06+e21*e00*e26+e21*e22*e08+e21*e02*e28+e04*e23*e26+e04*e24*e27+e04*e25*e28+e24*e23*e06+e24*e03*e26+e24*e25*e08+e24*e05*e28+0.5*e212*e07+0.5*e242*e07+0.5*e07*e262+e01*e20*e26+e01*e21*e27-0.5*e07*e202-0.5*e07*e232-0.5*e07*e222; - A[5 + 10*8]=-e27*e25*e15-e27*e23*e13-e27*e22*e12-0.5*e17*e252-0.5*e17*e202-0.5*e17*e222-0.5*e17*e232+0.5*e17*e262+1.5*e17*e272+0.5*e17*e282+e24*e23*e16+e24*e13*e26+e24*e25*e18+e24*e15*e28+e27*e26*e16+e27*e28*e18-e27*e20*e10+e14*e24*e27+e14*e25*e28+0.5*e212*e17+0.5*e242*e17+e11*e20*e26+e11*e21*e27+e11*e22*e28+e21*e20*e16+e21*e10*e26+e21*e22*e18+e21*e12*e28+e14*e23*e26; - A[5 + 10*9]=e21*e20*e26+0.5*e212*e27+e21*e22*e28+e24*e23*e26+0.5*e242*e27+e24*e25*e28+0.5*e27*e262+0.5*e273+0.5*e27*e282-0.5*e27*e202-0.5*e27*e222-0.5*e27*e232-0.5*e27*e252; - A[5 + 10*10]=e04*e05*e38+e01*e30*e06-0.5*e37*e002-0.5*e37*e022-0.5*e37*e032-0.5*e37*e052-e07*e32*e02-e07*e35*e05-e07*e33*e03+e07*e36*e06+e07*e38*e08-e07*e30*e00+1.5*e37*e072+0.5*e37*e062+0.5*e37*e082+e01*e02*e38+e31*e00*e06+e31*e02*e08+e04*e33*e06+e04*e03*e36+e04*e34*e07+e04*e35*e08+e34*e03*e06+e34*e05*e08+0.5*e012*e37+0.5*e042*e37+e01*e00*e36+e01*e31*e07+e01*e32*e08; - A[5 + 10*11]=e14*e33*e06+e11*e30*e06+e11*e00*e36+e11*e31*e07+e31*e10*e06+e11*e32*e08+e11*e02*e38+e31*e00*e16+e31*e12*e08+e31*e02*e18+e04*e33*e16+e04*e13*e36+e04*e35*e18+e04*e15*e38+e01*e10*e36+e01*e32*e18+e01*e12*e38+e01*e31*e17+e01*e11*e37+e01*e30*e16-e17*e35*e05-e37*e10*e00-e37*e12*e02-e37*e13*e03-e37*e15*e05+e37*e18*e08-e07*e30*e10-e07*e35*e15-e07*e33*e13-e07*e32*e12-e17*e30*e00-e17*e32*e02-e17*e33*e03+e07*e38*e18+3*e07*e37*e17+e17*e36*e06+e17*e38*e08+e37*e16*e06+e04*e34*e17+e04*e14*e37+e14*e03*e36+e14*e34*e07+e14*e35*e08+e14*e05*e38+e34*e13*e06+e34*e03*e16+e34*e15*e08+e34*e05*e18+e07*e36*e16; - A[5 + 10*12]=e11*e32*e18-0.5*e37*e102-0.5*e37*e152-0.5*e37*e132-0.5*e37*e122+0.5*e112*e37+0.5*e142*e37+1.5*e37*e172+0.5*e37*e162+0.5*e37*e182+e11*e10*e36+e11*e12*e38+e11*e31*e17+e31*e10*e16+e31*e12*e18+e14*e33*e16+e14*e13*e36+e14*e35*e18+e14*e15*e38+e14*e34*e17+e34*e13*e16+e34*e15*e18+e17*e36*e16+e17*e38*e18-e17*e30*e10-e17*e35*e15-e17*e33*e13-e17*e32*e12+e11*e30*e16; - A[5 + 10*13]=e01*e20*e36+e01*e31*e27+e01*e21*e37+e01*e32*e28+e01*e22*e38+e21*e30*e06+e21*e00*e36+e21*e31*e07+e21*e32*e08+e21*e02*e38+e01*e30*e26+e31*e20*e06+e31*e00*e26+e31*e22*e08+e31*e02*e28+e04*e33*e26+e04*e23*e36+e04*e34*e27+e04*e24*e37+e04*e35*e28+e04*e25*e38+e24*e33*e06+e24*e03*e36+e24*e34*e07+e24*e35*e08+e24*e05*e38+e34*e23*e06+e34*e03*e26+e34*e25*e08+e34*e05*e28+e07*e36*e26+3*e07*e37*e27+e07*e38*e28+e27*e36*e06+e27*e38*e08+e37*e26*e06+e37*e28*e08-e07*e30*e20-e07*e32*e22-e07*e33*e23-e07*e35*e25-e27*e30*e00-e27*e32*e02-e27*e33*e03-e27*e35*e05-e37*e20*e00-e37*e22*e02-e37*e23*e03-e37*e25*e05; - A[5 + 10*14]=e11*e30*e26+e11*e20*e36+e11*e31*e27+e11*e21*e37+e11*e32*e28+e11*e22*e38+e21*e10*e36+e21*e32*e18+e21*e12*e38+e21*e31*e17+e31*e20*e16+e31*e10*e26+e31*e22*e18+e31*e12*e28+e14*e33*e26+e14*e23*e36+e14*e34*e27+e14*e24*e37+e14*e35*e28+e14*e25*e38+e24*e33*e16+e24*e13*e36+e24*e35*e18+e24*e15*e38+e24*e34*e17+e34*e23*e16+e34*e13*e26+e34*e25*e18+e34*e15*e28+e17*e36*e26+3*e17*e37*e27+e17*e38*e28+e27*e36*e16+e27*e38*e18+e37*e26*e16+e37*e28*e18-e17*e30*e20-e17*e32*e22-e17*e33*e23-e17*e35*e25-e27*e30*e10-e27*e35*e15-e27*e33*e13-e27*e32*e12-e37*e20*e10-e37*e25*e15-e37*e23*e13-e37*e22*e12+e21*e30*e16; - A[5 + 10*15]=e21*e20*e36+e21*e31*e27+e21*e32*e28+e21*e22*e38+e31*e22*e28+e24*e33*e26+e24*e23*e36+e24*e34*e27+e24*e35*e28+e24*e25*e38+e34*e23*e26+e34*e25*e28+e27*e36*e26+e27*e38*e28-e27*e30*e20-e27*e32*e22-e27*e33*e23-e27*e35*e25+0.5*e242*e37+1.5*e37*e272+0.5*e37*e262+0.5*e37*e282+e31*e20*e26+e21*e30*e26+0.5*e212*e37-0.5*e37*e202-0.5*e37*e222-0.5*e37*e232-0.5*e37*e252; - A[5 + 10*16]=e01*e30*e36+e01*e32*e38+e01*e31*e37+e31*e30*e06+e31*e00*e36+e31*e32*e08+e31*e02*e38+e04*e33*e36+e04*e35*e38+e04*e34*e37+e34*e33*e06+e34*e03*e36+e34*e35*e08+e34*e05*e38+e37*e36*e06+e37*e38*e08-e37*e30*e00-e37*e32*e02-e37*e33*e03-e37*e35*e05+0.5*e312*e07+0.5*e342*e07+0.5*e07*e362+0.5*e07*e382+1.5*e07*e372-0.5*e07*e302-0.5*e07*e352-0.5*e07*e322-0.5*e07*e332; - A[5 + 10*17]=0.5*e312*e17+0.5*e342*e17+0.5*e17*e362+0.5*e17*e382+1.5*e17*e372-0.5*e17*e302-0.5*e17*e352-0.5*e17*e322-0.5*e17*e332-e37*e32*e12-e37*e33*e13+e11*e30*e36+e11*e32*e38+e11*e31*e37+e31*e30*e16+e31*e10*e36+e31*e32*e18+e31*e12*e38+e14*e33*e36+e14*e35*e38+e14*e34*e37+e34*e33*e16+e34*e13*e36+e34*e35*e18+e34*e15*e38+e37*e36*e16+e37*e38*e18-e37*e30*e10-e37*e35*e15; - A[5 + 10*18]=e21*e31*e37-0.5*e27*e332+e21*e30*e36+e21*e32*e38+e31*e30*e26+e31*e20*e36+e31*e32*e28+e31*e22*e38+e24*e33*e36+e24*e35*e38+e24*e34*e37+e34*e33*e26+e34*e23*e36+e34*e35*e28+e34*e25*e38+e37*e36*e26+e37*e38*e28-e37*e30*e20-e37*e32*e22-e37*e33*e23-e37*e35*e25+0.5*e312*e27+0.5*e342*e27+0.5*e27*e362+0.5*e27*e382+1.5*e27*e372-0.5*e27*e302-0.5*e27*e352-0.5*e27*e322; - A[5 + 10*19]=e31*e30*e36+e31*e32*e38+0.5*e312*e37+e34*e33*e36+e34*e35*e38+0.5*e342*e37+0.5*e37*e362+0.5*e37*e382+0.5*e373-0.5*e37*e302-0.5*e37*e352-0.5*e37*e322-0.5*e37*e332; - A[6 + 10*0]=0.5*e02*e002+0.5*e02*e012+0.5*e023+e05*e00*e03+e05*e01*e04+0.5*e02*e052+e08*e00*e06+e08*e01*e07+0.5*e02*e082-0.5*e02*e032-0.5*e02*e042-0.5*e02*e062-0.5*e02*e072; - A[6 + 10*1]=-0.5*e12*e042-0.5*e12*e062-0.5*e12*e072+0.5*e12*e082-0.5*e12*e032+1.5*e12*e022+0.5*e12*e002+0.5*e12*e012+0.5*e12*e052+e02*e10*e00+e02*e11*e01+e05*e10*e03+e05*e00*e13+e05*e11*e04+e05*e01*e14+e05*e02*e15+e15*e00*e03+e15*e01*e04+e08*e10*e06+e08*e00*e16+e08*e11*e07+e08*e01*e17+e08*e02*e18+e18*e00*e06+e18*e01*e07-e02*e13*e03-e02*e14*e04-e02*e16*e06-e02*e17*e07; - A[6 + 10*2]=0.5*e02*e102+1.5*e02*e122+0.5*e02*e112+0.5*e02*e152+0.5*e02*e182-0.5*e02*e162-0.5*e02*e172-0.5*e02*e132-0.5*e02*e142+e12*e10*e00+e12*e11*e01+e05*e10*e13+e05*e12*e15+e05*e11*e14+e15*e10*e03+e15*e00*e13+e15*e11*e04+e15*e01*e14+e08*e10*e16+e08*e12*e18+e08*e11*e17+e18*e10*e06+e18*e00*e16+e18*e11*e07+e18*e01*e17-e12*e13*e03-e12*e14*e04-e12*e16*e06-e12*e17*e07; - A[6 + 10*3]=0.5*e12*e102+0.5*e123+0.5*e12*e112+e15*e10*e13+0.5*e12*e152+e15*e11*e14+e18*e10*e16+0.5*e12*e182+e18*e11*e17-0.5*e12*e162-0.5*e12*e172-0.5*e12*e132-0.5*e12*e142; - A[6 + 10*4]=-0.5*e22*e032-0.5*e22*e042-0.5*e22*e062-0.5*e22*e072+0.5*e22*e082+1.5*e22*e022+0.5*e22*e002+0.5*e22*e012+0.5*e22*e052+e02*e20*e00+e02*e21*e01+e05*e20*e03+e05*e00*e23+e05*e21*e04+e05*e01*e24+e05*e02*e25+e25*e00*e03+e25*e01*e04+e08*e20*e06+e08*e00*e26+e08*e21*e07+e08*e01*e27+e08*e02*e28+e28*e00*e06+e28*e01*e07-e02*e27*e07-e02*e23*e03-e02*e24*e04-e02*e26*e06; - A[6 + 10*5]=-e22*e17*e07-e22*e16*e06-e22*e14*e04-e22*e13*e03-e12*e26*e06-e12*e24*e04-e12*e23*e03-e12*e27*e07-e02*e24*e14-e02*e23*e13-e02*e27*e17-e02*e26*e16+e28*e01*e17+e28*e11*e07+e28*e00*e16+e28*e10*e06+e18*e02*e28+e18*e01*e27+e18*e21*e07+e18*e00*e26+e18*e20*e06+e08*e11*e27+e08*e21*e17+e08*e12*e28+e08*e22*e18+e08*e10*e26+e25*e01*e14+e25*e11*e04+e25*e00*e13+e25*e10*e03+e15*e01*e24+e02*e21*e11+e12*e21*e01+e15*e02*e25+e15*e21*e04+e05*e22*e15+e05*e11*e24+e15*e20*e03+e15*e00*e23+e05*e10*e23+e05*e12*e25+e05*e21*e14+e22*e10*e00+e22*e11*e01+e02*e20*e10+3*e02*e22*e12+e12*e20*e00+e08*e20*e16+e05*e20*e13; - A[6 + 10*6]=-e12*e24*e14-e12*e23*e13-e12*e27*e17-e12*e26*e16+e28*e11*e17+e28*e10*e16+e18*e11*e27+e18*e21*e17+e18*e12*e28+e18*e10*e26+e18*e20*e16+e25*e11*e14+e25*e10*e13+e15*e11*e24+e15*e21*e14+e15*e12*e25+e15*e10*e23+e15*e20*e13+e12*e21*e11+0.5*e22*e182+0.5*e22*e152+1.5*e22*e122+0.5*e22*e102+e12*e20*e10+0.5*e22*e112-0.5*e22*e172-0.5*e22*e132-0.5*e22*e142-0.5*e22*e162; - A[6 + 10*7]=0.5*e02*e282+e28*e01*e27-e22*e27*e07-e22*e23*e03-e22*e24*e04-e22*e26*e06+0.5*e02*e252+e05*e20*e23+e05*e22*e25+e25*e20*e03+e25*e00*e23+e25*e21*e04+e25*e01*e24+e08*e20*e26+e08*e21*e27+e08*e22*e28+e28*e20*e06+e28*e00*e26+e28*e21*e07+e05*e21*e24+0.5*e02*e202+0.5*e02*e212+1.5*e02*e222+e22*e20*e00+e22*e21*e01-0.5*e02*e272-0.5*e02*e242-0.5*e02*e232-0.5*e02*e262; - A[6 + 10*8]=-e22*e27*e17-e22*e23*e13-e22*e24*e14-0.5*e12*e232-0.5*e12*e262-0.5*e12*e242-0.5*e12*e272+0.5*e12*e282+e18*e21*e27+e28*e20*e16+e28*e10*e26+e28*e21*e17+e28*e11*e27-e22*e26*e16+e18*e22*e28+0.5*e12*e252+0.5*e12*e202+0.5*e12*e212+1.5*e12*e222+e22*e20*e10+e15*e20*e23+e15*e21*e24+e15*e22*e25+e25*e20*e13+e25*e10*e23+e25*e21*e14+e25*e11*e24+e18*e20*e26+e22*e21*e11; - A[6 + 10*9]=0.5*e22*e202+0.5*e22*e212+0.5*e223+e25*e20*e23+e25*e21*e24+0.5*e22*e252+e28*e20*e26+e28*e21*e27+0.5*e22*e282-0.5*e22*e232-0.5*e22*e262-0.5*e22*e242-0.5*e22*e272; - A[6 + 10*10]=e08*e31*e07-0.5*e32*e032-e02*e33*e03-e02*e34*e04-e02*e36*e06-0.5*e32*e042-0.5*e32*e062-0.5*e32*e072+e38*e01*e07+e38*e00*e06-e02*e37*e07+e05*e31*e04+e05*e01*e34+e05*e02*e35+e35*e01*e04+e35*e00*e03+e08*e30*e06+e08*e00*e36+e08*e01*e37+e08*e02*e38+0.5*e32*e052+e02*e30*e00+e02*e31*e01+e05*e30*e03+e05*e00*e33+1.5*e32*e022+0.5*e32*e012+0.5*e32*e002+0.5*e32*e082; - A[6 + 10*11]=e05*e32*e15+e32*e11*e01+e38*e10*e06+e08*e12*e38-e32*e14*e04-e32*e16*e06-e32*e17*e07-e12*e36*e06-e32*e13*e03-e02*e34*e14-e12*e37*e07-e12*e33*e03-e12*e34*e04-e02*e37*e17-e02*e33*e13+e38*e01*e17-e02*e36*e16+e18*e01*e37+e18*e02*e38+e38*e00*e16+e38*e11*e07+e08*e30*e16+e08*e10*e36+e08*e32*e18+e08*e31*e17+e08*e11*e37+e18*e30*e06+e18*e00*e36+e18*e31*e07+e35*e10*e03+e35*e00*e13+e35*e11*e04+e35*e01*e14+e15*e02*e35+e05*e10*e33+e05*e12*e35+e05*e31*e14+e05*e11*e34+e15*e30*e03+e15*e00*e33+e15*e31*e04+e15*e01*e34+e05*e30*e13+e02*e30*e10+e02*e31*e11+3*e02*e32*e12+e12*e30*e00+e12*e31*e01+e32*e10*e00; - A[6 + 10*12]=0.5*e32*e102+0.5*e32*e112+e12*e30*e10+1.5*e32*e122+e12*e31*e11+e15*e30*e13+e15*e10*e33+e15*e12*e35+e15*e31*e14+e15*e11*e34+e35*e10*e13-0.5*e32*e162-0.5*e32*e172-0.5*e32*e132-0.5*e32*e142-e12*e37*e17-e12*e33*e13-e12*e34*e14+0.5*e32*e182+0.5*e32*e152+e35*e11*e14+e18*e30*e16+e18*e10*e36+e18*e12*e38+e18*e31*e17+e18*e11*e37+e38*e10*e16+e38*e11*e17-e12*e36*e16; - A[6 + 10*13]=3*e02*e32*e22+e05*e31*e24+e08*e22*e38+e02*e31*e21+e22*e30*e00+e22*e31*e01+e32*e20*e00+e32*e21*e01+e05*e30*e23+e05*e20*e33+e05*e21*e34-e22*e37*e07-e22*e33*e03-e22*e34*e04-e22*e36*e06-e32*e27*e07-e32*e23*e03-e32*e24*e04-e32*e26*e06+e05*e32*e25+e25*e30*e03+e25*e00*e33+e25*e31*e04+e25*e01*e34+e25*e02*e35+e35*e20*e03+e35*e00*e23+e35*e21*e04+e35*e01*e24+e08*e30*e26+e08*e20*e36+e08*e31*e27+e08*e21*e37+e08*e32*e28+e28*e30*e06+e28*e00*e36+e28*e31*e07+e28*e01*e37+e28*e02*e38+e38*e20*e06+e38*e00*e26+e38*e21*e07+e38*e01*e27-e02*e33*e23-e02*e36*e26-e02*e34*e24-e02*e37*e27+e05*e22*e35+e02*e30*e20; - A[6 + 10*14]=e18*e22*e38+e12*e31*e21+3*e12*e32*e22+e22*e30*e10+e22*e31*e11+e32*e20*e10+e32*e21*e11+e15*e30*e23+e15*e20*e33+e15*e31*e24+e15*e21*e34+e15*e32*e25+e15*e22*e35+e25*e30*e13+e25*e10*e33+e25*e12*e35+e25*e31*e14+e25*e11*e34+e35*e20*e13+e35*e10*e23+e35*e21*e14+e35*e11*e24+e18*e30*e26+e18*e20*e36+e18*e31*e27+e18*e21*e37+e18*e32*e28+e28*e30*e16+e28*e10*e36+e28*e12*e38+e28*e31*e17+e28*e11*e37+e38*e20*e16+e38*e10*e26+e12*e30*e20-e22*e37*e17-e22*e33*e13-e22*e34*e14-e32*e26*e16-e32*e27*e17-e32*e23*e13-e32*e24*e14-e22*e36*e16+e38*e21*e17+e38*e11*e27-e12*e33*e23-e12*e36*e26-e12*e34*e24-e12*e37*e27; - A[6 + 10*15]=e25*e30*e23+e22*e30*e20+e22*e31*e21+e25*e20*e33+e25*e31*e24+e25*e21*e34+e25*e22*e35+e35*e20*e23+e35*e21*e24+e28*e30*e26+e28*e20*e36+e28*e31*e27+e28*e21*e37+e28*e22*e38+e38*e20*e26+e38*e21*e27-e22*e33*e23-e22*e36*e26-e22*e34*e24-e22*e37*e27+0.5*e32*e212+0.5*e32*e252+1.5*e32*e222+0.5*e32*e202+0.5*e32*e282-0.5*e32*e232-0.5*e32*e262-0.5*e32*e242-0.5*e32*e272; - A[6 + 10*16]=0.5*e02*e302+1.5*e02*e322+0.5*e02*e312+0.5*e02*e352+0.5*e02*e382-0.5*e02*e342-0.5*e02*e362-0.5*e02*e332-0.5*e02*e372+e38*e30*e06+e32*e30*e00+e32*e31*e01+e05*e30*e33+e05*e32*e35+e05*e31*e34+e35*e30*e03+e35*e00*e33+e35*e31*e04+e35*e01*e34+e08*e30*e36+e08*e32*e38+e08*e31*e37+e38*e00*e36+e38*e31*e07+e38*e01*e37-e32*e37*e07-e32*e33*e03-e32*e34*e04-e32*e36*e06; - A[6 + 10*17]=e32*e30*e10+e32*e31*e11+e15*e30*e33+e15*e32*e35+e15*e31*e34+e35*e30*e13+e35*e10*e33+e35*e31*e14+e35*e11*e34+e18*e30*e36+e18*e32*e38+e18*e31*e37+e38*e30*e16+e38*e10*e36+e38*e31*e17+e38*e11*e37-e32*e36*e16-e32*e37*e17-e32*e33*e13-e32*e34*e14+0.5*e12*e382-0.5*e12*e342-0.5*e12*e362-0.5*e12*e332-0.5*e12*e372+0.5*e12*e352+1.5*e12*e322+0.5*e12*e312+0.5*e12*e302; - A[6 + 10*18]=0.5*e22*e302+0.5*e22*e312+0.5*e22*e352+0.5*e22*e382-0.5*e22*e342-0.5*e22*e362-0.5*e22*e332-0.5*e22*e372+1.5*e22*e322+e32*e30*e20+e32*e31*e21+e25*e30*e33+e25*e32*e35+e25*e31*e34+e35*e30*e23+e35*e20*e33+e35*e31*e24+e35*e21*e34+e28*e30*e36+e28*e32*e38+e28*e31*e37+e38*e30*e26+e38*e20*e36+e38*e31*e27+e38*e21*e37-e32*e33*e23-e32*e36*e26-e32*e34*e24-e32*e37*e27; - A[6 + 10*19]=0.5*e32*e302+0.5*e323+0.5*e32*e312+e35*e30*e33+0.5*e32*e352+e35*e31*e34+e38*e30*e36+0.5*e32*e382+e38*e31*e37-0.5*e32*e342-0.5*e32*e362-0.5*e32*e332-0.5*e32*e372; - A[7 + 10*0]=e02*e01*e04+e02*e00*e03+0.5*e022*e05+0.5*e05*e032+0.5*e05*e042+0.5*e053+e08*e03*e06+e08*e04*e07+0.5*e05*e082-0.5*e05*e002-0.5*e05*e062-0.5*e05*e012-0.5*e05*e072; - A[7 + 10*1]=e08*e13*e06+e02*e10*e03+e02*e00*e13+e02*e11*e04+e02*e01*e14+e02*e12*e05+e12*e01*e04+e12*e00*e03+e05*e13*e03+e05*e14*e04+e08*e03*e16+e08*e14*e07+e08*e04*e17+e08*e05*e18+e18*e03*e06+e18*e04*e07-e05*e10*e00-e05*e11*e01-e05*e16*e06-e05*e17*e07+0.5*e022*e15+1.5*e15*e052+0.5*e15*e032+0.5*e15*e042+0.5*e15*e082-0.5*e15*e002-0.5*e15*e062-0.5*e15*e012-0.5*e15*e072; - A[7 + 10*2]=0.5*e122*e05+0.5*e05*e132+1.5*e05*e152+0.5*e05*e142+0.5*e05*e182-0.5*e05*e102-0.5*e05*e162-0.5*e05*e112-0.5*e05*e172+e02*e10*e13+e02*e12*e15+e02*e11*e14+e12*e10*e03+e12*e00*e13+e12*e11*e04+e12*e01*e14+e15*e13*e03+e15*e14*e04+e08*e13*e16+e08*e15*e18+e08*e14*e17+e18*e13*e06+e18*e03*e16+e18*e14*e07+e18*e04*e17-e15*e11*e01-e15*e16*e06-e15*e17*e07-e15*e10*e00; - A[7 + 10*3]=e12*e10*e13+0.5*e122*e15+e12*e11*e14+0.5*e15*e132+0.5*e153+0.5*e15*e142+e18*e13*e16+0.5*e15*e182+e18*e14*e17-0.5*e15*e102-0.5*e15*e162-0.5*e15*e112-0.5*e15*e172; - A[7 + 10*4]=0.5*e25*e082-0.5*e25*e002-0.5*e25*e062-0.5*e25*e012-0.5*e25*e072+e02*e20*e03+e02*e00*e23+e02*e21*e04+e02*e01*e24+e02*e22*e05+e22*e01*e04+e22*e00*e03+e05*e23*e03+e05*e24*e04+e08*e23*e06+e08*e03*e26+e08*e24*e07+e08*e04*e27+e08*e05*e28+e28*e03*e06+e28*e04*e07-e05*e20*e00-e05*e27*e07-e05*e21*e01-e05*e26*e06+0.5*e022*e25+1.5*e25*e052+0.5*e25*e032+0.5*e25*e042; - A[7 + 10*5]=-e25*e17*e07-e25*e16*e06-e25*e11*e01-e25*e10*e00-e15*e26*e06-e15*e21*e01-e15*e27*e07-e15*e20*e00-e05*e27*e17-e05*e21*e11-e05*e26*e16-e05*e20*e10+e28*e04*e17+e28*e14*e07+e28*e03*e16+e28*e13*e06+e18*e05*e28+e18*e04*e27+e18*e24*e07+e18*e03*e26+e18*e23*e06+e08*e14*e27+e08*e24*e17+e08*e15*e28+e08*e25*e18+e08*e13*e26+e08*e23*e16+e25*e14*e04+e25*e13*e03+e15*e24*e04+e15*e23*e03+e05*e24*e14+3*e05*e25*e15+e05*e23*e13+e22*e01*e14+e22*e11*e04+e22*e00*e13+e22*e10*e03+e12*e22*e05+e12*e01*e24+e12*e21*e04+e12*e00*e23+e12*e20*e03+e02*e11*e24+e02*e21*e14+e02*e12*e25+e02*e22*e15+e02*e10*e23+e02*e20*e13; - A[7 + 10*6]=-e15*e27*e17-e15*e21*e11-e15*e26*e16+e28*e14*e17+e28*e13*e16+e18*e14*e27+e18*e24*e17+e18*e15*e28+e18*e13*e26+e15*e24*e14+e15*e23*e13+e22*e11*e14+e22*e10*e13+e12*e11*e24+e12*e21*e14+e12*e22*e15+e12*e10*e23+e18*e23*e16+0.5*e25*e142+0.5*e25*e182+1.5*e25*e152+0.5*e25*e132+0.5*e122*e25+e12*e20*e13-0.5*e25*e172-0.5*e25*e162-0.5*e25*e112-0.5*e25*e102-e15*e20*e10; - A[7 + 10*7]=e28*e24*e07-0.5*e05*e272-0.5*e05*e262-0.5*e05*e212+0.5*e05*e282-0.5*e05*e202+e28*e23*e06+e08*e23*e26+e08*e25*e28+e08*e24*e27+e28*e03*e26+e28*e04*e27-e25*e27*e07-e25*e21*e01-e25*e26*e06+e02*e20*e23+e02*e22*e25+e02*e21*e24+e22*e20*e03+e22*e00*e23+e22*e21*e04+e22*e01*e24+e25*e23*e03+e25*e24*e04+0.5*e222*e05+0.5*e05*e232+1.5*e05*e252+0.5*e05*e242-e25*e20*e00; - A[7 + 10*8]=-0.5*e15*e202-0.5*e15*e262-0.5*e15*e212-0.5*e15*e272+e18*e23*e26+e18*e25*e28+e18*e24*e27+e28*e23*e16+e28*e13*e26+e28*e24*e17+e28*e14*e27-e25*e20*e10-e25*e26*e16-e25*e21*e11-e25*e27*e17+0.5*e15*e282+0.5*e15*e232+1.5*e15*e252+0.5*e15*e242+0.5*e222*e15+e12*e21*e24+e22*e20*e13+e22*e10*e23+e22*e21*e14+e22*e11*e24+e25*e23*e13+e25*e24*e14+e12*e20*e23+e12*e22*e25; - A[7 + 10*9]=e22*e20*e23+0.5*e222*e25+e22*e21*e24+0.5*e25*e232+0.5*e253+0.5*e25*e242+e28*e23*e26+0.5*e25*e282+e28*e24*e27-0.5*e25*e202-0.5*e25*e262-0.5*e25*e212-0.5*e25*e272; - A[7 + 10*10]=-0.5*e35*e062-0.5*e35*e012-0.5*e35*e072-e05*e30*e00-e05*e31*e01-e05*e36*e06-e05*e37*e07-0.5*e35*e002+0.5*e35*e082+e05*e34*e04+e08*e33*e06+e08*e03*e36+e08*e34*e07+e08*e04*e37+e08*e05*e38+e38*e04*e07+e38*e03*e06+0.5*e022*e35+1.5*e35*e052+0.5*e35*e042+0.5*e35*e032+e02*e30*e03+e02*e00*e33+e02*e31*e04+e02*e01*e34+e02*e32*e05+e32*e01*e04+e32*e00*e03+e05*e33*e03; - A[7 + 10*11]=e08*e33*e16-e35*e16*e06-e35*e17*e07-e15*e30*e00-e15*e37*e07-e15*e31*e01-e15*e36*e06-e35*e10*e00-e35*e11*e01-e05*e37*e17-e05*e31*e11+e38*e04*e17-e05*e30*e10-e05*e36*e16+e18*e33*e06+e18*e03*e36+e18*e34*e07+e18*e04*e37+e18*e05*e38+e38*e13*e06+e38*e03*e16+e38*e14*e07+e35*e14*e04+e08*e13*e36+e08*e35*e18+e08*e15*e38+e08*e34*e17+e08*e14*e37+e35*e13*e03+e05*e33*e13+3*e05*e35*e15+e05*e34*e14+e15*e33*e03+e15*e34*e04+e12*e01*e34+e12*e32*e05+e32*e10*e03+e32*e00*e13+e32*e11*e04+e32*e01*e14+e12*e30*e03+e02*e30*e13+e02*e32*e15+e02*e10*e33+e02*e12*e35+e12*e00*e33+e02*e31*e14+e02*e11*e34+e12*e31*e04; - A[7 + 10*12]=-0.5*e35*e162-0.5*e35*e172-e15*e36*e16-e15*e31*e11-e15*e37*e17-0.5*e35*e102-0.5*e35*e112-e15*e30*e10+e18*e13*e36+e18*e15*e38+e18*e34*e17+e18*e14*e37+e38*e13*e16+e38*e14*e17+e18*e33*e16+1.5*e35*e152+0.5*e35*e132+0.5*e35*e142+0.5*e35*e182+0.5*e122*e35+e32*e10*e13+e32*e11*e14+e15*e33*e13+e15*e34*e14+e12*e10*e33+e12*e32*e15+e12*e31*e14+e12*e11*e34+e12*e30*e13; - A[7 + 10*13]=e05*e33*e23+3*e05*e35*e25+e05*e34*e24+e25*e33*e03+e25*e34*e04+e35*e23*e03+e35*e24*e04+e08*e33*e26+e08*e23*e36+e08*e35*e28+e02*e20*e33+e02*e32*e25+e02*e22*e35+e02*e31*e24+e02*e21*e34+e22*e30*e03+e22*e00*e33+e22*e31*e04+e22*e01*e34+e22*e32*e05+e32*e20*e03+e32*e00*e23+e32*e21*e04+e32*e01*e24+e02*e30*e23-e35*e27*e07-e35*e21*e01-e35*e26*e06+e08*e25*e38+e08*e34*e27+e08*e24*e37+e28*e33*e06+e28*e03*e36+e28*e34*e07+e28*e04*e37+e28*e05*e38+e38*e23*e06+e38*e03*e26+e38*e24*e07+e38*e04*e27-e05*e30*e20-e05*e36*e26-e05*e31*e21-e05*e37*e27-e25*e30*e00-e25*e37*e07-e25*e31*e01-e25*e36*e06-e35*e20*e00; - A[7 + 10*14]=e12*e21*e34+e18*e25*e38+e12*e30*e23+e12*e20*e33+e12*e32*e25+e12*e22*e35+e12*e31*e24+e22*e30*e13+e22*e10*e33+e22*e32*e15+e22*e31*e14+e22*e11*e34+e32*e20*e13+e32*e10*e23+e32*e21*e14-e25*e30*e10-e25*e36*e16-e25*e31*e11-e25*e37*e17-e35*e20*e10-e35*e26*e16-e35*e21*e11-e35*e27*e17+e15*e33*e23+3*e15*e35*e25+e15*e34*e24+e25*e33*e13+e25*e34*e14+e35*e23*e13+e35*e24*e14+e18*e33*e26+e18*e23*e36+e18*e35*e28+e18*e34*e27+e18*e24*e37+e28*e33*e16+e28*e13*e36+e28*e15*e38+e28*e34*e17+e28*e14*e37+e38*e23*e16+e38*e13*e26+e38*e24*e17+e38*e14*e27-e15*e30*e20-e15*e36*e26-e15*e31*e21-e15*e37*e27+e32*e11*e24; - A[7 + 10*15]=-0.5*e35*e202-0.5*e35*e262-0.5*e35*e212-0.5*e35*e272+e25*e34*e24+e28*e23*e36+e28*e25*e38+e28*e34*e27+e28*e24*e37+e38*e23*e26+e38*e24*e27-e25*e30*e20-e25*e36*e26-e25*e31*e21-e25*e37*e27+e25*e33*e23+0.5*e222*e35+1.5*e35*e252+0.5*e35*e232+0.5*e35*e242+0.5*e35*e282+e22*e30*e23+e22*e20*e33+e22*e32*e25+e22*e31*e24+e22*e21*e34+e32*e20*e23+e32*e21*e24+e28*e33*e26; - A[7 + 10*16]=-e35*e30*e00-e35*e31*e01-e35*e36*e06-e35*e37*e07+0.5*e322*e05+0.5*e05*e332+0.5*e05*e342+1.5*e05*e352+0.5*e05*e382-0.5*e05*e302-0.5*e05*e362-0.5*e05*e312-0.5*e05*e372+e02*e30*e33+e02*e31*e34+e02*e32*e35+e32*e30*e03+e32*e00*e33+e32*e31*e04+e32*e01*e34+e35*e33*e03+e35*e34*e04+e08*e33*e36+e08*e34*e37+e08*e35*e38+e38*e33*e06+e38*e03*e36+e38*e34*e07+e38*e04*e37; - A[7 + 10*17]=-e35*e30*e10+e12*e32*e35-0.5*e15*e362-0.5*e15*e312-0.5*e15*e372-e35*e36*e16+0.5*e322*e15+0.5*e15*e332+0.5*e15*e342+1.5*e15*e352+0.5*e15*e382-0.5*e15*e302+e12*e30*e33+e12*e31*e34+e32*e30*e13+e32*e10*e33+e32*e31*e14+e32*e11*e34+e35*e33*e13+e35*e34*e14+e18*e33*e36+e18*e34*e37+e18*e35*e38+e38*e33*e16+e38*e13*e36+e38*e34*e17+e38*e14*e37-e35*e31*e11-e35*e37*e17; - A[7 + 10*18]=-0.5*e25*e302-0.5*e25*e362-0.5*e25*e312-0.5*e25*e372+0.5*e322*e25+0.5*e25*e332+0.5*e25*e342+1.5*e25*e352+0.5*e25*e382+e22*e30*e33+e22*e31*e34+e22*e32*e35+e32*e30*e23+e32*e20*e33+e32*e31*e24+e32*e21*e34+e35*e33*e23+e35*e34*e24+e28*e33*e36+e28*e34*e37+e28*e35*e38+e38*e33*e26+e38*e23*e36+e38*e34*e27+e38*e24*e37-e35*e30*e20-e35*e36*e26-e35*e31*e21-e35*e37*e27; - A[7 + 10*19]=e32*e30*e33+e32*e31*e34+0.5*e322*e35+0.5*e35*e332+0.5*e35*e342+0.5*e353+e38*e33*e36+e38*e34*e37+0.5*e35*e382-0.5*e35*e302-0.5*e35*e362-0.5*e35*e312-0.5*e35*e372; - A[8 + 10*0]=e02*e00*e06+e02*e01*e07+0.5*e022*e08+e05*e04*e07+e05*e03*e06+0.5*e052*e08+0.5*e08*e062+0.5*e08*e072+0.5*e083-0.5*e08*e042-0.5*e08*e002-0.5*e08*e012-0.5*e08*e032; - A[8 + 10*1]=e02*e10*e06+e02*e00*e16+e02*e11*e07+e02*e01*e17+e02*e12*e08+e12*e00*e06+e12*e01*e07+e05*e13*e06+e05*e03*e16+e05*e14*e07+e05*e04*e17+e05*e15*e08+e15*e04*e07+e15*e03*e06+e08*e16*e06+e08*e17*e07-e08*e10*e00-e08*e11*e01-e08*e13*e03-e08*e14*e04+0.5*e022*e18+0.5*e052*e18+1.5*e18*e082+0.5*e18*e062+0.5*e18*e072-0.5*e18*e042-0.5*e18*e002-0.5*e18*e012-0.5*e18*e032; - A[8 + 10*2]=e12*e01*e17+0.5*e152*e08+0.5*e08*e162+1.5*e08*e182+0.5*e08*e172-0.5*e08*e102-0.5*e08*e112-0.5*e08*e132-0.5*e08*e142+e05*e13*e16+e05*e14*e17+e05*e15*e18+e15*e13*e06+e15*e03*e16+e15*e14*e07+e15*e04*e17+e18*e16*e06+e18*e17*e07-e18*e10*e00-e18*e11*e01-e18*e13*e03-e18*e14*e04+0.5*e122*e08+e02*e10*e16+e02*e12*e18+e02*e11*e17+e12*e10*e06+e12*e00*e16+e12*e11*e07; - A[8 + 10*3]=e12*e10*e16+0.5*e122*e18+e12*e11*e17+e15*e13*e16+e15*e14*e17+0.5*e152*e18+0.5*e18*e162+0.5*e183+0.5*e18*e172-0.5*e18*e102-0.5*e18*e112-0.5*e18*e132-0.5*e18*e142; - A[8 + 10*4]=-e08*e20*e00+e08*e27*e07-e08*e21*e01-e08*e23*e03-e08*e24*e04+e02*e20*e06+e02*e00*e26+e02*e21*e07+e02*e01*e27+e02*e22*e08+e22*e00*e06+e22*e01*e07+e05*e23*e06+e05*e03*e26+e05*e24*e07+e05*e04*e27+e05*e25*e08+e25*e04*e07+e25*e03*e06+e08*e26*e06+0.5*e022*e28+0.5*e052*e28+1.5*e28*e082+0.5*e28*e062+0.5*e28*e072-0.5*e28*e042-0.5*e28*e002-0.5*e28*e012-0.5*e28*e032; - A[8 + 10*5]=e22*e10*e06+e22*e11*e07+e22*e01*e17+e05*e23*e16+e05*e13*e26+e05*e25*e18+e05*e15*e28+e05*e24*e17+e05*e14*e27+e15*e23*e06+e15*e03*e26+e15*e24*e07+e15*e04*e27+e15*e25*e08+e25*e13*e06+e25*e03*e16+e25*e14*e07+e25*e04*e17+e08*e26*e16+3*e08*e28*e18+e08*e27*e17+e18*e26*e06+e18*e27*e07+e22*e00*e16+e28*e16*e06+e28*e17*e07-e08*e20*e10-e08*e21*e11-e08*e23*e13-e08*e24*e14-e18*e20*e00-e18*e21*e01-e18*e23*e03-e18*e24*e04-e28*e10*e00-e28*e11*e01-e28*e13*e03-e28*e14*e04+e02*e20*e16+e02*e10*e26+e02*e22*e18+e02*e12*e28+e02*e21*e17+e02*e11*e27+e12*e20*e06+e12*e00*e26+e12*e21*e07+e12*e01*e27+e12*e22*e08; - A[8 + 10*6]=-e18*e24*e14-e18*e21*e11-e18*e23*e13-e18*e20*e10+e18*e27*e17+e18*e26*e16+e25*e14*e17+e25*e13*e16+e15*e25*e18+e15*e14*e27+e15*e24*e17+e15*e13*e26+e15*e23*e16+e22*e11*e17+e22*e10*e16+e12*e11*e27+e12*e21*e17+e12*e22*e18+e12*e10*e26+e12*e20*e16+0.5*e28*e162+0.5*e28*e172+1.5*e28*e182+0.5*e152*e28-0.5*e28*e142-0.5*e28*e112-0.5*e28*e132-0.5*e28*e102+0.5*e122*e28; - A[8 + 10*7]=-e28*e24*e04-e28*e21*e01-e28*e23*e03-e28*e20*e00+e28*e27*e07+e28*e26*e06+e25*e04*e27+e25*e24*e07+e25*e03*e26+e05*e24*e27+e05*e25*e28+e05*e23*e26+e22*e01*e27+e22*e21*e07+e22*e00*e26+e22*e20*e06+e02*e22*e28+e02*e20*e26+e02*e21*e27+0.5*e222*e08-0.5*e08*e242-0.5*e08*e212-0.5*e08*e232-0.5*e08*e202+0.5*e08*e262+0.5*e08*e272+1.5*e08*e282+0.5*e252*e08+e25*e23*e06; - A[8 + 10*8]=e25*e24*e17+e25*e14*e27+e28*e26*e16+e28*e27*e17-e28*e21*e11-e28*e24*e14+e12*e22*e28+e22*e10*e26+e22*e21*e17+e22*e11*e27+e15*e23*e26+e15*e25*e28+e15*e24*e27+e25*e23*e16+e25*e13*e26+e22*e20*e16+0.5*e222*e18+0.5*e252*e18+0.5*e18*e262+0.5*e18*e272+e12*e20*e26+e12*e21*e27-e28*e20*e10-0.5*e18*e232-0.5*e18*e242-e28*e23*e13-0.5*e18*e212+1.5*e18*e282-0.5*e18*e202; - A[8 + 10*9]=e22*e20*e26+e22*e21*e27+0.5*e222*e28+e25*e23*e26+0.5*e252*e28+e25*e24*e27+0.5*e28*e262+0.5*e28*e272+0.5*e283-0.5*e28*e202-0.5*e28*e212-0.5*e28*e232-0.5*e28*e242; - A[8 + 10*10]=-e08*e30*e00-0.5*e38*e042-0.5*e38*e002-0.5*e38*e012-0.5*e38*e032+1.5*e38*e082+0.5*e38*e062+0.5*e38*e072+e32*e01*e07+e05*e33*e06+e05*e03*e36+e05*e34*e07+e05*e04*e37+e05*e35*e08+e35*e04*e07+e35*e03*e06+e08*e36*e06+e08*e37*e07+0.5*e052*e38+e32*e00*e06+e02*e30*e06+e02*e00*e36+e02*e31*e07+e02*e01*e37+e02*e32*e08+0.5*e022*e38-e08*e33*e03-e08*e31*e01-e08*e34*e04; - A[8 + 10*11]=-e38*e11*e01-e38*e14*e04-e38*e10*e00-e38*e13*e03-e18*e30*e00-e18*e33*e03-e18*e31*e01-e18*e34*e04-e08*e30*e10-e08*e33*e13-e08*e31*e11-e08*e34*e14+3*e08*e38*e18+e08*e37*e17+e18*e36*e06+e18*e37*e07+e38*e16*e06+e38*e17*e07+e15*e35*e08+e35*e13*e06+e35*e03*e16+e35*e14*e07+e35*e04*e17+e08*e36*e16+e05*e35*e18+e05*e15*e38+e15*e33*e06+e15*e03*e36+e15*e34*e07+e15*e04*e37+e05*e14*e37+e12*e30*e06+e12*e31*e07+e12*e01*e37+e12*e00*e36+e12*e32*e08+e32*e10*e06+e32*e00*e16+e32*e11*e07+e32*e01*e17+e05*e33*e16+e05*e13*e36+e05*e34*e17+e02*e30*e16+e02*e10*e36+e02*e32*e18+e02*e12*e38+e02*e31*e17+e02*e11*e37; - A[8 + 10*12]=e12*e30*e16+e12*e10*e36+e12*e32*e18+e12*e31*e17+e12*e11*e37+e32*e10*e16+e32*e11*e17+e15*e33*e16+e15*e13*e36-0.5*e38*e102-0.5*e38*e112-0.5*e38*e132-0.5*e38*e142+0.5*e38*e162+0.5*e38*e172+e15*e34*e17+e15*e14*e37+e15*e35*e18+e35*e13*e16+e35*e14*e17+e18*e36*e16+e18*e37*e17-e18*e30*e10-e18*e33*e13-e18*e31*e11-e18*e34*e14+0.5*e122*e38+0.5*e152*e38+1.5*e38*e182; - A[8 + 10*13]=e22*e30*e06-e28*e34*e04+e05*e35*e28+e02*e22*e38+e22*e00*e36+e22*e31*e07+e22*e01*e37+e02*e32*e28+e02*e21*e37-e38*e20*e00-e28*e31*e01-e38*e23*e03-e38*e21*e01-e38*e24*e04-e28*e30*e00-e08*e30*e20-e08*e31*e21-e08*e33*e23-e08*e34*e24-e28*e33*e03+e35*e24*e07+e35*e04*e27+e08*e36*e26+e08*e37*e27+3*e08*e38*e28+e28*e36*e06+e28*e37*e07+e38*e26*e06+e38*e27*e07+e25*e04*e37+e25*e35*e08+e35*e23*e06+e35*e03*e26+e05*e23*e36+e05*e25*e38+e05*e34*e27+e05*e24*e37+e25*e33*e06+e25*e03*e36+e25*e34*e07+e05*e33*e26+e32*e21*e07+e32*e01*e27+e22*e32*e08+e32*e20*e06+e32*e00*e26+e02*e30*e26+e02*e20*e36+e02*e31*e27; - A[8 + 10*14]=e35*e13*e26-e38*e21*e11-e38*e24*e14+e35*e24*e17+e35*e14*e27+e18*e36*e26+e18*e37*e27+3*e18*e38*e28+e28*e36*e16+e28*e37*e17+e38*e26*e16+e38*e27*e17-e18*e30*e20-e18*e31*e21-e18*e33*e23-e18*e34*e24-e28*e30*e10-e28*e33*e13-e28*e31*e11-e28*e34*e14-e38*e20*e10-e38*e23*e13+e35*e23*e16+e12*e20*e36+e12*e30*e26+e12*e31*e27+e12*e21*e37+e12*e32*e28+e12*e22*e38+e22*e30*e16+e22*e10*e36+e22*e32*e18+e22*e31*e17+e22*e11*e37+e32*e20*e16+e32*e10*e26+e32*e21*e17+e32*e11*e27+e15*e33*e26+e15*e23*e36+e15*e35*e28+e15*e25*e38+e15*e34*e27+e15*e24*e37+e25*e33*e16+e25*e13*e36+e25*e34*e17+e25*e14*e37+e25*e35*e18; - A[8 + 10*15]=-e28*e30*e20+e22*e30*e26+e22*e20*e36+e22*e31*e27+e22*e21*e37+e22*e32*e28+e32*e20*e26+e32*e21*e27+e25*e33*e26+e25*e23*e36+e25*e35*e28+e25*e34*e27+e25*e24*e37+e35*e23*e26+e35*e24*e27+e28*e36*e26+e28*e37*e27-e28*e31*e21-e28*e33*e23-e28*e34*e24-0.5*e38*e242+0.5*e252*e38+1.5*e38*e282+0.5*e38*e262+0.5*e38*e272-0.5*e38*e202-0.5*e38*e212-0.5*e38*e232+0.5*e222*e38; - A[8 + 10*16]=-0.5*e08*e312-0.5*e08*e342+0.5*e352*e08+0.5*e08*e362+1.5*e08*e382+0.5*e08*e372-0.5*e08*e302-0.5*e08*e332+e02*e30*e36+e02*e32*e38+e02*e31*e37+e32*e30*e06+e32*e00*e36+e32*e31*e07+e32*e01*e37+e05*e33*e36+e05*e34*e37+e05*e35*e38+e35*e33*e06+e35*e03*e36+e35*e34*e07+e35*e04*e37+0.5*e322*e08+e38*e36*e06+e38*e37*e07-e38*e30*e00-e38*e33*e03-e38*e31*e01-e38*e34*e04; - A[8 + 10*17]=-e38*e30*e10+e38*e36*e16+e38*e37*e17-e38*e33*e13-e38*e31*e11-e38*e34*e14+0.5*e18*e362+e12*e30*e36+e12*e32*e38+e12*e31*e37+e32*e30*e16+e32*e10*e36+e32*e31*e17+e32*e11*e37+e15*e33*e36+e15*e34*e37+e15*e35*e38+e35*e33*e16+e35*e13*e36+e35*e34*e17+e35*e14*e37+0.5*e322*e18+0.5*e352*e18+1.5*e18*e382+0.5*e18*e372-0.5*e18*e302-0.5*e18*e332-0.5*e18*e312-0.5*e18*e342; - A[8 + 10*18]=-e38*e30*e20+e25*e35*e38+e22*e30*e36+e22*e32*e38+e22*e31*e37+e32*e30*e26+e32*e20*e36+e32*e31*e27+e32*e21*e37+e25*e33*e36+e25*e34*e37+e35*e33*e26+e35*e23*e36+e35*e34*e27+e35*e24*e37+e38*e36*e26+e38*e37*e27-e38*e31*e21-e38*e33*e23-e38*e34*e24-0.5*e28*e332-0.5*e28*e312-0.5*e28*e342+0.5*e322*e28+0.5*e352*e28+0.5*e28*e362+1.5*e28*e382+0.5*e28*e372-0.5*e28*e302; - A[8 + 10*19]=e32*e30*e36+0.5*e322*e38+e32*e31*e37+e35*e33*e36+e35*e34*e37+0.5*e352*e38+0.5*e38*e362+0.5*e383+0.5*e38*e372-0.5*e38*e302-0.5*e38*e332-0.5*e38*e312-0.5*e38*e342; - A[9 + 10*0]=e00*e04*e08-e00*e05*e07+e03*e02*e07-e03*e01*e08-e06*e02*e04+e06*e01*e05; - A[9 + 10*1]=e06*e01*e15-e16*e02*e04+e16*e01*e05+e03*e02*e17-e13*e01*e08+e06*e11*e05+e13*e02*e07+e00*e04*e18+e00*e14*e08-e00*e05*e17-e10*e05*e07-e00*e15*e07-e06*e12*e04-e06*e02*e14-e03*e01*e18-e03*e11*e08+e10*e04*e08+e03*e12*e07; - A[9 + 10*2]=-e13*e01*e18-e13*e11*e08+e13*e12*e07+e13*e02*e17+e03*e12*e17-e10*e15*e07+e10*e04*e18+e10*e14*e08-e10*e05*e17-e00*e15*e17+e00*e14*e18+e16*e01*e15+e06*e11*e15-e06*e12*e14-e16*e12*e04-e16*e02*e14+e16*e11*e05-e03*e11*e18; - A[9 + 10*3]=e10*e14*e18-e10*e15*e17-e13*e11*e18+e13*e12*e17+e16*e11*e15-e16*e12*e14; - A[9 + 10*4]=-e20*e05*e07+e03*e22*e07+e06*e21*e05+e06*e01*e25-e23*e01*e08+e23*e02*e07+e00*e24*e08-e00*e25*e07-e00*e05*e27+e00*e04*e28-e06*e22*e04-e06*e02*e24-e03*e21*e08-e03*e01*e28-e26*e02*e04+e26*e01*e05+e03*e02*e27+e20*e04*e08; - A[9 + 10*5]=e23*e12*e07-e26*e02*e14+e16*e21*e05-e23*e11*e08+e10*e24*e08-e20*e05*e17+e26*e11*e05+e26*e01*e15+e10*e04*e28+e00*e24*e18-e00*e15*e27+e03*e22*e17-e13*e01*e28+e23*e02*e17+e16*e01*e25+e20*e04*e18+e06*e11*e25+e13*e02*e27-e23*e01*e18-e20*e15*e07-e10*e25*e07+e13*e22*e07-e06*e22*e14-e26*e12*e04-e03*e11*e28-e03*e21*e18-e16*e22*e04-e16*e02*e24-e06*e12*e24+e06*e21*e15+e00*e14*e28-e00*e25*e17+e20*e14*e08-e13*e21*e08-e10*e05*e27+e03*e12*e27; - A[9 + 10*6]=-e13*e11*e28+e13*e12*e27+e13*e22*e17+e16*e11*e25+e10*e14*e28-e13*e21*e18-e23*e11*e18+e23*e12*e17+e20*e14*e18-e20*e15*e17+e26*e11*e15-e10*e15*e27-e10*e25*e17-e16*e22*e14-e16*e12*e24+e16*e21*e15-e26*e12*e14+e10*e24*e18; - A[9 + 10*7]=e26*e21*e05+e26*e01*e25+e20*e04*e28+e20*e24*e08-e20*e25*e07+e23*e22*e07+e03*e22*e27-e03*e21*e28-e26*e22*e04-e20*e05*e27-e00*e25*e27+e06*e21*e25-e06*e22*e24+e00*e24*e28-e26*e02*e24-e23*e21*e08-e23*e01*e28+e23*e02*e27; - A[9 + 10*8]=-e10*e25*e27+e10*e24*e28-e20*e15*e27-e20*e25*e17+e20*e14*e28+e20*e24*e18+e26*e11*e25+e23*e22*e17-e23*e11*e28+e23*e12*e27-e23*e21*e18-e13*e21*e28+e13*e22*e27-e26*e12*e24+e26*e21*e15-e16*e22*e24+e16*e21*e25-e26*e22*e14; - A[9 + 10*9]=-e20*e25*e27+e20*e24*e28-e23*e21*e28+e23*e22*e27-e26*e22*e24+e26*e21*e25; - A[9 + 10*10]=e03*e02*e37-e03*e31*e08-e03*e01*e38+e03*e32*e07-e00*e35*e07+e30*e04*e08+e06*e31*e05-e36*e02*e04+e36*e01*e05-e06*e32*e04-e06*e02*e34+e06*e01*e35+e00*e04*e38-e00*e05*e37+e33*e02*e07-e33*e01*e08-e30*e05*e07+e00*e34*e08; - A[9 + 10*11]=-e36*e12*e04+e30*e04*e18-e30*e15*e07-e36*e02*e14-e30*e05*e17+e30*e14*e08-e00*e35*e17-e00*e15*e37+e33*e02*e17-e06*e32*e14-e06*e12*e34-e16*e32*e04+e06*e31*e15+e06*e11*e35+e00*e34*e18-e10*e35*e07-e33*e11*e08-e33*e01*e18+e16*e01*e35-e16*e02*e34+e16*e31*e05-e03*e31*e18-e03*e11*e38+e03*e32*e17+e13*e02*e37-e13*e31*e08-e13*e01*e38+e10*e34*e08+e00*e14*e38+e36*e11*e05+e36*e01*e15+e03*e12*e37-e10*e05*e37+e10*e04*e38+e33*e12*e07+e13*e32*e07; - A[9 + 10*12]=-e36*e12*e14-e30*e15*e17+e13*e32*e17-e13*e31*e18-e33*e11*e18+e33*e12*e17+e10*e14*e38+e30*e14*e18-e13*e11*e38+e13*e12*e37-e10*e35*e17+e10*e34*e18-e16*e12*e34-e16*e32*e14+e16*e11*e35+e16*e31*e15+e36*e11*e15-e10*e15*e37; - A[9 + 10*13]=-e06*e22*e34-e06*e32*e24-e00*e25*e37-e00*e35*e27+e23*e02*e37+e00*e24*e38-e23*e01*e38-e03*e31*e28-e33*e01*e28+e03*e22*e37+e03*e32*e27+e33*e02*e27-e03*e21*e38-e26*e32*e04-e33*e21*e08+e36*e01*e25+e36*e21*e05-e20*e05*e37+e20*e04*e38+e30*e04*e28-e20*e35*e07+e33*e22*e07+e30*e24*e08-e30*e25*e07-e23*e31*e08+e23*e32*e07+e00*e34*e28+e06*e21*e35+e06*e31*e25-e36*e02*e24+e26*e01*e35-e36*e22*e04+e26*e31*e05-e26*e02*e34+e20*e34*e08-e30*e05*e27; - A[9 + 10*14]=e33*e22*e17+e33*e12*e27+e16*e21*e35-e16*e22*e34-e16*e32*e24+e23*e32*e17-e23*e11*e38-e23*e31*e18+e23*e12*e37-e13*e21*e38-e13*e31*e28+e13*e22*e37+e36*e21*e15-e36*e12*e24+e36*e11*e25-e26*e12*e34-e20*e35*e17+e20*e14*e38+e20*e34*e18+e30*e24*e18-e30*e15*e27-e30*e25*e17+e30*e14*e28-e33*e21*e18+e10*e34*e28+e10*e24*e38-e10*e35*e27-e10*e25*e37-e20*e15*e37-e26*e32*e14+e26*e11*e35+e26*e31*e15-e36*e22*e14+e13*e32*e27+e16*e31*e25-e33*e11*e28; - A[9 + 10*15]=-e20*e35*e27-e20*e25*e37+e20*e34*e28+e20*e24*e38+e30*e24*e28-e30*e25*e27+e23*e32*e27+e23*e22*e37-e23*e31*e28-e23*e21*e38+e33*e22*e27-e26*e22*e34-e26*e32*e24+e26*e21*e35+e26*e31*e25-e36*e22*e24+e36*e21*e25-e33*e21*e28; - A[9 + 10*16]=-e33*e01*e38-e03*e31*e38+e00*e34*e38+e33*e32*e07+e03*e32*e37+e06*e31*e35-e00*e35*e37-e36*e32*e04-e06*e32*e34-e36*e02*e34+e36*e01*e35+e36*e31*e05+e30*e04*e38+e30*e34*e08-e33*e31*e08+e33*e02*e37-e30*e05*e37-e30*e35*e07; - A[9 + 10*17]=-e33*e31*e18-e33*e11*e38+e10*e34*e38+e30*e14*e38-e10*e35*e37-e30*e15*e37-e13*e31*e38+e13*e32*e37-e30*e35*e17+e33*e12*e37+e30*e34*e18+e33*e32*e17+e16*e31*e35-e16*e32*e34-e36*e12*e34-e36*e32*e14+e36*e11*e35+e36*e31*e15; - A[9 + 10*18]=-e20*e35*e37+e20*e34*e38+e30*e24*e38-e30*e35*e27-e30*e25*e37+e30*e34*e28+e23*e32*e37-e23*e31*e38-e33*e21*e38-e33*e31*e28+e33*e22*e37+e33*e32*e27+e26*e31*e35-e26*e32*e34-e36*e22*e34-e36*e32*e24+e36*e21*e35+e36*e31*e25; - A[9 + 10*19]=-e33*e31*e38-e30*e35*e37+e36*e31*e35+e33*e32*e37+e30*e34*e38-e36*e32*e34; - -} - - - - diff --git a/modules/calib3d/src/fundam.cpp b/modules/calib3d/src/fundam.cpp index f15dac1f9d..f28885acf8 100644 --- a/modules/calib3d/src/fundam.cpp +++ b/modules/calib3d/src/fundam.cpp @@ -7,10 +7,11 @@ // copy or use the software. // // -// Intel License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -23,7 +24,7 @@ // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // -// * The name of Intel Corporation may not be used to endorse or promote products +// * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and @@ -40,11 +41,35 @@ //M*/ #include "precomp.hpp" -#include "_modelest.h" +#include -using namespace cv; +namespace cv +{ -template int icvCompressPoints( T* ptr, const uchar* mask, int mstep, int count ) +static bool haveCollinearPoints( const Mat& m, int count ) +{ + int j, k, i = count-1; + const Point2f* ptr = m.ptr(); + + // check that the i-th selected point does not belong + // to a line connecting some previously selected points + for( j = 0; j < i; j++ ) + { + double dx1 = ptr[j].x - ptr[i].x; + double dy1 = ptr[j].y - ptr[i].y; + for( k = 0; k < j; k++ ) + { + double dx2 = ptr[k].x - ptr[i].x; + double dy2 = ptr[k].y - ptr[i].y; + if( fabs(dx2*dy1 - dy2*dx1) <= FLT_EPSILON*(fabs(dx1) + fabs(dy1) + fabs(dx2) + fabs(dy2))) + return true; + } + } + return false; +} + + +template int compressPoints( T* ptr, const uchar* mask, int mstep, int count ) { int i, j; for( i = j = 0; i < count; i++ ) @@ -57,308 +82,280 @@ template int icvCompressPoints( T* ptr, const uchar* mask, int mstep return j; } -class CvHomographyEstimator : public CvModelEstimator2 + +class HomographyEstimatorCallback : public PointSetRegistrator::Callback { public: - CvHomographyEstimator( int modelPoints ); - - virtual int runKernel( const CvMat* m1, const CvMat* m2, CvMat* model ); - virtual bool refine( const CvMat* m1, const CvMat* m2, - CvMat* model, int maxIters ); -protected: - virtual void computeReprojError( const CvMat* m1, const CvMat* m2, - const CvMat* model, CvMat* error ); - virtual bool isMinimalSetConsistent( const CvMat* m1, const CvMat* m2 ); - virtual bool weakConstraint ( const CvMat* srcPoints, const CvMat* dstPoints, int t1, int t2, int t3 ); -}; + bool checkSubset( InputArray _ms1, InputArray _ms2, int count ) const + { + Mat ms1 = _ms1.getMat(), ms2 = _ms2.getMat(); + if( haveCollinearPoints(ms1, count) || haveCollinearPoints(ms2, count) ) + return false; + + // We check whether the minimal set of points for the homography estimation + // are geometrically consistent. We check if every 3 correspondences sets + // fulfills the constraint. + // + // The usefullness of this constraint is explained in the paper: + // + // "Speeding-up homography estimation in mobile devices" + // Journal of Real-Time Image Processing. 2013. DOI: 10.1007/s11554-012-0314-1 + // Pablo Marquez-Neila, Javier Lopez-Alberca, Jose M. Buenaposada, Luis Baumela + if( count == 4 ) + { + static const int tt[][3] = {{0, 1, 2}, {1, 2, 3}, {0, 2, 3}, {0, 1, 3}}; + const Point2f* src = ms1.ptr(); + const Point2f* dst = ms2.ptr(); + int negative = 0; + for( int i = 0; i < 4; i++ ) + { + const int* t = tt[i]; + Matx33d A(src[t[0]].x, src[t[0]].y, 1., src[t[1]].x, src[t[1]].y, 1., src[t[2]].x, src[t[2]].y, 1.); + Matx33d B(dst[t[0]].x, dst[t[0]].y, 1., dst[t[1]].x, dst[t[1]].y, 1., dst[t[2]].x, dst[t[2]].y, 1.); -CvHomographyEstimator::CvHomographyEstimator(int _modelPoints) - : CvModelEstimator2(_modelPoints, cvSize(3,3), 1) -{ - assert( _modelPoints == 4 || _modelPoints == 5 ); - checkPartialSubsets = false; -} + negative += determinant(A)*determinant(B) < 0; + } + if( negative != 0 && negative != 4 ) + return false; + } -int CvHomographyEstimator::runKernel( const CvMat* m1, const CvMat* m2, CvMat* H ) -{ - int i, count = m1->rows*m1->cols; - const CvPoint2D64f* M = (const CvPoint2D64f*)m1->data.ptr; - const CvPoint2D64f* m = (const CvPoint2D64f*)m2->data.ptr; - - double LtL[9][9], W[9][1], V[9][9]; - CvMat _LtL = cvMat( 9, 9, CV_64F, LtL ); - CvMat matW = cvMat( 9, 1, CV_64F, W ); - CvMat matV = cvMat( 9, 9, CV_64F, V ); - CvMat _H0 = cvMat( 3, 3, CV_64F, V[8] ); - CvMat _Htemp = cvMat( 3, 3, CV_64F, V[7] ); - CvPoint2D64f cM={0,0}, cm={0,0}, sM={0,0}, sm={0,0}; + return true; + } - for( i = 0; i < count; i++ ) + int runKernel( InputArray _m1, InputArray _m2, OutputArray _model ) const { - cm.x += m[i].x; cm.y += m[i].y; - cM.x += M[i].x; cM.y += M[i].y; - } + Mat m1 = _m1.getMat(), m2 = _m2.getMat(); + int i, count = m1.checkVector(2); + const Point2f* M = m1.ptr(); + const Point2f* m = m2.ptr(); - cm.x /= count; cm.y /= count; - cM.x /= count; cM.y /= count; + double LtL[9][9], W[9][1], V[9][9]; + Mat _LtL( 9, 9, CV_64F, LtL ); + Mat matW( 9, 1, CV_64F, W ); + Mat matV( 9, 9, CV_64F, V ); + Mat _H0( 3, 3, CV_64F, V[8] ); + Mat _Htemp( 3, 3, CV_64F, V[7] ); + Point2d cM(0,0), cm(0,0), sM(0,0), sm(0,0); - for( i = 0; i < count; i++ ) - { - sm.x += fabs(m[i].x - cm.x); - sm.y += fabs(m[i].y - cm.y); - sM.x += fabs(M[i].x - cM.x); - sM.y += fabs(M[i].y - cM.y); - } + for( i = 0; i < count; i++ ) + { + cm.x += m[i].x; cm.y += m[i].y; + cM.x += M[i].x; cM.y += M[i].y; + } - if( fabs(sm.x) < DBL_EPSILON || fabs(sm.y) < DBL_EPSILON || - fabs(sM.x) < DBL_EPSILON || fabs(sM.y) < DBL_EPSILON ) - return 0; - sm.x = count/sm.x; sm.y = count/sm.y; - sM.x = count/sM.x; sM.y = count/sM.y; + cm.x /= count; + cm.y /= count; + cM.x /= count; + cM.y /= count; + + for( i = 0; i < count; i++ ) + { + sm.x += fabs(m[i].x - cm.x); + sm.y += fabs(m[i].y - cm.y); + sM.x += fabs(M[i].x - cM.x); + sM.y += fabs(M[i].y - cM.y); + } - double invHnorm[9] = { 1./sm.x, 0, cm.x, 0, 1./sm.y, cm.y, 0, 0, 1 }; - double Hnorm2[9] = { sM.x, 0, -cM.x*sM.x, 0, sM.y, -cM.y*sM.y, 0, 0, 1 }; - CvMat _invHnorm = cvMat( 3, 3, CV_64FC1, invHnorm ); - CvMat _Hnorm2 = cvMat( 3, 3, CV_64FC1, Hnorm2 ); + if( fabs(sm.x) < DBL_EPSILON || fabs(sm.y) < DBL_EPSILON || + fabs(sM.x) < DBL_EPSILON || fabs(sM.y) < DBL_EPSILON ) + return 0; + sm.x = count/sm.x; sm.y = count/sm.y; + sM.x = count/sM.x; sM.y = count/sM.y; - cvZero( &_LtL ); - for( i = 0; i < count; i++ ) - { - double x = (m[i].x - cm.x)*sm.x, y = (m[i].y - cm.y)*sm.y; - double X = (M[i].x - cM.x)*sM.x, Y = (M[i].y - cM.y)*sM.y; - double Lx[] = { X, Y, 1, 0, 0, 0, -x*X, -x*Y, -x }; - double Ly[] = { 0, 0, 0, X, Y, 1, -y*X, -y*Y, -y }; - int j, k; - for( j = 0; j < 9; j++ ) - for( k = j; k < 9; k++ ) - LtL[j][k] += Lx[j]*Lx[k] + Ly[j]*Ly[k]; + double invHnorm[9] = { 1./sm.x, 0, cm.x, 0, 1./sm.y, cm.y, 0, 0, 1 }; + double Hnorm2[9] = { sM.x, 0, -cM.x*sM.x, 0, sM.y, -cM.y*sM.y, 0, 0, 1 }; + Mat _invHnorm( 3, 3, CV_64FC1, invHnorm ); + Mat _Hnorm2( 3, 3, CV_64FC1, Hnorm2 ); + + _LtL.setTo(Scalar::all(0)); + for( i = 0; i < count; i++ ) + { + double x = (m[i].x - cm.x)*sm.x, y = (m[i].y - cm.y)*sm.y; + double X = (M[i].x - cM.x)*sM.x, Y = (M[i].y - cM.y)*sM.y; + double Lx[] = { X, Y, 1, 0, 0, 0, -x*X, -x*Y, -x }; + double Ly[] = { 0, 0, 0, X, Y, 1, -y*X, -y*Y, -y }; + int j, k; + for( j = 0; j < 9; j++ ) + for( k = j; k < 9; k++ ) + LtL[j][k] += Lx[j]*Lx[k] + Ly[j]*Ly[k]; + } + completeSymm( _LtL ); + + eigen( _LtL, matW, matV ); + _Htemp = _invHnorm*_H0; + _H0 = _Htemp*_Hnorm2; + _H0.convertTo(_model, _H0.type(), 1./_H0.at(2,2) ); + + return 1; } - cvCompleteSymm( &_LtL ); - //cvSVD( &_LtL, &matW, 0, &matV, CV_SVD_MODIFY_A + CV_SVD_V_T ); - cvEigenVV( &_LtL, &matV, &matW ); - cvMatMul( &_invHnorm, &_H0, &_Htemp ); - cvMatMul( &_Htemp, &_Hnorm2, &_H0 ); - cvConvertScale( &_H0, H, 1./_H0.data.db[8] ); + void computeError( InputArray _m1, InputArray _m2, InputArray _model, OutputArray _err ) const + { + Mat m1 = _m1.getMat(), m2 = _m2.getMat(), model = _model.getMat(); + int i, count = m1.checkVector(2); + const Point2f* M = m1.ptr(); + const Point2f* m = m2.ptr(); + const double* H = model.ptr(); + float Hf[] = { (float)H[0], (float)H[1], (float)H[2], (float)H[3], (float)H[4], (float)H[5], (float)H[6], (float)H[7] }; - return 1; -} + _err.create(count, 1, CV_32F); + float* err = _err.getMat().ptr(); + for( i = 0; i < count; i++ ) + { + float ww = 1.f/(Hf[6]*M[i].x + Hf[7]*M[i].y + 1.f); + float dx = (Hf[0]*M[i].x + Hf[1]*M[i].y + Hf[2])*ww - m[i].x; + float dy = (Hf[3]*M[i].x + Hf[4]*M[i].y + Hf[5])*ww - m[i].y; + err[i] = (float)(dx*dx + dy*dy); + } + } +}; -void CvHomographyEstimator::computeReprojError( const CvMat* m1, const CvMat* m2, - const CvMat* model, CvMat* _err ) -{ - int i, count = m1->rows*m1->cols; - const CvPoint2D64f* M = (const CvPoint2D64f*)m1->data.ptr; - const CvPoint2D64f* m = (const CvPoint2D64f*)m2->data.ptr; - const double* H = model->data.db; - float* err = _err->data.fl; - for( i = 0; i < count; i++ ) +class HomographyRefineCallback : public LMSolver::Callback +{ +public: + HomographyRefineCallback(InputArray _src, InputArray _dst) { - double ww = 1./(H[6]*M[i].x + H[7]*M[i].y + 1.); - double dx = (H[0]*M[i].x + H[1]*M[i].y + H[2])*ww - m[i].x; - double dy = (H[3]*M[i].x + H[4]*M[i].y + H[5])*ww - m[i].y; - err[i] = (float)(dx*dx + dy*dy); + src = _src.getMat(); + dst = _dst.getMat(); } -} -bool CvHomographyEstimator::refine( const CvMat* m1, const CvMat* m2, CvMat* model, int maxIters ) -{ - CvLevMarq solver(8, 0, cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, maxIters, DBL_EPSILON)); - int i, j, k, count = m1->rows*m1->cols; - const CvPoint2D64f* M = (const CvPoint2D64f*)m1->data.ptr; - const CvPoint2D64f* m = (const CvPoint2D64f*)m2->data.ptr; - CvMat modelPart = cvMat( solver.param->rows, solver.param->cols, model->type, model->data.ptr ); - cvCopy( &modelPart, solver.param ); - - for(;;) + bool compute(InputArray _param, OutputArray _err, OutputArray _Jac) const { - const CvMat* _param = 0; - CvMat *_JtJ = 0, *_JtErr = 0; - double* _errNorm = 0; + int i, count = src.checkVector(2); + Mat param = _param.getMat(); + _err.create(count*2, 1, CV_64F); + Mat err = _err.getMat(), J; + if( _Jac.needed()) + { + _Jac.create(count*2, param.rows, CV_64F); + J = _Jac.getMat(); + CV_Assert( J.isContinuous() && J.cols == 8 ); + } - if( !solver.updateAlt( _param, _JtJ, _JtErr, _errNorm )) - break; + const Point2f* M = src.ptr(); + const Point2f* m = dst.ptr(); + const double* h = param.ptr(); + double* errptr = err.ptr(); + double* Jptr = J.data ? J.ptr() : 0; for( i = 0; i < count; i++ ) { - const double* h = _param->data.db; double Mx = M[i].x, My = M[i].y; double ww = h[6]*Mx + h[7]*My + 1.; ww = fabs(ww) > DBL_EPSILON ? 1./ww : 0; - double _xi = (h[0]*Mx + h[1]*My + h[2])*ww; - double _yi = (h[3]*Mx + h[4]*My + h[5])*ww; - double err[] = { _xi - m[i].x, _yi - m[i].y }; - if( _JtJ || _JtErr ) + double xi = (h[0]*Mx + h[1]*My + h[2])*ww; + double yi = (h[3]*Mx + h[4]*My + h[5])*ww; + errptr[i*2] = xi - m[i].x; + errptr[i*2+1] = yi - m[i].y; + + if( Jptr ) { - double J[][8] = - { - { Mx*ww, My*ww, ww, 0, 0, 0, -Mx*ww*_xi, -My*ww*_xi }, - { 0, 0, 0, Mx*ww, My*ww, ww, -Mx*ww*_yi, -My*ww*_yi } - }; - - for( j = 0; j < 8; j++ ) - { - for( k = j; k < 8; k++ ) - _JtJ->data.db[j*8+k] += J[0][j]*J[0][k] + J[1][j]*J[1][k]; - _JtErr->data.db[j] += J[0][j]*err[0] + J[1][j]*err[1]; - } + Jptr[0] = Mx*ww; Jptr[1] = My*ww; Jptr[2] = ww; + Jptr[3] = Jptr[4] = Jptr[5] = 0.; + Jptr[6] = -Mx*ww*xi; Jptr[7] = -My*ww*xi; + Jptr[8] = Jptr[9] = Jptr[10] = 0.; + Jptr[11] = Mx*ww; Jptr[12] = My*ww; Jptr[13] = ww; + Jptr[14] = -Mx*ww*yi; Jptr[15] = -My*ww*yi; } - if( _errNorm ) - *_errNorm += err[0]*err[0] + err[1]*err[1]; } + + return true; } - cvCopy( solver.param, &modelPart ); - return true; + Mat src, dst; +}; + } -CV_IMPL int -cvFindHomography( const CvMat* objectPoints, const CvMat* imagePoints, - CvMat* __H, int method, double ransacReprojThreshold, - CvMat* mask ) +cv::Mat cv::findHomography( InputArray _points1, InputArray _points2, + int method, double ransacReprojThreshold, OutputArray _mask ) { const double confidence = 0.995; const int maxIters = 2000; const double defaultRANSACReprojThreshold = 3; bool result = false; - Ptr m, M, tempMask; - double H[9]; - CvMat matH = cvMat( 3, 3, CV_64FC1, H ); - int count; + Mat points1 = _points1.getMat(), points2 = _points2.getMat(); + Mat src, dst, H, tempMask; + int npoints = -1; + + for( int i = 1; i <= 2; i++ ) + { + Mat& p = i == 1 ? points1 : points2; + Mat& m = i == 1 ? src : dst; + npoints = p.checkVector(2, -1, false); + if( npoints < 0 ) + { + npoints = p.checkVector(3, -1, false); + if( npoints < 0 ) + CV_Error(CV_StsBadArg, "The input arrays should be 2D or 3D point sets"); + if( npoints == 0 ) + return Mat(); + convertPointsFromHomogeneous(p, p); + } + p.reshape(2, npoints).convertTo(m, CV_32F); + } - CV_Assert( CV_IS_MAT(imagePoints) && CV_IS_MAT(objectPoints) ); + CV_Assert( src.checkVector(2) == dst.checkVector(2) ); - count = MAX(imagePoints->cols, imagePoints->rows); - CV_Assert( count >= 4 ); if( ransacReprojThreshold <= 0 ) ransacReprojThreshold = defaultRANSACReprojThreshold; - m = cvCreateMat( 1, count, CV_64FC2 ); - cvConvertPointsHomogeneous( imagePoints, m ); - - M = cvCreateMat( 1, count, CV_64FC2 ); - cvConvertPointsHomogeneous( objectPoints, M ); + Ptr cb = new HomographyEstimatorCallback; - if( mask ) + if( method == 0 || npoints == 4 ) { - CV_Assert( CV_IS_MASK_ARR(mask) && CV_IS_MAT_CONT(mask->type) && - (mask->rows == 1 || mask->cols == 1) && - mask->rows*mask->cols == count ); + tempMask = Mat::ones(npoints, 1, CV_8U); + result = cb->runKernel(src, dst, H) > 0; } - if( mask || count > 4 ) - tempMask = cvCreateMat( 1, count, CV_8U ); - if( !tempMask.empty() ) - cvSet( tempMask, cvScalarAll(1.) ); - - CvHomographyEstimator estimator(4); - if( count == 4 ) - method = 0; - if( method == CV_LMEDS ) - result = estimator.runLMeDS( M, m, &matH, tempMask, confidence, maxIters ); - else if( method == CV_RANSAC ) - result = estimator.runRANSAC( M, m, &matH, tempMask, ransacReprojThreshold, confidence, maxIters); + else if( method == RANSAC ) + result = createRANSACPointSetRegistrator(cb, 4, ransacReprojThreshold, confidence, maxIters)->run(src, dst, H, tempMask); + else if( method == LMEDS ) + result = createLMeDSPointSetRegistrator(cb, 4, confidence, maxIters)->run(src, dst, H, tempMask); else - result = estimator.runKernel( M, m, &matH ) > 0; + CV_Error(CV_StsBadArg, "Unknown estimation method"); - if( result && count > 4 ) + if( result && npoints > 4 ) { - icvCompressPoints( (CvPoint2D64f*)M->data.ptr, tempMask->data.ptr, 1, count ); - count = icvCompressPoints( (CvPoint2D64f*)m->data.ptr, tempMask->data.ptr, 1, count ); - M->cols = m->cols = count; - if( method == CV_RANSAC ) - estimator.runKernel( M, m, &matH ); - estimator.refine( M, m, &matH, 10 ); + compressPoints( src.ptr(), tempMask.ptr(), 1, npoints ); + npoints = compressPoints( dst.ptr(), tempMask.ptr(), 1, npoints ); + if( npoints > 0 ) + { + Mat src1 = src.rowRange(0, npoints); + Mat dst1 = dst.rowRange(0, npoints); + src = src1; + dst = dst1; + if( method == RANSAC || method == LMEDS ) + cb->runKernel( src, dst, H ); + Mat H8(8, 1, CV_64F, H.ptr()); + createLMSolver(new HomographyRefineCallback(src, dst), 10)->run(H8); + } } if( result ) - cvConvert( &matH, __H ); - - if( mask && tempMask ) { - if( CV_ARE_SIZES_EQ(mask, tempMask) ) - cvCopy( tempMask, mask ); - else - cvTranspose( tempMask, mask ); + if( _mask.needed() ) + tempMask.copyTo(_mask); } + else + H.release(); - return (int)result; + return H; } -// We check whether three correspondences for the homography estimation -// are geometrically consistent (the points in the source image should -// maintain the same circular order than in the destination image). -// -// The usefullness of this constraint is explained in the paper: -// -// "Speeding-up homography estimation in mobile devices" -// Journal of Real-Time Image Processing. 2013. DOI: 10.1007/s11554-012-0314-1 -// Pablo Marquez-Neila, Javier Lopez-Alberca, Jose M. Buenaposada, Luis Baumela -bool -CvHomographyEstimator::weakConstraint ( const CvMat* srcPoints, const CvMat* dstPoints, int t1, int t2, int t3 ) -{ - const CvPoint2D64f* src = (const CvPoint2D64f*)srcPoints->data.ptr; - const CvPoint2D64f* dst = (const CvPoint2D64f*)dstPoints->data.ptr; - - CvMat* A = cvCreateMat( 3, 3, CV_64F ); - CvMat* B = cvCreateMat( 3, 3, CV_64F ); - - double detA; - double detB; - - cvmSet(A, 0, 0, src[t1].x); - cvmSet(A, 0, 1, src[t1].y); - cvmSet(A, 0, 2, 1); - cvmSet(A, 1, 0, src[t2].x); - cvmSet(A, 1, 1, src[t2].y); - cvmSet(A, 1, 2, 1); - cvmSet(A, 2, 0, src[t3].x); - cvmSet(A, 2, 1, src[t3].y); - cvmSet(A, 2, 2, 1); - - cvmSet(B, 0, 0, dst[t1].x); - cvmSet(B, 0, 1, dst[t1].y); - cvmSet(B, 0, 2, 1); - cvmSet(B, 1, 0, dst[t2].x); - cvmSet(B, 1, 1, dst[t2].y); - cvmSet(B, 1, 2, 1); - cvmSet(B, 2, 0, dst[t3].x); - cvmSet(B, 2, 1, dst[t3].y); - cvmSet(B, 2, 2, 1); - - detA = cvDet(A); - detB = cvDet(B); - - cvReleaseMat(&A); - cvReleaseMat(&B); - - return (detA*detB >= 0); -}; - -// We check whether the minimal set of points for the homography estimation -// are geometrically consistent. We check if every 3 correspondences sets -// fulfills the constraint. -// -// The usefullness of this constraint is explained in the paper: -// -// "Speeding-up homography estimation in mobile devices" -// Journal of Real-Time Image Processing. 2013. DOI: 10.1007/s11554-012-0314-1 -// Pablo Marquez-Neila, Javier Lopez-Alberca, Jose M. Buenaposada, Luis Baumela -bool -CvHomographyEstimator::isMinimalSetConsistent ( const CvMat* srcPoints, const CvMat* dstPoints ) +cv::Mat cv::findHomography( InputArray _points1, InputArray _points2, + OutputArray _mask, int method, double ransacReprojThreshold ) { - return weakConstraint(srcPoints, dstPoints, 0, 1, 2) && - weakConstraint(srcPoints, dstPoints, 1, 2, 3) && - weakConstraint(srcPoints, dstPoints, 0, 2, 3) && - weakConstraint(srcPoints, dstPoints, 0, 1, 3); + return cv::findHomography(_points1, _points2, method, ransacReprojThreshold, _mask); } -/* Evaluation of Fundamental Matrix from point correspondences. + +/* Estimation of Fundamental Matrix from point correspondences. The original code has been written by Valery Mosyagin */ /* The algorithms (except for RANSAC) and the notation have been taken from @@ -367,44 +364,23 @@ CvHomographyEstimator::isMinimalSetConsistent ( const CvMat* srcPoints, const Cv that can be found at http://www-sop.inria.fr/robotvis/personnel/zzhang/zzhang-eng.html */ /************************************** 7-point algorithm *******************************/ -class CvFMEstimator : public CvModelEstimator2 +namespace cv { -public: - CvFMEstimator( int _modelPoints ); - - virtual int runKernel( const CvMat* m1, const CvMat* m2, CvMat* model ); - virtual int run7Point( const CvMat* m1, const CvMat* m2, CvMat* model ); - virtual int run8Point( const CvMat* m1, const CvMat* m2, CvMat* model ); -protected: - virtual void computeReprojError( const CvMat* m1, const CvMat* m2, - const CvMat* model, CvMat* error ); -}; -CvFMEstimator::CvFMEstimator( int _modelPoints ) -: CvModelEstimator2( _modelPoints, cvSize(3,3), _modelPoints == 7 ? 3 : 1 ) +static int run7Point( const Mat& _m1, const Mat& _m2, Mat& _fmatrix ) { - assert( _modelPoints == 7 || _modelPoints == 8 ); -} - - -int CvFMEstimator::runKernel( const CvMat* m1, const CvMat* m2, CvMat* model ) -{ - return modelPoints == 7 ? run7Point( m1, m2, model ) : run8Point( m1, m2, model ); -} - -int CvFMEstimator::run7Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatrix ) -{ - double a[7*9], w[7], v[9*9], c[4], r[3]; + double a[7*9], w[7], u[9*9], v[9*9], c[4], r[3]; double* f1, *f2; double t0, t1, t2; - CvMat A = cvMat( 7, 9, CV_64F, a ); - CvMat V = cvMat( 9, 9, CV_64F, v ); - CvMat W = cvMat( 7, 1, CV_64F, w ); - CvMat coeffs = cvMat( 1, 4, CV_64F, c ); - CvMat roots = cvMat( 1, 3, CV_64F, r ); - const CvPoint2D64f* m1 = (const CvPoint2D64f*)_m1->data.ptr; - const CvPoint2D64f* m2 = (const CvPoint2D64f*)_m2->data.ptr; - double* fmatrix = _fmatrix->data.db; + Mat A( 7, 9, CV_64F, a ); + Mat U( 7, 9, CV_64F, u ); + Mat Vt( 9, 9, CV_64F, v ); + Mat W( 7, 1, CV_64F, w ); + Mat coeffs( 1, 4, CV_64F, c ); + Mat roots( 1, 3, CV_64F, r ); + const Point2f* m1 = _m1.ptr(); + const Point2f* m2 = _m2.ptr(); + double* fmatrix = _fmatrix.ptr(); int i, k, n; // form a linear system: i-th row of A(=a) represents @@ -429,7 +405,7 @@ int CvFMEstimator::run7Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatri // the solution is linear subspace of dimensionality 2. // => use the last two singular vectors as a basis of the space // (according to SVD properties) - cvSVD( &A, &W, 0, &V, CV_SVD_MODIFY_A + CV_SVD_V_T ); + SVDecomp( A, W, U, Vt, SVD::MODIFY_A + SVD::FULL_UV ); f1 = v + 7*9; f2 = v + 8*9; @@ -449,29 +425,29 @@ int CvFMEstimator::run7Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatri c[3] = f2[0]*t0 - f2[1]*t1 + f2[2]*t2; c[2] = f1[0]*t0 - f1[1]*t1 + f1[2]*t2 - - f1[3]*(f2[1]*f2[8] - f2[2]*f2[7]) + - f1[4]*(f2[0]*f2[8] - f2[2]*f2[6]) - - f1[5]*(f2[0]*f2[7] - f2[1]*f2[6]) + - f1[6]*(f2[1]*f2[5] - f2[2]*f2[4]) - - f1[7]*(f2[0]*f2[5] - f2[2]*f2[3]) + - f1[8]*(f2[0]*f2[4] - f2[1]*f2[3]); + f1[3]*(f2[1]*f2[8] - f2[2]*f2[7]) + + f1[4]*(f2[0]*f2[8] - f2[2]*f2[6]) - + f1[5]*(f2[0]*f2[7] - f2[1]*f2[6]) + + f1[6]*(f2[1]*f2[5] - f2[2]*f2[4]) - + f1[7]*(f2[0]*f2[5] - f2[2]*f2[3]) + + f1[8]*(f2[0]*f2[4] - f2[1]*f2[3]); t0 = f1[4]*f1[8] - f1[5]*f1[7]; t1 = f1[3]*f1[8] - f1[5]*f1[6]; t2 = f1[3]*f1[7] - f1[4]*f1[6]; c[1] = f2[0]*t0 - f2[1]*t1 + f2[2]*t2 - - f2[3]*(f1[1]*f1[8] - f1[2]*f1[7]) + - f2[4]*(f1[0]*f1[8] - f1[2]*f1[6]) - - f2[5]*(f1[0]*f1[7] - f1[1]*f1[6]) + - f2[6]*(f1[1]*f1[5] - f1[2]*f1[4]) - - f2[7]*(f1[0]*f1[5] - f1[2]*f1[3]) + - f2[8]*(f1[0]*f1[4] - f1[1]*f1[3]); + f2[3]*(f1[1]*f1[8] - f1[2]*f1[7]) + + f2[4]*(f1[0]*f1[8] - f1[2]*f1[6]) - + f2[5]*(f1[0]*f1[7] - f1[1]*f1[6]) + + f2[6]*(f1[1]*f1[5] - f1[2]*f1[4]) - + f2[7]*(f1[0]*f1[5] - f1[2]*f1[3]) + + f2[8]*(f1[0]*f1[4] - f1[1]*f1[3]); c[0] = f1[0]*t0 - f1[1]*t1 + f1[2]*t2; // solve the cubic equation; there can be 1 to 3 roots ... - n = cvSolveCubic( &coeffs, &roots ); + n = solveCubic( coeffs, roots ); if( n < 1 || n > 3 ) return n; @@ -499,77 +475,77 @@ int CvFMEstimator::run7Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatri return n; } - -int CvFMEstimator::run8Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatrix ) + +static int run8Point( const Mat& _m1, const Mat& _m2, Mat& _fmatrix ) { double a[9*9], w[9], v[9*9]; - CvMat W = cvMat( 1, 9, CV_64F, w ); - CvMat V = cvMat( 9, 9, CV_64F, v ); - CvMat A = cvMat( 9, 9, CV_64F, a ); - CvMat U, F0, TF; + Mat W( 9, 1, CV_64F, w ); + Mat V( 9, 9, CV_64F, v ); + Mat A( 9, 9, CV_64F, a ); + Mat U, F0, TF; - CvPoint2D64f m0c = {0,0}, m1c = {0,0}; - double t, scale0 = 0, scale1 = 0; + Point2d m1c(0,0), m2c(0,0); + double t, scale1 = 0, scale2 = 0; - const CvPoint2D64f* m1 = (const CvPoint2D64f*)_m1->data.ptr; - const CvPoint2D64f* m2 = (const CvPoint2D64f*)_m2->data.ptr; - double* fmatrix = _fmatrix->data.db; - CV_Assert( (_m1->cols == 1 || _m1->rows == 1) && CV_ARE_SIZES_EQ(_m1, _m2)); - int i, j, k, count = _m1->cols*_m1->rows; + const Point2f* m1 = _m1.ptr(); + const Point2f* m2 = _m2.ptr(); + double* fmatrix = _fmatrix.ptr(); + CV_Assert( (_m1.cols == 1 || _m1.rows == 1) && _m1.size() == _m2.size()); + int i, j, k, count = _m1.checkVector(2); // compute centers and average distances for each of the two point sets for( i = 0; i < count; i++ ) { double x = m1[i].x, y = m1[i].y; - m0c.x += x; m0c.y += y; + m1c.x += x; m1c.y += y; x = m2[i].x, y = m2[i].y; - m1c.x += x; m1c.y += y; + m2c.x += x; m2c.y += y; } // calculate the normalizing transformations for each of the point sets: // after the transformation each set will have the mass center at the coordinate origin // and the average distance from the origin will be ~sqrt(2). t = 1./count; - m0c.x *= t; m0c.y *= t; m1c.x *= t; m1c.y *= t; + m2c.x *= t; m2c.y *= t; for( i = 0; i < count; i++ ) { - double x = m1[i].x - m0c.x, y = m1[i].y - m0c.y; - scale0 += sqrt(x*x + y*y); + double x = m1[i].x - m1c.x, y = m1[i].y - m1c.y; + scale1 += std::sqrt(x*x + y*y); - x = m2[i].x - m1c.x, y = m2[i].y - m1c.y; - scale1 += sqrt(x*x + y*y); + x = m2[i].x - m2c.x, y = m2[i].y - m2c.y; + scale2 += std::sqrt(x*x + y*y); } - scale0 *= t; scale1 *= t; + scale2 *= t; - if( scale0 < FLT_EPSILON || scale1 < FLT_EPSILON ) + if( scale1 < FLT_EPSILON || scale2 < FLT_EPSILON ) return 0; - scale0 = sqrt(2.)/scale0; - scale1 = sqrt(2.)/scale1; + scale1 = std::sqrt(2.)/scale1; + scale2 = std::sqrt(2.)/scale2; - cvZero( &A ); + A.setTo(Scalar::all(0)); // form a linear system Ax=0: for each selected pair of points m1 & m2, // the row of A(=a) represents the coefficients of equation: (m2, 1)'*F*(m1, 1) = 0 // to save computation time, we compute (At*A) instead of A and then solve (At*A)x=0. for( i = 0; i < count; i++ ) { - double x0 = (m1[i].x - m0c.x)*scale0; - double y0 = (m1[i].y - m0c.y)*scale0; - double x1 = (m2[i].x - m1c.x)*scale1; - double y1 = (m2[i].y - m1c.y)*scale1; - double r[9] = { x1*x0, x1*y0, x1, y1*x0, y1*y0, y1, x0, y0, 1 }; + double x1 = (m1[i].x - m1c.x)*scale1; + double y1 = (m1[i].y - m1c.y)*scale1; + double x2 = (m2[i].x - m2c.x)*scale2; + double y2 = (m2[i].y - m2c.y)*scale2; + double r[9] = { x2*x1, x2*y1, x2, y2*x1, y2*y1, y2, x1, y1, 1 }; for( j = 0; j < 9; j++ ) for( k = 0; k < 9; k++ ) a[j*9+k] += r[j]*r[k]; } - cvEigenVV(&A, &V, &W); + eigen(A, W, V); for( i = 0; i < 9; i++ ) { @@ -580,122 +556,149 @@ int CvFMEstimator::run8Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatri if( i < 8 ) return 0; - F0 = cvMat( 3, 3, CV_64F, v + 9*8 ); // take the last column of v as a solution of Af = 0 + F0 = Mat( 3, 3, CV_64F, v + 9*8 ); // take the last column of v as a solution of Af = 0 // make F0 singular (of rank 2) by decomposing it with SVD, // zeroing the last diagonal element of W and then composing the matrices back. // use v as a temporary storage for different 3x3 matrices W = U = V = TF = F0; - W.data.db = v; - U.data.db = v + 9; - V.data.db = v + 18; - TF.data.db = v + 27; + W = Mat(3, 1, CV_64F, v); + U = Mat(3, 3, CV_64F, v + 9); + V = Mat(3, 3, CV_64F, v + 18); + TF = Mat(3, 3, CV_64F, v + 27); - cvSVD( &F0, &W, &U, &V, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T ); - W.data.db[8] = 0.; + SVDecomp( F0, W, U, V, SVD::MODIFY_A ); + W.at(2) = 0.; // F0 <- U*diag([W(1), W(2), 0])*V' - cvGEMM( &U, &W, 1., 0, 0., &TF, CV_GEMM_A_T ); - cvGEMM( &TF, &V, 1., 0, 0., &F0, 0/*CV_GEMM_B_T*/ ); + gemm( U, Mat::diag(W), 1., 0, 0., TF, GEMM_1_T ); + gemm( TF, V, 1., 0, 0., F0, 0/*CV_GEMM_B_T*/ ); // apply the transformation that is inverse // to what we used to normalize the point coordinates - { - double tt0[] = { scale0, 0, -scale0*m0c.x, 0, scale0, -scale0*m0c.y, 0, 0, 1 }; - double tt1[] = { scale1, 0, -scale1*m1c.x, 0, scale1, -scale1*m1c.y, 0, 0, 1 }; - CvMat T0, T1; - T0 = T1 = F0; - T0.data.db = tt0; - T1.data.db = tt1; - - // F0 <- T1'*F0*T0 - cvGEMM( &T1, &F0, 1., 0, 0., &TF, CV_GEMM_A_T ); - F0.data.db = fmatrix; - cvGEMM( &TF, &T0, 1., 0, 0., &F0, 0 ); - - // make F(3,3) = 1 - if( fabs(F0.data.db[8]) > FLT_EPSILON ) - cvScale( &F0, &F0, 1./F0.data.db[8] ); - } - + double tt1[] = { scale1, 0, -scale1*m1c.x, 0, scale1, -scale1*m1c.y, 0, 0, 1 }; + double tt2[] = { scale2, 0, -scale2*m2c.x, 0, scale2, -scale2*m2c.y, 0, 0, 1 }; + Mat T1(3, 3, CV_64F, tt1), T2(3, 3, CV_64F, tt2); + + // F0 <- T2'*F0*T1 + gemm( T2, F0, 1., 0, 0., TF, GEMM_1_T ); + F0 = Mat(3, 3, CV_64F, fmatrix); + gemm( TF, T1, 1., 0, 0., F0, 0 ); + + // make F(3,3) = 1 + if( fabs(F0.at(2,2)) > FLT_EPSILON ) + F0 *= 1./F0.at(2,2); + return 1; } -void CvFMEstimator::computeReprojError( const CvMat* _m1, const CvMat* _m2, - const CvMat* model, CvMat* _err ) +class FMEstimatorCallback : public PointSetRegistrator::Callback { - int i, count = _m1->rows*_m1->cols; - const CvPoint2D64f* m1 = (const CvPoint2D64f*)_m1->data.ptr; - const CvPoint2D64f* m2 = (const CvPoint2D64f*)_m2->data.ptr; - const double* F = model->data.db; - float* err = _err->data.fl; +public: + bool checkSubset( InputArray _ms1, InputArray _ms2, int count ) const + { + Mat ms1 = _ms1.getMat(), ms2 = _ms2.getMat(); + return !haveCollinearPoints(ms1, count) && !haveCollinearPoints(ms2, count); + } - for( i = 0; i < count; i++ ) + int runKernel( InputArray _m1, InputArray _m2, OutputArray _model ) const + { + double f[9*3]; + Mat m1 = _m1.getMat(), m2 = _m2.getMat(); + int count = m1.checkVector(2); + Mat F(count == 7 ? 9 : 3, 3, CV_64F, f); + int n = count == 7 ? run7Point(m1, m2, F) : run8Point(m1, m2, F); + + if( n == 0 ) + _model.release(); + else + F.rowRange(0, n*3).copyTo(_model); + + return n; + } + + void computeError( InputArray _m1, InputArray _m2, InputArray _model, OutputArray _err ) const { - double a, b, c, d1, d2, s1, s2; + Mat __m1 = _m1.getMat(), __m2 = _m2.getMat(), __model = _model.getMat(); + int i, count = __m1.checkVector(2); + const Point2f* m1 = __m1.ptr(); + const Point2f* m2 = __m2.ptr(); + const double* F = __model.ptr(); + _err.create(count, 1, CV_32F); + float* err = _err.getMat().ptr(); - a = F[0]*m1[i].x + F[1]*m1[i].y + F[2]; - b = F[3]*m1[i].x + F[4]*m1[i].y + F[5]; - c = F[6]*m1[i].x + F[7]*m1[i].y + F[8]; + for( i = 0; i < count; i++ ) + { + double a, b, c, d1, d2, s1, s2; - s2 = 1./(a*a + b*b); - d2 = m2[i].x*a + m2[i].y*b + c; + a = F[0]*m1[i].x + F[1]*m1[i].y + F[2]; + b = F[3]*m1[i].x + F[4]*m1[i].y + F[5]; + c = F[6]*m1[i].x + F[7]*m1[i].y + F[8]; - a = F[0]*m2[i].x + F[3]*m2[i].y + F[6]; - b = F[1]*m2[i].x + F[4]*m2[i].y + F[7]; - c = F[2]*m2[i].x + F[5]*m2[i].y + F[8]; + s2 = 1./(a*a + b*b); + d2 = m2[i].x*a + m2[i].y*b + c; - s1 = 1./(a*a + b*b); - d1 = m1[i].x*a + m1[i].y*b + c; + a = F[0]*m2[i].x + F[3]*m2[i].y + F[6]; + b = F[1]*m2[i].x + F[4]*m2[i].y + F[7]; + c = F[2]*m2[i].x + F[5]*m2[i].y + F[8]; - err[i] = (float)std::max(d1*d1*s1, d2*d2*s2); + s1 = 1./(a*a + b*b); + d1 = m1[i].x*a + m1[i].y*b + c; + + err[i] = (float)std::max(d1*d1*s1, d2*d2*s2); + } } -} +}; +} -CV_IMPL int cvFindFundamentalMat( const CvMat* points1, const CvMat* points2, - CvMat* fmatrix, int method, - double param1, double param2, CvMat* mask ) +cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2, + int method, double param1, double param2, + OutputArray _mask ) { - int result = 0; - Ptr m1, m2, tempMask; - - double F[3*9]; - CvMat _F3x3 = cvMat( 3, 3, CV_64FC1, F ), _F9x3 = cvMat( 9, 3, CV_64FC1, F ); - int count; + Mat points1 = _points1.getMat(), points2 = _points2.getMat(); + Mat m1, m2, F; + int npoints = -1; - CV_Assert( CV_IS_MAT(points1) && CV_IS_MAT(points2) && CV_ARE_SIZES_EQ(points1, points2) ); - CV_Assert( CV_IS_MAT(fmatrix) && fmatrix->cols == 3 && - (fmatrix->rows == 3 || (fmatrix->rows == 9 && method == CV_FM_7POINT)) ); + for( int i = 1; i <= 2; i++ ) + { + Mat& p = i == 1 ? points1 : points2; + Mat& m = i == 1 ? m1 : m2; + npoints = p.checkVector(2, -1, false); + if( npoints < 0 ) + { + npoints = p.checkVector(3, -1, false); + if( npoints < 0 ) + CV_Error(CV_StsBadArg, "The input arrays should be 2D or 3D point sets"); + if( npoints == 0 ) + return Mat(); + convertPointsFromHomogeneous(p, p); + } + p.reshape(2, npoints).convertTo(m, CV_32F); + } - count = MAX(points1->cols, points1->rows); - if( count < 7 ) - return 0; + CV_Assert( m1.checkVector(2) == m2.checkVector(2) ); - m1 = cvCreateMat( 1, count, CV_64FC2 ); - cvConvertPointsHomogeneous( points1, m1 ); + if( npoints < 7 ) + return Mat(); - m2 = cvCreateMat( 1, count, CV_64FC2 ); - cvConvertPointsHomogeneous( points2, m2 ); + Ptr cb = new FMEstimatorCallback; + int result; - if( mask ) + if( npoints == 7 || method == FM_8POINT ) { - CV_Assert( CV_IS_MASK_ARR(mask) && CV_IS_MAT_CONT(mask->type) && - (mask->rows == 1 || mask->cols == 1) && - mask->rows*mask->cols == count ); + result = cb->runKernel(m1, m2, F); + if( _mask.needed() ) + { + if( !_mask.fixedSize() ) + _mask.create(npoints, 1, CV_8U); + Mat mask = _mask.getMat(); + CV_Assert( (mask.cols == 1 || mask.rows == 1) && (int)mask.total() == npoints ); + mask.setTo(Scalar::all(1)); + } } - if( mask || count >= 8 ) - tempMask = cvCreateMat( 1, count, CV_8U ); - if( !tempMask.empty() ) - cvSet( tempMask, cvScalarAll(1.) ); - - CvFMEstimator estimator(7); - if( count == 7 ) - result = estimator.run7Point(m1, m2, &_F9x3); - else if( method == CV_FM_8POINT ) - result = estimator.run8Point(m1, m2, &_F3x3); else { if( param1 <= 0 ) @@ -703,546 +706,279 @@ CV_IMPL int cvFindFundamentalMat( const CvMat* points1, const CvMat* points2, if( param2 < DBL_EPSILON || param2 > 1 - DBL_EPSILON ) param2 = 0.99; - if( (method & ~3) == CV_RANSAC && count >= 15 ) - result = estimator.runRANSAC(m1, m2, &_F3x3, tempMask, param1, param2 ); + if( (method & ~3) == FM_RANSAC && npoints >= 15 ) + result = createRANSACPointSetRegistrator(cb, 7, param1, param2)->run(m1, m2, F, _mask); else - result = estimator.runLMeDS(m1, m2, &_F3x3, tempMask, param2 ); - if( result <= 0 ) - return 0; - /*icvCompressPoints( (CvPoint2D64f*)m1->data.ptr, tempMask->data.ptr, 1, count ); - count = icvCompressPoints( (CvPoint2D64f*)m2->data.ptr, tempMask->data.ptr, 1, count ); - assert( count >= 8 ); - m1->cols = m2->cols = count; - estimator.run8Point(m1, m2, &_F3x3);*/ + result = createLMeDSPointSetRegistrator(cb, 7, param2)->run(m1, m2, F, _mask); } - if( result ) - cvConvert( fmatrix->rows == 3 ? &_F3x3 : &_F9x3, fmatrix ); + if( result <= 0 ) + return Mat(); - if( mask && tempMask ) - { - if( CV_ARE_SIZES_EQ(mask, tempMask) ) - cvCopy( tempMask, mask ); - else - cvTranspose( tempMask, mask ); - } + return F; +} - return result; +cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2, + OutputArray _mask, int method, double param1, double param2 ) +{ + return cv::findFundamentalMat(_points1, _points2, method, param1, param2, _mask); } -CV_IMPL void cvComputeCorrespondEpilines( const CvMat* points, int pointImageID, - const CvMat* fmatrix, CvMat* lines ) +void cv::computeCorrespondEpilines( InputArray _points, int whichImage, + InputArray _Fmat, OutputArray _lines ) { - int abc_stride, abc_plane_stride, abc_elem_size; - int plane_stride, stride, elem_size; - int i, dims, count, depth, cn, abc_dims, abc_count, abc_depth, abc_cn; - uchar *ap, *bp, *cp; - const uchar *xp, *yp, *zp; double f[9]; - CvMat F = cvMat( 3, 3, CV_64F, f ); - - if( !CV_IS_MAT(points) ) - CV_Error( !points ? CV_StsNullPtr : CV_StsBadArg, "points parameter is not a valid matrix" ); - - depth = CV_MAT_DEPTH(points->type); - cn = CV_MAT_CN(points->type); - if( (depth != CV_32F && depth != CV_64F) || (cn != 1 && cn != 2 && cn != 3) ) - CV_Error( CV_StsUnsupportedFormat, "The format of point matrix is unsupported" ); - - if( cn > 1 ) - { - dims = cn; - CV_Assert( points->rows == 1 || points->cols == 1 ); - count = points->rows * points->cols; - } - else if( points->rows > points->cols ) - { - dims = cn*points->cols; - count = points->rows; - } - else - { - if( (points->rows > 1 && cn > 1) || (points->rows == 1 && cn == 1) ) - CV_Error( CV_StsBadSize, "The point matrix does not have a proper layout (2xn, 3xn, nx2 or nx3)" ); - dims = points->rows; - count = points->cols; - } - - if( dims != 2 && dims != 3 ) - CV_Error( CV_StsOutOfRange, "The dimensionality of points must be 2 or 3" ); - - if( !CV_IS_MAT(fmatrix) ) - CV_Error( !fmatrix ? CV_StsNullPtr : CV_StsBadArg, "fmatrix is not a valid matrix" ); - - if( CV_MAT_TYPE(fmatrix->type) != CV_32FC1 && CV_MAT_TYPE(fmatrix->type) != CV_64FC1 ) - CV_Error( CV_StsUnsupportedFormat, "fundamental matrix must have 32fC1 or 64fC1 type" ); - - if( fmatrix->cols != 3 || fmatrix->rows != 3 ) - CV_Error( CV_StsBadSize, "fundamental matrix must be 3x3" ); - - if( !CV_IS_MAT(lines) ) - CV_Error( !lines ? CV_StsNullPtr : CV_StsBadArg, "lines parameter is not a valid matrix" ); + Mat tempF(3, 3, CV_64F, f); + Mat points = _points.getMat(), F = _Fmat.getMat(); - abc_depth = CV_MAT_DEPTH(lines->type); - abc_cn = CV_MAT_CN(lines->type); - if( (abc_depth != CV_32F && abc_depth != CV_64F) || (abc_cn != 1 && abc_cn != 3) ) - CV_Error( CV_StsUnsupportedFormat, "The format of the matrix of lines is unsupported" ); + if( !points.isContinuous() ) + points = points.clone(); - if( abc_cn > 1 ) - { - abc_dims = abc_cn; - CV_Assert( lines->rows == 1 || lines->cols == 1 ); - abc_count = lines->rows * lines->cols; - } - else if( lines->rows > lines->cols ) - { - abc_dims = abc_cn*lines->cols; - abc_count = lines->rows; - } - else + int npoints = points.checkVector(2); + if( npoints < 0 ) { - if( (lines->rows > 1 && abc_cn > 1) || (lines->rows == 1 && abc_cn == 1) ) - CV_Error( CV_StsBadSize, "The lines matrix does not have a proper layout (3xn or nx3)" ); - abc_dims = lines->rows; - abc_count = lines->cols; + npoints = points.checkVector(3); + if( npoints < 0 ) + CV_Error( CV_StsBadArg, "The input should be a 2D or 3D point set"); + Mat temp; + convertPointsFromHomogeneous(points, temp); + points = temp; } + int depth = points.depth(); + CV_Assert( depth == CV_32F || depth == CV_32S || depth == CV_64F ); - if( abc_dims != 3 ) - CV_Error( CV_StsOutOfRange, "The lines matrix does not have a proper layout (3xn or nx3)" ); - - if( abc_count != count ) - CV_Error( CV_StsUnmatchedSizes, "The numbers of points and lines are different" ); - - elem_size = CV_ELEM_SIZE(depth); - abc_elem_size = CV_ELEM_SIZE(abc_depth); + CV_Assert(F.size() == Size(3,3)); + F.convertTo(tempF, CV_64F); + if( whichImage == 2 ) + transpose(tempF, tempF); - if( cn == 1 && points->rows == dims ) + int ltype = CV_MAKETYPE(MAX(depth, CV_32F), 3); + _lines.create(npoints, 1, ltype); + Mat lines = _lines.getMat(); + if( !lines.isContinuous() ) { - plane_stride = points->step; - stride = elem_size; - } - else - { - plane_stride = elem_size; - stride = points->rows == 1 ? dims*elem_size : points->step; + _lines.release(); + _lines.create(npoints, 1, ltype); + lines = _lines.getMat(); } + CV_Assert( lines.isContinuous()); - if( abc_cn == 1 && lines->rows == 3 ) + if( depth == CV_32S || depth == CV_32F ) { - abc_plane_stride = lines->step; - abc_stride = abc_elem_size; + const Point* ptsi = (const Point*)points.data; + const Point2f* ptsf = (const Point2f*)points.data; + Point3f* dstf = lines.ptr(); + for( int i = 0; i < npoints; i++ ) + { + Point2f pt = depth == CV_32F ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y); + double a = f[0]*pt.x + f[1]*pt.y + f[2]; + double b = f[3]*pt.x + f[4]*pt.y + f[5]; + double c = f[6]*pt.x + f[7]*pt.y + f[8]; + double nu = a*a + b*b; + nu = nu ? 1./std::sqrt(nu) : 1.; + a *= nu; b *= nu; c *= nu; + dstf[i] = Point3f((float)a, (float)b, (float)c); + } } else { - abc_plane_stride = abc_elem_size; - abc_stride = lines->rows == 1 ? 3*abc_elem_size : lines->step; - } - - cvConvert( fmatrix, &F ); - if( pointImageID == 2 ) - cvTranspose( &F, &F ); - - xp = points->data.ptr; - yp = xp + plane_stride; - zp = dims == 3 ? yp + plane_stride : 0; - - ap = lines->data.ptr; - bp = ap + abc_plane_stride; - cp = bp + abc_plane_stride; - - for( i = 0; i < count; i++ ) - { - double x, y, z = 1.; - double a, b, c, nu; - - if( depth == CV_32F ) + const Point2d* ptsd = (const Point2d*)points.data; + Point3d* dstd = lines.ptr(); + for( int i = 0; i < npoints; i++ ) { - x = *(float*)xp; y = *(float*)yp; - if( zp ) - z = *(float*)zp, zp += stride; + Point2d pt = ptsd[i]; + double a = f[0]*pt.x + f[1]*pt.y + f[2]; + double b = f[3]*pt.x + f[4]*pt.y + f[5]; + double c = f[6]*pt.x + f[7]*pt.y + f[8]; + double nu = a*a + b*b; + nu = nu ? 1./std::sqrt(nu) : 1.; + a *= nu; b *= nu; c *= nu; + dstd[i] = Point3d(a, b, c); } - else - { - x = *(double*)xp; y = *(double*)yp; - if( zp ) - z = *(double*)zp, zp += stride; - } - - xp += stride; yp += stride; - - a = f[0]*x + f[1]*y + f[2]*z; - b = f[3]*x + f[4]*y + f[5]*z; - c = f[6]*x + f[7]*y + f[8]*z; - nu = a*a + b*b; - nu = nu ? 1./sqrt(nu) : 1.; - a *= nu; b *= nu; c *= nu; - - if( abc_depth == CV_32F ) - { - *(float*)ap = (float)a; - *(float*)bp = (float)b; - *(float*)cp = (float)c; - } - else - { - *(double*)ap = a; - *(double*)bp = b; - *(double*)cp = c; - } - - ap += abc_stride; - bp += abc_stride; - cp += abc_stride; } } - -CV_IMPL void cvConvertPointsHomogeneous( const CvMat* src, CvMat* dst ) +void cv::convertPointsFromHomogeneous( InputArray _src, OutputArray _dst ) { - Ptr temp, denom; - - int i, s_count, s_dims, d_count, d_dims; - CvMat _src, _dst, _ones; - CvMat* ones = 0; - - if( !CV_IS_MAT(src) ) - CV_Error( !src ? CV_StsNullPtr : CV_StsBadArg, - "The input parameter is not a valid matrix" ); - - if( !CV_IS_MAT(dst) ) - CV_Error( !dst ? CV_StsNullPtr : CV_StsBadArg, - "The output parameter is not a valid matrix" ); - - if( src == dst || src->data.ptr == dst->data.ptr ) - { - if( src != dst && (!CV_ARE_TYPES_EQ(src, dst) || !CV_ARE_SIZES_EQ(src,dst)) ) - CV_Error( CV_StsBadArg, "Invalid inplace operation" ); - return; - } - - if( src->rows > src->cols ) - { - if( !((src->cols > 1) ^ (CV_MAT_CN(src->type) > 1)) ) - CV_Error( CV_StsBadSize, "Either the number of channels or columns or rows must be =1" ); - - s_dims = CV_MAT_CN(src->type)*src->cols; - s_count = src->rows; - } - else + Mat src = _src.getMat(); + if( !src.isContinuous() ) + src = src.clone(); + int i, npoints = src.checkVector(3), depth = src.depth(), cn = 3; + if( npoints < 0 ) { - if( !((src->rows > 1) ^ (CV_MAT_CN(src->type) > 1)) ) - CV_Error( CV_StsBadSize, "Either the number of channels or columns or rows must be =1" ); - - s_dims = CV_MAT_CN(src->type)*src->rows; - s_count = src->cols; + npoints = src.checkVector(4); + CV_Assert(npoints >= 0); + cn = 4; } + CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F || depth == CV_64F)); - if( src->rows == 1 || src->cols == 1 ) - src = cvReshape( src, &_src, 1, s_count ); - - if( dst->rows > dst->cols ) - { - if( !((dst->cols > 1) ^ (CV_MAT_CN(dst->type) > 1)) ) - CV_Error( CV_StsBadSize, - "Either the number of channels or columns or rows in the input matrix must be =1" ); - - d_dims = CV_MAT_CN(dst->type)*dst->cols; - d_count = dst->rows; - } - else + int dtype = CV_MAKETYPE(depth <= CV_32F ? CV_32F : CV_64F, cn-1); + _dst.create(npoints, 1, dtype); + Mat dst = _dst.getMat(); + if( !dst.isContinuous() ) { - if( !((dst->rows > 1) ^ (CV_MAT_CN(dst->type) > 1)) ) - CV_Error( CV_StsBadSize, - "Either the number of channels or columns or rows in the output matrix must be =1" ); - - d_dims = CV_MAT_CN(dst->type)*dst->rows; - d_count = dst->cols; + _dst.release(); + _dst.create(npoints, 1, dtype); + dst = _dst.getMat(); } + CV_Assert( dst.isContinuous() ); - if( dst->rows == 1 || dst->cols == 1 ) - dst = cvReshape( dst, &_dst, 1, d_count ); - - if( s_count != d_count ) - CV_Error( CV_StsUnmatchedSizes, "Both matrices must have the same number of points" ); - - if( CV_MAT_DEPTH(src->type) < CV_32F || CV_MAT_DEPTH(dst->type) < CV_32F ) - CV_Error( CV_StsUnsupportedFormat, - "Both matrices must be floating-point (single or double precision)" ); - - if( s_dims < 2 || s_dims > 4 || d_dims < 2 || d_dims > 4 ) - CV_Error( CV_StsOutOfRange, - "Both input and output point dimensionality must be 2, 3 or 4" ); - - if( s_dims < d_dims - 1 || s_dims > d_dims + 1 ) - CV_Error( CV_StsUnmatchedSizes, - "The dimensionalities of input and output point sets differ too much" ); - - if( s_dims == d_dims - 1 ) + if( depth == CV_32S ) { - if( d_count == dst->rows ) + if( cn == 3 ) { - ones = cvGetSubRect( dst, &_ones, cvRect( s_dims, 0, 1, d_count )); - dst = cvGetSubRect( dst, &_dst, cvRect( 0, 0, s_dims, d_count )); + const Point3i* sptr = (const Point3i*)src.data; + Point2f* dptr = (Point2f*)dst.data; + for( i = 0; i < npoints; i++ ) + { + float scale = sptr[i].z != 0 ? 1.f/sptr[i].z : 1.f; + dptr[i] = Point2f(sptr[i].x*scale, sptr[i].y*scale); + } } else { - ones = cvGetSubRect( dst, &_ones, cvRect( 0, s_dims, d_count, 1 )); - dst = cvGetSubRect( dst, &_dst, cvRect( 0, 0, d_count, s_dims )); + const Vec4i* sptr = (const Vec4i*)src.data; + Point3f* dptr = (Point3f*)dst.data; + for( i = 0; i < npoints; i++ ) + { + float scale = sptr[i][3] != 0 ? 1.f/sptr[i][3] : 1.f; + dptr[i] = Point3f(sptr[i][0]*scale, sptr[i][1]*scale, sptr[i][2]*scale); + } } } - - if( s_dims <= d_dims ) + else if( depth == CV_32F ) { - if( src->rows == dst->rows && src->cols == dst->cols ) + if( cn == 3 ) { - if( CV_ARE_TYPES_EQ( src, dst ) ) - cvCopy( src, dst ); - else - cvConvert( src, dst ); + const Point3f* sptr = (const Point3f*)src.data; + Point2f* dptr = (Point2f*)dst.data; + for( i = 0; i < npoints; i++ ) + { + float scale = sptr[i].z != 0.f ? 1.f/sptr[i].z : 1.f; + dptr[i] = Point2f(sptr[i].x*scale, sptr[i].y*scale); + } } else { - if( !CV_ARE_TYPES_EQ( src, dst )) + const Vec4f* sptr = (const Vec4f*)src.data; + Point3f* dptr = (Point3f*)dst.data; + for( i = 0; i < npoints; i++ ) { - temp = cvCreateMat( src->rows, src->cols, dst->type ); - cvConvert( src, temp ); - src = temp; + float scale = sptr[i][3] != 0.f ? 1.f/sptr[i][3] : 1.f; + dptr[i] = Point3f(sptr[i][0]*scale, sptr[i][1]*scale, sptr[i][2]*scale); } - cvTranspose( src, dst ); } - - if( ones ) - cvSet( ones, cvRealScalar(1.) ); } - else + else if( depth == CV_64F ) { - int s_plane_stride, s_stride, d_plane_stride, d_stride, elem_size; - - if( !CV_ARE_TYPES_EQ( src, dst )) - { - temp = cvCreateMat( src->rows, src->cols, dst->type ); - cvConvert( src, temp ); - src = temp; - } - - elem_size = CV_ELEM_SIZE(src->type); - - if( s_count == src->cols ) - s_plane_stride = src->step / elem_size, s_stride = 1; - else - s_stride = src->step / elem_size, s_plane_stride = 1; - - if( d_count == dst->cols ) - d_plane_stride = dst->step / elem_size, d_stride = 1; - else - d_stride = dst->step / elem_size, d_plane_stride = 1; - - denom = cvCreateMat( 1, d_count, dst->type ); - - if( CV_MAT_DEPTH(dst->type) == CV_32F ) + if( cn == 3 ) { - const float* xs = src->data.fl; - const float* ys = xs + s_plane_stride; - const float* zs = 0; - const float* ws = xs + (s_dims - 1)*s_plane_stride; - - float* iw = denom->data.fl; - - float* xd = dst->data.fl; - float* yd = xd + d_plane_stride; - float* zd = 0; - - if( d_dims == 3 ) + const Point3d* sptr = (const Point3d*)src.data; + Point2d* dptr = (Point2d*)dst.data; + for( i = 0; i < npoints; i++ ) { - zs = ys + s_plane_stride; - zd = yd + d_plane_stride; + double scale = sptr[i].z != 0. ? 1./sptr[i].z : 1.; + dptr[i] = Point2d(sptr[i].x*scale, sptr[i].y*scale); } - - for( i = 0; i < d_count; i++, ws += s_stride ) - { - float t = *ws; - iw[i] = fabs((double)t) > FLT_EPSILON ? t : 1.f; - } - - cvDiv( 0, denom, denom ); - - if( d_dims == 3 ) - for( i = 0; i < d_count; i++ ) - { - float w = iw[i]; - float x = *xs * w, y = *ys * w, z = *zs * w; - xs += s_stride; ys += s_stride; zs += s_stride; - *xd = x; *yd = y; *zd = z; - xd += d_stride; yd += d_stride; zd += d_stride; - } - else - for( i = 0; i < d_count; i++ ) - { - float w = iw[i]; - float x = *xs * w, y = *ys * w; - xs += s_stride; ys += s_stride; - *xd = x; *yd = y; - xd += d_stride; yd += d_stride; - } } else { - const double* xs = src->data.db; - const double* ys = xs + s_plane_stride; - const double* zs = 0; - const double* ws = xs + (s_dims - 1)*s_plane_stride; - - double* iw = denom->data.db; - - double* xd = dst->data.db; - double* yd = xd + d_plane_stride; - double* zd = 0; - - if( d_dims == 3 ) + const Vec4d* sptr = (const Vec4d*)src.data; + Point3d* dptr = (Point3d*)dst.data; + for( i = 0; i < npoints; i++ ) { - zs = ys + s_plane_stride; - zd = yd + d_plane_stride; + double scale = sptr[i][3] != 0.f ? 1./sptr[i][3] : 1.; + dptr[i] = Point3d(sptr[i][0]*scale, sptr[i][1]*scale, sptr[i][2]*scale); } - - for( i = 0; i < d_count; i++, ws += s_stride ) - { - double t = *ws; - iw[i] = fabs(t) > DBL_EPSILON ? t : 1.; - } - - cvDiv( 0, denom, denom ); - - if( d_dims == 3 ) - for( i = 0; i < d_count; i++ ) - { - double w = iw[i]; - double x = *xs * w, y = *ys * w, z = *zs * w; - xs += s_stride; ys += s_stride; zs += s_stride; - *xd = x; *yd = y; *zd = z; - xd += d_stride; yd += d_stride; zd += d_stride; - } - else - for( i = 0; i < d_count; i++ ) - { - double w = iw[i]; - double x = *xs * w, y = *ys * w; - xs += s_stride; ys += s_stride; - *xd = x; *yd = y; - xd += d_stride; yd += d_stride; - } } } + else + CV_Error(CV_StsUnsupportedFormat, ""); } -cv::Mat cv::findHomography( InputArray _points1, InputArray _points2, - int method, double ransacReprojThreshold, OutputArray _mask ) + +void cv::convertPointsToHomogeneous( InputArray _src, OutputArray _dst ) { - Mat points1 = _points1.getMat(), points2 = _points2.getMat(); - int npoints = points1.checkVector(2); - CV_Assert( npoints >= 0 && points2.checkVector(2) == npoints && - points1.type() == points2.type()); - - Mat H(3, 3, CV_64F); - CvMat _pt1 = points1, _pt2 = points2; - CvMat matH = H, c_mask, *p_mask = 0; - if( _mask.needed() ) + Mat src = _src.getMat(); + if( !src.isContinuous() ) + src = src.clone(); + int i, npoints = src.checkVector(2), depth = src.depth(), cn = 2; + if( npoints < 0 ) { - _mask.create(npoints, 1, CV_8U, -1, true); - p_mask = &(c_mask = _mask.getMat()); + npoints = src.checkVector(3); + CV_Assert(npoints >= 0); + cn = 3; } - bool ok = cvFindHomography( &_pt1, &_pt2, &matH, method, ransacReprojThreshold, p_mask ) > 0; - if( !ok ) - H = Scalar(0); - return H; -} - -cv::Mat cv::findHomography( InputArray _points1, InputArray _points2, - OutputArray _mask, int method, double ransacReprojThreshold ) -{ - return cv::findHomography(_points1, _points2, method, ransacReprojThreshold, _mask); -} + CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F || depth == CV_64F)); -cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2, - int method, double param1, double param2, - OutputArray _mask ) -{ - Mat points1 = _points1.getMat(), points2 = _points2.getMat(); - int npoints = points1.checkVector(2); - CV_Assert( npoints >= 0 && points2.checkVector(2) == npoints && - points1.type() == points2.type()); - - Mat F(method == CV_FM_7POINT ? 9 : 3, 3, CV_64F); - CvMat _pt1 = points1, _pt2 = points2; - CvMat matF = F, c_mask, *p_mask = 0; - if( _mask.needed() ) + int dtype = CV_MAKETYPE(depth <= CV_32F ? CV_32F : CV_64F, cn+1); + _dst.create(npoints, 1, dtype); + Mat dst = _dst.getMat(); + if( !dst.isContinuous() ) { - _mask.create(npoints, 1, CV_8U, -1, true); - p_mask = &(c_mask = _mask.getMat()); + _dst.release(); + _dst.create(npoints, 1, dtype); + dst = _dst.getMat(); } - int n = cvFindFundamentalMat( &_pt1, &_pt2, &matF, method, param1, param2, p_mask ); - if( n <= 0 ) - F = Scalar(0); - if( n == 1 ) - F = F.rowRange(0, 3); - return F; -} - -cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2, - OutputArray _mask, int method, double param1, double param2 ) -{ - return cv::findFundamentalMat(_points1, _points2, method, param1, param2, _mask); -} - + CV_Assert( dst.isContinuous() ); -void cv::computeCorrespondEpilines( InputArray _points, int whichImage, - InputArray _Fmat, OutputArray _lines ) -{ - Mat points = _points.getMat(), F = _Fmat.getMat(); - int npoints = points.checkVector(2); - if( npoints < 0 ) - npoints = points.checkVector(3); - CV_Assert( npoints >= 0 && (points.depth() == CV_32F || points.depth() == CV_32S)); - - _lines.create(npoints, 1, CV_32FC3, -1, true); - CvMat c_points = points, c_lines = _lines.getMat(), c_F = F; - cvComputeCorrespondEpilines(&c_points, whichImage, &c_F, &c_lines); -} - -void cv::convertPointsFromHomogeneous( InputArray _src, OutputArray _dst ) -{ - Mat src = _src.getMat(); - int npoints = src.checkVector(3), cn = 3; - if( npoints < 0 ) + if( depth == CV_32S ) { - npoints = src.checkVector(4); - if( npoints >= 0 ) - cn = 4; + if( cn == 2 ) + { + const Point2i* sptr = (const Point2i*)src.data; + Point3i* dptr = (Point3i*)dst.data; + for( i = 0; i < npoints; i++ ) + dptr[i] = Point3i(sptr[i].x, sptr[i].y, 1); + } + else + { + const Point3i* sptr = (const Point3i*)src.data; + Vec4i* dptr = (Vec4i*)dst.data; + for( i = 0; i < npoints; i++ ) + dptr[i] = Vec4i(sptr[i].x, sptr[i].y, sptr[i].z, 1); + } } - CV_Assert( npoints >= 0 && (src.depth() == CV_32F || src.depth() == CV_32S)); - - _dst.create(npoints, 1, CV_MAKETYPE(CV_32F, cn-1)); - CvMat c_src = src, c_dst = _dst.getMat(); - cvConvertPointsHomogeneous(&c_src, &c_dst); -} - -void cv::convertPointsToHomogeneous( InputArray _src, OutputArray _dst ) -{ - Mat src = _src.getMat(); - int npoints = src.checkVector(2), cn = 2; - if( npoints < 0 ) + else if( depth == CV_32F ) { - npoints = src.checkVector(3); - if( npoints >= 0 ) - cn = 3; + if( cn == 2 ) + { + const Point2f* sptr = (const Point2f*)src.data; + Point3f* dptr = (Point3f*)dst.data; + for( i = 0; i < npoints; i++ ) + dptr[i] = Point3f(sptr[i].x, sptr[i].y, 1.f); + } + else + { + const Point3f* sptr = (const Point3f*)src.data; + Vec4f* dptr = (Vec4f*)dst.data; + for( i = 0; i < npoints; i++ ) + dptr[i] = Vec4f(sptr[i].x, sptr[i].y, sptr[i].z, 1.f); + } } - CV_Assert( npoints >= 0 && (src.depth() == CV_32F || src.depth() == CV_32S)); - - _dst.create(npoints, 1, CV_MAKETYPE(CV_32F, cn+1)); - CvMat c_src = src, c_dst = _dst.getMat(); - cvConvertPointsHomogeneous(&c_src, &c_dst); + else if( depth == CV_64F ) + { + if( cn == 2 ) + { + const Point2d* sptr = (const Point2d*)src.data; + Point3d* dptr = (Point3d*)dst.data; + for( i = 0; i < npoints; i++ ) + dptr[i] = Point3d(sptr[i].x, sptr[i].y, 1.); + } + else + { + const Point3d* sptr = (const Point3d*)src.data; + Vec4d* dptr = (Vec4d*)dst.data; + for( i = 0; i < npoints; i++ ) + dptr[i] = Vec4d(sptr[i].x, sptr[i].y, sptr[i].z, 1.); + } + } + else + CV_Error(CV_StsUnsupportedFormat, ""); } + void cv::convertPointsHomogeneous( InputArray _src, OutputArray _dst ) { int stype = _src.type(), dtype = _dst.type(); diff --git a/modules/calib3d/src/levmarq.cpp b/modules/calib3d/src/levmarq.cpp new file mode 100644 index 0000000000..58b6f2b454 --- /dev/null +++ b/modules/calib3d/src/levmarq.cpp @@ -0,0 +1,226 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include + +/* + This is translation to C++ of the Matlab's LMSolve package by Miroslav Balda. + Here is the original copyright: + ============================================================================ + + Copyright (c) 2007, Miroslav Balda + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +namespace cv +{ + +class LMSolverImpl : public LMSolver +{ +public: + LMSolverImpl() : maxIters(100) { init(); }; + LMSolverImpl(const Ptr& _cb, int _maxIters) : cb(_cb), maxIters(_maxIters) { init(); } + + void init() + { + epsx = epsf = FLT_EPSILON; + printInterval = 0; + } + + int run(InputOutputArray _param0) const + { + Mat param0 = _param0.getMat(), x, xd, r, rd, J, A, Ap, v, temp_d, d; + int ptype = param0.type(); + + CV_Assert( (param0.cols == 1 || param0.rows == 1) && (ptype == CV_32F || ptype == CV_64F)); + CV_Assert( !cb.empty() ); + + int lx = param0.rows + param0.cols - 1; + param0.convertTo(x, CV_64F); + + if( x.cols != 1 ) + transpose(x, x); + + if( !cb->compute(x, r, J) ) + return -1; + double S = norm(r, NORM_L2SQR); + int nfJ = 2; + + mulTransposed(J, A, true); + gemm(J, r, 1, noArray(), 0, v, GEMM_1_T); + + Mat D = A.diag().clone(); + + const double Rlo = 0.25, Rhi = 0.75; + double lambda = 1, lc = 0.75; + int i, iter = 0; + + if( printInterval != 0 ) + { + printf("************************************************************************************\n"); + printf("\titr\tnfJ\t\tSUM(r^2)\t\tx\t\tdx\t\tl\t\tlc\n"); + printf("************************************************************************************\n"); + } + + for( ;; ) + { + CV_Assert( A.type() == CV_64F && A.rows == lx ); + A.copyTo(Ap); + for( i = 0; i < lx; i++ ) + Ap.at(i, i) += lambda*D.at(i); + solve(Ap, v, d, DECOMP_EIG); + subtract(x, d, xd); + if( !cb->compute(xd, rd, noArray()) ) + return -1; + nfJ++; + double Sd = norm(rd, NORM_L2SQR); + gemm(A, d, -1, v, 2, temp_d); + double dS = d.dot(temp_d); + double R = (S - Sd)/(fabs(dS) > DBL_EPSILON ? dS : 1); + + if( R > Rhi ) + { + lambda *= 0.5; + if( lambda < lc ) + lambda = 0; + } + else if( R < Rlo ) + { + // find new nu if R too low + double t = d.dot(v); + double nu = (Sd - S)/(fabs(t) > DBL_EPSILON ? t : 1) + 2; + nu = std::min(std::max(nu, 2.), 10.); + if( lambda == 0 ) + { + invert(A, Ap, DECOMP_EIG); + double maxval = DBL_EPSILON; + for( i = 0; i < lx; i++ ) + maxval = std::max(maxval, std::abs(Ap.at(i,i))); + lambda = lc = 1./maxval; + nu *= 0.5; + } + lambda *= nu; + } + + if( Sd < S ) + { + nfJ++; + S = Sd; + std::swap(x, xd); + if( !cb->compute(x, r, J) ) + return -1; + mulTransposed(J, A, true); + gemm(J, r, 1, noArray(), 0, v, GEMM_1_T); + } + + iter++; + bool proceed = iter < maxIters && norm(d, NORM_INF) >= epsx && norm(r, NORM_INF) >= epsf; + + if( printInterval != 0 && (iter % printInterval == 0 || iter == 1 || !proceed) ) + { + printf("%c%10d %10d %15.4e %16.4e %17.4e %16.4e %17.4e\n", + (proceed ? ' ' : '*'), iter, nfJ, S, x.at(0), d.at(0), lambda, lc); + } + + if(!proceed) + break; + } + + if( param0.size != x.size ) + transpose(x, x); + + x.convertTo(param0, ptype); + if( iter == maxIters ) + iter = -iter; + + return iter; + } + + void setCallback(const Ptr& _cb) { cb = _cb; } + + AlgorithmInfo* info() const; + + Ptr cb; + + double epsx; + double epsf; + int maxIters; + int printInterval; +}; + + +CV_INIT_ALGORITHM(LMSolverImpl, "LMSolver", + obj.info()->addParam(obj, "epsx", obj.epsx); + obj.info()->addParam(obj, "epsf", obj.epsf); + obj.info()->addParam(obj, "maxIters", obj.maxIters); + obj.info()->addParam(obj, "printInterval", obj.printInterval)); + +CV_EXPORTS Ptr createLMSolver(const Ptr& cb, int maxIters) +{ + CV_Assert( !LMSolverImpl_info_auto.name().empty() ); + return new LMSolverImpl(cb, maxIters); +} + +} diff --git a/modules/calib3d/src/modelest.cpp b/modules/calib3d/src/modelest.cpp deleted file mode 100644 index 3c54c218b8..0000000000 --- a/modules/calib3d/src/modelest.cpp +++ /dev/null @@ -1,502 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "precomp.hpp" -#include "_modelest.h" -#include -#include -#include - -CvModelEstimator2::CvModelEstimator2(int _modelPoints, CvSize _modelSize, int _maxBasicSolutions) -{ - modelPoints = _modelPoints; - modelSize = _modelSize; - maxBasicSolutions = _maxBasicSolutions; - checkPartialSubsets = true; - rng = cvRNG(-1); -} - -CvModelEstimator2::~CvModelEstimator2() -{ -} - -void CvModelEstimator2::setSeed( int64 seed ) -{ - rng = cvRNG(seed); -} - - -int CvModelEstimator2::findInliers( const CvMat* m1, const CvMat* m2, - const CvMat* model, CvMat* _err, - CvMat* _mask, double threshold ) -{ - int i, count = _err->rows*_err->cols, goodCount = 0; - const float* err = _err->data.fl; - uchar* mask = _mask->data.ptr; - - computeReprojError( m1, m2, model, _err ); - threshold *= threshold; - for( i = 0; i < count; i++ ) - goodCount += mask[i] = err[i] <= threshold; - return goodCount; -} - - -CV_IMPL int -cvRANSACUpdateNumIters( double p, double ep, - int model_points, int max_iters ) -{ - if( model_points <= 0 ) - CV_Error( CV_StsOutOfRange, "the number of model points should be positive" ); - - p = MAX(p, 0.); - p = MIN(p, 1.); - ep = MAX(ep, 0.); - ep = MIN(ep, 1.); - - // avoid inf's & nan's - double num = MAX(1. - p, DBL_MIN); - double denom = 1. - pow(1. - ep,model_points); - if( denom < DBL_MIN ) - return 0; - - num = log(num); - denom = log(denom); - - return denom >= 0 || -num >= max_iters*(-denom) ? - max_iters : cvRound(num/denom); -} - -bool CvModelEstimator2::runRANSAC( const CvMat* m1, const CvMat* m2, CvMat* model, - CvMat* mask0, double reprojThreshold, - double confidence, int maxIters ) -{ - bool result = false; - cv::Ptr mask = cvCloneMat(mask0); - cv::Ptr models, err, tmask; - cv::Ptr ms1, ms2; - - int iter, niters = maxIters; - int count = m1->rows*m1->cols, maxGoodCount = 0; - CV_Assert( CV_ARE_SIZES_EQ(m1, m2) && CV_ARE_SIZES_EQ(m1, mask) ); - - if( count < modelPoints ) - return false; - - models = cvCreateMat( modelSize.height*maxBasicSolutions, modelSize.width, CV_64FC1 ); - err = cvCreateMat( 1, count, CV_32FC1 ); - tmask = cvCreateMat( 1, count, CV_8UC1 ); - - if( count > modelPoints ) - { - ms1 = cvCreateMat( 1, modelPoints, m1->type ); - ms2 = cvCreateMat( 1, modelPoints, m2->type ); - } - else - { - niters = 1; - ms1 = cvCloneMat(m1); - ms2 = cvCloneMat(m2); - } - - for( iter = 0; iter < niters; iter++ ) - { - int i, goodCount, nmodels; - if( count > modelPoints ) - { - bool found = getSubset( m1, m2, ms1, ms2, 300 ); - if( !found ) - { - if( iter == 0 ) - return false; - break; - } - - // Here we check for model specific geometrical - // constraints that allow to avoid "runKernel" - // and not checking for inliers if not fulfilled. - // - // The usefullness of this constraint for homographies is explained in the paper: - // - // "Speeding-up homography estimation in mobile devices" - // Journal of Real-Time Image Processing. 2013. DOI: 10.1007/s11554-012-0314-1 - // Pablo Márquez-Neila, Javier López-Alberca, José M. Buenaposada, Luis Baumela - if ( !isMinimalSetConsistent( ms1, ms2 ) ) - continue; - } - - nmodels = runKernel( ms1, ms2, models ); - if( nmodels <= 0 ) - continue; - for( i = 0; i < nmodels; i++ ) - { - CvMat model_i; - cvGetRows( models, &model_i, i*modelSize.height, (i+1)*modelSize.height ); - goodCount = findInliers( m1, m2, &model_i, err, tmask, reprojThreshold ); - - if( goodCount > MAX(maxGoodCount, modelPoints-1) ) - { - std::swap(tmask, mask); - cvCopy( &model_i, model ); - maxGoodCount = goodCount; - niters = cvRANSACUpdateNumIters( confidence, - (double)(count - goodCount)/count, modelPoints, niters ); - } - } - } - - if( maxGoodCount > 0 ) - { - if( mask != mask0 ) - cvCopy( mask, mask0 ); - result = true; - } - - return result; -} - - -static CV_IMPLEMENT_QSORT( icvSortDistances, int, CV_LT ) - -bool CvModelEstimator2::runLMeDS( const CvMat* m1, const CvMat* m2, CvMat* model, - CvMat* mask, double confidence, int maxIters ) -{ - const double outlierRatio = 0.45; - bool result = false; - cv::Ptr models; - cv::Ptr ms1, ms2; - cv::Ptr err; - - int iter, niters = maxIters; - int count = m1->rows*m1->cols; - double minMedian = DBL_MAX, sigma; - - CV_Assert( CV_ARE_SIZES_EQ(m1, m2) && CV_ARE_SIZES_EQ(m1, mask) ); - - if( count < modelPoints ) - return false; - - models = cvCreateMat( modelSize.height*maxBasicSolutions, modelSize.width, CV_64FC1 ); - err = cvCreateMat( 1, count, CV_32FC1 ); - - if( count > modelPoints ) - { - ms1 = cvCreateMat( 1, modelPoints, m1->type ); - ms2 = cvCreateMat( 1, modelPoints, m2->type ); - } - else - { - niters = 1; - ms1 = cvCloneMat(m1); - ms2 = cvCloneMat(m2); - } - - niters = cvRound(log(1-confidence)/log(1-pow(1-outlierRatio,(double)modelPoints))); - niters = MIN( MAX(niters, 3), maxIters ); - - for( iter = 0; iter < niters; iter++ ) - { - int i, nmodels; - if( count > modelPoints ) - { - bool found = getSubset( m1, m2, ms1, ms2, 300 ); - if( !found ) - { - if( iter == 0 ) - return false; - break; - } - } - - nmodels = runKernel( ms1, ms2, models ); - if( nmodels <= 0 ) - continue; - for( i = 0; i < nmodels; i++ ) - { - CvMat model_i; - cvGetRows( models, &model_i, i*modelSize.height, (i+1)*modelSize.height ); - computeReprojError( m1, m2, &model_i, err ); - icvSortDistances( err->data.i, count, 0 ); - - double median = count % 2 != 0 ? - err->data.fl[count/2] : (err->data.fl[count/2-1] + err->data.fl[count/2])*0.5; - - if( median < minMedian ) - { - minMedian = median; - cvCopy( &model_i, model ); - } - } - } - - if( minMedian < DBL_MAX ) - { - sigma = 2.5*1.4826*(1 + 5./(count - modelPoints))*std::sqrt(minMedian); - sigma = MAX( sigma, 0.001 ); - - count = findInliers( m1, m2, model, err, mask, sigma ); - result = count >= modelPoints; - } - - return result; -} - - -bool CvModelEstimator2::getSubset( const CvMat* m1, const CvMat* m2, - CvMat* ms1, CvMat* ms2, int maxAttempts ) -{ - cv::AutoBuffer _idx(modelPoints); - int* idx = _idx; - int i = 0, j, k, idx_i, iters = 0; - int type = CV_MAT_TYPE(m1->type), elemSize = CV_ELEM_SIZE(type); - const int *m1ptr = m1->data.i, *m2ptr = m2->data.i; - int *ms1ptr = ms1->data.i, *ms2ptr = ms2->data.i; - int count = m1->cols*m1->rows; - - assert( CV_IS_MAT_CONT(m1->type & m2->type) && (elemSize % sizeof(int) == 0) ); - elemSize /= sizeof(int); - - for(; iters < maxAttempts; iters++) - { - for( i = 0; i < modelPoints && iters < maxAttempts; ) - { - idx[i] = idx_i = cvRandInt(&rng) % count; - for( j = 0; j < i; j++ ) - if( idx_i == idx[j] ) - break; - if( j < i ) - continue; - for( k = 0; k < elemSize; k++ ) - { - ms1ptr[i*elemSize + k] = m1ptr[idx_i*elemSize + k]; - ms2ptr[i*elemSize + k] = m2ptr[idx_i*elemSize + k]; - } - if( checkPartialSubsets && (!checkSubset( ms1, i+1 ) || !checkSubset( ms2, i+1 ))) - { - iters++; - continue; - } - i++; - } - if( !checkPartialSubsets && i == modelPoints && - (!checkSubset( ms1, i ) || !checkSubset( ms2, i ))) - continue; - break; - } - - return i == modelPoints && iters < maxAttempts; -} - - -bool CvModelEstimator2::checkSubset( const CvMat* m, int count ) -{ - if( count <= 2 ) - return true; - - int j, k, i, i0, i1; - CvPoint2D64f* ptr = (CvPoint2D64f*)m->data.ptr; - - assert( CV_MAT_TYPE(m->type) == CV_64FC2 ); - - if( checkPartialSubsets ) - i0 = i1 = count - 1; - else - i0 = 0, i1 = count - 1; - - for( i = i0; i <= i1; i++ ) - { - // check that the i-th selected point does not belong - // to a line connecting some previously selected points - for( j = 0; j < i; j++ ) - { - double dx1 = ptr[j].x - ptr[i].x; - double dy1 = ptr[j].y - ptr[i].y; - for( k = 0; k < j; k++ ) - { - double dx2 = ptr[k].x - ptr[i].x; - double dy2 = ptr[k].y - ptr[i].y; - if( fabs(dx2*dy1 - dy2*dx1) <= FLT_EPSILON*(fabs(dx1) + fabs(dy1) + fabs(dx2) + fabs(dy2))) - break; - } - if( k < j ) - break; - } - if( j < i ) - break; - } - - return i > i1; -} - - -namespace cv -{ - -class Affine3DEstimator : public CvModelEstimator2 -{ -public: - Affine3DEstimator() : CvModelEstimator2(4, cvSize(4, 3), 1) {} - virtual int runKernel( const CvMat* m1, const CvMat* m2, CvMat* model ); -protected: - virtual void computeReprojError( const CvMat* m1, const CvMat* m2, const CvMat* model, CvMat* error ); - virtual bool checkSubset( const CvMat* ms1, int count ); -}; - -} - -int cv::Affine3DEstimator::runKernel( const CvMat* m1, const CvMat* m2, CvMat* model ) -{ - const Point3d* from = reinterpret_cast(m1->data.ptr); - const Point3d* to = reinterpret_cast(m2->data.ptr); - - Mat A(12, 12, CV_64F); - Mat B(12, 1, CV_64F); - A = Scalar(0.0); - - for(int i = 0; i < modelPoints; ++i) - { - *B.ptr(3*i) = to[i]; - - double *aptr = A.ptr(3*i); - for(int k = 0; k < 3; ++k) - { - aptr[3] = 1.0; - *reinterpret_cast(aptr) = from[i]; - aptr += 16; - } - } - - CvMat cvA = A; - CvMat cvB = B; - CvMat cvX; - cvReshape(model, &cvX, 1, 12); - cvSolve(&cvA, &cvB, &cvX, CV_SVD ); - - return 1; -} - -void cv::Affine3DEstimator::computeReprojError( const CvMat* m1, const CvMat* m2, const CvMat* model, CvMat* error ) -{ - int count = m1->rows * m1->cols; - const Point3d* from = reinterpret_cast(m1->data.ptr); - const Point3d* to = reinterpret_cast(m2->data.ptr); - const double* F = model->data.db; - float* err = error->data.fl; - - for(int i = 0; i < count; i++ ) - { - const Point3d& f = from[i]; - const Point3d& t = to[i]; - - double a = F[0]*f.x + F[1]*f.y + F[ 2]*f.z + F[ 3] - t.x; - double b = F[4]*f.x + F[5]*f.y + F[ 6]*f.z + F[ 7] - t.y; - double c = F[8]*f.x + F[9]*f.y + F[10]*f.z + F[11] - t.z; - - err[i] = (float)std::sqrt(a*a + b*b + c*c); - } -} - -bool cv::Affine3DEstimator::checkSubset( const CvMat* ms1, int count ) -{ - CV_Assert( CV_MAT_TYPE(ms1->type) == CV_64FC3 ); - - int j, k, i = count - 1; - const Point3d* ptr = reinterpret_cast(ms1->data.ptr); - - // check that the i-th selected point does not belong - // to a line connecting some previously selected points - - for(j = 0; j < i; ++j) - { - Point3d d1 = ptr[j] - ptr[i]; - double n1 = norm(d1); - - for(k = 0; k < j; ++k) - { - Point3d d2 = ptr[k] - ptr[i]; - double n = norm(d2) * n1; - - if (fabs(d1.dot(d2) / n) > 0.996) - break; - } - if( k < j ) - break; - } - - return j == i; -} - -int cv::estimateAffine3D(InputArray _from, InputArray _to, - OutputArray _out, OutputArray _inliers, - double param1, double param2) -{ - Mat from = _from.getMat(), to = _to.getMat(); - int count = from.checkVector(3); - - CV_Assert( count >= 0 && to.checkVector(3) == count ); - - _out.create(3, 4, CV_64F); - Mat out = _out.getMat(); - - Mat inliers(1, count, CV_8U); - inliers = Scalar::all(1); - - Mat dFrom, dTo; - from.convertTo(dFrom, CV_64F); - to.convertTo(dTo, CV_64F); - dFrom = dFrom.reshape(3, 1); - dTo = dTo.reshape(3, 1); - - CvMat F3x4 = out; - CvMat mask = inliers; - CvMat m1 = dFrom; - CvMat m2 = dTo; - - const double epsilon = std::numeric_limits::epsilon(); - param1 = param1 <= 0 ? 3 : param1; - param2 = (param2 < epsilon) ? 0.99 : (param2 > 1 - epsilon) ? 0.99 : param2; - - int ok = Affine3DEstimator().runRANSAC(&m1, &m2, &F3x4, &mask, param1, param2 ); - if( _inliers.needed() ) - transpose(inliers, _inliers); - - return ok; -} diff --git a/modules/calib3d/src/precomp.hpp b/modules/calib3d/src/precomp.hpp index 9b1f433ad4..7883390f4a 100644 --- a/modules/calib3d/src/precomp.hpp +++ b/modules/calib3d/src/precomp.hpp @@ -59,4 +59,51 @@ #define GET_OPTIMIZED(func) (func) #endif + +namespace cv +{ + +int RANSACUpdateNumIters( double p, double ep, int modelPoints, int maxIters ); + +class CV_EXPORTS LMSolver : public Algorithm +{ +public: + class CV_EXPORTS Callback + { + public: + virtual ~Callback() {} + virtual bool compute(InputArray param, OutputArray err, OutputArray J) const = 0; + }; + + virtual void setCallback(const Ptr& cb) = 0; + virtual int run(InputOutputArray _param0) const = 0; +}; + +CV_EXPORTS Ptr createLMSolver(const Ptr& cb, int maxIters); + +class PointSetRegistrator : public Algorithm +{ +public: + class CV_EXPORTS Callback + { + public: + virtual ~Callback() {} + virtual int runKernel(InputArray m1, InputArray m2, OutputArray model) const = 0; + virtual void computeError(InputArray m1, InputArray m2, InputArray model, OutputArray err) const = 0; + virtual bool checkSubset(InputArray, InputArray, int) const { return true; } + }; + + virtual void setCallback(const Ptr& cb) = 0; + virtual bool run(InputArray m1, InputArray m2, OutputArray model, OutputArray mask) const = 0; +}; + +CV_EXPORTS Ptr createRANSACPointSetRegistrator(const Ptr& cb, + int modelPoints, double threshold, + double confidence=0.99, int maxIters=1000 ); + +CV_EXPORTS Ptr createLMeDSPointSetRegistrator(const Ptr& cb, + int modelPoints, double confidence=0.99, int maxIters=1000 ); + +} + #endif diff --git a/modules/calib3d/src/ptsetreg.cpp b/modules/calib3d/src/ptsetreg.cpp new file mode 100644 index 0000000000..9a202d3cca --- /dev/null +++ b/modules/calib3d/src/ptsetreg.cpp @@ -0,0 +1,545 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +#include +#include +#include + +namespace cv +{ + +int RANSACUpdateNumIters( double p, double ep, int modelPoints, int maxIters ) +{ + if( modelPoints <= 0 ) + CV_Error( CV_StsOutOfRange, "the number of model points should be positive" ); + + p = MAX(p, 0.); + p = MIN(p, 1.); + ep = MAX(ep, 0.); + ep = MIN(ep, 1.); + + // avoid inf's & nan's + double num = MAX(1. - p, DBL_MIN); + double denom = 1. - std::pow(1. - ep, modelPoints); + if( denom < DBL_MIN ) + return 0; + + num = std::log(num); + denom = std::log(denom); + + return denom >= 0 || -num >= maxIters*(-denom) ? maxIters : cvRound(num/denom); +} + + +class RANSACPointSetRegistrator : public PointSetRegistrator +{ +public: + RANSACPointSetRegistrator(const Ptr& _cb=Ptr(), + int _modelPoints=0, double _threshold=0, double _confidence=0.99, int _maxIters=1000) + : cb(_cb), modelPoints(_modelPoints), threshold(_threshold), confidence(_confidence), maxIters(_maxIters) + { + checkPartialSubsets = true; + } + + virtual ~RANSACPointSetRegistrator() {} + + int findInliers( const Mat& m1, const Mat& m2, const Mat& model, Mat& err, Mat& mask, double thresh ) const + { + cb->computeError( m1, m2, model, err ); + mask.create(err.size(), CV_8U); + + CV_Assert( err.isContinuous() && err.type() == CV_32F && mask.isContinuous() && mask.type() == CV_8U); + const float* errptr = err.ptr(); + uchar* maskptr = mask.ptr(); + float t = (float)(thresh*thresh); + int i, n = (int)err.total(), nz = 0; + for( i = 0; i < n; i++ ) + { + int f = errptr[i] <= t; + maskptr[i] = (uchar)f; + nz += f; + } + return nz; + } + + bool getSubset( const Mat& m1, const Mat& m2, + Mat& ms1, Mat& ms2, RNG& rng, + int maxAttempts=1000 ) const + { + cv::AutoBuffer _idx(modelPoints); + int* idx = _idx; + int i = 0, j, k, iters = 0; + int esz1 = (int)m1.elemSize(), esz2 = (int)m2.elemSize(); + int d1 = m1.channels() > 1 ? m1.channels() : m1.cols; + int d2 = m2.channels() > 1 ? m2.channels() : m2.cols; + int count = m1.checkVector(d1), count2 = m2.checkVector(d2); + const int *m1ptr = (const int*)m1.data, *m2ptr = (const int*)m2.data; + + ms1.create(modelPoints, 1, CV_MAKETYPE(m1.depth(), d1)); + ms2.create(modelPoints, 1, CV_MAKETYPE(m2.depth(), d2)); + + int *ms1ptr = (int*)ms1.data, *ms2ptr = (int*)ms2.data; + + CV_Assert( count >= modelPoints && count == count2 ); + CV_Assert( (esz1 % sizeof(int)) == 0 && (esz2 % sizeof(int)) == 0 ); + esz1 /= sizeof(int); + esz2 /= sizeof(int); + + for(; iters < maxAttempts; iters++) + { + for( i = 0; i < modelPoints && iters < maxAttempts; ) + { + int idx_i = 0; + for(;;) + { + idx_i = idx[i] = rng.uniform(0, count); + for( j = 0; j < i; j++ ) + if( idx_i == idx[j] ) + break; + if( j == i ) + break; + } + for( k = 0; k < esz1; k++ ) + ms1ptr[i*esz1 + k] = m1ptr[idx_i*esz1 + k]; + for( k = 0; k < esz2; k++ ) + ms2ptr[i*esz2 + k] = m2ptr[idx_i*esz2 + k]; + if( checkPartialSubsets && !cb->checkSubset( ms1, ms2, i+1 )) + { + iters++; + continue; + } + i++; + } + if( !checkPartialSubsets && i == modelPoints && !cb->checkSubset(ms1, ms2, i)) + continue; + break; + } + + return i == modelPoints && iters < maxAttempts; + } + + bool run(InputArray _m1, InputArray _m2, OutputArray _model, OutputArray _mask) const + { + bool result = false; + Mat m1 = _m1.getMat(), m2 = _m2.getMat(); + Mat err, mask, model, bestModel, ms1, ms2; + + int iter, niters = MAX(maxIters, 1); + int d1 = m1.channels() > 1 ? m1.channels() : m1.cols; + int d2 = m2.channels() > 1 ? m2.channels() : m2.cols; + int count = m1.checkVector(d1), count2 = m2.checkVector(d2), maxGoodCount = 0; + + RNG rng((uint64)-1); + + CV_Assert( !cb.empty() ); + CV_Assert( confidence > 0 && confidence < 1 ); + + CV_Assert( count >= 0 && count2 == count ); + if( count < modelPoints ) + return false; + + Mat bestMask0, bestMask; + + if( _mask.needed() ) + { + if( !_mask.fixedSize() ) + _mask.create(count, 1, CV_8U); + bestMask0 = bestMask = _mask.getMat(); + CV_Assert( (bestMask.cols == 1 || bestMask.rows == 1) && (int)bestMask.total() == count ); + } + else + { + bestMask.create(count, 1, CV_8U); + bestMask0 = bestMask; + } + + if( count == modelPoints ) + { + if( cb->runKernel(m1, m2, bestModel) <= 0 ) + return false; + bestModel.copyTo(_model); + bestMask.setTo(Scalar::all(1)); + return true; + } + + for( iter = 0; iter < niters; iter++ ) + { + int i, goodCount, nmodels; + if( count > modelPoints ) + { + bool found = getSubset( m1, m2, ms1, ms2, rng ); + if( !found ) + { + if( iter == 0 ) + return false; + break; + } + } + + nmodels = cb->runKernel( ms1, ms2, model ); + if( nmodels <= 0 ) + continue; + CV_Assert( model.rows % nmodels == 0 ); + Size modelSize(model.cols, model.rows/nmodels); + + for( i = 0; i < nmodels; i++ ) + { + Mat model_i = model.rowRange( i*modelSize.height, (i+1)*modelSize.height ); + goodCount = findInliers( m1, m2, model_i, err, mask, threshold ); + + if( goodCount > MAX(maxGoodCount, modelPoints-1) ) + { + std::swap(mask, bestMask); + model_i.copyTo(bestModel); + maxGoodCount = goodCount; + niters = RANSACUpdateNumIters( confidence, (double)(count - goodCount)/count, modelPoints, niters ); + } + } + } + + if( maxGoodCount > 0 ) + { + if( bestMask.data != bestMask0.data ) + { + if( bestMask.size() == bestMask0.size() ) + bestMask.copyTo(bestMask0); + else + transpose(bestMask, bestMask0); + } + bestModel.copyTo(_model); + result = true; + } + else + _model.release(); + + return result; + } + + void setCallback(const Ptr& _cb) { cb = _cb; } + + AlgorithmInfo* info() const; + + Ptr cb; + int modelPoints; + int maxBasicSolutions; + bool checkPartialSubsets; + double threshold; + double confidence; + int maxIters; +}; + + +static CV_IMPLEMENT_QSORT( sortDistances, int, CV_LT ) + +class LMeDSPointSetRegistrator : public RANSACPointSetRegistrator +{ +public: + LMeDSPointSetRegistrator(const Ptr& _cb=Ptr(), + int _modelPoints=0, double _confidence=0.99, int _maxIters=1000) + : RANSACPointSetRegistrator(_cb, _modelPoints, 0, _confidence, _maxIters) {} + + bool run(InputArray _m1, InputArray _m2, OutputArray _model, OutputArray _mask) const + { + const double outlierRatio = 0.45; + bool result = false; + Mat m1 = _m1.getMat(), m2 = _m2.getMat(); + Mat ms1, ms2, err, errf, model, bestModel, mask, mask0; + + int d1 = m1.channels() > 1 ? m1.channels() : m1.cols; + int d2 = m2.channels() > 1 ? m2.channels() : m2.cols; + int count = m1.checkVector(d1), count2 = m2.checkVector(d2); + double minMedian = DBL_MAX, sigma; + + RNG rng((uint64)-1); + + CV_Assert( !cb.empty() ); + CV_Assert( confidence > 0 && confidence < 1 ); + + CV_Assert( count >= 0 && count2 == count ); + if( count < modelPoints ) + return false; + + if( _mask.needed() ) + { + if( !_mask.fixedSize() ) + _mask.create(count, 1, CV_8U); + mask0 = mask = _mask.getMat(); + CV_Assert( (mask.cols == 1 || mask.rows == 1) && (int)mask.total() == count ); + } + + if( count == modelPoints ) + { + if( cb->runKernel(m1, m2, bestModel) <= 0 ) + return false; + bestModel.copyTo(_model); + mask.setTo(Scalar::all(1)); + return true; + } + + int iter, niters = cvRound(std::log(1-confidence)/ + std::log(1-std::pow(1-outlierRatio,(double)modelPoints))); + niters = MIN( MAX(niters, 3), maxIters ); + + for( iter = 0; iter < niters; iter++ ) + { + int i, nmodels; + if( count > modelPoints ) + { + bool found = getSubset( m1, m2, ms1, ms2, rng ); + if( !found ) + { + if( iter == 0 ) + return false; + break; + } + } + + nmodels = cb->runKernel( ms1, ms2, model ); + if( nmodels <= 0 ) + continue; + + CV_Assert( model.rows % nmodels == 0 ); + Size modelSize(model.cols, model.rows/nmodels); + + for( i = 0; i < nmodels; i++ ) + { + Mat model_i = model.rowRange( i*modelSize.height, (i+1)*modelSize.height ); + cb->computeError( m1, m2, model_i, err ); + if( err.depth() != CV_32F ) + err.convertTo(errf, CV_32F); + else + errf = err; + CV_Assert( errf.isContinuous() && errf.type() == CV_32F && (int)errf.total() == count ); + sortDistances( (int*)errf.data, count, 0 ); + + double median = count % 2 != 0 ? + errf.at(count/2) : (errf.at(count/2-1) + errf.at(count/2))*0.5; + + if( median < minMedian ) + { + minMedian = median; + model_i.copyTo(bestModel); + } + } + } + + if( minMedian < DBL_MAX ) + { + sigma = 2.5*1.4826*(1 + 5./(count - modelPoints))*std::sqrt(minMedian); + sigma = MAX( sigma, 0.001 ); + + count = findInliers( m1, m2, bestModel, err, mask, sigma ); + if( _mask.needed() && mask0.data != mask.data ) + { + if( mask0.size() == mask.size() ) + mask.copyTo(mask0); + else + transpose(mask, mask0); + } + bestModel.copyTo(_model); + result = count >= modelPoints; + } + else + _model.release(); + + return result; + } + + AlgorithmInfo* info() const; +}; + + +CV_INIT_ALGORITHM(RANSACPointSetRegistrator, "PointSetRegistrator.RANSAC", + obj.info()->addParam(obj, "threshold", obj.threshold); + obj.info()->addParam(obj, "confidence", obj.confidence); + obj.info()->addParam(obj, "maxIters", obj.maxIters)); + +CV_INIT_ALGORITHM(LMeDSPointSetRegistrator, "PointSetRegistrator.LMeDS", + obj.info()->addParam(obj, "confidence", obj.confidence); + obj.info()->addParam(obj, "maxIters", obj.maxIters)); + +Ptr createRANSACPointSetRegistrator(const Ptr& _cb, + int _modelPoints, double _threshold, + double _confidence, int _maxIters) +{ + CV_Assert( !RANSACPointSetRegistrator_info_auto.name().empty() ); + return new RANSACPointSetRegistrator(_cb, _modelPoints, _threshold, _confidence, _maxIters); +} + + +Ptr createLMeDSPointSetRegistrator(const Ptr& _cb, + int _modelPoints, double _confidence, int _maxIters) +{ + CV_Assert( !LMeDSPointSetRegistrator_info_auto.name().empty() ); + return new LMeDSPointSetRegistrator(_cb, _modelPoints, _confidence, _maxIters); +} + +class Affine3DEstimatorCallback : public PointSetRegistrator::Callback +{ +public: + int runKernel( InputArray _m1, InputArray _m2, OutputArray _model ) const + { + Mat m1 = _m1.getMat(), m2 = _m2.getMat(); + const Point3f* from = m1.ptr(); + const Point3f* to = m2.ptr(); + + const int N = 12; + double buf[N*N + N + N]; + Mat A(N, N, CV_64F, &buf[0]); + Mat B(N, 1, CV_64F, &buf[0] + N*N); + Mat X(N, 1, CV_64F, &buf[0] + N*N + N); + double* Adata = A.ptr(); + double* Bdata = B.ptr(); + A = Scalar::all(0); + + for( int i = 0; i < (N/3); i++ ) + { + Bdata[i*3] = to[i].x; + Bdata[i*3+1] = to[i].y; + Bdata[i*3+2] = to[i].z; + + double *aptr = Adata + i*3*N; + for(int k = 0; k < 3; ++k) + { + aptr[0] = from[i].x; + aptr[1] = from[i].y; + aptr[2] = from[i].z; + aptr[3] = 1.0; + aptr += 16; + } + } + + solve(A, B, X, DECOMP_SVD); + X.reshape(1, 3).copyTo(_model); + + return 1; + } + + void computeError( InputArray _m1, InputArray _m2, InputArray _model, OutputArray _err ) const + { + Mat m1 = _m1.getMat(), m2 = _m2.getMat(), model = _model.getMat(); + const Point3f* from = m1.ptr(); + const Point3f* to = m2.ptr(); + const double* F = model.ptr(); + + int count = m1.checkVector(3); + CV_Assert( count > 0 ); + + _err.create(count, 1, CV_32F); + Mat err = _err.getMat(); + float* errptr = err.ptr(); + + for(int i = 0; i < count; i++ ) + { + const Point3f& f = from[i]; + const Point3f& t = to[i]; + + double a = F[0]*f.x + F[1]*f.y + F[ 2]*f.z + F[ 3] - t.x; + double b = F[4]*f.x + F[5]*f.y + F[ 6]*f.z + F[ 7] - t.y; + double c = F[8]*f.x + F[9]*f.y + F[10]*f.z + F[11] - t.z; + + errptr[i] = (float)std::sqrt(a*a + b*b + c*c); + } + } + + bool checkSubset( InputArray _ms1, InputArray _ms2, int count ) const + { + const float threshold = 0.996f; + Mat ms1 = _ms1.getMat(), ms2 = _ms2.getMat(); + + for( int inp = 1; inp <= 2; inp++ ) + { + int j, k, i = count - 1; + const Mat* msi = inp == 1 ? &ms1 : &ms2; + const Point3f* ptr = msi->ptr(); + + CV_Assert( count <= msi->rows ); + + // check that the i-th selected point does not belong + // to a line connecting some previously selected points + for(j = 0; j < i; ++j) + { + Point3f d1 = ptr[j] - ptr[i]; + float n1 = d1.x*d1.x + d1.y*d1.y; + + for(k = 0; k < j; ++k) + { + Point3f d2 = ptr[k] - ptr[i]; + float denom = (d2.x*d2.x + d2.y*d2.y)*n1; + float num = d1.x*d2.x + d1.y*d2.y; + + if( num*num > threshold*threshold*denom ) + return false; + } + } + } + return true; + } +}; + +} + +int cv::estimateAffine3D(InputArray _from, InputArray _to, + OutputArray _out, OutputArray _inliers, + double param1, double param2) +{ + Mat from = _from.getMat(), to = _to.getMat(); + int count = from.checkVector(3); + + CV_Assert( count >= 0 && to.checkVector(3) == count ); + + Mat dFrom, dTo; + from.convertTo(dFrom, CV_32F); + to.convertTo(dTo, CV_32F); + dFrom = dFrom.reshape(3, count); + dTo = dTo.reshape(3, count); + + const double epsilon = DBL_EPSILON; + param1 = param1 <= 0 ? 3 : param1; + param2 = (param2 < epsilon) ? 0.99 : (param2 > 1 - epsilon) ? 0.99 : param2; + + return createRANSACPointSetRegistrator(new Affine3DEstimatorCallback, 4, param1, param2)->run(dFrom, dTo, _out, _inliers); +} + diff --git a/modules/calib3d/test/test_affine3d_estimator.cpp b/modules/calib3d/test/test_affine3d_estimator.cpp index eedfa687c6..ff061aacfa 100644 --- a/modules/calib3d/test/test_affine3d_estimator.cpp +++ b/modules/calib3d/test/test_affine3d_estimator.cpp @@ -163,6 +163,8 @@ bool CV_Affine3D_EstTest::testNPoints() const double thres = 1e-4; if (norm(aff_est, aff, NORM_INF) > thres) { + cout << "aff est: " << aff_est << endl; + cout << "aff ref: " << aff << endl; ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); return false; } diff --git a/modules/calib3d/test/test_fundam.cpp b/modules/calib3d/test/test_fundam.cpp index 08ffcf6626..19ee70fa1b 100644 --- a/modules/calib3d/test/test_fundam.cpp +++ b/modules/calib3d/test/test_fundam.cpp @@ -1020,7 +1020,7 @@ void CV_FundamentalMatTest::prepare_to_validation( int test_case_idx ) F0 *= 1./f0[8]; uchar* status = test_mat[TEMP][1].data; - double err_level = get_success_error_level( test_case_idx, OUTPUT, 1 ); + double err_level = method <= CV_FM_8POINT ? 1 : get_success_error_level( test_case_idx, OUTPUT, 1 ); uchar* mtfm1 = test_mat[REF_OUTPUT][1].data; uchar* mtfm2 = test_mat[OUTPUT][1].data; double* f_prop1 = (double*)test_mat[REF_OUTPUT][0].data; diff --git a/modules/calib3d/test/test_modelest.cpp b/modules/calib3d/test/test_modelest.cpp index b3254c8be1..5b0a860169 100644 --- a/modules/calib3d/test/test_modelest.cpp +++ b/modules/calib3d/test/test_modelest.cpp @@ -40,6 +40,8 @@ //M*/ #include "test_precomp.hpp" + +#if 0 #include "_modelest.h" using namespace std; @@ -225,3 +227,6 @@ void CV_ModelEstimator2_Test::run_func() } TEST(Calib3d_ModelEstimator2, accuracy) { CV_ModelEstimator2_Test test; test.safe_run(); } + +#endif + diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 0528ce2122..cda2c33974 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -1145,7 +1145,7 @@ Size _InputArray::size(int i) const const std::vector& v = *(const std::vector*)obj; const std::vector& iv = *(const std::vector*)obj; size_t szb = v.size(), szi = iv.size(); - return szb == szi ? Size((int)szb, 1) : Size((int)(szb/CV_ELEM_SIZE(flags)), 1); + return szb == szi ? Size(1, (int)szb) : Size(1, (int)(szb/CV_ELEM_SIZE(flags))); } if( k == NONE ) @@ -1155,19 +1155,19 @@ Size _InputArray::size(int i) const { const std::vector >& vv = *(const std::vector >*)obj; if( i < 0 ) - return vv.empty() ? Size() : Size((int)vv.size(), 1); + return vv.empty() ? Size() : Size(1, (int)vv.size()); CV_Assert( i < (int)vv.size() ); const std::vector >& ivv = *(const std::vector >*)obj; size_t szb = vv[i].size(), szi = ivv[i].size(); - return szb == szi ? Size((int)szb, 1) : Size((int)(szb/CV_ELEM_SIZE(flags)), 1); + return szb == szi ? Size(1, (int)szb) : Size(1, (int)(szb/CV_ELEM_SIZE(flags))); } if( k == STD_VECTOR_MAT ) { const std::vector& vv = *(const std::vector*)obj; if( i < 0 ) - return vv.empty() ? Size() : Size((int)vv.size(), 1); + return vv.empty() ? Size() : Size(1, (int)vv.size()); CV_Assert( i < (int)vv.size() ); return vv[i].size(); diff --git a/modules/core/test/test_operations.cpp b/modules/core/test/test_operations.cpp index 6b36883cfe..09d5f0575c 100644 --- a/modules/core/test/test_operations.cpp +++ b/modules/core/test/test_operations.cpp @@ -487,7 +487,7 @@ bool CV_OperationsTest::TestSubMatAccess() coords.push_back(T_bs(i)); //std::cout << T_bs1(i) << std::endl; } - CV_Assert( norm(coords, T_bs.reshape(1,1), NORM_INF) == 0 ); + CV_Assert( norm(coords, T_bs.reshape(1,1).t(), NORM_INF) == 0 ); } catch (const test_excep& e) {