// 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,
// 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
//
//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
using namespace cv;
-CvLevMarq::CvLevMarq()
-{
- mask = prevParam = param = J = err = JtJ = JtJN = JtErr = JtJV = JtJW = Ptr<CvMat>();
- 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<CvMat>();
- 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 )
{
else
idealPt = Point2f(j*squareSize, i*squareSize);
- std::vector<float> query = Mat(idealPt);
+ Mat query(1, 2, CV_32F, &idealPt);
int knn = 1;
- std::vector<int> indices(knn);
- std::vector<float> 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;
--- /dev/null
+/*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<CvMat>();
+ 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<CvMat>();
+ 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());
+ }
+}
+
+/*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 <complex>
-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<std::complex<double> > roots;
+ solvePoly(coeffs, roots);
+
+ std::vector<double> xs, ys, zs;
+ int count = 0;
+
+ Mat ematrix(10*3, 3, CV_64F);
+ double* e = ematrix.ptr<double>();
+ 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<double>(2)) < 1e-10) continue;
+ xs.push_back(xy1.at<double>(0) / xy1.at<double>(2));
+ ys.push_back(xy1.at<double>(1) / xy1.at<double>(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<Point2d>();
+ const Point2d* x2ptr = X2.ptr<Point2d>();
+ int n = X1.checkVector(2);
+ Matx33d E(model.ptr<double>());
+
+ _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<float>(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<double>(i, 0) = (points1.at<double>(i, 0) - pp.x)*ifocal;
+ points1.at<double>(i, 1) = (points1.at<double>(i, 1) - pp.y)*ifocal;
+ points2.at<double>(i, 0) = (points2.at<double>(i, 0) - pp.x)*ifocal;
+ points2.at<double>(i, 1) = (points2.at<double>(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_<double>(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_<double>(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<std::complex<double> > roots;
- solvePoly(coeffs, roots);
-
- std::vector<double> 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<double>(2)) < 1e-10) continue;
- xs.push_back(xy1.at<double>(0) / xy1.at<double>(2));
- ys.push_back(xy1.at<double>(1) / xy1.at<double>(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_<double>(3, 1) << X1.at<double>(i, 0), X1.at<double>(i, 1), 1.0);
- Mat x2 = (Mat_<double>(3, 1) << X2.at<double>(i, 0), X2.at<double>(i, 1), 1.0);
- double x2tEx1 = x2.dot(E * x1);
- Mat Ex1 = E * x1;
- Mat Etx2 = E * x2;
- double a = Ex1.at<double>(0) * Ex1.at<double>(0);
- double b = Ex1.at<double>(1) * Ex1.at<double>(1);
- double c = Etx2.at<double>(0) * Etx2.at<double>(0);
- double d = Etx2.at<double>(0) * Etx2.at<double>(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;
-
-}
-
-
-
-
// 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,
// 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
//M*/
#include "precomp.hpp"
-#include "_modelest.h"
+#include <iostream>
-using namespace cv;
+namespace cv
+{
-template<typename T> 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<Point2f>();
+
+ // 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<typename T> int compressPoints( T* ptr, const uchar* mask, int mstep, int count )
{
int i, j;
for( i = j = 0; i < count; i++ )
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<Point2f>();
+ const Point2f* dst = ms2.ptr<Point2f>();
+ 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<Point2f>();
+ const Point2f* m = m2.ptr<Point2f>();
- 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<double>(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<Point2f>();
+ const Point2f* m = m2.ptr<Point2f>();
+ const double* H = model.ptr<double>();
+ 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<float>();
+ 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<Point2f>();
+ const Point2f* m = dst.ptr<Point2f>();
+ const double* h = param.ptr<double>();
+ double* errptr = err.ptr<double>();
+ double* Jptr = J.data ? J.ptr<double>() : 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<CvMat> 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<PointSetRegistrator::Callback> 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<Point2f>(), tempMask.ptr<uchar>(), 1, npoints );
+ npoints = compressPoints( dst.ptr<Point2f>(), tempMask.ptr<uchar>(), 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<double>());
+ 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
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<Point2f>();
+ const Point2f* m2 = _m2.ptr<Point2f>();
+ double* fmatrix = _fmatrix.ptr<double>();
int i, k, n;
// form a linear system: i-th row of A(=a) represents
// 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;
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;
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<Point2f>();
+ const Point2f* m2 = _m2.ptr<Point2f>();
+ double* fmatrix = _fmatrix.ptr<double>();
+ 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++ )
{
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<double>(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<double>(2,2)) > FLT_EPSILON )
+ F0 *= 1./F0.at<double>(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<Point2f>();
+ const Point2f* m2 = __m2.ptr<Point2f>();
+ const double* F = __model.ptr<double>();
+ _err.create(count, 1, CV_32F);
+ float* err = _err.getMat().ptr<float>();
- 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<CvMat> 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<PointSetRegistrator::Callback> 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 )
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<Point3f>();
+ 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<Point3d>();
+ 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<CvMat> 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();
--- /dev/null
+/*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 <stdio.h>
+
+/*
+ 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<LMSolver::Callback>& _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<double>(i, i) += lambda*D.at<double>(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<double>(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<double>(0), d.at<double>(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<LMSolver::Callback>& _cb) { cb = _cb; }
+
+ AlgorithmInfo* info() const;
+
+ Ptr<LMSolver::Callback> 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<LMSolver> createLMSolver(const Ptr<LMSolver::Callback>& cb, int maxIters)
+{
+ CV_Assert( !LMSolverImpl_info_auto.name().empty() );
+ return new LMSolverImpl(cb, maxIters);
+}
+
+}
+++ /dev/null
-/*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 <algorithm>
-#include <iterator>
-#include <limits>
-
-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<CvMat> mask = cvCloneMat(mask0);
- cv::Ptr<CvMat> models, err, tmask;
- cv::Ptr<CvMat> 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<CvMat> models;
- cv::Ptr<CvMat> ms1, ms2;
- cv::Ptr<CvMat> 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<int> _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<const Point3d*>(m1->data.ptr);
- const Point3d* to = reinterpret_cast<const Point3d*>(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<Point3d>(3*i) = to[i];
-
- double *aptr = A.ptr<double>(3*i);
- for(int k = 0; k < 3; ++k)
- {
- aptr[3] = 1.0;
- *reinterpret_cast<Point3d*>(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<const Point3d*>(m1->data.ptr);
- const Point3d* to = reinterpret_cast<const Point3d*>(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<const Point3d*>(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<double>::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;
-}
#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<LMSolver::Callback>& cb) = 0;
+ virtual int run(InputOutputArray _param0) const = 0;
+};
+
+CV_EXPORTS Ptr<LMSolver> createLMSolver(const Ptr<LMSolver::Callback>& 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<PointSetRegistrator::Callback>& cb) = 0;
+ virtual bool run(InputArray m1, InputArray m2, OutputArray model, OutputArray mask) const = 0;
+};
+
+CV_EXPORTS Ptr<PointSetRegistrator> createRANSACPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& cb,
+ int modelPoints, double threshold,
+ double confidence=0.99, int maxIters=1000 );
+
+CV_EXPORTS Ptr<PointSetRegistrator> createLMeDSPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& cb,
+ int modelPoints, double confidence=0.99, int maxIters=1000 );
+
+}
+
#endif
--- /dev/null
+/*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 <algorithm>
+#include <iterator>
+#include <limits>
+
+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<PointSetRegistrator::Callback>& _cb=Ptr<PointSetRegistrator::Callback>(),
+ 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<float>();
+ uchar* maskptr = mask.ptr<uchar>();
+ 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<int> _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<PointSetRegistrator::Callback>& _cb) { cb = _cb; }
+
+ AlgorithmInfo* info() const;
+
+ Ptr<PointSetRegistrator::Callback> 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<PointSetRegistrator::Callback>& _cb=Ptr<PointSetRegistrator::Callback>(),
+ 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<float>(count/2) : (errf.at<float>(count/2-1) + errf.at<float>(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<PointSetRegistrator> createRANSACPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& _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<PointSetRegistrator> createLMeDSPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& _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<Point3f>();
+ const Point3f* to = m2.ptr<Point3f>();
+
+ 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>();
+ double* Bdata = B.ptr<double>();
+ 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<Point3f>();
+ const Point3f* to = m2.ptr<Point3f>();
+ const double* F = model.ptr<double>();
+
+ int count = m1.checkVector(3);
+ CV_Assert( count > 0 );
+
+ _err.create(count, 1, CV_32F);
+ Mat err = _err.getMat();
+ float* errptr = err.ptr<float>();
+
+ 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<Point3f>();
+
+ 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);
+}
+
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;
}
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;
//M*/
#include "test_precomp.hpp"
+
+#if 0
#include "_modelest.h"
using namespace std;
}
TEST(Calib3d_ModelEstimator2, accuracy) { CV_ModelEstimator2_Test test; test.safe_run(); }
+
+#endif
+
const std::vector<uchar>& v = *(const std::vector<uchar>*)obj;
const std::vector<int>& iv = *(const std::vector<int>*)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 )
{
const std::vector<std::vector<uchar> >& vv = *(const std::vector<std::vector<uchar> >*)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<std::vector<int> >& ivv = *(const std::vector<std::vector<int> >*)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<Mat>& vv = *(const std::vector<Mat>*)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();
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)
{