2015-11-22 18:08:32 -05:00
/*
2016-07-17 21:57:10 -04:00
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
2015-11-22 18:08:32 -05:00
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.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may 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 COPYRIGHT HOLDER 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.
*/
#include <rtabmap/core/RegistrationVis.h>
#include <rtabmap/core/util3d_motion_estimation.h>
#include <rtabmap/core/util3d_features.h>
2023-10-25 14:54:20 -07:00
#include <rtabmap/core/util3d_transforms.h>
2015-12-21 17:27:05 -05:00
#include <rtabmap/core/util3d.h>
#include <rtabmap/core/VWDictionary.h>
2016-02-15 19:35:24 -05:00
#include <rtabmap/core/util2d.h>
2015-12-21 17:27:05 -05:00
#include <rtabmap/core/Features2d.h>
2016-11-14 19:54:31 -05:00
#include <rtabmap/core/VisualWord.h>
#include <rtabmap/core/Optimizer.h>
#include <rtabmap/core/util3d_transforms.h>
2015-11-22 18:08:32 -05:00
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UConversion.h>
#include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UTimer.h>
2015-12-21 17:27:05 -05:00
#include <rtabmap/utilite/UMath.h>
2019-07-25 13:14:57 -04:00
#include <opencv2/core/core_c.h>
2015-11-22 18:08:32 -05:00
2020-05-11 13:23:26 -04:00
#if defined(HAVE_OPENCV_XFEATURES2D) && (CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION==3 && CV_MINOR_VERSION >=4 && CV_SUBMINOR_VERSION >= 1))
#include <opencv2/xfeatures2d.hpp> // For GMS matcher
#endif
2016-02-22 16:13:14 -05:00
#include <rtflann/flann.hpp>
2020-05-09 21:13:41 -04:00
2021-01-17 01:56:27 -05:00
#ifdef RTABMAP_PYTHON
#include "python/PyMatcher.h"
2020-05-09 21:13:41 -04:00
#endif
2015-11-22 18:08:32 -05:00
namespace rtabmap {
2016-01-06 17:26:55 -05:00
RegistrationVis :: RegistrationVis ( const ParametersMap & parameters , Registration * child ) :
Registration ( parameters , child ),
2015-11-25 12:15:41 -05:00
_minInliers ( Parameters :: defaultVisMinInliers ()),
_inlierDistance ( Parameters :: defaultVisInlierDistance ()),
_iterations ( Parameters :: defaultVisIterations ()),
_refineIterations ( Parameters :: defaultVisRefineIterations ()),
_epipolarGeometryVar ( Parameters :: defaultVisEpipolarGeometryVar ()),
_estimationType ( Parameters :: defaultVisEstimationType ()),
2015-12-21 17:27:05 -05:00
_forwardEstimateOnly ( Parameters :: defaultVisForwardEstOnly ()),
2015-11-25 12:15:41 -05:00
_PnPReprojError ( Parameters :: defaultVisPnPReprojError ()),
2015-12-21 17:27:05 -05:00
_PnPFlags ( Parameters :: defaultVisPnPFlags ()),
2015-12-22 19:32:52 -05:00
_PnPRefineIterations ( Parameters :: defaultVisPnPRefineIterations ()),
2023-07-27 16:13:30 -07:00
_PnPVarMedianRatio ( Parameters :: defaultVisPnPVarianceMedianRatio ()),
2022-09-24 12:29:42 -07:00
_PnPMaxVar ( Parameters :: defaultVisPnPMaxVariance ()),
2024-02-07 14:43:16 -08:00
_PnPSplitLinearCovarianceComponents ( Parameters :: defaultVisPnPSplitLinearCovComponents ()),
2023-07-22 11:05:21 -04:00
_multiSamplingPolicy ( Parameters :: defaultVisPnPSamplingPolicy ()),
2015-12-21 17:27:05 -05:00
_correspondencesApproach ( Parameters :: defaultVisCorType ()),
_flowWinSize ( Parameters :: defaultVisCorFlowWinSize ()),
_flowIterations ( Parameters :: defaultVisCorFlowIterations ()),
_flowEps ( Parameters :: defaultVisCorFlowEps ()),
2016-01-13 09:20:15 -05:00
_flowMaxLevel ( Parameters :: defaultVisCorFlowMaxLevel ()),
2016-02-22 16:13:14 -05:00
_nndr ( Parameters :: defaultVisCorNNDR ()),
2020-05-09 21:13:41 -04:00
_nnType ( Parameters :: defaultVisCorNNType ()),
2020-05-11 13:23:26 -04:00
_gmsWithRotation ( Parameters :: defaultGMSWithRotation ()),
_gmsWithScale ( Parameters :: defaultGMSWithScale ()),
_gmsThresholdFactor ( Parameters :: defaultGMSThresholdFactor ()),
2016-11-14 19:54:31 -05:00
_guessWinSize ( Parameters :: defaultVisCorGuessWinSize ()),
2017-12-09 21:44:53 -05:00
_guessMatchToProjection ( Parameters :: defaultVisCorGuessMatchToProjection ()),
2018-02-01 22:17:46 -05:00
_bundleAdjustment ( Parameters :: defaultVisBundleAdjustment ()),
2019-06-16 18:54:39 -04:00
_depthAsMask ( Parameters :: defaultVisDepthAsMask ()),
_minInliersDistributionThr ( Parameters :: defaultVisMinInliersDistribution ()),
2020-04-16 17:59:45 -04:00
_maxInliersMeanDistance ( Parameters :: defaultVisMeanInliersDistance ()),
_detectorFrom ( 0 ),
2020-05-09 21:41:38 -04:00
_detectorTo ( 0 )
2021-01-17 01:56:27 -05:00
#ifdef RTABMAP_PYTHON
2020-05-09 21:41:38 -04:00
,
2020-05-20 09:45:39 -04:00
_pyMatcher ( 0 )
2020-05-09 21:41:38 -04:00
#endif
2015-11-22 18:08:32 -05:00
{
2015-11-25 19:56:14 -05:00
_featureParameters = Parameters :: getDefaultParameters ();
2015-12-21 17:27:05 -05:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpNNStrategy (), _featureParameters . at ( Parameters :: kVisCorNNType ())));
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpNndrRatio (), _featureParameters . at ( Parameters :: kVisCorNNDR ())));
2015-11-25 19:56:14 -05:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpDetectorStrategy (), _featureParameters . at ( Parameters :: kVisFeatureType ())));
2015-12-21 17:27:05 -05:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpMaxFeatures (), _featureParameters . at ( Parameters :: kVisMaxFeatures ())));
2024-05-20 09:21:00 +08:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpSSC (), _featureParameters . at ( Parameters :: kVisSSC ())));
2015-11-25 19:56:14 -05:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpMaxDepth (), _featureParameters . at ( Parameters :: kVisMaxDepth ())));
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpMinDepth (), _featureParameters . at ( Parameters :: kVisMinDepth ())));
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpRoiRatios (), _featureParameters . at ( Parameters :: kVisRoiRatios ())));
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpSubPixEps (), _featureParameters . at ( Parameters :: kVisSubPixWinSize ())));
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpSubPixIterations (), _featureParameters . at ( Parameters :: kVisSubPixIterations ())));
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpSubPixWinSize (), _featureParameters . at ( Parameters :: kVisSubPixEps ())));
2017-11-30 16:52:03 -05:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpGridRows (), _featureParameters . at ( Parameters :: kVisGridRows ())));
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpGridCols (), _featureParameters . at ( Parameters :: kVisGridCols ())));
2016-02-15 19:35:24 -05:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpNewWordsComparedTogether (), "false" ));
2015-11-25 19:56:14 -05:00
2015-11-22 18:08:32 -05:00
this -> parseParameters ( parameters );
}
void RegistrationVis :: parseParameters ( const ParametersMap & parameters )
{
Registration :: parseParameters ( parameters );
2015-11-25 12:15:41 -05:00
Parameters :: parse ( parameters , Parameters :: kVisMinInliers (), _minInliers );
Parameters :: parse ( parameters , Parameters :: kVisInlierDistance (), _inlierDistance );
Parameters :: parse ( parameters , Parameters :: kVisIterations (), _iterations );
Parameters :: parse ( parameters , Parameters :: kVisRefineIterations (), _refineIterations );
Parameters :: parse ( parameters , Parameters :: kVisEstimationType (), _estimationType );
2017-01-03 21:05:00 -05:00
Parameters :: parse ( parameters , Parameters :: kVisForwardEstOnly (), _forwardEstimateOnly );
2015-11-25 12:15:41 -05:00
Parameters :: parse ( parameters , Parameters :: kVisEpipolarGeometryVar (), _epipolarGeometryVar );
Parameters :: parse ( parameters , Parameters :: kVisPnPReprojError (), _PnPReprojError );
Parameters :: parse ( parameters , Parameters :: kVisPnPFlags (), _PnPFlags );
2015-12-22 19:32:52 -05:00
Parameters :: parse ( parameters , Parameters :: kVisPnPRefineIterations (), _PnPRefineIterations );
2023-07-27 16:13:30 -07:00
Parameters :: parse ( parameters , Parameters :: kVisPnPVarianceMedianRatio (), _PnPVarMedianRatio );
2022-09-24 12:29:42 -07:00
Parameters :: parse ( parameters , Parameters :: kVisPnPMaxVariance (), _PnPMaxVar );
2024-02-07 14:43:16 -08:00
Parameters :: parse ( parameters , Parameters :: kVisPnPSplitLinearCovComponents (), _PnPSplitLinearCovarianceComponents );
2023-07-22 11:05:21 -04:00
Parameters :: parse ( parameters , Parameters :: kVisPnPSamplingPolicy (), _multiSamplingPolicy );
2015-12-21 17:27:05 -05:00
Parameters :: parse ( parameters , Parameters :: kVisCorType (), _correspondencesApproach );
Parameters :: parse ( parameters , Parameters :: kVisCorFlowWinSize (), _flowWinSize );
Parameters :: parse ( parameters , Parameters :: kVisCorFlowIterations (), _flowIterations );
Parameters :: parse ( parameters , Parameters :: kVisCorFlowEps (), _flowEps );
Parameters :: parse ( parameters , Parameters :: kVisCorFlowMaxLevel (), _flowMaxLevel );
2016-02-22 16:13:14 -05:00
Parameters :: parse ( parameters , Parameters :: kVisCorNNDR (), _nndr );
2020-05-09 21:13:41 -04:00
Parameters :: parse ( parameters , Parameters :: kVisCorNNType (), _nnType );
2020-05-11 13:23:26 -04:00
Parameters :: parse ( parameters , Parameters :: kGMSWithRotation (), _gmsWithRotation );
Parameters :: parse ( parameters , Parameters :: kGMSWithScale (), _gmsWithScale );
Parameters :: parse ( parameters , Parameters :: kGMSThresholdFactor (), _gmsThresholdFactor );
2016-02-22 16:13:14 -05:00
Parameters :: parse ( parameters , Parameters :: kVisCorGuessWinSize (), _guessWinSize );
2017-12-09 21:44:53 -05:00
Parameters :: parse ( parameters , Parameters :: kVisCorGuessMatchToProjection (), _guessMatchToProjection );
2016-11-14 19:54:31 -05:00
Parameters :: parse ( parameters , Parameters :: kVisBundleAdjustment (), _bundleAdjustment );
2018-02-01 22:17:46 -05:00
Parameters :: parse ( parameters , Parameters :: kVisDepthAsMask (), _depthAsMask );
2019-06-16 18:54:39 -04:00
Parameters :: parse ( parameters , Parameters :: kVisMinInliersDistribution (), _minInliersDistributionThr );
Parameters :: parse ( parameters , Parameters :: kVisMeanInliersDistance (), _maxInliersMeanDistance );
2016-11-14 19:54:31 -05:00
uInsert ( _bundleParameters , parameters );
2015-11-22 18:08:32 -05:00
2019-11-03 14:10:02 -05:00
if ( _minInliers < 6 )
{
UWARN ( "%s should be >= 6 but it is set to %d, setting to 6." , Parameters :: kVisMinInliers (). c_str (), _minInliers );
_minInliers = 6 ;
}
2015-11-25 12:15:41 -05:00
UASSERT_MSG ( _inlierDistance > 0.0f , uFormat ( "value=%f" , _inlierDistance ). c_str ());
UASSERT_MSG ( _iterations > 0 , uFormat ( "value=%d" , _iterations ). c_str ());
2015-11-25 19:56:14 -05:00
2020-05-09 21:13:41 -04:00
if ( _nnType == 6 )
{
2020-05-20 09:45:39 -04:00
// verify that we have Python3 support
2021-01-17 01:56:27 -05:00
#ifndef RTABMAP_PYTHON
2020-05-20 09:45:39 -04:00
UWARN ( "%s is set to 6 but RTAB-Map is not built with Python3 support, using default %d." ,
2020-05-09 21:13:41 -04:00
Parameters :: kVisCorNNType (). c_str (), Parameters :: defaultVisCorNNType ());
_nnType = Parameters :: defaultVisCorNNType ();
#else
2020-05-20 09:45:39 -04:00
int iterations = _pyMatcher ? _pyMatcher -> iterations () : Parameters :: defaultPyMatcherIterations ();
float matchThr = _pyMatcher ? _pyMatcher -> matchThreshold () : Parameters :: defaultPyMatcherThreshold ();
std :: string path = _pyMatcher ? _pyMatcher -> path () : Parameters :: defaultPyMatcherPath ();
bool cuda = _pyMatcher ? _pyMatcher -> cuda () : Parameters :: defaultPyMatcherCuda ();
std :: string model = _pyMatcher ? _pyMatcher -> model () : Parameters :: defaultPyMatcherModel ();
Parameters :: parse ( parameters , Parameters :: kPyMatcherIterations (), iterations );
Parameters :: parse ( parameters , Parameters :: kPyMatcherThreshold (), matchThr );
Parameters :: parse ( parameters , Parameters :: kPyMatcherPath (), path );
Parameters :: parse ( parameters , Parameters :: kPyMatcherCuda (), cuda );
Parameters :: parse ( parameters , Parameters :: kPyMatcherModel (), model );
2020-05-09 21:13:41 -04:00
if ( path . empty ())
{
2020-05-20 09:45:39 -04:00
UERROR ( "%s parameter should be set to use Python3 matching (%s=6), using default %d." ,
Parameters :: kPyMatcherPath (). c_str (),
2020-05-09 21:13:41 -04:00
Parameters :: kVisCorNNType (). c_str (),
Parameters :: defaultVisCorNNType ());
_nnType = Parameters :: defaultVisCorNNType ();
}
else
{
2020-05-20 09:45:39 -04:00
delete _pyMatcher ;
_pyMatcher = new PyMatcher ( path , matchThr , iterations , cuda , model );
2020-05-09 21:13:41 -04:00
}
#endif
}
2020-05-11 13:23:26 -04:00
#if !defined(HAVE_OPENCV_XFEATURES2D) || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION<4 || CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION<1))
else if ( _nnType == 7 )
2020-05-12 10:23:29 -04:00
{
2020-05-11 13:23:26 -04:00
UWARN ( "%s is set to 7 but RTAB-Map is not built with OpenCV's xfeatures2d support (OpenCV >= 3.4.1 also required), using default %d." ,
Parameters :: kVisCorNNType (). c_str (), Parameters :: defaultVisCorNNType ());
_nnType = Parameters :: defaultVisCorNNType ();
}
#endif
2020-05-09 21:13:41 -04:00
2015-11-25 19:56:14 -05:00
// override feature parameters
for ( ParametersMap :: const_iterator iter = parameters . begin (); iter != parameters . end (); ++ iter )
{
2015-12-17 14:13:19 -05:00
std :: string group = uSplit ( iter -> first , '/' ). front ();
if ( Parameters :: isFeatureParameter ( iter -> first ) || group . compare ( "Stereo" ) == 0 )
2015-11-25 19:56:14 -05:00
{
uInsert ( _featureParameters , ParametersPair ( iter -> first , iter -> second ));
}
}
2015-12-21 17:27:05 -05:00
if ( uContains ( parameters , Parameters :: kVisCorNNType ()))
2015-11-25 19:56:14 -05:00
{
2020-05-09 21:13:41 -04:00
if ( _nnType < VWDictionary :: kNNUndef )
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpNNStrategy (), uNumber2Str ( _nnType )));
}
2015-11-25 19:56:14 -05:00
}
2015-12-21 17:27:05 -05:00
if ( uContains ( parameters , Parameters :: kVisCorNNDR ()))
2015-11-25 19:56:14 -05:00
{
2015-12-21 17:27:05 -05:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpNndrRatio (), parameters . at ( Parameters :: kVisCorNNDR ())));
2015-11-25 19:56:14 -05:00
}
2020-09-28 10:29:14 -04:00
if ( uContains ( parameters , Parameters :: kKpByteToFloat ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpByteToFloat (), parameters . at ( Parameters :: kKpByteToFloat ())));
}
2015-11-25 19:56:14 -05:00
if ( uContains ( parameters , Parameters :: kVisFeatureType ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpDetectorStrategy (), parameters . at ( Parameters :: kVisFeatureType ())));
}
if ( uContains ( parameters , Parameters :: kVisMaxFeatures ()))
{
2015-12-21 17:27:05 -05:00
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpMaxFeatures (), parameters . at ( Parameters :: kVisMaxFeatures ())));
2015-11-25 19:56:14 -05:00
}
2024-05-20 09:21:00 +08:00
if ( uContains ( parameters , Parameters :: kVisSSC ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpSSC (), parameters . at ( Parameters :: kVisSSC ())));
}
2015-11-25 19:56:14 -05:00
if ( uContains ( parameters , Parameters :: kVisMaxDepth ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpMaxDepth (), parameters . at ( Parameters :: kVisMaxDepth ())));
}
if ( uContains ( parameters , Parameters :: kVisMinDepth ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpMinDepth (), parameters . at ( Parameters :: kVisMinDepth ())));
}
if ( uContains ( parameters , Parameters :: kVisRoiRatios ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpRoiRatios (), parameters . at ( Parameters :: kVisRoiRatios ())));
}
if ( uContains ( parameters , Parameters :: kVisSubPixEps ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpSubPixEps (), parameters . at ( Parameters :: kVisSubPixEps ())));
}
if ( uContains ( parameters , Parameters :: kVisSubPixIterations ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpSubPixIterations (), parameters . at ( Parameters :: kVisSubPixIterations ())));
}
if ( uContains ( parameters , Parameters :: kVisSubPixWinSize ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpSubPixWinSize (), parameters . at ( Parameters :: kVisSubPixWinSize ())));
}
2017-11-30 16:52:03 -05:00
if ( uContains ( parameters , Parameters :: kVisGridRows ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpGridRows (), parameters . at ( Parameters :: kVisGridRows ())));
}
if ( uContains ( parameters , Parameters :: kVisGridCols ()))
{
uInsert ( _featureParameters , ParametersPair ( Parameters :: kKpGridCols (), parameters . at ( Parameters :: kVisGridCols ())));
}
2020-04-16 17:59:45 -04:00
delete _detectorFrom ;
delete _detectorTo ;
_detectorFrom = Feature2D :: create ( _featureParameters );
_detectorTo = Feature2D :: create ( _featureParameters );
2015-11-25 19:56:14 -05:00
}
RegistrationVis ::~ RegistrationVis ()
{
2020-04-16 17:59:45 -04:00
delete _detectorFrom ;
delete _detectorTo ;
2021-01-17 01:56:27 -05:00
#ifdef RTABMAP_PYTHON
2020-05-20 09:45:39 -04:00
delete _pyMatcher ;
2020-05-09 21:13:41 -04:00
#endif
2016-02-22 16:13:14 -05:00
}
2016-01-06 17:26:55 -05:00
Transform RegistrationVis :: computeTransformationImpl (
2015-12-21 17:27:05 -05:00
Signature & fromSignature ,
Signature & toSignature ,
2016-02-22 16:13:14 -05:00
Transform guess , // (flowMaxLevel is set to 0 when guess is used)
2016-01-06 17:26:55 -05:00
RegistrationInfo & info ) const
2015-11-22 18:08:32 -05:00
{
2015-12-21 17:27:05 -05:00
UDEBUG ( "%s=%d" , Parameters :: kVisMinInliers (). c_str (), _minInliers );
UDEBUG ( "%s=%f" , Parameters :: kVisInlierDistance (). c_str (), _inlierDistance );
UDEBUG ( "%s=%d" , Parameters :: kVisIterations (). c_str (), _iterations );
UDEBUG ( "%s=%d" , Parameters :: kVisEstimationType (). c_str (), _estimationType );
UDEBUG ( "%s=%d" , Parameters :: kVisForwardEstOnly (). c_str (), _forwardEstimateOnly );
UDEBUG ( "%s=%f" , Parameters :: kVisEpipolarGeometryVar (). c_str (), _epipolarGeometryVar );
UDEBUG ( "%s=%f" , Parameters :: kVisPnPReprojError (). c_str (), _PnPReprojError );
UDEBUG ( "%s=%d" , Parameters :: kVisPnPFlags (). c_str (), _PnPFlags );
2022-09-24 12:29:42 -07:00
UDEBUG ( "%s=%f" , Parameters :: kVisPnPMaxVariance (). c_str (), _PnPMaxVar );
2024-02-07 14:43:16 -08:00
UDEBUG ( "%s=%f" , Parameters :: kVisPnPSplitLinearCovComponents (). c_str (), _PnPSplitLinearCovarianceComponents );
2016-03-11 23:27:41 -05:00
UDEBUG ( "%s=%d" , Parameters :: kVisCorType (). c_str (), _correspondencesApproach );
2015-12-21 17:27:05 -05:00
UDEBUG ( "%s=%d" , Parameters :: kVisCorFlowWinSize (). c_str (), _flowWinSize );
UDEBUG ( "%s=%d" , Parameters :: kVisCorFlowIterations (). c_str (), _flowIterations );
UDEBUG ( "%s=%f" , Parameters :: kVisCorFlowEps (). c_str (), _flowEps );
UDEBUG ( "%s=%d" , Parameters :: kVisCorFlowMaxLevel (). c_str (), _flowMaxLevel );
2020-05-01 22:12:56 -04:00
UDEBUG ( "%s=%f" , Parameters :: kVisCorNNDR (). c_str (), _nndr );
2020-05-09 21:13:41 -04:00
UDEBUG ( "%s=%d" , Parameters :: kVisCorNNType (). c_str (), _nnType );
2020-05-19 15:01:50 -04:00
UDEBUG ( "%s=%d" , Parameters :: kVisCorGuessWinSize (). c_str (), _guessWinSize );
UDEBUG ( "%s=%d" , Parameters :: kVisCorGuessMatchToProjection (). c_str (), _guessMatchToProjection ? 1 : 0 );
2020-05-09 21:13:41 -04:00
UDEBUG ( "Feature Detector = %d" , ( int ) _detectorFrom -> getType ());
2016-11-09 16:44:08 -05:00
UDEBUG ( "guess=%s" , guess . prettyPrint (). c_str ());
2015-12-21 17:27:05 -05:00
2020-04-30 14:17:46 -04:00
UDEBUG ( "Input(%d): from=%d words, %d 3D words, %d words descriptors, %d kpts, %d kpts3D, %d descriptors, image=%dx%d models=%d stereo=%d" ,
2015-12-21 17:27:05 -05:00
fromSignature . id (),
( int ) fromSignature . getWords (). size (),
( int ) fromSignature . getWords3 (). size (),
2020-10-05 17:34:32 -04:00
( int ) fromSignature . getWordsDescriptors (). rows ,
2015-12-21 17:27:05 -05:00
( int ) fromSignature . sensorData (). keypoints (). size (),
2017-01-03 21:05:00 -05:00
( int ) fromSignature . sensorData (). keypoints3D (). size (),
2017-01-05 19:31:18 -05:00
fromSignature . sensorData (). descriptors (). rows ,
fromSignature . sensorData (). imageRaw (). cols ,
2020-04-30 14:17:46 -04:00
fromSignature . sensorData (). imageRaw (). rows ,
( int ) fromSignature . sensorData (). cameraModels (). size (),
2022-07-20 15:20:14 -04:00
( int ) fromSignature . sensorData (). stereoCameraModels (). size ());
2015-12-21 17:27:05 -05:00
2020-04-30 14:17:46 -04:00
UDEBUG ( "Input(%d): to=%d words, %d 3D words, %d words descriptors, %d kpts, %d kpts3D, %d descriptors, image=%dx%d models=%d stereo=%d" ,
2015-12-21 17:27:05 -05:00
toSignature . id (),
( int ) toSignature . getWords (). size (),
( int ) toSignature . getWords3 (). size (),
2020-10-05 17:34:32 -04:00
( int ) toSignature . getWordsDescriptors (). rows ,
2015-12-21 17:27:05 -05:00
( int ) toSignature . sensorData (). keypoints (). size (),
2017-01-03 21:05:00 -05:00
( int ) toSignature . sensorData (). keypoints3D (). size (),
2017-01-05 19:31:18 -05:00
toSignature . sensorData (). descriptors (). rows ,
toSignature . sensorData (). imageRaw (). cols ,
2020-04-30 14:17:46 -04:00
toSignature . sensorData (). imageRaw (). rows ,
( int ) toSignature . sensorData (). cameraModels (). size (),
2022-07-20 15:20:14 -04:00
( int ) toSignature . sensorData (). stereoCameraModels (). size ());
2015-12-21 17:27:05 -05:00
2015-11-22 18:08:32 -05:00
std :: string msg ;
2018-02-01 22:17:46 -05:00
info . projectedIDs . clear ();
2015-11-22 18:08:32 -05:00
2015-12-21 17:27:05 -05:00
////////////////////
// Find correspondences
////////////////////
2016-02-15 19:35:24 -05:00
//recompute correspondences if descriptors are provided
if (( fromSignature . getWordsDescriptors (). empty () && toSignature . getWordsDescriptors (). empty ()) &&
( _estimationType < 2 || fromSignature . getWords (). size ()) && // required only for 2D->2D
2016-01-07 13:59:21 -05:00
( _estimationType == 0 || toSignature . getWords (). size ()) && // required only for 3D->2D or 2D->2D
fromSignature . getWords3 (). size () && // required in all estimation approaches
( _estimationType == 1 || toSignature . getWords3 (). size ())) // required only for 3D->3D and 2D->2D
2015-11-22 18:08:32 -05:00
{
2015-12-21 17:27:05 -05:00
// no need to extract new features, we have all the data we need
2018-10-25 16:31:13 -04:00
UDEBUG ( "Bypassing feature matching as descriptors and images are empty. We assume features are already matched." );
2015-11-22 18:08:32 -05:00
}
else
{
2015-12-21 17:27:05 -05:00
UDEBUG ( "" );
// just some checks to make sure that input data are ok
2016-02-22 16:13:14 -05:00
UASSERT ( fromSignature . getWords (). empty () ||
fromSignature . getWords3 (). empty () ||
2015-12-21 17:27:05 -05:00
( fromSignature . getWords (). size () == fromSignature . getWords3 (). size ()));
2016-01-05 15:44:34 -05:00
UASSERT (( int ) fromSignature . sensorData (). keypoints (). size () == fromSignature . sensorData (). descriptors (). rows ||
2020-10-05 17:34:32 -04:00
( int ) fromSignature . getWords (). size () == fromSignature . getWordsDescriptors (). rows ||
fromSignature . sensorData (). descriptors (). empty () ||
fromSignature . getWordsDescriptors (). empty () == 0 );
2015-12-21 17:27:05 -05:00
UASSERT (( toSignature . getWords (). empty () && toSignature . getWords3 (). empty ()) ||
2016-11-27 14:30:11 -05:00
( toSignature . getWords (). size () && toSignature . getWords3 (). empty ()) ||
2015-12-21 17:27:05 -05:00
( toSignature . getWords (). size () == toSignature . getWords3 (). size ()));
2016-01-05 15:44:34 -05:00
UASSERT (( int ) toSignature . sensorData (). keypoints (). size () == toSignature . sensorData (). descriptors (). rows ||
2020-10-05 17:34:32 -04:00
( int ) toSignature . getWords (). size () == toSignature . getWordsDescriptors (). rows ||
toSignature . sensorData (). descriptors (). empty () ||
toSignature . getWordsDescriptors (). empty ());
2016-02-22 16:13:14 -05:00
UASSERT ( fromSignature . sensorData (). imageRaw (). empty () ||
fromSignature . sensorData (). imageRaw (). type () == CV_8UC1 ||
2015-12-21 17:27:05 -05:00
fromSignature . sensorData (). imageRaw (). type () == CV_8UC3 );
2016-02-22 16:13:14 -05:00
UASSERT ( toSignature . sensorData (). imageRaw (). empty () ||
toSignature . sensorData (). imageRaw (). type () == CV_8UC1 ||
2015-12-21 17:27:05 -05:00
toSignature . sensorData (). imageRaw (). type () == CV_8UC3 );
std :: vector < cv :: KeyPoint > kptsFrom ;
2016-04-08 16:15:08 -04:00
cv :: Mat imageFrom = fromSignature . sensorData (). imageRaw ();
cv :: Mat imageTo = toSignature . sensorData (). imageRaw ();
2016-11-14 19:54:31 -05:00
std :: vector < int > orignalWordsFromIds ;
2020-10-05 17:34:32 -04:00
int kptsFromSource = 0 ;
2015-12-21 17:27:05 -05:00
if ( fromSignature . getWords (). empty ())
{
if ( fromSignature . sensorData (). keypoints (). empty ())
{
2016-04-08 16:15:08 -04:00
if ( ! imageFrom . empty ())
2015-12-21 17:27:05 -05:00
{
2016-04-08 16:15:08 -04:00
if ( imageFrom . channels () > 1 )
2016-02-15 19:35:24 -05:00
{
2016-02-22 16:13:14 -05:00
cv :: Mat tmp ;
2016-04-08 16:15:08 -04:00
cv :: cvtColor ( imageFrom , tmp , cv :: COLOR_BGR2GRAY );
imageFrom = tmp ;
2016-02-15 19:35:24 -05:00
}
2016-02-22 16:13:14 -05:00
cv :: Mat depthMask ;
2018-02-01 22:17:46 -05:00
if ( ! fromSignature . sensorData (). depthRaw (). empty () && _depthAsMask )
2016-02-22 16:13:14 -05:00
{
2016-04-08 16:15:08 -04:00
if ( imageFrom . rows % fromSignature . sensorData (). depthRaw (). rows == 0 &&
imageFrom . cols % fromSignature . sensorData (). depthRaw (). cols == 0 &&
imageFrom . rows / fromSignature . sensorData (). depthRaw (). rows == fromSignature . sensorData (). imageRaw (). cols / fromSignature . sensorData (). depthRaw (). cols )
2016-02-22 16:13:14 -05:00
{
depthMask = util2d :: interpolate ( fromSignature . sensorData (). depthRaw (), fromSignature . sensorData (). imageRaw (). rows / fromSignature . sensorData (). depthRaw (). rows , 0.1f );
}
2021-06-25 12:54:52 -04:00
else
{
UWARN ( "%s is true, but RGB size (%dx%d) modulo depth size (%dx%d) is not 0. Ignoring depth mask for feature detection." ,
Parameters :: kVisDepthAsMask (). c_str (),
fromSignature . sensorData (). imageRaw (). rows , fromSignature . sensorData (). imageRaw (). cols ,
fromSignature . sensorData (). depthRaw (). rows , fromSignature . sensorData (). depthRaw (). cols );
}
2016-02-22 16:13:14 -05:00
}
2020-04-16 17:59:45 -04:00
kptsFrom = _detectorFrom -> generateKeypoints (
2016-04-08 16:15:08 -04:00
imageFrom ,
2016-02-22 16:13:14 -05:00
depthMask );
}
2015-12-21 17:27:05 -05:00
}
else
{
kptsFrom = fromSignature . sensorData (). keypoints ();
2020-10-05 17:34:32 -04:00
kptsFromSource = 1 ;
2015-12-21 17:27:05 -05:00
}
}
else
{
2020-10-05 17:34:32 -04:00
kptsFromSource = 2 ;
2016-11-14 19:54:31 -05:00
orignalWordsFromIds . resize ( fromSignature . getWords (). size ());
int i = 0 ;
2017-02-15 19:07:10 -05:00
bool allUniques = true ;
2020-10-05 17:34:32 -04:00
int previousIdAdded = 0 ;
kptsFrom = fromSignature . getWordsKpts ();
for ( std :: multimap < int , int >:: const_iterator iter = fromSignature . getWords (). begin (); iter != fromSignature . getWords (). end (); ++ iter )
2016-11-14 19:54:31 -05:00
{
2020-10-05 17:34:32 -04:00
UASSERT ( iter -> second >= 0 && iter -> second < ( int ) orignalWordsFromIds . size ());
orignalWordsFromIds [ iter -> second ] = iter -> first ;
if ( i > 0 && iter -> first == previousIdAdded )
2017-02-15 19:07:10 -05:00
{
allUniques = false ;
}
2020-10-05 17:34:32 -04:00
previousIdAdded = iter -> first ;
2017-02-15 19:07:10 -05:00
++ i ;
}
if ( ! allUniques )
{
UDEBUG ( "IDs are not unique, IDs will be regenerated!" );
orignalWordsFromIds . clear ();
2016-11-14 19:54:31 -05:00
}
2015-12-21 17:27:05 -05:00
}
2020-10-05 17:34:32 -04:00
std :: multimap < int , int > wordsFrom ;
std :: multimap < int , int > wordsTo ;
std :: vector < cv :: KeyPoint > wordsKptsFrom ;
std :: vector < cv :: KeyPoint > wordsKptsTo ;
std :: vector < cv :: Point3f > words3From ;
std :: vector < cv :: Point3f > words3To ;
cv :: Mat wordsDescFrom ;
cv :: Mat wordsDescTo ;
2017-11-14 16:28:47 -05:00
if ( _correspondencesApproach == 1 ) //Optical Flow
2015-12-21 17:27:05 -05:00
{
UDEBUG ( "" );
// convert to grayscale
2016-04-08 16:15:08 -04:00
if ( imageFrom . channels () > 1 )
2015-12-21 17:27:05 -05:00
{
cv :: Mat tmp ;
2016-04-08 16:15:08 -04:00
cv :: cvtColor ( imageFrom , tmp , cv :: COLOR_BGR2GRAY );
imageFrom = tmp ;
2015-12-21 17:27:05 -05:00
}
2016-04-08 16:15:08 -04:00
if ( imageTo . channels () > 1 )
2015-12-21 17:27:05 -05:00
{
cv :: Mat tmp ;
2016-04-08 16:15:08 -04:00
cv :: cvtColor ( imageTo , tmp , cv :: COLOR_BGR2GRAY );
imageTo = tmp ;
2015-12-21 17:27:05 -05:00
}
std :: vector < cv :: Point3f > kptsFrom3D ;
2017-01-03 21:05:00 -05:00
if ( kptsFrom . size () == fromSignature . getWords3 (). size ())
2015-12-21 17:27:05 -05:00
{
2020-10-05 17:34:32 -04:00
kptsFrom3D = fromSignature . getWords3 ();
2017-01-03 21:05:00 -05:00
}
else if ( kptsFrom . size () == fromSignature . sensorData (). keypoints3D (). size ())
{
kptsFrom3D = fromSignature . sensorData (). keypoints3D ();
2015-12-21 17:27:05 -05:00
}
else
{
2020-04-16 17:59:45 -04:00
kptsFrom3D = _detectorFrom -> generateKeypoints3D ( fromSignature . sensorData (), kptsFrom );
2015-12-21 17:27:05 -05:00
}
2017-11-14 16:28:47 -05:00
if ( ! imageFrom . empty () && ! imageTo . empty ())
2015-12-21 17:27:05 -05:00
{
2023-10-25 14:54:20 -07:00
UASSERT ( ! toSignature . sensorData (). cameraModels (). empty () || ! toSignature . sensorData (). stereoCameraModels (). empty ());
2015-12-21 17:27:05 -05:00
std :: vector < cv :: Point2f > cornersFrom ;
cv :: KeyPoint :: convert ( kptsFrom , cornersFrom );
std :: vector < cv :: Point2f > cornersTo ;
bool guessSet = ! guess . isIdentity () && ! guess . isNull ();
if ( guessSet )
{
2022-12-20 20:51:56 -08:00
if ( toSignature . sensorData (). cameraModels (). size () == 1 || toSignature . sensorData (). stereoCameraModels (). size () == 1 )
2022-07-20 15:20:14 -04:00
{
2022-12-20 20:51:56 -08:00
Transform localTransform = toSignature . sensorData (). cameraModels (). size () ? toSignature . sensorData (). cameraModels ()[ 0 ]. localTransform () : toSignature . sensorData (). stereoCameraModels ()[ 0 ]. left (). localTransform ();
2022-07-20 15:20:14 -04:00
Transform guessCameraRef = ( guess * localTransform ). inverse ();
cv :: Mat R = ( cv :: Mat_ < double > ( 3 , 3 ) <<
( double ) guessCameraRef . r11 (), ( double ) guessCameraRef . r12 (), ( double ) guessCameraRef . r13 (),
( double ) guessCameraRef . r21 (), ( double ) guessCameraRef . r22 (), ( double ) guessCameraRef . r23 (),
( double ) guessCameraRef . r31 (), ( double ) guessCameraRef . r32 (), ( double ) guessCameraRef . r33 ());
cv :: Mat rvec ( 1 , 3 , CV_64FC1 );
cv :: Rodrigues ( R , rvec );
cv :: Mat tvec = ( cv :: Mat_ < double > ( 1 , 3 ) << ( double ) guessCameraRef . x (), ( double ) guessCameraRef . y (), ( double ) guessCameraRef . z ());
2022-12-20 20:51:56 -08:00
cv :: Mat K = toSignature . sensorData (). cameraModels (). size () ? toSignature . sensorData (). cameraModels ()[ 0 ]. K () : toSignature . sensorData (). stereoCameraModels ()[ 0 ]. left (). K ();
2022-07-20 15:20:14 -04:00
cv :: projectPoints ( kptsFrom3D , rvec , tvec , K , cv :: Mat (), cornersTo );
}
else
{
2023-10-25 14:54:20 -07:00
UTimer t ;
int nCameras = toSignature . sensorData (). cameraModels (). size () ? toSignature . sensorData (). cameraModels (). size () : toSignature . sensorData (). stereoCameraModels (). size ();
cornersTo = cornersFrom ;
// compute inverse transforms one time
std :: vector < Transform > inverseTransforms ( nCameras );
for ( int c = 0 ; c < nCameras ; ++ c )
{
Transform localTransform = toSignature . sensorData (). cameraModels (). size () ? toSignature . sensorData (). cameraModels ()[ c ]. localTransform () : toSignature . sensorData (). stereoCameraModels ()[ c ]. left (). localTransform ();
inverseTransforms [ c ] = ( guess * localTransform ). inverse ();
UDEBUG ( "inverse transforms: cam %d -> %s" , c , inverseTransforms [ c ]. prettyPrint (). c_str ());
}
// Project 3D points in each camera
int inFrame = 0 ;
UASSERT ( kptsFrom3D . size () == cornersTo . size ());
int subImageWidth = toSignature . sensorData (). cameraModels (). size () ? toSignature . sensorData (). cameraModels ()[ 0 ]. imageWidth () : toSignature . sensorData (). stereoCameraModels ()[ 0 ]. left (). imageWidth ();
UASSERT ( subImageWidth > 0 );
for ( size_t i = 0 ; i < kptsFrom3D . size (); ++ i )
{
// Start from camera having the reference corner first (in case there is overlap between the cameras)
int startIndex = cornersFrom [ i ]. x / subImageWidth ;
UASSERT ( startIndex < nCameras );
for ( int c = startIndex ; ( c + 1 ) % nCameras != 0 ; ++ c )
{
const CameraModel & model = toSignature . sensorData (). cameraModels (). size () ? toSignature . sensorData (). cameraModels ()[ c ] : toSignature . sensorData (). stereoCameraModels ()[ c ]. left ();
cv :: Point3f ptsInCamFrame = util3d :: transformPoint ( kptsFrom3D [ i ], inverseTransforms [ c ]);
if ( ptsInCamFrame . z > 0 )
{
float u , v ;
model . reproject ( ptsInCamFrame . x , ptsInCamFrame . y , ptsInCamFrame . z , u , v );
if ( model . inFrame ( u , v ))
{
cornersTo [ i ]. x = u + model . imageWidth () * c ;
cornersTo [ i ]. y = v ;
++ inFrame ;
break ;
}
}
}
}
2023-10-27 17:10:10 -07:00
UDEBUG ( "Projected %d/%ld points inside %d cameras (time=%fs)" ,
2023-10-25 14:54:20 -07:00
inFrame , cornersTo . size (), nCameras , t . ticks ());
2022-07-20 15:20:14 -04:00
}
2015-12-21 17:27:05 -05:00
}
// Find features in the new left image
UDEBUG ( "guessSet = %d" , guessSet ? 1 : 0 );
std :: vector < unsigned char > status ;
std :: vector < float > err ;
UDEBUG ( "cv::calcOpticalFlowPyrLK() begin" );
cv :: calcOpticalFlowPyrLK (
2016-04-08 16:15:08 -04:00
imageFrom ,
imageTo ,
2015-12-21 17:27:05 -05:00
cornersFrom ,
cornersTo ,
status ,
err ,
2016-02-22 16:13:14 -05:00
cv :: Size ( _flowWinSize , _flowWinSize ),
2015-12-21 17:27:05 -05:00
guessSet ? 0 : _flowMaxLevel ,
cv :: TermCriteria ( cv :: TermCriteria :: COUNT + cv :: TermCriteria :: EPS , _flowIterations , _flowEps ),
cv :: OPTFLOW_LK_GET_MIN_EIGENVALS | ( guessSet ? cv :: OPTFLOW_USE_INITIAL_FLOW : 0 ), 1e-4 );
UDEBUG ( "cv::calcOpticalFlowPyrLK() end" );
UASSERT ( kptsFrom . size () == kptsFrom3D . size ());
std :: vector < cv :: KeyPoint > kptsTo ( kptsFrom . size ());
std :: vector < cv :: Point3f > kptsFrom3DKept ( kptsFrom3D . size ());
2016-11-14 19:54:31 -05:00
std :: vector < int > orignalWordsFromIdsCpy = orignalWordsFromIds ;
2015-12-21 17:27:05 -05:00
int ki = 0 ;
for ( unsigned int i = 0 ; i < status . size (); ++ i )
{
if ( status [ i ] &&
2016-04-08 16:15:08 -04:00
uIsInBounds ( cornersTo [ i ]. x , 0.0f , float ( imageTo . cols )) &&
uIsInBounds ( cornersTo [ i ]. y , 0.0f , float ( imageTo . rows )))
2015-12-21 17:27:05 -05:00
{
2016-11-14 19:54:31 -05:00
if ( orignalWordsFromIdsCpy . size ())
{
orignalWordsFromIds [ ki ] = orignalWordsFromIdsCpy [ i ];
}
2015-12-21 17:27:05 -05:00
kptsFrom [ ki ] = cv :: KeyPoint ( cornersFrom [ i ], 1 );
kptsFrom3DKept [ ki ] = kptsFrom3D [ i ];
kptsTo [ ki ++ ] = cv :: KeyPoint ( cornersTo [ i ], 1 );
}
}
2016-11-14 19:54:31 -05:00
if ( orignalWordsFromIds . size ())
{
orignalWordsFromIds . resize ( ki );
}
2015-12-21 17:27:05 -05:00
kptsFrom . resize ( ki );
kptsTo . resize ( ki );
kptsFrom3DKept . resize ( ki );
2017-01-03 21:05:00 -05:00
kptsFrom3D = kptsFrom3DKept ;
2015-12-21 17:27:05 -05:00
std :: vector < cv :: Point3f > kptsTo3D ;
2017-11-30 16:52:03 -05:00
if ( _estimationType == 0 || _estimationType == 1 || ! _forwardEstimateOnly )
2015-12-21 17:27:05 -05:00
{
2020-04-16 17:59:45 -04:00
kptsTo3D = _detectorTo -> generateKeypoints3D ( toSignature . sensorData (), kptsTo );
2015-12-21 17:27:05 -05:00
}
UASSERT ( kptsFrom . size () == kptsFrom3DKept . size ());
UASSERT ( kptsFrom . size () == kptsTo . size ());
UASSERT ( kptsTo3D . size () == 0 || kptsTo . size () == kptsTo3D . size ());
for ( unsigned int i = 0 ; i < kptsFrom3DKept . size (); ++ i )
{
2020-10-05 17:34:32 -04:00
int id = ! orignalWordsFromIds . empty () ? orignalWordsFromIds [ i ] : i ;
wordsFrom . insert ( wordsFrom . end (), std :: make_pair ( id , wordsFrom . size ()));
wordsKptsFrom . push_back ( kptsFrom [ i ]);
words3From . push_back ( kptsFrom3DKept [ i ]);
wordsTo . insert ( wordsTo . end (), std :: make_pair ( id , wordsTo . size ()));
wordsKptsTo . push_back ( kptsTo [ i ]);
if ( ! kptsTo3D . empty ())
2015-12-21 17:27:05 -05:00
{
2020-10-05 17:34:32 -04:00
words3To . push_back ( kptsTo3D [ i ]);
2015-12-21 17:27:05 -05:00
}
}
2017-01-03 21:05:00 -05:00
toSignature . sensorData (). setFeatures ( kptsTo , kptsTo3D , cv :: Mat ());
2015-12-21 17:27:05 -05:00
}
else
{
2017-11-14 16:28:47 -05:00
if ( imageFrom . empty ())
{
UERROR ( "Optical flow correspondences requires images in data!" );
}
2015-12-21 17:27:05 -05:00
UASSERT ( kptsFrom . size () == kptsFrom3D . size ());
for ( unsigned int i = 0 ; i < kptsFrom3D . size (); ++ i )
{
if ( util3d :: isFinite ( kptsFrom3D [ i ]))
{
2020-10-05 17:34:32 -04:00
int id = ! orignalWordsFromIds . empty () ? orignalWordsFromIds [ i ] : i ;
wordsFrom . insert ( wordsFrom . end (), std :: make_pair ( id , wordsFrom . size ()));
wordsKptsFrom . push_back ( kptsFrom [ i ]);
words3From . push_back ( kptsFrom3D [ i ]);
2015-12-21 17:27:05 -05:00
}
}
2017-01-03 21:05:00 -05:00
toSignature . sensorData (). setFeatures ( std :: vector < cv :: KeyPoint > (), std :: vector < cv :: Point3f > (), cv :: Mat ());
2015-12-21 17:27:05 -05:00
}
2017-01-03 21:05:00 -05:00
fromSignature . sensorData (). setFeatures ( kptsFrom , kptsFrom3D , cv :: Mat ());
2015-12-21 17:27:05 -05:00
}
else // Features Matching
{
UDEBUG ( "" );
std :: vector < cv :: KeyPoint > kptsTo ;
2020-10-05 17:34:32 -04:00
int kptsToSource = 0 ;
2015-12-21 17:27:05 -05:00
if ( toSignature . getWords (). empty ())
{
if ( toSignature . sensorData (). keypoints (). empty () &&
2016-04-08 16:15:08 -04:00
! imageTo . empty ())
2015-12-21 17:27:05 -05:00
{
2016-04-08 16:15:08 -04:00
if ( imageTo . channels () > 1 )
2015-12-21 17:27:05 -05:00
{
cv :: Mat tmp ;
2016-04-08 16:15:08 -04:00
cv :: cvtColor ( imageTo , tmp , cv :: COLOR_BGR2GRAY );
imageTo = tmp ;
2015-12-21 17:27:05 -05:00
}
2016-02-15 19:35:24 -05:00
cv :: Mat depthMask ;
2018-02-01 22:17:46 -05:00
if ( ! toSignature . sensorData (). depthRaw (). empty () && _depthAsMask )
2016-02-15 19:35:24 -05:00
{
2016-04-08 16:15:08 -04:00
if ( imageTo . rows % toSignature . sensorData (). depthRaw (). rows == 0 &&
imageTo . cols % toSignature . sensorData (). depthRaw (). cols == 0 &&
imageTo . rows / toSignature . sensorData (). depthRaw (). rows == imageTo . cols / toSignature . sensorData (). depthRaw (). cols )
2016-02-15 19:35:24 -05:00
{
2016-04-08 16:15:08 -04:00
depthMask = util2d :: interpolate ( toSignature . sensorData (). depthRaw (), imageTo . rows / toSignature . sensorData (). depthRaw (). rows , 0.1f );
2016-02-15 19:35:24 -05:00
}
2021-06-25 12:54:52 -04:00
else
{
UWARN ( "%s is true, but RGB size (%dx%d) modulo depth size (%dx%d) is not 0. Ignoring depth mask for feature detection." ,
Parameters :: kVisDepthAsMask (). c_str (),
toSignature . sensorData (). imageRaw (). rows , toSignature . sensorData (). imageRaw (). cols ,
toSignature . sensorData (). depthRaw (). rows , toSignature . sensorData (). depthRaw (). cols );
}
2016-02-15 19:35:24 -05:00
}
2020-04-16 17:59:45 -04:00
kptsTo = _detectorTo -> generateKeypoints (
2016-04-08 16:15:08 -04:00
imageTo ,
2016-02-15 19:35:24 -05:00
depthMask );
2015-12-21 17:27:05 -05:00
}
else
{
kptsTo = toSignature . sensorData (). keypoints ();
2020-10-05 17:34:32 -04:00
kptsToSource = 1 ;
2015-12-21 17:27:05 -05:00
}
}
else
{
2020-10-05 17:34:32 -04:00
kptsTo = toSignature . getWordsKpts ();
kptsToSource = 2 ;
2015-12-21 17:27:05 -05:00
}
// extract descriptors
2020-10-05 17:34:32 -04:00
UDEBUG ( "kptsFrom=%d kptsFromSource=%d" , ( int ) kptsFrom . size (), kptsFromSource );
UDEBUG ( "kptsTo=%d kptsToSource=%d" , ( int ) kptsTo . size (), kptsToSource );
2015-12-21 17:27:05 -05:00
cv :: Mat descriptorsFrom ;
2020-10-05 17:34:32 -04:00
if ( kptsFromSource == 2 &&
fromSignature . getWordsDescriptors (). rows &&
(( kptsFrom . empty () && fromSignature . getWordsDescriptors (). rows ) ||
fromSignature . getWordsDescriptors (). rows == ( int ) kptsFrom . size ()))
2016-02-15 19:35:24 -05:00
{
2020-10-05 17:34:32 -04:00
descriptorsFrom = fromSignature . getWordsDescriptors ();
2016-02-15 19:35:24 -05:00
}
2020-10-05 17:34:32 -04:00
else if ( kptsFromSource == 1 &&
fromSignature . sensorData (). descriptors (). rows == ( int ) kptsFrom . size ())
2016-02-22 16:13:14 -05:00
{
descriptorsFrom = fromSignature . sensorData (). descriptors ();
}
2016-04-08 16:15:08 -04:00
else if ( ! imageFrom . empty ())
2016-02-22 16:13:14 -05:00
{
2016-04-08 16:15:08 -04:00
if ( imageFrom . channels () > 1 )
2016-03-09 19:17:29 -05:00
{
cv :: Mat tmp ;
2016-04-08 16:15:08 -04:00
cv :: cvtColor ( imageFrom , tmp , cv :: COLOR_BGR2GRAY );
imageFrom = tmp ;
2016-03-09 19:17:29 -05:00
}
2019-06-16 18:54:39 -04:00
UDEBUG ( "cleared orignalWordsFromIds" );
2017-01-03 21:05:00 -05:00
orignalWordsFromIds . clear ();
2020-04-16 17:59:45 -04:00
descriptorsFrom = _detectorFrom -> generateDescriptors ( imageFrom , kptsFrom );
2016-02-22 16:13:14 -05:00
}
2016-02-15 19:35:24 -05:00
2015-12-21 17:27:05 -05:00
cv :: Mat descriptorsTo ;
2016-02-15 19:35:24 -05:00
if ( kptsTo . size ())
2015-12-21 17:27:05 -05:00
{
2020-10-05 17:34:32 -04:00
if ( kptsToSource == 2 &&
toSignature . getWordsDescriptors (). rows == ( int ) kptsTo . size ())
2016-02-15 19:35:24 -05:00
{
2020-10-05 17:34:32 -04:00
descriptorsTo = toSignature . getWordsDescriptors ();
2016-02-15 19:35:24 -05:00
}
2020-10-05 17:34:32 -04:00
else if ( kptsToSource == 1 &&
toSignature . sensorData (). descriptors (). rows == ( int ) kptsTo . size ())
2016-02-15 19:35:24 -05:00
{
descriptorsTo = toSignature . sensorData (). descriptors ();
}
2016-04-08 16:15:08 -04:00
else if ( ! imageTo . empty ())
2016-02-15 19:35:24 -05:00
{
2016-04-08 16:15:08 -04:00
if ( imageTo . channels () > 1 )
2016-03-09 19:17:29 -05:00
{
cv :: Mat tmp ;
2016-04-08 16:15:08 -04:00
cv :: cvtColor ( imageTo , tmp , cv :: COLOR_BGR2GRAY );
imageTo = tmp ;
2016-03-09 19:17:29 -05:00
}
2020-04-16 17:59:45 -04:00
descriptorsTo = _detectorTo -> generateDescriptors ( imageTo , kptsTo );
2016-02-15 19:35:24 -05:00
}
2015-12-21 17:27:05 -05:00
}
// create 3D keypoints
std :: vector < cv :: Point3f > kptsFrom3D ;
std :: vector < cv :: Point3f > kptsTo3D ;
2020-10-05 17:34:32 -04:00
if ( kptsFromSource == 2 &&
kptsFrom . size () == fromSignature . getWords3 (). size ())
2017-01-03 21:05:00 -05:00
{
2020-10-05 17:34:32 -04:00
kptsFrom3D = fromSignature . getWords3 ();
2017-01-03 21:05:00 -05:00
}
2020-10-05 17:34:32 -04:00
else if ( kptsFromSource == 1 &&
kptsFrom . size () == fromSignature . sensorData (). keypoints3D (). size ())
2017-01-03 21:05:00 -05:00
{
kptsFrom3D = fromSignature . sensorData (). keypoints3D ();
}
else
2015-12-21 17:27:05 -05:00
{
2016-03-09 19:17:29 -05:00
if ( fromSignature . getWords3 (). size () && kptsFrom . size () != fromSignature . getWords3 (). size ())
{
UWARN ( "kptsFrom (%d) is not the same size as fromSignature.getWords3() (%d), there "
2018-02-01 22:17:46 -05:00
"is maybe a problem with the logic above (getWords3() should be null or equal to kptsfrom). Regenerating kptsFrom3D..." ,
2017-01-03 21:05:00 -05:00
kptsFrom . size (),
fromSignature . getWords3 (). size ());
}
else if ( fromSignature . sensorData (). keypoints3D (). size () && kptsFrom . size () != fromSignature . sensorData (). keypoints3D (). size ())
{
UWARN ( "kptsFrom (%d) is not the same size as fromSignature.sensorData().keypoints3D() (%d), there "
2018-02-01 22:17:46 -05:00
"is maybe a problem with the logic above (keypoints3D should be null or equal to kptsfrom). Regenerating kptsFrom3D..." ,
2017-01-03 21:05:00 -05:00
kptsFrom . size (),
fromSignature . sensorData (). keypoints3D (). size ());
2016-03-09 19:17:29 -05:00
}
2020-04-16 17:59:45 -04:00
kptsFrom3D = _detectorFrom -> generateKeypoints3D ( fromSignature . sensorData (), kptsFrom );
2017-01-03 21:05:00 -05:00
UDEBUG ( "generated kptsFrom3D=%d" , ( int ) kptsFrom3D . size ());
2020-04-30 15:07:32 -04:00
}
2016-03-13 16:58:36 -04:00
2020-04-30 15:07:32 -04:00
if ( ! kptsFrom3D . empty () &&
( _detectorFrom -> getMinDepth () > 0.0f || _detectorFrom -> getMaxDepth () > 0.0f ) &&
2022-07-20 15:20:14 -04:00
( ! fromSignature . sensorData (). cameraModels (). empty () || ! fromSignature . sensorData (). stereoCameraModels (). empty ())) // Ignore local map from OdometryF2M
2020-04-30 15:07:32 -04:00
{
_detectorFrom -> filterKeypointsByDepth ( kptsFrom , descriptorsFrom , kptsFrom3D , _detectorFrom -> getMinDepth (), _detectorFrom -> getMaxDepth ());
2015-12-21 17:27:05 -05:00
}
2017-01-03 21:05:00 -05:00
2020-10-05 17:34:32 -04:00
if ( kptsToSource == 2 && kptsTo . size () == toSignature . getWords3 (). size ())
2015-12-21 17:27:05 -05:00
{
2020-10-05 17:34:32 -04:00
kptsTo3D = toSignature . getWords3 ();
2015-12-21 17:27:05 -05:00
}
2020-10-05 17:34:32 -04:00
else if ( kptsToSource == 1 &&
kptsTo . size () == toSignature . sensorData (). keypoints3D (). size ())
2017-01-03 21:05:00 -05:00
{
kptsTo3D = toSignature . sensorData (). keypoints3D ();
}
else
2015-12-21 17:27:05 -05:00
{
2016-03-09 19:17:29 -05:00
if ( toSignature . getWords3 (). size () && kptsTo . size () != toSignature . getWords3 (). size ())
{
UWARN ( "kptsTo (%d) is not the same size as toSignature.getWords3() (%d), there "
2018-02-01 22:17:46 -05:00
"is maybe a problem with the logic above (getWords3() should be null or equal to kptsTo). Regenerating kptsTo3D..." ,
2017-01-03 21:05:00 -05:00
( int ) kptsTo . size (),
( int ) toSignature . getWords3 (). size ());
}
else if ( toSignature . sensorData (). keypoints3D (). size () && kptsTo . size () != toSignature . sensorData (). keypoints3D (). size ())
{
UWARN ( "kptsTo (%d) is not the same size as toSignature.sensorData().keypoints3D() (%d), there "
2018-02-01 22:17:46 -05:00
"is maybe a problem with the logic above (keypoints3D() should be null or equal to kptsTo). Regenerating kptsTo3D..." ,
2017-01-03 21:05:00 -05:00
( int ) kptsTo . size (),
( int ) toSignature . sensorData (). keypoints3D (). size ());
2016-03-09 19:17:29 -05:00
}
2020-04-16 17:59:45 -04:00
kptsTo3D = _detectorTo -> generateKeypoints3D ( toSignature . sensorData (), kptsTo );
2020-04-30 15:07:32 -04:00
}
2016-03-13 16:58:36 -04:00
2020-04-30 15:07:32 -04:00
if ( kptsTo3D . size () &&
( _detectorTo -> getMinDepth () > 0.0f || _detectorTo -> getMaxDepth () > 0.0f ) &&
2022-07-20 15:20:14 -04:00
( ! toSignature . sensorData (). cameraModels (). empty () || ! toSignature . sensorData (). stereoCameraModels (). empty ())) // Ignore local map from OdometryF2M
2020-04-30 15:07:32 -04:00
{
_detectorTo -> filterKeypointsByDepth ( kptsTo , descriptorsTo , kptsTo3D , _detectorTo -> getMinDepth (), _detectorTo -> getMaxDepth ());
2015-12-21 17:27:05 -05:00
}
2016-08-12 10:59:43 -04:00
UASSERT ( kptsFrom . empty () || descriptorsFrom . rows == 0 || int ( kptsFrom . size ()) == descriptorsFrom . rows );
2016-03-08 12:31:32 -05:00
2017-01-03 21:05:00 -05:00
fromSignature . sensorData (). setFeatures ( kptsFrom , kptsFrom3D , descriptorsFrom );
toSignature . sensorData (). setFeatures ( kptsTo , kptsTo3D , descriptorsTo );
2016-02-22 16:13:14 -05:00
UDEBUG ( "descriptorsFrom=%d" , descriptorsFrom . rows );
UDEBUG ( "descriptorsTo=%d" , descriptorsTo . rows );
2019-06-16 18:54:39 -04:00
UDEBUG ( "orignalWordsFromIds=%d" , ( int ) orignalWordsFromIds . size ());
2016-02-22 16:13:14 -05:00
// We have all data we need here, so match!
if ( descriptorsFrom . rows > 0 && descriptorsTo . rows > 0 )
{
2022-07-20 15:20:14 -04:00
std :: vector < CameraModel > models ;
if ( ! toSignature . sensorData (). stereoCameraModels (). empty ())
2016-03-09 17:15:05 -05:00
{
2022-07-20 15:20:14 -04:00
for ( size_t i = 0 ; i < toSignature . sensorData (). stereoCameraModels (). size (); ++ i )
{
models . push_back ( toSignature . sensorData (). stereoCameraModels ()[ i ]. left ());
}
}
else
{
models = toSignature . sensorData (). cameraModels ();
2016-03-09 17:15:05 -05:00
}
2017-11-30 16:52:03 -05:00
2022-07-20 15:20:14 -04:00
bool isCalibrated = ! models . empty ();
for ( size_t i = 0 ; i < models . size () && isCalibrated ; ++ i )
{
isCalibrated = models [ i ]. isValidForProjection ();
// For old database formats
if ( isCalibrated && ( models [ i ]. imageWidth () == 0 || models [ i ]. imageHeight () == 0 ))
{
if ( ! toSignature . sensorData (). imageRaw (). empty ())
{
models [ i ]. setImageSize ( cv :: Size ( toSignature . sensorData (). imageRaw (). cols / models . size (), toSignature . sensorData (). imageRaw (). rows ));
}
else
{
isCalibrated = false ;
}
}
}
2016-03-09 17:15:05 -05:00
2016-02-22 16:13:14 -05:00
// If guess is set, limit the search of matches using optical flow window size
bool guessSet = ! guess . isIdentity () && ! guess . isNull ();
2016-03-09 17:15:05 -05:00
if ( guessSet && _guessWinSize > 0 && kptsFrom3D . size () &&
2020-05-19 15:01:50 -04:00
isCalibrated && // needed for projection
_estimationType != 2 ) // To make sure we match all features for 2D->2D
2016-02-22 16:13:14 -05:00
{
2022-07-20 15:20:14 -04:00
// Use guess to project 3D "from" keypoints into "to" image
2016-02-22 16:13:14 -05:00
UDEBUG ( "" );
2016-02-23 11:06:24 -05:00
UASSERT (( int ) kptsTo . size () == descriptorsTo . rows );
2016-02-24 12:45:00 -05:00
UASSERT (( int ) kptsFrom3D . size () == descriptorsFrom . rows );
2016-02-22 16:13:14 -05:00
2022-07-20 15:20:14 -04:00
std :: vector < cv :: Point2f > cornersProjected ;
std :: vector < int > projectedIndexToDescIndex ;
float subImageWidth = models [ 0 ]. imageWidth ();
std :: set < int > added ;
int duplicates = 0 ;
for ( size_t m = 0 ; m < models . size (); ++ m )
2016-02-22 16:13:14 -05:00
{
2022-07-20 15:20:14 -04:00
Transform guessCameraRef = ( guess * models [ m ]. localTransform ()). inverse ();
cv :: Mat R = ( cv :: Mat_ < double > ( 3 , 3 ) <<
( double ) guessCameraRef . r11 (), ( double ) guessCameraRef . r12 (), ( double ) guessCameraRef . r13 (),
( double ) guessCameraRef . r21 (), ( double ) guessCameraRef . r22 (), ( double ) guessCameraRef . r23 (),
( double ) guessCameraRef . r31 (), ( double ) guessCameraRef . r32 (), ( double ) guessCameraRef . r33 ());
cv :: Mat rvec ( 1 , 3 , CV_64FC1 );
cv :: Rodrigues ( R , rvec );
cv :: Mat tvec = ( cv :: Mat_ < double > ( 1 , 3 ) << ( double ) guessCameraRef . x (), ( double ) guessCameraRef . y (), ( double ) guessCameraRef . z ());
cv :: Mat K = models [ m ]. K ();
std :: vector < cv :: Point2f > projected ;
cv :: projectPoints ( kptsFrom3D , rvec , tvec , K , cv :: Mat (), projected );
UDEBUG ( "Projected points=%d" , ( int ) projected . size ());
2016-06-15 18:13:11 -04:00
2022-07-20 15:20:14 -04:00
//remove projected points outside of the image
UASSERT (( int ) projected . size () == descriptorsFrom . rows );
int cornersInFrame = 0 ;
for ( unsigned int i = 0 ; i < projected . size (); ++ i )
2016-02-22 16:13:14 -05:00
{
2022-07-20 15:20:14 -04:00
if ( uIsInBounds ( projected [ i ]. x , 0.0f , float ( models [ m ]. imageWidth () - 1 )) &&
uIsInBounds ( projected [ i ]. y , 0.0f , float ( models [ m ]. imageHeight () - 1 )) &&
util3d :: transformPoint ( kptsFrom3D [ i ], guessCameraRef ). z > 0.0 )
{
if ( added . find ( i ) != added . end ())
{
++ duplicates ;
continue ;
}
projectedIndexToDescIndex . push_back ( i );
projected [ i ]. x += subImageWidth * float ( m ); // Convert in multicam stitched image
cornersProjected . push_back ( projected [ i ]);
++ cornersInFrame ;
added . insert ( i );
}
2016-02-22 16:13:14 -05:00
}
2022-07-20 15:20:14 -04:00
UDEBUG ( "corners in frame=%d (camera index=%ld)" , cornersInFrame , m );
2016-02-22 16:13:14 -05:00
}
// For each projected feature guess of "from" in "to", find its matching feature in
// the radius around the projected guess.
// TODO: do cross-check?
2022-07-20 15:20:14 -04:00
UDEBUG ( "guessMatchToProjection=%d, cornersProjected=%d orignalWordsFromIds=%d (added=%ld, duplicates=%d)" ,
_guessMatchToProjection ? 1 : 0 , ( int ) cornersProjected . size (), ( int ) orignalWordsFromIds . size (),
added . size (), duplicates );
2016-02-22 16:13:14 -05:00
if ( cornersProjected . size ())
{
2017-12-09 21:44:53 -05:00
if ( _guessMatchToProjection )
2016-02-22 16:13:14 -05:00
{
2020-05-01 22:12:56 -04:00
UDEBUG ( "match frame to projected" );
2017-11-30 16:52:03 -05:00
// Create kd-tree for projected keypoints
rtflann :: Matrix < float > cornersProjectedMat (( float * ) cornersProjected . data (), cornersProjected . size (), 2 );
rtflann :: Index < rtflann :: L2_Simple < float > > index ( cornersProjectedMat , rtflann :: KDTreeIndexParams ());
index . buildIndex ();
std :: vector < std :: vector < size_t > > indices ;
std :: vector < std :: vector < float > > dists ;
float radius = ( float ) _guessWinSize ; // pixels
std :: vector < cv :: Point2f > pointsTo ;
cv :: KeyPoint :: convert ( kptsTo , pointsTo );
rtflann :: Matrix < float > pointsToMat (( float * ) pointsTo . data (), pointsTo . size (), 2 );
index . radiusSearch ( pointsToMat , indices , dists , radius * radius , rtflann :: SearchParams ());
UASSERT ( indices . size () == pointsToMat . rows );
UASSERT ( descriptorsFrom . cols == descriptorsTo . cols );
UASSERT ( descriptorsFrom . rows == ( int ) kptsFrom . size ());
UASSERT (( int ) pointsToMat . rows == descriptorsTo . rows );
UASSERT ( pointsToMat . rows == kptsTo . size ());
UDEBUG ( "radius search done for guess" );
// Process results (Nearest Neighbor Distance Ratio)
2020-10-05 17:34:32 -04:00
int newToId = ! orignalWordsFromIds . empty () ? fromSignature . getWords (). rbegin () -> first + 1 : descriptorsFrom . rows ;
2017-11-30 16:52:03 -05:00
std :: map < int , int > addedWordsFrom ; //<id, index>
std :: map < int , int > duplicates ; //<fromId, toId>
int newWords = 0 ;
2017-12-09 21:44:53 -05:00
cv :: Mat descriptors ( 10 , descriptorsTo . cols , descriptorsTo . type ());
2017-11-30 16:52:03 -05:00
for ( unsigned int i = 0 ; i < pointsToMat . rows ; ++ i )
2016-02-22 16:13:14 -05:00
{
2019-03-06 12:35:54 -05:00
int matchedIndex = - 1 ;
if ( indices [ i ]. size () >= 2 )
2016-02-22 16:13:14 -05:00
{
2019-03-06 12:35:54 -05:00
std :: vector < int > descriptorsIndices ( indices [ i ]. size ());
int oi = 0 ;
if (( int ) indices [ i ]. size () > descriptors . rows )
2016-02-24 12:45:00 -05:00
{
2019-03-06 12:35:54 -05:00
descriptors . resize ( indices [ i ]. size ());
2016-02-24 12:45:00 -05:00
}
2019-03-06 12:35:54 -05:00
for ( unsigned int j = 0 ; j < indices [ i ]. size (); ++ j )
2016-02-24 12:45:00 -05:00
{
2019-04-24 01:24:55 -04:00
descriptorsFrom . row ( projectedIndexToDescIndex [ indices [ i ]. at ( j )]). copyTo ( descriptors . row ( oi ));
descriptorsIndices [ oi ++ ] = indices [ i ]. at ( j );
2017-11-30 16:52:03 -05:00
}
2019-03-06 12:35:54 -05:00
descriptorsIndices . resize ( oi );
2019-04-24 01:24:55 -04:00
UASSERT ( oi >= 2 );
2020-05-09 21:13:41 -04:00
cv :: BFMatcher matcher ( descriptors . type () == CV_8U ? cv :: NORM_HAMMING : cv :: NORM_L2SQR , _nnType == 5 );
if ( _nnType == 5 ) // bruteforce cross check
2017-11-30 16:52:03 -05:00
{
2020-05-01 22:12:56 -04:00
std :: vector < cv :: DMatch > matches ;
matcher . match ( descriptorsTo . row ( i ), cv :: Mat ( descriptors , cv :: Range ( 0 , oi )), matches );
if ( ! matches . empty ())
{
matchedIndex = descriptorsIndices . at ( matches . at ( 0 ). trainIdx );
}
2019-03-06 12:35:54 -05:00
}
2020-05-09 21:13:41 -04:00
else // bruteforce knn
2020-05-01 22:12:56 -04:00
{
std :: vector < std :: vector < cv :: DMatch > > matches ;
matcher . knnMatch ( descriptorsTo . row ( i ), cv :: Mat ( descriptors , cv :: Range ( 0 , oi )), matches , 2 );
UASSERT ( matches . size () == 1 );
UASSERT ( matches [ 0 ]. size () == 2 );
if ( matches [ 0 ]. at ( 0 ). distance < _nndr * matches [ 0 ]. at ( 1 ). distance )
{
matchedIndex = descriptorsIndices . at ( matches [ 0 ]. at ( 0 ). trainIdx );
}
}
2019-03-06 12:35:54 -05:00
}
else if ( indices [ i ]. size () == 1 )
{
2019-04-24 01:24:55 -04:00
matchedIndex = indices [ i ]. at ( 0 );
2019-03-06 12:35:54 -05:00
}
2016-02-22 16:13:14 -05:00
2019-03-06 12:35:54 -05:00
if ( matchedIndex >= 0 )
{
matchedIndex = projectedIndexToDescIndex [ matchedIndex ];
2020-10-05 17:34:32 -04:00
int id = ! orignalWordsFromIds . empty () ? orignalWordsFromIds [ matchedIndex ] : matchedIndex ;
2016-02-22 16:13:14 -05:00
2019-03-06 12:35:54 -05:00
if ( addedWordsFrom . find ( matchedIndex ) != addedWordsFrom . end ())
{
id = addedWordsFrom . at ( matchedIndex );
duplicates . insert ( std :: make_pair ( matchedIndex , id ));
2016-02-24 12:45:00 -05:00
}
else
{
2019-03-06 12:35:54 -05:00
addedWordsFrom . insert ( std :: make_pair ( matchedIndex , id ));
2016-02-22 16:13:14 -05:00
2020-10-05 17:34:32 -04:00
wordsFrom . insert ( wordsFrom . end (), std :: make_pair ( id , wordsFrom . size ()));
if ( ! kptsFrom . empty ())
2019-03-06 12:35:54 -05:00
{
2020-10-05 17:34:32 -04:00
wordsKptsFrom . push_back ( kptsFrom [ matchedIndex ]);
2019-03-06 12:35:54 -05:00
}
2020-10-05 17:34:32 -04:00
words3From . push_back ( kptsFrom3D [ matchedIndex ]);
wordsDescFrom . push_back ( descriptorsFrom . row ( matchedIndex ));
2016-02-24 12:45:00 -05:00
}
2019-03-06 12:35:54 -05:00
2020-10-05 17:34:32 -04:00
wordsTo . insert ( wordsTo . end (), std :: make_pair ( id , wordsTo . size ()));
wordsKptsTo . push_back ( kptsTo [ i ]);
wordsDescTo . push_back ( descriptorsTo . row ( i ));
if ( ! kptsTo3D . empty ())
2019-03-06 12:35:54 -05:00
{
2020-10-05 17:34:32 -04:00
words3To . push_back ( kptsTo3D [ i ]);
2019-03-06 12:35:54 -05:00
}
}
else
{
// gen fake ids
2020-10-05 17:34:32 -04:00
wordsTo . insert ( wordsTo . end (), std :: make_pair ( newToId , wordsTo . size ()));
wordsKptsTo . push_back ( kptsTo [ i ]);
wordsDescTo . push_back ( descriptorsTo . row ( i ));
if ( ! kptsTo3D . empty ())
2019-03-06 12:35:54 -05:00
{
2020-10-05 17:34:32 -04:00
words3To . push_back ( kptsTo3D [ i ]);
2019-03-06 12:35:54 -05:00
}
++ newToId ;
++ newWords ;
2016-02-24 12:45:00 -05:00
}
2017-11-30 16:52:03 -05:00
}
UDEBUG ( "addedWordsFrom=%d/%d (duplicates=%d, newWords=%d), kptsTo=%d, wordsTo=%d, words3From=%d" ,
( int ) addedWordsFrom . size (), ( int ) cornersProjected . size (), ( int ) duplicates . size (), newWords ,
( int ) kptsTo . size (), ( int ) wordsTo . size (), ( int ) words3From . size ());
// create fake ids for not matched words from "from"
int addWordsFromNotMatched = 0 ;
for ( unsigned int i = 0 ; i < kptsFrom3D . size (); ++ i )
{
if ( util3d :: isFinite ( kptsFrom3D [ i ]) && addedWordsFrom . find ( i ) == addedWordsFrom . end ())
{
2020-10-05 17:34:32 -04:00
int id = ! orignalWordsFromIds . empty () ? orignalWordsFromIds [ i ] : i ;
wordsFrom . insert ( wordsFrom . end (), std :: make_pair ( id , wordsFrom . size ()));
wordsKptsFrom . push_back ( kptsFrom [ i ]);
wordsDescFrom . push_back ( descriptorsFrom . row ( i ));
words3From . push_back ( kptsFrom3D [ i ]);
2017-11-30 16:52:03 -05:00
++ addWordsFromNotMatched ;
}
}
UDEBUG ( "addWordsFromNotMatched=%d -> words3From=%d" , addWordsFromNotMatched , ( int ) words3From . size ());
}
else
{
2020-05-01 22:12:56 -04:00
UDEBUG ( "match projected to frame" );
2017-11-30 16:52:03 -05:00
std :: vector < cv :: Point2f > pointsTo ;
cv :: KeyPoint :: convert ( kptsTo , pointsTo );
rtflann :: Matrix < float > pointsToMat (( float * ) pointsTo . data (), pointsTo . size (), 2 );
rtflann :: Index < rtflann :: L2_Simple < float > > index ( pointsToMat , rtflann :: KDTreeIndexParams ());
index . buildIndex ();
std :: vector < std :: vector < size_t > > indices ;
std :: vector < std :: vector < float > > dists ;
float radius = ( float ) _guessWinSize ; // pixels
rtflann :: Matrix < float > cornersProjectedMat (( float * ) cornersProjected . data (), cornersProjected . size (), 2 );
2023-11-19 01:05:52 -08:00
index . radiusSearch ( cornersProjectedMat , indices , dists , radius * radius , rtflann :: SearchParams ( 32 , 0 , false ));
2017-11-30 16:52:03 -05:00
UASSERT ( indices . size () == cornersProjectedMat . rows );
UASSERT ( descriptorsFrom . cols == descriptorsTo . cols );
UASSERT ( descriptorsFrom . rows == ( int ) kptsFrom . size ());
UASSERT (( int ) pointsToMat . rows == descriptorsTo . rows );
UASSERT ( pointsToMat . rows == kptsTo . size ());
UDEBUG ( "radius search done for guess" );
// Process results (Nearest Neighbor Distance Ratio)
std :: set < int > addedWordsTo ;
std :: set < int > addedWordsFrom ;
2017-12-09 21:44:53 -05:00
double bruteForceTotalTime = 0.0 ;
double bruteForceDescCopy = 0.0 ;
UTimer bruteForceTimer ;
cv :: Mat descriptors ( 10 , descriptorsTo . cols , descriptorsTo . type ());
2017-11-30 16:52:03 -05:00
for ( unsigned int i = 0 ; i < cornersProjectedMat . rows ; ++ i )
{
int matchedIndexFrom = projectedIndexToDescIndex [ i ];
2018-02-01 22:17:46 -05:00
if ( indices [ i ]. size ())
{
2020-10-05 17:34:32 -04:00
info . projectedIDs . push_back ( ! orignalWordsFromIds . empty () ? orignalWordsFromIds [ matchedIndexFrom ] : matchedIndexFrom );
2018-02-01 22:17:46 -05:00
}
2017-11-30 16:52:03 -05:00
if ( util3d :: isFinite ( kptsFrom3D [ matchedIndexFrom ]))
{
int matchedIndexTo = - 1 ;
if ( indices [ i ]. size () >= 2 )
{
2017-12-09 21:44:53 -05:00
bruteForceTimer . restart ();
2017-11-30 16:52:03 -05:00
std :: vector < int > descriptorsIndices ( indices [ i ]. size ());
int oi = 0 ;
2017-12-09 21:44:53 -05:00
if (( int ) indices [ i ]. size () > descriptors . rows )
{
descriptors . resize ( indices [ i ]. size ());
}
2017-11-30 16:52:03 -05:00
for ( unsigned int j = 0 ; j < indices [ i ]. size (); ++ j )
{
2019-04-24 01:24:55 -04:00
descriptorsTo . row ( indices [ i ]. at ( j )). copyTo ( descriptors . row ( oi ));
descriptorsIndices [ oi ++ ] = indices [ i ]. at ( j );
2017-11-30 16:52:03 -05:00
}
2017-12-09 21:44:53 -05:00
bruteForceDescCopy += bruteForceTimer . ticks ();
2019-04-24 01:24:55 -04:00
UASSERT ( oi >= 2 );
2020-05-09 21:13:41 -04:00
cv :: BFMatcher matcher ( descriptors . type () == CV_8U ? cv :: NORM_HAMMING : cv :: NORM_L2SQR , _nnType == 5 );
if ( _nnType == 5 ) // bruteforce cross check
2017-11-30 16:52:03 -05:00
{
2020-05-01 22:12:56 -04:00
std :: vector < cv :: DMatch > matches ;
matcher . match ( descriptorsFrom . row ( matchedIndexFrom ), cv :: Mat ( descriptors , cv :: Range ( 0 , oi )), matches );
if ( ! matches . empty ())
{
matchedIndexTo = descriptorsIndices . at ( matches . at ( 0 ). trainIdx );
}
}
2020-05-09 21:13:41 -04:00
else // bruteforce knn
2020-05-01 22:12:56 -04:00
{
std :: vector < std :: vector < cv :: DMatch > > matches ;
matcher . knnMatch ( descriptorsFrom . row ( matchedIndexFrom ), cv :: Mat ( descriptors , cv :: Range ( 0 , oi )), matches , 2 );
UASSERT ( matches . size () == 1 );
UASSERT ( matches [ 0 ]. size () == 2 );
bruteForceTotalTime += bruteForceTimer . elapsed ();
if ( matches [ 0 ]. at ( 0 ). distance < _nndr * matches [ 0 ]. at ( 1 ). distance )
{
matchedIndexTo = descriptorsIndices . at ( matches [ 0 ]. at ( 0 ). trainIdx );
}
2017-11-30 16:52:03 -05:00
}
}
else if ( indices [ i ]. size () == 1 )
{
2019-04-24 01:24:55 -04:00
matchedIndexTo = indices [ i ]. at ( 0 );
2017-11-30 16:52:03 -05:00
}
2020-10-05 17:34:32 -04:00
int id = ! orignalWordsFromIds . empty () ? orignalWordsFromIds [ matchedIndexFrom ] : matchedIndexFrom ;
2017-12-09 21:44:53 -05:00
addedWordsFrom . insert ( addedWordsFrom . end (), matchedIndexFrom );
2017-11-30 16:52:03 -05:00
2020-10-05 17:34:32 -04:00
wordsFrom . insert ( wordsFrom . end (), std :: make_pair ( id , wordsFrom . size ()));
if ( ! kptsFrom . empty ())
2017-11-30 16:52:03 -05:00
{
2020-10-05 17:34:32 -04:00
wordsKptsFrom . push_back ( kptsFrom [ matchedIndexFrom ]);
2017-11-30 16:52:03 -05:00
}
2020-10-05 17:34:32 -04:00
words3From . push_back ( kptsFrom3D [ matchedIndexFrom ]);
wordsDescFrom . push_back ( descriptorsFrom . row ( matchedIndexFrom ));
2017-11-30 16:52:03 -05:00
2019-03-06 12:35:54 -05:00
if ( matchedIndexTo >= 0 &&
2017-11-30 16:52:03 -05:00
addedWordsTo . find ( matchedIndexTo ) == addedWordsTo . end ())
{
addedWordsTo . insert ( matchedIndexTo );
2020-10-05 17:34:32 -04:00
wordsTo . insert ( wordsTo . end (), std :: make_pair ( id , wordsTo . size ()));
wordsKptsTo . push_back ( kptsTo [ matchedIndexTo ]);
wordsDescTo . push_back ( descriptorsTo . row ( matchedIndexTo ));
if ( ! kptsTo3D . empty ())
2017-11-30 16:52:03 -05:00
{
2020-10-05 17:34:32 -04:00
words3To . push_back ( kptsTo3D [ matchedIndexTo ]);
2017-11-30 16:52:03 -05:00
}
}
}
}
2017-12-09 21:44:53 -05:00
UDEBUG ( "bruteForceDescCopy=%fs, bruteForceTotalTime=%fs" , bruteForceDescCopy , bruteForceTotalTime );
2017-11-30 16:52:03 -05:00
// create fake ids for not matched words from "from"
for ( unsigned int i = 0 ; i < kptsFrom3D . size (); ++ i )
{
if ( util3d :: isFinite ( kptsFrom3D [ i ]) && addedWordsFrom . find ( i ) == addedWordsFrom . end ())
{
2020-10-05 17:34:32 -04:00
int id = ! orignalWordsFromIds . empty () ? orignalWordsFromIds [ i ] : i ;
wordsFrom . insert ( wordsFrom . end (), std :: make_pair ( id , wordsFrom . size ()));
wordsKptsFrom . push_back ( kptsFrom [ i ]);
wordsDescFrom . push_back ( descriptorsFrom . row ( i ));
words3From . push_back ( kptsFrom3D [ i ]);
2017-11-30 16:52:03 -05:00
}
}
2020-10-05 17:34:32 -04:00
int newToId = ! orignalWordsFromIds . empty () ? fromSignature . getWords (). rbegin () -> first + 1 : descriptorsFrom . rows ;
2017-11-30 16:52:03 -05:00
for ( unsigned int i = 0 ; i < kptsTo . size (); ++ i )
{
2019-04-22 19:50:41 -04:00
if ( addedWordsTo . find ( i ) == addedWordsTo . end ())
2016-02-24 12:45:00 -05:00
{
2020-10-05 17:34:32 -04:00
wordsTo . insert ( wordsTo . end (), std :: make_pair ( newToId , wordsTo . size ()));
wordsKptsTo . push_back ( kptsTo [ i ]);
wordsDescTo . push_back ( descriptorsTo . row ( i ));
if ( ! kptsTo3D . empty ())
2016-02-24 12:45:00 -05:00
{
2020-10-05 17:34:32 -04:00
words3To . push_back ( kptsTo3D [ i ]);
2016-02-24 12:45:00 -05:00
}
2016-02-24 17:42:23 -05:00
++ newToId ;
2016-02-24 12:45:00 -05:00
}
2016-02-22 16:13:14 -05:00
}
}
}
2016-11-27 20:10:05 -05:00
else
{
UWARN ( "All projected points are outside the camera. Guess (%s) is wrong or images are not overlapping." , guess . prettyPrint (). c_str ());
}
2016-02-22 16:13:14 -05:00
UDEBUG ( "" );
}
else
{
2016-03-09 17:15:05 -05:00
if ( guessSet && _guessWinSize > 0 && kptsFrom3D . size () && ! isCalibrated )
{
2022-07-20 15:20:14 -04:00
UWARN ( "Calibration not found! Finding correspondences "
"with the guess cannot be done, global matching is "
"done instead." );
2016-03-09 17:15:05 -05:00
}
2016-02-22 16:13:14 -05:00
UDEBUG ( "" );
// match between all descriptors
2016-11-14 19:54:31 -05:00
std :: list < int > fromWordIds ;
2020-05-01 22:12:56 -04:00
std :: list < int > toWordIds ;
2021-01-17 01:56:27 -05:00
#ifdef RTABMAP_PYTHON
2020-05-20 09:45:39 -04:00
if ( _nnType == 5 || ( _nnType == 6 && _pyMatcher ) || _nnType == 7 )
2020-05-09 21:13:41 -04:00
#else
2020-05-11 13:23:26 -04:00
if ( _nnType == 5 || _nnType == 7 ) // bruteforce cross check or GMS
2020-05-09 21:13:41 -04:00
#endif
2016-11-14 19:54:31 -05:00
{
2020-05-01 22:12:56 -04:00
std :: vector < int > fromWordIdsV ( descriptorsFrom . rows );
for ( int i = 0 ; i < descriptorsFrom . rows ; ++ i )
{
int id = i + 1 ;
if ( ! orignalWordsFromIds . empty ())
{
id = orignalWordsFromIds [ i ];
}
fromWordIds . push_back ( id );
fromWordIdsV [ i ] = id ;
}
if ( descriptorsTo . rows )
{
std :: vector < int > toWordIdsV ( descriptorsTo . rows , 0 );
std :: vector < cv :: DMatch > matches ;
2021-01-17 01:56:27 -05:00
#ifdef RTABMAP_PYTHON
2020-05-20 09:45:39 -04:00
if ( _nnType == 6 && _pyMatcher &&
2020-05-09 21:13:41 -04:00
descriptorsTo . cols == descriptorsFrom . cols &&
descriptorsTo . rows == ( int ) kptsTo . size () &&
descriptorsTo . type () == CV_32F &&
descriptorsFrom . type () == CV_32F &&
descriptorsFrom . rows == ( int ) kptsFrom . size () &&
2022-07-20 15:20:14 -04:00
models . size () == 1 )
2020-05-09 21:13:41 -04:00
{
2020-05-20 09:45:39 -04:00
UDEBUG ( "Python matching" );
2022-07-20 15:20:14 -04:00
matches = _pyMatcher -> match ( descriptorsTo , descriptorsFrom , kptsTo , kptsFrom , models [ 0 ]. imageSize ());
2020-05-09 21:13:41 -04:00
}
else
{
2020-05-20 09:45:39 -04:00
if ( _nnType == 6 && _pyMatcher )
2020-05-09 21:13:41 -04:00
{
2022-07-20 15:20:14 -04:00
UDEBUG ( "Invalid inputs for Python matching (desc type=%d, only float descriptors supported, multicam not supported), doing bruteforce matching instead." , descriptorsFrom . type ());
2020-05-09 21:13:41 -04:00
}
#else
{
#endif
2020-05-11 13:23:26 -04:00
bool doCrossCheck = true ;
#ifdef HAVE_OPENCV_XFEATURES2D
#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION==3 && CV_MINOR_VERSION >=4 && CV_SUBMINOR_VERSION >= 1)
cv :: Size imageSizeFrom ;
if ( _nnType == 7 )
{
imageSizeFrom = imageFrom . size ();
2022-07-20 15:20:14 -04:00
if (( imageSizeFrom . height == 0 || imageSizeFrom . width == 0 ) && ( fromSignature . sensorData (). cameraModels (). size () || fromSignature . sensorData (). stereoCameraModels (). size ()))
2020-05-11 13:23:26 -04:00
{
2022-07-20 15:20:14 -04:00
imageSizeFrom = fromSignature . sensorData (). cameraModels (). size () == 1 ? fromSignature . sensorData (). cameraModels ()[ 0 ]. imageSize () : fromSignature . sensorData (). stereoCameraModels ()[ 0 ]. left (). imageSize ();
2020-05-11 13:23:26 -04:00
}
2022-07-20 15:20:14 -04:00
if ( ! models . empty () && models [ 0 ]. imageSize (). height > 0 && models [ 0 ]. imageSize (). width > 0 &&
2020-05-11 13:23:26 -04:00
imageSizeFrom . height > 0 && imageSizeFrom . width > 0 )
{
doCrossCheck = false ;
}
else
{
UDEBUG ( "Invalid inputs for GMS matching, image size should be set for both inputs, doing bruteforce matching instead." );
}
}
#endif
#endif
UDEBUG ( "BruteForce matching%s" , _nnType != 7 ? " with crosscheck" : " with GMS" );
cv :: BFMatcher matcher ( descriptorsFrom . type () == CV_8U ? cv :: NORM_HAMMING : cv :: NORM_L2SQR , doCrossCheck );
2020-05-09 21:13:41 -04:00
matcher . match ( descriptorsTo , descriptorsFrom , matches );
2020-05-11 13:23:26 -04:00
#if defined(HAVE_OPENCV_XFEATURES2D) && (CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION==3 && CV_MINOR_VERSION >=4 && CV_SUBMINOR_VERSION >= 1))
if ( ! doCrossCheck )
{
2022-07-20 15:20:14 -04:00
UASSERT ( ! models . empty ());
2020-05-11 13:23:26 -04:00
std :: vector < cv :: DMatch > matchesGMS ;
2022-07-20 15:20:14 -04:00
cv :: xfeatures2d :: matchGMS ( models [ 0 ]. imageSize (), imageSizeFrom , kptsTo , kptsFrom , matches , matchesGMS , _gmsWithRotation , _gmsWithScale , _gmsThresholdFactor );
2020-05-11 13:23:26 -04:00
matches = matchesGMS ;
}
#endif
2020-05-09 21:13:41 -04:00
}
2020-05-01 22:12:56 -04:00
for ( size_t i = 0 ; i < matches . size (); ++ i )
{
toWordIdsV [ matches [ i ]. queryIdx ] = fromWordIdsV [ matches [ i ]. trainIdx ];
}
for ( size_t i = 0 ; i < toWordIdsV . size (); ++ i )
{
int toId = toWordIdsV [ i ];
if ( toId == 0 )
{
toId = fromWordIds . back () + i + 1 ;
}
toWordIds . push_back ( toId );
}
}
2019-04-24 01:24:55 -04:00
}
else
{
2020-05-09 21:13:41 -04:00
UDEBUG ( "VWDictionary knn matching" );
2020-05-01 22:12:56 -04:00
VWDictionary dictionary ( _featureParameters );
if ( orignalWordsFromIds . empty ())
2019-04-24 01:24:55 -04:00
{
2020-05-01 22:12:56 -04:00
fromWordIds = dictionary . addNewWords ( descriptorsFrom , 1 );
}
else
{
for ( int i = 0 ; i < descriptorsFrom . rows ; ++ i )
{
int id = orignalWordsFromIds [ i ];
dictionary . addWord ( new VisualWord ( id , descriptorsFrom . row ( i ), 1 ));
fromWordIds . push_back ( id );
}
2019-04-24 01:24:55 -04:00
}
2016-02-22 16:13:14 -05:00
2020-05-01 22:12:56 -04:00
if ( descriptorsTo . rows )
{
dictionary . update ();
toWordIds = dictionary . addNewWords ( descriptorsTo , 2 );
}
dictionary . clear ( false );
2016-02-22 16:13:14 -05:00
}
std :: multiset < int > fromWordIdsSet ( fromWordIds . begin (), fromWordIds . end ());
std :: multiset < int > toWordIdsSet ( toWordIds . begin (), toWordIds . end ());
UASSERT ( kptsFrom3D . empty () || fromWordIds . size () == kptsFrom3D . size ());
2016-02-23 11:06:24 -05:00
UASSERT ( int ( fromWordIds . size ()) == descriptorsFrom . rows );
2016-02-22 16:13:14 -05:00
int i = 0 ;
for ( std :: list < int >:: iterator iter = fromWordIds . begin (); iter != fromWordIds . end (); ++ iter )
{
if ( fromWordIdsSet . count ( * iter ) == 1 )
{
2020-10-05 17:34:32 -04:00
wordsFrom . insert ( wordsFrom . end (), std :: make_pair ( * iter , wordsFrom . size ()));
if ( ! kptsFrom . empty ())
2016-11-25 19:52:34 -05:00
{
2020-10-05 17:34:32 -04:00
wordsKptsFrom . push_back ( kptsFrom [ i ]);
2016-11-25 19:52:34 -05:00
}
2020-10-05 17:34:32 -04:00
if ( ! kptsFrom3D . empty ())
2016-02-22 16:13:14 -05:00
{
2020-10-05 17:34:32 -04:00
words3From . push_back ( kptsFrom3D [ i ]);
2016-02-22 16:13:14 -05:00
}
2020-10-05 17:34:32 -04:00
wordsDescFrom . push_back ( descriptorsFrom . row ( i ));
2016-02-22 16:13:14 -05:00
}
++ i ;
}
UASSERT ( kptsTo3D . size () == 0 || kptsTo3D . size () == kptsTo . size ());
UASSERT ( toWordIds . size () == kptsTo . size ());
2016-02-23 11:06:24 -05:00
UASSERT ( int ( toWordIds . size ()) == descriptorsTo . rows );
2016-02-22 16:13:14 -05:00
i = 0 ;
for ( std :: list < int >:: iterator iter = toWordIds . begin (); iter != toWordIds . end (); ++ iter )
{
if ( toWordIdsSet . count ( * iter ) == 1 )
{
2020-10-05 17:34:32 -04:00
wordsTo . insert ( wordsTo . end (), std :: make_pair ( * iter , wordsTo . size ()));
wordsKptsTo . push_back ( kptsTo [ i ]);
wordsDescTo . push_back ( descriptorsTo . row ( i ));
if ( ! kptsTo3D . empty ())
2016-02-22 16:13:14 -05:00
{
2020-10-05 17:34:32 -04:00
words3To . push_back ( kptsTo3D [ i ]);
2016-02-22 16:13:14 -05:00
}
}
++ i ;
}
}
}
else if ( descriptorsFrom . rows )
{
//just create fake words
2016-03-01 17:33:27 -05:00
UASSERT ( kptsFrom3D . empty () || int ( kptsFrom3D . size ()) == descriptorsFrom . rows );
for ( int i = 0 ; i < descriptorsFrom . rows ; ++ i )
2016-02-22 16:13:14 -05:00
{
2020-10-05 17:34:32 -04:00
wordsFrom . insert ( wordsFrom . end (), std :: make_pair ( i , wordsFrom . size ()));
wordsKptsFrom . push_back ( kptsFrom [ i ]);
wordsDescFrom . push_back ( descriptorsFrom . row ( i ));
if ( ! kptsFrom3D . empty ())
2016-02-22 16:13:14 -05:00
{
2020-10-05 17:34:32 -04:00
words3From . push_back ( kptsFrom3D [ i ]);
2016-02-22 16:13:14 -05:00
}
}
}
2015-12-21 17:27:05 -05:00
}
2020-10-05 17:34:32 -04:00
fromSignature . setWords ( wordsFrom , wordsKptsFrom , words3From , wordsDescFrom );
toSignature . setWords ( wordsTo , wordsKptsTo , words3To , wordsDescTo );
2015-11-22 18:08:32 -05:00
}
2015-12-21 17:27:05 -05:00
/////////////////////
// Motion estimation
/////////////////////
Transform transform ;
2017-05-04 16:13:45 -04:00
cv :: Mat covariance = cv :: Mat :: eye ( 6 , 6 , CV_64FC1 );
2016-01-06 17:26:55 -05:00
int inliersCount = 0 ;
2016-01-07 13:59:21 -05:00
int matchesCount = 0 ;
2018-02-01 22:17:46 -05:00
info . inliersIDs . clear ();
info . matchesIDs . clear ();
2016-04-08 16:15:08 -04:00
if ( toSignature . getWords (). size ())
2015-11-22 18:08:32 -05:00
{
2015-12-21 17:27:05 -05:00
Transform transforms [ 2 ];
std :: vector < int > inliers [ 2 ];
2016-01-07 13:59:21 -05:00
std :: vector < int > matches [ 2 ];
2017-05-04 16:13:45 -04:00
cv :: Mat covariances [ 2 ];
covariances [ 0 ] = cv :: Mat :: eye ( 6 , 6 , CV_64FC1 );
covariances [ 1 ] = cv :: Mat :: eye ( 6 , 6 , CV_64FC1 );
2015-12-21 17:27:05 -05:00
for ( int dir = 0 ; dir < ( ! _forwardEstimateOnly ? 2 : 1 ); ++ dir )
2015-11-22 18:08:32 -05:00
{
2015-12-21 17:27:05 -05:00
// A to B
2016-11-14 19:54:31 -05:00
Signature * signatureA ;
Signature * signatureB ;
2015-12-21 17:27:05 -05:00
if ( dir == 0 )
2015-11-22 18:08:32 -05:00
{
2015-12-21 17:27:05 -05:00
signatureA = & fromSignature ;
signatureB = & toSignature ;
}
else
{
signatureA = & toSignature ;
signatureB = & fromSignature ;
}
if ( _estimationType == 2 ) // Epipolar Geometry
{
UDEBUG ( "" );
2022-07-20 15:20:14 -04:00
if (( signatureB -> sensorData (). stereoCameraModels (). size () != 1 ||
! signatureB -> sensorData (). stereoCameraModels ()[ 0 ]. isValidForProjection ()) &&
2015-12-21 17:27:05 -05:00
( signatureB -> sensorData (). cameraModels (). size () != 1 ||
2016-01-19 21:01:56 -05:00
! signatureB -> sensorData (). cameraModels ()[ 0 ]. isValidForProjection ()))
2015-11-22 18:08:32 -05:00
{
2015-12-21 17:27:05 -05:00
UERROR ( "Calibrated camera required (multi-cameras not supported)." );
}
else if (( int ) signatureA -> getWords (). size () >= _minInliers &&
( int ) signatureB -> getWords (). size () >= _minInliers )
{
2022-07-20 15:20:14 -04:00
UASSERT (( signatureA -> sensorData (). stereoCameraModels (). size () == 1 && signatureA -> sensorData (). stereoCameraModels ()[ 0 ]. isValidForProjection ()) || ( signatureA -> sensorData (). cameraModels (). size () == 1 && signatureA -> sensorData (). cameraModels ()[ 0 ]. isValidForProjection ()));
const CameraModel & cameraModel = signatureA -> sensorData (). stereoCameraModels (). size () ? signatureA -> sensorData (). stereoCameraModels ()[ 0 ]. left () : signatureA -> sensorData (). cameraModels ()[ 0 ];
2015-12-21 17:27:05 -05:00
// we only need the camera transform, send guess words3 for scale estimation
Transform cameraTransform ;
2017-05-04 16:13:45 -04:00
double variance = 1.0f ;
2020-05-09 21:13:41 -04:00
std :: vector < int > matchesV ;
2020-10-05 17:34:32 -04:00
std :: map < int , int > uniqueWordsA = uMultimapToMapUnique ( signatureA -> getWords ());
std :: map < int , int > uniqueWordsB = uMultimapToMapUnique ( signatureB -> getWords ());
std :: map < int , cv :: KeyPoint > wordsA ;
std :: map < int , cv :: Point3f > words3A ;
std :: map < int , cv :: KeyPoint > wordsB ;
for ( std :: map < int , int >:: iterator iter = uniqueWordsA . begin (); iter != uniqueWordsA . end (); ++ iter )
{
wordsA . insert ( std :: make_pair ( iter -> first , signatureA -> getWordsKpts ()[ iter -> second ]));
if ( ! signatureA -> getWords3 (). empty ())
{
words3A . insert ( std :: make_pair ( iter -> first , signatureA -> getWords3 ()[ iter -> second ]));
}
}
for ( std :: map < int , int >:: iterator iter = uniqueWordsB . begin (); iter != uniqueWordsB . end (); ++ iter )
{
wordsB . insert ( std :: make_pair ( iter -> first , signatureB -> getWordsKpts ()[ iter -> second ]));
}
2015-12-21 17:27:05 -05:00
std :: map < int , cv :: Point3f > inliers3D = util3d :: generateWords3DMono (
2020-10-05 17:34:32 -04:00
wordsA ,
wordsB ,
2015-12-21 17:27:05 -05:00
cameraModel ,
cameraTransform ,
2020-05-09 21:13:41 -04:00
_PnPReprojError ,
2015-12-21 17:27:05 -05:00
0.99f ,
2020-10-05 17:34:32 -04:00
words3A , // for scale estimation
2020-05-09 21:13:41 -04:00
& variance ,
& matchesV );
2017-05-04 16:13:45 -04:00
covariances [ dir ] *= variance ;
2015-12-21 17:27:05 -05:00
inliers [ dir ] = uKeys ( inliers3D );
2020-05-09 21:13:41 -04:00
matches [ dir ] = matchesV ;
2015-12-21 17:27:05 -05:00
if ( ! cameraTransform . isNull ())
2015-11-22 18:08:32 -05:00
{
2015-12-21 17:27:05 -05:00
if (( int ) inliers3D . size () >= _minInliers )
{
2017-05-04 16:13:45 -04:00
if ( variance <= _epipolarGeometryVar )
2015-12-21 17:27:05 -05:00
{
2017-12-21 10:16:46 -05:00
if ( this -> force3DoF ())
{
transforms [ dir ] = cameraTransform . to3DoF ();
}
else
{
transforms [ dir ] = cameraTransform ;
}
2015-12-21 17:27:05 -05:00
}
else
{
2020-05-10 14:13:41 -04:00
msg = uFormat ( "Variance is too high! (Max %s=%f, variance=%f)" , Parameters :: kVisEpipolarGeometryVar (). c_str (), _epipolarGeometryVar , variance );
2015-12-21 17:27:05 -05:00
UINFO ( msg . c_str ());
}
}
else
{
msg = uFormat ( "Not enough inliers %d < %d" , ( int ) inliers3D . size (), _minInliers );
UINFO ( msg . c_str ());
}
2015-11-22 18:08:32 -05:00
}
else
{
2015-12-21 17:27:05 -05:00
msg = uFormat ( "No camera transform found" );
UINFO ( msg . c_str ());
}
}
else if ( signatureA -> getWords (). size () == 0 )
{
msg = uFormat ( "No enough features (%d)" , ( int ) signatureA -> getWords (). size ());
UWARN ( msg . c_str ());
}
else
{
msg = uFormat ( "No camera model" );
UWARN ( msg . c_str ());
}
}
else if ( _estimationType == 1 ) // PnP
{
UDEBUG ( "" );
2022-07-20 15:20:14 -04:00
if (( signatureB -> sensorData (). stereoCameraModels (). empty () || ! signatureB -> sensorData (). stereoCameraModels ()[ 0 ]. isValidForProjection ()) &&
( signatureB -> sensorData (). cameraModels (). empty () || ! signatureB -> sensorData (). cameraModels ()[ 0 ]. isValidForProjection ()))
2015-12-21 17:27:05 -05:00
{
2022-07-20 15:20:14 -04:00
UERROR ( "Calibrated camera required. Id=%d Models=%d StereoModels=%d weight=%d" ,
2015-12-21 17:27:05 -05:00
signatureB -> id (),
( int ) signatureB -> sensorData (). cameraModels (). size (),
2022-07-20 15:20:14 -04:00
signatureB -> sensorData (). stereoCameraModels (). size (),
2015-12-21 17:27:05 -05:00
signatureB -> getWeight ());
}
2022-07-20 15:20:14 -04:00
#ifndef RTABMAP_OPENGV
else if ( signatureB -> sensorData (). cameraModels (). size () > 1 )
{
UERROR ( "Multi-camera 2D-3D PnP registration is only available if rtabmap is built "
"with OpenGV dependency. Use 3D-3D registration approach instead for multi-camera." );
}
#endif
2015-12-21 17:27:05 -05:00
else
{
UDEBUG ( "words from3D=%d to2D=%d" , ( int ) signatureA -> getWords3 (). size (), ( int ) signatureB -> getWords (). size ());
// 3D to 2D
if (( int ) signatureA -> getWords3 (). size () >= _minInliers &&
( int ) signatureB -> getWords (). size () >= _minInliers )
{
std :: vector < int > inliersV ;
2016-01-07 13:59:21 -05:00
std :: vector < int > matchesV ;
2020-10-05 17:34:32 -04:00
std :: map < int , int > uniqueWordsA = uMultimapToMapUnique ( signatureA -> getWords ());
std :: map < int , int > uniqueWordsB = uMultimapToMapUnique ( signatureB -> getWords ());
std :: map < int , cv :: Point3f > words3A ;
std :: map < int , cv :: Point3f > words3B ;
std :: map < int , cv :: KeyPoint > wordsB ;
for ( std :: map < int , int >:: iterator iter = uniqueWordsA . begin (); iter != uniqueWordsA . end (); ++ iter )
{
words3A . insert ( std :: make_pair ( iter -> first , signatureA -> getWords3 ()[ iter -> second ]));
}
for ( std :: map < int , int >:: iterator iter = uniqueWordsB . begin (); iter != uniqueWordsB . end (); ++ iter )
{
wordsB . insert ( std :: make_pair ( iter -> first , signatureB -> getWordsKpts ()[ iter -> second ]));
if ( ! signatureB -> getWords3 (). empty ())
{
words3B . insert ( std :: make_pair ( iter -> first , signatureB -> getWords3 ()[ iter -> second ]));
}
}
2022-07-20 15:20:14 -04:00
std :: vector < CameraModel > models ;
if ( signatureB -> sensorData (). stereoCameraModels (). size ())
{
for ( size_t i = 0 ; i < signatureB -> sensorData (). stereoCameraModels (). size (); ++ i )
{
models . push_back ( signatureB -> sensorData (). stereoCameraModels ()[ i ]. left ());
}
}
else
{
models = signatureB -> sensorData (). cameraModels ();
}
if ( models . size () > 1 )
{
// Multi-Camera
UASSERT ( models [ 0 ]. isValidForProjection ());
transforms [ dir ] = util3d :: estimateMotion3DTo2D (
words3A ,
wordsB ,
models ,
2023-07-22 11:05:21 -04:00
_multiSamplingPolicy ,
2022-07-20 15:20:14 -04:00
_minInliers ,
_iterations ,
_PnPReprojError ,
_PnPFlags ,
_PnPRefineIterations ,
2023-07-27 16:13:30 -07:00
_PnPVarMedianRatio ,
2022-09-24 12:29:42 -07:00
_PnPMaxVar ,
2022-07-20 15:20:14 -04:00
dir == 0 ? ( ! guess . isNull () ? guess : Transform :: getIdentity ()) :! transforms [ 0 ]. isNull () ? transforms [ 0 ]. inverse () : ( ! guess . isNull () ? guess . inverse () : Transform :: getIdentity ()),
words3B ,
& covariances [ dir ],
& matchesV ,
2024-02-07 14:43:16 -08:00
& inliersV ,
_PnPSplitLinearCovarianceComponents );
2022-07-20 15:20:14 -04:00
inliers [ dir ] = inliersV ;
matches [ dir ] = matchesV ;
}
else
{
UASSERT ( models . size () == 1 && models [ 0 ]. isValidForProjection ());
transforms [ dir ] = util3d :: estimateMotion3DTo2D (
words3A ,
wordsB ,
models [ 0 ],
_minInliers ,
_iterations ,
_PnPReprojError ,
_PnPFlags ,
_PnPRefineIterations ,
2023-07-27 16:13:30 -07:00
_PnPVarMedianRatio ,
2022-09-24 12:29:42 -07:00
_PnPMaxVar ,
2022-07-20 15:20:14 -04:00
dir == 0 ? ( ! guess . isNull () ? guess : Transform :: getIdentity ()) :! transforms [ 0 ]. isNull () ? transforms [ 0 ]. inverse () : ( ! guess . isNull () ? guess . inverse () : Transform :: getIdentity ()),
words3B ,
& covariances [ dir ],
& matchesV ,
2024-02-07 14:43:16 -08:00
& inliersV ,
_PnPSplitLinearCovarianceComponents );
2022-07-20 15:20:14 -04:00
inliers [ dir ] = inliersV ;
matches [ dir ] = matchesV ;
}
2019-03-06 12:35:54 -05:00
UDEBUG ( "inliers: %d/%d" , ( int ) inliersV . size (), ( int ) matchesV . size ());
2015-12-21 17:27:05 -05:00
if ( transforms [ dir ]. isNull ())
{
2016-02-22 16:13:14 -05:00
msg = uFormat ( "Not enough inliers %d/%d (matches=%d) between %d and %d" ,
( int ) inliers [ dir ]. size (), _minInliers , ( int ) matches [ dir ]. size (), signatureA -> id (), signatureB -> id ());
2015-12-21 17:27:05 -05:00
UINFO ( msg . c_str ());
}
2017-12-21 10:16:46 -05:00
else if ( this -> force3DoF ())
{
transforms [ dir ] = transforms [ dir ]. to3DoF ();
}
2015-12-21 17:27:05 -05:00
}
else
{
msg = uFormat ( "Not enough features in images (old=%d, new=%d, min=%d)" ,
( int ) signatureA -> getWords3 (). size (), ( int ) signatureB -> getWords (). size (), _minInliers );
UINFO ( msg . c_str ());
}
}
}
else
{
UDEBUG ( "" );
// 3D -> 3D
if (( int ) signatureA -> getWords3 (). size () >= _minInliers &&
( int ) signatureB -> getWords3 (). size () >= _minInliers )
{
std :: vector < int > inliersV ;
2016-01-07 13:59:21 -05:00
std :: vector < int > matchesV ;
2020-10-05 17:34:32 -04:00
std :: map < int , int > uniqueWordsA = uMultimapToMapUnique ( signatureA -> getWords ());
std :: map < int , int > uniqueWordsB = uMultimapToMapUnique ( signatureB -> getWords ());
std :: map < int , cv :: Point3f > words3A ;
std :: map < int , cv :: Point3f > words3B ;
for ( std :: map < int , int >:: iterator iter = uniqueWordsA . begin (); iter != uniqueWordsA . end (); ++ iter )
{
words3A . insert ( std :: make_pair ( iter -> first , signatureA -> getWords3 ()[ iter -> second ]));
}
for ( std :: map < int , int >:: iterator iter = uniqueWordsB . begin (); iter != uniqueWordsB . end (); ++ iter )
{
words3B . insert ( std :: make_pair ( iter -> first , signatureB -> getWords3 ()[ iter -> second ]));
}
2015-12-21 17:27:05 -05:00
transforms [ dir ] = util3d :: estimateMotion3DTo3D (
2020-10-05 17:34:32 -04:00
words3A ,
words3B ,
2015-12-21 17:27:05 -05:00
_minInliers ,
_inlierDistance ,
_iterations ,
_refineIterations ,
2017-05-04 16:13:45 -04:00
& covariances [ dir ],
2016-01-07 13:59:21 -05:00
& matchesV ,
2015-12-21 17:27:05 -05:00
& inliersV );
inliers [ dir ] = inliersV ;
2016-01-07 13:59:21 -05:00
matches [ dir ] = matchesV ;
2019-03-06 12:35:54 -05:00
UDEBUG ( "inliers: %d/%d" , ( int ) inliersV . size (), ( int ) matchesV . size ());
2015-12-21 17:27:05 -05:00
if ( transforms [ dir ]. isNull ())
{
2017-02-09 18:32:44 -05:00
msg = uFormat ( "Not enough inliers %d/%d (matches=%d) between %d and %d" ,
( int ) inliers [ dir ]. size (), _minInliers , ( int ) matches [ dir ]. size (), signatureA -> id (), signatureB -> id ());
2015-11-22 18:08:32 -05:00
UINFO ( msg . c_str ());
}
2017-12-21 10:16:46 -05:00
else if ( this -> force3DoF ())
{
transforms [ dir ] = transforms [ dir ]. to3DoF ();
}
2015-11-22 18:08:32 -05:00
}
else
{
2015-12-21 17:27:05 -05:00
msg = uFormat ( "Not enough 3D features in images (old=%d, new=%d, min=%d)" ,
( int ) signatureA -> getWords3 (). size (), ( int ) signatureB -> getWords3 (). size (), _minInliers );
2015-11-22 18:08:32 -05:00
UINFO ( msg . c_str ());
}
}
}
2016-01-19 17:43:33 -05:00
if ( ! _forwardEstimateOnly )
{
UDEBUG ( "from->to=%s" , transforms [ 0 ]. prettyPrint (). c_str ());
2017-01-03 21:05:00 -05:00
UDEBUG ( "to->from=%s" , transforms [ 1 ]. prettyPrint (). c_str ());
}
std :: vector < int > allInliers = inliers [ 0 ];
if ( inliers [ 1 ]. size ())
{
std :: set < int > allInliersSet ( allInliers . begin (), allInliers . end ());
unsigned int oi = allInliers . size ();
allInliers . resize ( allInliers . size () + inliers [ 1 ]. size ());
for ( unsigned int i = 0 ; i < inliers [ 1 ]. size (); ++ i )
{
if ( allInliersSet . find ( inliers [ 1 ][ i ]) == allInliersSet . end ())
{
allInliers [ oi ++ ] = inliers [ 1 ][ i ];
}
}
allInliers . resize ( oi );
}
std :: vector < int > allMatches = matches [ 0 ];
if ( matches [ 1 ]. size ())
{
std :: set < int > allMatchesSet ( allMatches . begin (), allMatches . end ());
unsigned int oi = allMatches . size ();
allMatches . resize ( allMatches . size () + matches [ 1 ]. size ());
for ( unsigned int i = 0 ; i < matches [ 1 ]. size (); ++ i )
{
if ( allMatchesSet . find ( matches [ 1 ][ i ]) == allMatchesSet . end ())
{
allMatches [ oi ++ ] = matches [ 1 ][ i ];
}
}
allMatches . resize ( oi );
2016-01-19 17:43:33 -05:00
}
2016-11-14 19:54:31 -05:00
if ( _bundleAdjustment > 0 &&
_estimationType < 2 &&
! transforms [ 0 ]. isNull () &&
2017-01-03 21:05:00 -05:00
allInliers . size () &&
2016-11-14 19:54:31 -05:00
fromSignature . getWords3 (). size () &&
toSignature . getWords (). size () &&
2022-07-20 15:20:14 -04:00
( fromSignature . sensorData (). stereoCameraModels (). size () >= 1 || fromSignature . sensorData (). cameraModels (). size () >= 1 ) &&
( toSignature . sensorData (). stereoCameraModels (). size () >= 1 || toSignature . sensorData (). cameraModels (). size () >= 1 ))
2016-11-14 19:54:31 -05:00
{
2019-03-06 12:35:54 -05:00
UDEBUG ( "Refine with bundle adjustment" );
2019-08-17 03:55:04 -04:00
Optimizer * sba = Optimizer :: create ( _bundleAdjustment == 3 ? Optimizer :: kTypeCeres : _bundleAdjustment == 2 ? Optimizer :: kTypeCVSBA : Optimizer :: kTypeG2O , _bundleParameters );
2017-01-03 21:05:00 -05:00
2016-11-14 19:54:31 -05:00
std :: map < int , Transform > poses ;
std :: multimap < int , Link > links ;
std :: map < int , cv :: Point3f > points3DMap ;
poses . insert ( std :: make_pair ( 1 , Transform :: getIdentity ()));
poses . insert ( std :: make_pair ( 2 , transforms [ 0 ]));
2017-11-30 16:52:03 -05:00
for ( int i = 0 ; i < 2 ; ++ i )
{
UASSERT ( covariances [ i ]. cols == 6 && covariances [ i ]. rows == 6 && covariances [ i ]. type () == CV_64FC1 );
2022-02-06 17:41:53 -05:00
if ( covariances [ i ]. at < double > ( 0 , 0 ) <= COVARIANCE_LINEAR_EPSILON )
covariances [ i ]. at < double > ( 0 , 0 ) = COVARIANCE_LINEAR_EPSILON ; // epsilon if exact transform
if ( covariances [ i ]. at < double > ( 1 , 1 ) <= COVARIANCE_LINEAR_EPSILON )
covariances [ i ]. at < double > ( 1 , 1 ) = COVARIANCE_LINEAR_EPSILON ; // epsilon if exact transform
if ( covariances [ i ]. at < double > ( 2 , 2 ) <= COVARIANCE_LINEAR_EPSILON )
covariances [ i ]. at < double > ( 2 , 2 ) = COVARIANCE_LINEAR_EPSILON ; // epsilon if exact transform
if ( covariances [ i ]. at < double > ( 3 , 3 ) <= COVARIANCE_ANGULAR_EPSILON )
covariances [ i ]. at < double > ( 3 , 3 ) = COVARIANCE_ANGULAR_EPSILON ; // epsilon if exact transform
if ( covariances [ i ]. at < double > ( 4 , 4 ) <= COVARIANCE_ANGULAR_EPSILON )
covariances [ i ]. at < double > ( 4 , 4 ) = COVARIANCE_ANGULAR_EPSILON ; // epsilon if exact transform
if ( covariances [ i ]. at < double > ( 5 , 5 ) <= COVARIANCE_ANGULAR_EPSILON )
covariances [ i ]. at < double > ( 5 , 5 ) = COVARIANCE_ANGULAR_EPSILON ; // epsilon if exact transform
2017-11-30 16:52:03 -05:00
}
2017-05-22 11:48:01 -04:00
cv :: Mat cov = covariances [ 0 ]. clone ();
2017-05-22 21:11:36 -04:00
2017-05-22 11:48:01 -04:00
links . insert ( std :: make_pair ( 1 , Link ( 1 , 2 , Link :: kNeighbor , transforms [ 0 ], cov . inv ())));
2016-11-14 19:54:31 -05:00
if ( ! transforms [ 1 ]. isNull () && inliers [ 1 ]. size ())
{
2017-05-22 11:48:01 -04:00
cov = covariances [ 1 ]. clone ();
links . insert ( std :: make_pair ( 2 , Link ( 2 , 1 , Link :: kNeighbor , transforms [ 1 ], cov . inv ())));
2016-11-14 19:54:31 -05:00
}
2017-01-03 21:05:00 -05:00
std :: map < int , Transform > optimizedPoses ;
2022-07-20 15:20:14 -04:00
UASSERT (( toSignature . sensorData (). stereoCameraModels (). size () >= 1 && toSignature . sensorData (). stereoCameraModels ()[ 0 ]. isValidForProjection ()) ||
( toSignature . sensorData (). cameraModels (). size () >= 1 && toSignature . sensorData (). cameraModels ()[ 0 ]. isValidForProjection ()));
2017-01-03 21:05:00 -05:00
2022-07-20 15:20:14 -04:00
std :: map < int , std :: vector < CameraModel > > models ;
2017-01-03 21:05:00 -05:00
2022-07-20 15:20:14 -04:00
std :: vector < CameraModel > cameraModelsFrom ;
if ( fromSignature . sensorData (). stereoCameraModels (). size ())
2016-11-14 19:54:31 -05:00
{
2022-07-20 15:20:14 -04:00
for ( size_t i = 0 ; i < fromSignature . sensorData (). stereoCameraModels (). size (); ++ i )
{
CameraModel cameraModel = fromSignature . sensorData (). stereoCameraModels ()[ i ]. left ();
// Set Tx=-baseline*fx for Stereo BA
cameraModel = CameraModel ( cameraModel . fx (),
cameraModel . fy (),
cameraModel . cx (),
cameraModel . cy (),
cameraModel . localTransform (),
- fromSignature . sensorData (). stereoCameraModels ()[ 0 ]. baseline () * cameraModel . fx (),
cameraModel . imageSize ());
cameraModelsFrom . push_back ( cameraModel );
}
2017-01-03 21:05:00 -05:00
}
2022-07-20 15:20:14 -04:00
else
2017-01-03 21:05:00 -05:00
{
2022-07-20 15:20:14 -04:00
cameraModelsFrom = fromSignature . sensorData (). cameraModels ();
2016-11-14 19:54:31 -05:00
}
2022-07-20 15:20:14 -04:00
std :: vector < CameraModel > cameraModelsTo ;
if ( toSignature . sensorData (). stereoCameraModels (). size ())
2016-11-14 19:54:31 -05:00
{
2022-07-20 15:20:14 -04:00
for ( size_t i = 0 ; i < toSignature . sensorData (). stereoCameraModels (). size (); ++ i )
{
CameraModel cameraModel = toSignature . sensorData (). stereoCameraModels ()[ i ]. left ();
// Set Tx=-baseline*fx for Stereo BA
cameraModel = CameraModel ( cameraModel . fx (),
cameraModel . fy (),
cameraModel . cx (),
cameraModel . cy (),
cameraModel . localTransform (),
- toSignature . sensorData (). stereoCameraModels ()[ 0 ]. baseline () * cameraModel . fx (),
cameraModel . imageSize ());
cameraModelsTo . push_back ( cameraModel );
}
2017-01-03 21:05:00 -05:00
}
2022-07-20 15:20:14 -04:00
else
2017-01-03 21:05:00 -05:00
{
2022-07-20 15:20:14 -04:00
cameraModelsTo = toSignature . sensorData (). cameraModels ();
2016-11-14 19:54:31 -05:00
}
2022-07-20 15:20:14 -04:00
models . insert ( std :: make_pair ( 1 , cameraModelsFrom ));
models . insert ( std :: make_pair ( 2 , cameraModelsTo ));
2017-01-03 21:05:00 -05:00
2018-10-24 20:01:57 -04:00
std :: map < int , std :: map < int , FeatureBA > > wordReferences ;
2020-09-15 15:18:49 -04:00
std :: set < int > sbaOutliers ;
2022-07-20 15:20:14 -04:00
UDEBUG ( "" );
2017-01-03 21:05:00 -05:00
for ( unsigned int i = 0 ; i < allInliers . size (); ++ i )
{
int wordId = allInliers [ i ];
2020-10-05 17:34:32 -04:00
int indexFrom = fromSignature . getWords (). find ( wordId ) -> second ;
const cv :: Point3f & pt3D = fromSignature . getWords3 ()[ indexFrom ];
2020-09-15 15:18:49 -04:00
if ( ! util3d :: isFinite ( pt3D ))
{
UASSERT_MSG ( ! _forwardEstimateOnly , uFormat ( "3D point %d is not finite!?" , wordId ). c_str ());
sbaOutliers . insert ( wordId );
continue ;
}
2017-01-03 21:05:00 -05:00
points3DMap . insert ( std :: make_pair ( wordId , pt3D ));
2018-10-24 20:01:57 -04:00
std :: map < int , FeatureBA > ptMap ;
2022-07-20 15:20:14 -04:00
if ( ! fromSignature . getWordsKpts (). empty ())
2017-01-03 21:05:00 -05:00
{
2022-07-20 15:20:14 -04:00
cv :: KeyPoint kpt = fromSignature . getWordsKpts ()[ indexFrom ];
int cameraIndex = 0 ;
const std :: vector < CameraModel > & cam = models . at ( 1 );
if ( cam . size () > 1 )
{
UASSERT ( cam [ 0 ]. imageWidth () > 0 );
float subImageWidth = cam [ 0 ]. imageWidth ();
cameraIndex = int ( kpt . pt . x / subImageWidth );
kpt . pt . x = kpt . pt . x - ( subImageWidth * float ( cameraIndex ));
}
UASSERT ( cam [ cameraIndex ]. isValidForProjection ());
float depthFrom = util3d :: transformPoint ( pt3D , cam [ cameraIndex ]. localTransform (). inverse ()). z ;
ptMap . insert ( std :: make_pair ( 1 , FeatureBA ( kpt , depthFrom , cv :: Mat (), cameraIndex )));
2017-01-03 21:05:00 -05:00
}
2022-07-20 15:20:14 -04:00
if ( ! toSignature . getWordsKpts (). empty ())
2017-01-03 21:05:00 -05:00
{
2020-10-05 17:34:32 -04:00
int indexTo = toSignature . getWords (). find ( wordId ) -> second ;
2022-07-20 15:20:14 -04:00
cv :: KeyPoint kpt = toSignature . getWordsKpts ()[ indexTo ];
int cameraIndex = 0 ;
const std :: vector < CameraModel > & cam = models . at ( 2 );
if ( cam . size () > 1 )
{
UASSERT ( cam [ 0 ]. imageWidth () > 0 );
float subImageWidth = cam [ 0 ]. imageWidth ();
cameraIndex = int ( kpt . pt . x / subImageWidth );
kpt . pt . x = kpt . pt . x - ( subImageWidth * float ( cameraIndex ));
}
UASSERT ( cam [ cameraIndex ]. isValidForProjection ());
2019-01-16 19:29:57 -05:00
float depthTo = 0.0f ;
2020-10-05 17:34:32 -04:00
if ( ! toSignature . getWords3 (). empty ())
2019-01-16 19:29:57 -05:00
{
2022-07-20 15:20:14 -04:00
depthTo = util3d :: transformPoint ( toSignature . getWords3 ()[ indexTo ], cam [ cameraIndex ]. localTransform (). inverse ()). z ;
2019-01-16 19:29:57 -05:00
}
2022-07-20 15:20:14 -04:00
ptMap . insert ( std :: make_pair ( 2 , FeatureBA ( kpt , depthTo , cv :: Mat (), cameraIndex )));
2017-01-03 21:05:00 -05:00
}
wordReferences . insert ( std :: make_pair ( wordId , ptMap ));
//UDEBUG("%d (%f,%f,%f)", wordId, points3DMap.at(wordId).x, points3DMap.at(wordId).y, points3DMap.at(wordId).z);
//for(std::map<int, cv::Point3f>::iterator iter=ptMap.begin(); iter!=ptMap.end(); ++iter)
//{
// UDEBUG("%d (%f,%f) d=%f", iter->first, iter->second.x, iter->second.y, iter->second.z);
//}
}
optimizedPoses = sba -> optimizeBA ( 1 , poses , links , models , points3DMap , wordReferences , & sbaOutliers );
2016-11-14 19:54:31 -05:00
delete sba ;
//update transform
if ( optimizedPoses . size () == 2 &&
! optimizedPoses . begin () -> second . isNull () &&
! optimizedPoses . rbegin () -> second . isNull ())
{
2017-01-03 21:05:00 -05:00
UDEBUG ( "Pose optimization: %s -> %s" , transforms [ 0 ]. prettyPrint (). c_str (), optimizedPoses . rbegin () -> second . prettyPrint (). c_str ());
if ( sbaOutliers . size ())
{
std :: vector < int > newInliers ( allInliers . size ());
int oi = 0 ;
for ( unsigned int i = 0 ; i < allInliers . size (); ++ i )
{
if ( sbaOutliers . find ( allInliers [ i ]) == sbaOutliers . end ())
{
newInliers [ oi ++ ] = allInliers [ i ];
}
}
newInliers . resize ( oi );
UDEBUG ( "BA outliers ratio %f" , float ( sbaOutliers . size ()) / float ( allInliers . size ()));
allInliers = newInliers ;
}
2018-02-01 22:17:46 -05:00
if (( int ) allInliers . size () < _minInliers )
{
msg = uFormat ( "Not enough inliers after bundle adjustment %d/%d (matches=%d) between %d and %d" ,
2018-10-15 17:07:18 -04:00
( int ) allInliers . size (), _minInliers , ( int ) allInliers . size () + sbaOutliers . size (), fromSignature . id (), toSignature . id ());
2018-02-01 22:17:46 -05:00
transforms [ 0 ]. setNull ();
}
else
{
transforms [ 0 ] = optimizedPoses . rbegin () -> second ;
}
// update 3D points, both from and to signatures
/*std::multimap<int, cv::Point3f> cpyWordsFrom3 = fromSignature.getWords3();
std::multimap<int, cv::Point3f> cpyWordsTo3 = toSignature.getWords3();
Transform invT = transforms[0].inverse();
for(std::map<int, cv::Point3f>::iterator iter=points3DMap.begin(); iter!=points3DMap.end(); ++iter)
{
cpyWordsFrom3.find(iter->first)->second = iter->second;
if(cpyWordsTo3.find(iter->first) != cpyWordsTo3.end())
{
cpyWordsTo3.find(iter->first)->second = util3d::transformPoint(iter->second, invT);
}
}
fromSignature.setWords3(cpyWordsFrom3);
toSignature.setWords3(cpyWordsTo3);*/
2016-11-14 19:54:31 -05:00
}
2018-02-11 16:07:26 -05:00
else
{
transforms [ 0 ]. setNull ();
}
transforms [ 1 ]. setNull ();
2016-11-14 19:54:31 -05:00
}
2017-01-03 21:05:00 -05:00
info . inliersIDs = allInliers ;
info . matchesIDs = allMatches ;
inliersCount = ( int ) allInliers . size ();
matchesCount = ( int ) allMatches . size ();
2015-12-21 17:27:05 -05:00
if ( ! transforms [ 1 ]. isNull ())
{
2017-01-03 21:05:00 -05:00
transforms [ 1 ] = transforms [ 1 ]. inverse ();
2015-12-21 17:27:05 -05:00
if ( transforms [ 0 ]. isNull ())
{
transform = transforms [ 1 ];
2017-05-04 16:13:45 -04:00
covariance = covariances [ 1 ];
2015-11-22 18:08:32 -05:00
}
else
{
2016-01-06 17:26:55 -05:00
transform = transforms [ 0 ]. interpolate ( 0.5f , transforms [ 1 ]);
2017-05-04 16:13:45 -04:00
covariance = ( covariances [ 0 ] + covariances [ 1 ]) / 2.0f ;
2015-11-22 18:08:32 -05:00
}
}
else
{
2015-12-21 17:27:05 -05:00
transform = transforms [ 0 ];
2017-05-04 16:13:45 -04:00
covariance = covariances [ 0 ];
2015-11-22 18:08:32 -05:00
}
2019-06-16 18:54:39 -04:00
if ( ! transform . isNull () && ! allInliers . empty () && ( _minInliersDistributionThr > 0.0f || _maxInliersMeanDistance > 0.0f ))
{
cv :: Mat pcaData ;
2022-09-24 12:29:42 -07:00
std :: vector < CameraModel > cameraModelsTo ;
if ( toSignature . sensorData (). stereoCameraModels (). size ())
{
for ( size_t i = 0 ; i < toSignature . sensorData (). stereoCameraModels (). size (); ++ i )
{
cameraModelsTo . push_back ( toSignature . sensorData (). stereoCameraModels ()[ i ]. left ());
}
}
else
{
cameraModelsTo = toSignature . sensorData (). cameraModels ();
}
2019-06-16 18:54:39 -04:00
if ( _minInliersDistributionThr > 0 )
{
2022-09-24 12:29:42 -07:00
if ( cameraModelsTo . size () >= 1 && cameraModelsTo [ 0 ]. isValidForReprojection ())
2019-06-16 18:54:39 -04:00
{
2022-09-24 12:29:42 -07:00
if ( cameraModelsTo [ 0 ]. imageWidth () > 0 && cameraModelsTo [ 0 ]. imageHeight () > 0 )
2019-06-16 18:54:39 -04:00
{
pcaData = cv :: Mat ( allInliers . size (), 2 , CV_32FC1 );
}
else
{
2022-09-24 12:29:42 -07:00
UERROR ( "Invalid calibration image size (%dx%d), cannot compute inliers distribution! (see %s=%f)" , cameraModelsTo [ 0 ]. imageWidth (), cameraModelsTo [ 0 ]. imageHeight (), Parameters :: kVisMinInliersDistribution (). c_str (), _minInliersDistributionThr );
2019-06-16 18:54:39 -04:00
}
}
else
{
UERROR ( "Calibration not valid, cannot compute inliers distribution! (see %s=%f)" , Parameters :: kVisMinInliersDistribution (). c_str (), _minInliersDistributionThr );
}
}
Transform transformInv = transform . inverse ();
std :: vector < float > distances ;
if ( _maxInliersMeanDistance > 0.0f )
{
distances . reserve ( allInliers . size ());
}
for ( unsigned int i = 0 ; i < allInliers . size (); ++ i )
{
2023-02-10 17:29:10 -08:00
std :: multimap < int , int >:: const_iterator wordsIter = toSignature . getWords (). find ( allInliers [ i ]);
if ( wordsIter != toSignature . getWords (). end () && ! toSignature . getWordsKpts (). empty ())
2019-06-16 18:54:39 -04:00
{
2022-09-24 12:29:42 -07:00
const cv :: KeyPoint & kpt = toSignature . getWordsKpts ()[ wordsIter -> second ];
int cameraIndex = ( int )( kpt . pt . x / cameraModelsTo [ 0 ]. imageWidth ());
UASSERT_MSG ( cameraIndex < ( int ) cameraModelsTo . size (), uFormat ( "cameraIndex=%d (x=%f models=%d camera width = %d)" , cameraIndex , kpt . pt . x , ( int ) cameraModelsTo . size (), cameraModelsTo [ 0 ]. imageWidth ()). c_str ());
2023-02-10 17:29:10 -08:00
if ( _maxInliersMeanDistance > 0.0f && ! toSignature . getWords3 (). empty ())
{
const cv :: Point3f & pt = toSignature . getWords3 ()[ wordsIter -> second ];
if ( util3d :: isFinite ( pt ))
{
UASSERT ( cameraModelsTo [ cameraIndex ]. isValidForProjection ());
float depth = util3d :: transformPoint ( pt , cameraModelsTo [ cameraIndex ]. localTransform (). inverse ()). z ;
distances . push_back ( depth );
}
}
if ( ! pcaData . empty ())
{
float * ptr = pcaData . ptr < float > ( i , 0 );
ptr [ 0 ] = ( kpt . pt . x - cameraIndex * cameraModelsTo [ cameraIndex ]. imageWidth () - cameraModelsTo [ cameraIndex ]. cx ()) / cameraModelsTo [ cameraIndex ]. imageWidth ();
ptr [ 1 ] = ( kpt . pt . y - cameraModelsTo [ cameraIndex ]. cy ()) / cameraModelsTo [ cameraIndex ]. imageHeight ();
}
2019-06-16 18:54:39 -04:00
}
}
if ( ! distances . empty ())
{
info . inliersMeanDistance = uMean ( distances );
if ( info . inliersMeanDistance > _maxInliersMeanDistance )
{
msg = uFormat ( "The mean distance of the inliers is over %s threshold (%f)" ,
info . inliersMeanDistance , Parameters :: kVisMeanInliersDistance (). c_str (), _maxInliersMeanDistance );
transform . setNull ();
}
}
if ( ! transform . isNull () && ! pcaData . empty ())
{
cv :: Mat pcaEigenVectors , pcaEigenValues ;
cv :: PCA pca_analysis ( pcaData , cv :: Mat (), CV_PCA_DATA_AS_ROW );
// We take the second eigen value
info . inliersDistribution = pca_analysis . eigenvalues . at < float > ( 0 , 1 );
if ( info . inliersDistribution < _minInliersDistributionThr )
{
msg = uFormat ( "The distribution (%f) of inliers is under %s threshold (%f)" ,
info . inliersDistribution , Parameters :: kVisMinInliersDistribution (). c_str (), _minInliersDistributionThr );
transform . setNull ();
}
}
}
2015-11-22 18:08:32 -05:00
}
2016-03-02 18:11:19 -05:00
else if ( toSignature . sensorData (). isValid ())
{
2020-05-21 21:26:29 -04:00
msg = uFormat ( "Missing correspondences for registration (%d->%d). fromWords = %d fromImageEmpty=%d toWords = %d toImageEmpty=%d" ,
2017-01-05 19:31:18 -05:00
fromSignature . id (), toSignature . id (),
( int ) fromSignature . getWords (). size (), fromSignature . sensorData (). imageRaw (). empty () ? 1 : 0 ,
( int ) toSignature . getWords (). size (), toSignature . sensorData (). imageRaw (). empty () ? 1 : 0 );
2016-03-02 18:11:19 -05:00
}
2015-11-22 18:08:32 -05:00
2016-01-06 17:26:55 -05:00
info . inliers = inliersCount ;
2020-10-05 17:34:32 -04:00
info . inliersRatio = ! toSignature . getWords (). empty () ? float ( inliersCount ) / float ( toSignature . getWords (). size ()) : 0 ;
2016-01-07 13:59:21 -05:00
info . matches = matchesCount ;
info . rejectedMsg = msg ;
2017-05-22 11:48:01 -04:00
info . covariance = covariance ;
2016-01-06 17:26:55 -05:00
2020-05-09 21:13:41 -04:00
UDEBUG ( "inliers=%d/%d" , info . inliers , info . matches );
2015-11-22 18:08:32 -05:00
UDEBUG ( "transform=%s" , transform . prettyPrint (). c_str ());
return transform ;
}
}