2021-03-07 12:27:21 -05:00
/*
Copyright (c) 2010-2021, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
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/camera/CameraDepthAI.h>
2023-06-17 16:53:25 +08:00
#include <rtabmap/core/util2d.h>
2021-03-07 12:27:21 -05:00
#include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/UThread.h>
#include <rtabmap/utilite/UEventsManager.h>
#include <rtabmap/utilite/UConversion.h>
#include <rtabmap/utilite/UFile.h>
namespace rtabmap {
bool CameraDepthAI :: available ()
{
#ifdef RTABMAP_DEPTHAI
return true ;
#else
return false ;
#endif
}
CameraDepthAI :: CameraDepthAI (
2023-07-15 20:58:00 +08:00
const std :: string & mxidOrName ,
2025-03-09 03:30:11 +08:00
int imageWidth ,
2021-03-07 12:27:21 -05:00
float imageRate ,
const Transform & localTransform ) :
Camera ( imageRate , localTransform )
#ifdef RTABMAP_DEPTHAI
,
2023-07-15 20:58:00 +08:00
mxidOrName_ ( mxidOrName ),
2023-12-15 01:59:35 +08:00
outputMode_ ( 0 ),
confThreshold_ ( 200 ),
lrcThreshold_ ( 5 ),
2025-03-09 03:30:11 +08:00
imageWidth_ ( imageWidth ),
2024-03-30 18:08:32 -07:00
extendedDisparity_ ( false ),
2025-03-09 03:30:11 +08:00
enableCompanding_ ( false ),
subpixelFractionalBits_ ( 3 ),
disparityWidth_ ( 1 ),
medianFilter_ ( 5 ),
2023-10-08 11:40:30 +08:00
useSpecTranslation_ ( false ),
2023-05-31 22:15:16 +08:00
alphaScaling_ ( 0.0 ),
2025-03-09 03:30:11 +08:00
imagesRectified_ ( true ),
2023-05-25 00:01:55 +08:00
imuPublished_ ( true ),
2023-05-27 21:28:43 +08:00
publishInterIMU_ ( false ),
2024-03-28 03:29:06 +08:00
dotIntensity_ ( 0.0 ),
floodIntensity_ ( 0.0 ),
2023-06-12 03:57:26 +08:00
detectFeatures_ ( 0 ),
useHarrisDetector_ ( false ),
minDistance_ ( 7.0 ),
2025-03-09 03:30:11 +08:00
numTargetFeatures_ ( 320 ),
2023-06-17 16:53:25 +08:00
threshold_ ( 0.01 ),
nms_ ( true ),
nmsRadius_ ( 4 )
2021-03-07 12:27:21 -05:00
#endif
{
#ifdef RTABMAP_DEPTHAI
2025-03-09 03:30:11 +08:00
UASSERT ( imageWidth_ == 640 || imageWidth_ == 1280 );
if ( this -> getImageRate () <= 0 )
this -> setImageRate ( 30 );
2021-03-07 12:27:21 -05:00
#endif
}
CameraDepthAI ::~ CameraDepthAI ()
{
2021-07-28 17:05:16 -04:00
#ifdef RTABMAP_DEPTHAI
2021-07-28 14:19:30 -04:00
if ( device_ . get ())
device_ -> close ();
2021-07-28 17:05:16 -04:00
#endif
2021-03-07 12:27:21 -05:00
}
2023-12-15 01:59:35 +08:00
void CameraDepthAI :: setOutputMode ( int outputMode )
2021-03-07 12:27:21 -05:00
{
#ifdef RTABMAP_DEPTHAI
2023-12-15 01:59:35 +08:00
outputMode_ = outputMode ;
2021-03-07 12:27:21 -05:00
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2023-12-15 01:59:35 +08:00
void CameraDepthAI :: setDepthProfile ( int confThreshold , int lrcThreshold )
{
#ifdef RTABMAP_DEPTHAI
confThreshold_ = confThreshold ;
lrcThreshold_ = lrcThreshold ;
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2025-03-09 03:30:11 +08:00
void CameraDepthAI :: setExtendedDisparity ( bool extendedDisparity , bool enableCompanding )
2024-03-30 18:08:32 -07:00
{
#ifdef RTABMAP_DEPTHAI
extendedDisparity_ = extendedDisparity ;
2025-03-09 03:30:11 +08:00
enableCompanding_ = enableCompanding ;
if ( extendedDisparity_ && enableCompanding_ )
2024-03-30 18:08:32 -07:00
{
2025-03-09 03:30:11 +08:00
UWARN ( "Extended disparity has been enabled while companding being also enabled, disabling companding..." );
enableCompanding_ = false ;
2024-03-30 18:08:32 -07:00
}
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
void CameraDepthAI :: setSubpixelMode ( bool enabled , int fractionalBits )
{
#ifdef RTABMAP_DEPTHAI
UASSERT ( fractionalBits >= 3 && fractionalBits <= 5 );
subpixelFractionalBits_ = enabled ? fractionalBits : 0 ;
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2025-03-09 03:30:11 +08:00
void CameraDepthAI :: setDisparityWidthAndFilter ( int disparityWidth , int medianFilter )
2024-03-30 18:08:32 -07:00
{
#ifdef RTABMAP_DEPTHAI
2025-03-09 03:30:11 +08:00
UASSERT ( disparityWidth == 64 || disparityWidth == 96 );
disparityWidth_ = disparityWidth ;
medianFilter_ = medianFilter ;
int maxDisp = ( extendedDisparity_ ? 2 : 1 ) * std :: pow ( 2 , subpixelFractionalBits_ ) * ( disparityWidth_ - 1 );
if ( medianFilter_ && maxDisp > 1024 )
2024-03-30 18:08:32 -07:00
{
2025-03-09 03:30:11 +08:00
UWARN ( "Maximum disparity value '%d' exceeds the maximum supported '1024' by median filter, disabling median filter..." , maxDisp );
medianFilter_ = 0 ;
2024-03-30 18:08:32 -07:00
}
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2024-06-30 17:11:37 -07:00
void CameraDepthAI :: setRectification ( bool useSpecTranslation , float alphaScaling , bool enabled )
2023-05-31 22:15:16 +08:00
{
#ifdef RTABMAP_DEPTHAI
2023-10-08 11:40:30 +08:00
useSpecTranslation_ = useSpecTranslation ;
alphaScaling_ = alphaScaling ;
2024-06-30 17:11:37 -07:00
imagesRectified_ = enabled ;
2022-07-20 15:20:14 -04:00
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2023-12-15 01:59:35 +08:00
void CameraDepthAI :: setIMU ( bool imuPublished , bool publishInterIMU )
2022-10-23 18:15:23 -07:00
{
#ifdef RTABMAP_DEPTHAI
2023-12-15 01:59:35 +08:00
imuPublished_ = imuPublished ;
publishInterIMU_ = publishInterIMU ;
2022-10-23 18:15:23 -07:00
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2024-03-28 03:29:06 +08:00
void CameraDepthAI :: setIrIntensity ( float dotIntensity , float floodIntensity )
2023-05-18 01:34:25 +08:00
{
#ifdef RTABMAP_DEPTHAI
2024-03-28 03:29:06 +08:00
dotIntensity_ = dotIntensity ;
floodIntensity_ = floodIntensity ;
2023-05-18 01:34:25 +08:00
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2025-03-09 03:30:11 +08:00
void CameraDepthAI :: setDetectFeatures ( int detectFeatures , const std :: string & blobPath )
2023-06-12 03:57:26 +08:00
{
#ifdef RTABMAP_DEPTHAI
detectFeatures_ = detectFeatures ;
2023-06-17 16:53:25 +08:00
blobPath_ = blobPath ;
2025-03-09 03:30:11 +08:00
if ( detectFeatures_ && outputMode_ == 2 )
{
UWARN ( "On-device feature detectors cannot be enabled on color camera input, disabling on-device feature detector..." );
detectFeatures_ = 0 ;
}
if ( detectFeatures_ >= 2 && blobPath_ . empty ())
{
UWARN ( "Missing MyriadX blob file, disabling on-device feature detector" );
detectFeatures_ = 0 ;
}
if ( detectFeatures_ >= 2 && this -> getImageRate () > 15 )
{
UWARN ( "On-device SuperPoint or HF-Net enabled, image rate is limited to 15 FPS!" );
this -> setImageRate ( 15 );
}
2023-06-17 16:53:25 +08:00
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
void CameraDepthAI :: setGFTTDetector ( bool useHarrisDetector , float minDistance , int numTargetFeatures )
2023-06-12 03:57:26 +08:00
{
#ifdef RTABMAP_DEPTHAI
useHarrisDetector_ = useHarrisDetector ;
minDistance_ = minDistance ;
numTargetFeatures_ = numTargetFeatures ;
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2023-06-17 16:53:25 +08:00
void CameraDepthAI :: setSuperPointDetector ( float threshold , bool nms , int nmsRadius )
{
#ifdef RTABMAP_DEPTHAI
threshold_ = threshold ;
nms_ = nms ;
nmsRadius_ = nmsRadius ;
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
}
2021-03-07 12:27:21 -05:00
bool CameraDepthAI :: init ( const std :: string & calibrationFolder , const std :: string & cameraName )
{
UDEBUG ( "" );
#ifdef RTABMAP_DEPTHAI
std :: vector < dai :: DeviceInfo > devices = dai :: Device :: getAllAvailableDevices ();
2023-11-16 11:50:07 +08:00
if ( devices . empty () && mxidOrName_ . empty ())
2021-03-07 12:27:21 -05:00
{
2023-11-16 11:50:07 +08:00
UERROR ( "No DepthAI device found or specified" );
2021-03-07 12:27:21 -05:00
return false ;
}
2021-07-28 14:19:30 -04:00
accBuffer_ . clear ();
gyroBuffer_ . clear ();
2023-07-15 20:58:00 +08:00
bool deviceFound = false ;
dai :: DeviceInfo deviceToUse ( mxidOrName_ );
if ( mxidOrName_ . empty ())
std :: tie ( deviceFound , deviceToUse ) = dai :: Device :: getFirstAvailableDevice ();
else if ( ! deviceToUse . mxid . empty ())
std :: tie ( deviceFound , deviceToUse ) = dai :: Device :: getDeviceByMxId ( deviceToUse . mxid );
else
2023-11-16 11:50:07 +08:00
deviceFound = true ;
2021-03-07 12:27:21 -05:00
2023-07-15 20:58:00 +08:00
if ( ! deviceFound )
2021-03-07 12:27:21 -05:00
{
2023-07-15 20:58:00 +08:00
UERROR ( "Could not find DepthAI device with MXID or IP/USB name \" %s \" , found devices:" , mxidOrName_ . c_str ());
for ( auto & device : devices )
UERROR ( "%s" , device . toString (). c_str ());
2021-03-07 12:27:21 -05:00
return false ;
}
2025-03-09 03:30:11 +08:00
device_ = std :: make_unique < dai :: Device > ( deviceToUse );
auto deviceName = device_ -> getDeviceName ();
auto imuType = device_ -> getConnectedIMU ();
UINFO ( "Device Name: %s, Device Serial: %s" , deviceName . c_str (), device_ -> getMxId (). c_str ());
UINFO ( "Available Camera Sensors: " );
2024-03-30 18:08:32 -07:00
for ( auto & sensor : device_ -> getCameraSensorNames ()) {
UINFO ( "Socket: CAM_%c - %s" , 'A' + ( unsigned char ) sensor . first , sensor . second . c_str ());
}
2025-03-09 03:30:11 +08:00
UINFO ( "IMU Type: %s" , imuType . c_str ());
2024-03-30 18:08:32 -07:00
2021-07-28 14:19:30 -04:00
UINFO ( "Loading eeprom calibration data" );
2025-03-09 03:30:11 +08:00
auto calibHandler = device_ -> readCalibration ();
auto boardName = calibHandler . getEepromData (). boardName ;
stereoModel_ = StereoCameraModel ();
targetSize_ = cv :: Size ( imageWidth_ , imageWidth_ / 640 * (( outputMode_ == 2 && boardName != "BC2087" ) ? 360 : 400 ));
2023-05-30 18:16:28 +08:00
2024-06-30 17:11:37 -07:00
if ( ! calibrationFolder . empty () && ! cameraName . empty () && imagesRectified_ )
{
UINFO ( "Flashing camera..." );
if ( outputMode_ == 2 )
{
stereoModel_ . setName ( cameraName , "rgb" , "depth" );
}
if ( stereoModel_ . load ( calibrationFolder , cameraName , false ))
{
std :: vector < std :: vector < float > > intrinsicsLeft ( 3 );
std :: vector < std :: vector < float > > intrinsicsRight ( 3 );
for ( int row = 0 ; row < 3 ; ++ row )
{
intrinsicsLeft [ row ]. resize ( 3 );
intrinsicsRight [ row ]. resize ( 3 );
for ( int col = 0 ; col < 3 ; ++ col )
{
intrinsicsLeft [ row ][ col ] = stereoModel_ . left (). K_raw (). at < double > ( row , col );
intrinsicsRight [ row ][ col ] = stereoModel_ . right (). K_raw (). at < double > ( row , col );
}
}
std :: vector < float > distortionsLeft = stereoModel_ . left (). D_raw ();
std :: vector < float > distortionsRight = stereoModel_ . right (). D_raw ();
std :: vector < std :: vector < float > > rotationMatrix ( 3 );
for ( int row = 0 ; row < 3 ; ++ row )
{
rotationMatrix [ row ]. resize ( 3 );
for ( int col = 0 ; col < 3 ; ++ col )
{
rotationMatrix [ row ][ col ] = stereoModel_ . stereoTransform ()( row , col );
}
}
std :: vector < float > translation ( 3 );
translation [ 0 ] = stereoModel_ . stereoTransform (). x () * 100.0f ;
translation [ 1 ] = stereoModel_ . stereoTransform (). y () * 100.0f ;
translation [ 2 ] = stereoModel_ . stereoTransform (). z () * 100.0f ;
if ( outputMode_ == 2 )
{
// Only set RGB intrinsics
calibHandler . setCameraIntrinsics ( dai :: CameraBoardSocket :: CAM_A , intrinsicsLeft , stereoModel_ . left (). imageWidth (), stereoModel_ . left (). imageHeight ());
calibHandler . setDistortionCoefficients ( dai :: CameraBoardSocket :: CAM_A , distortionsLeft );
std :: vector < float > specTranslation = calibHandler . getCameraTranslationVector ( dai :: CameraBoardSocket :: CAM_A , dai :: CameraBoardSocket :: CAM_C , true );
calibHandler . setCameraExtrinsics ( dai :: CameraBoardSocket :: CAM_A , dai :: CameraBoardSocket :: CAM_C , rotationMatrix , translation , specTranslation );
}
else
{
calibHandler . setCameraIntrinsics ( dai :: CameraBoardSocket :: CAM_B , intrinsicsLeft , stereoModel_ . left (). imageWidth (), stereoModel_ . left (). imageHeight ());
calibHandler . setDistortionCoefficients ( dai :: CameraBoardSocket :: CAM_B , distortionsLeft );
calibHandler . setCameraIntrinsics ( dai :: CameraBoardSocket :: CAM_C , intrinsicsRight , stereoModel_ . right (). imageWidth (), stereoModel_ . right (). imageHeight ());
calibHandler . setDistortionCoefficients ( dai :: CameraBoardSocket :: CAM_C , distortionsRight );
std :: vector < float > specTranslation = calibHandler . getCameraTranslationVector ( dai :: CameraBoardSocket :: CAM_B , dai :: CameraBoardSocket :: CAM_C , true );
calibHandler . setCameraExtrinsics ( dai :: CameraBoardSocket :: CAM_B , dai :: CameraBoardSocket :: CAM_C , rotationMatrix , translation , specTranslation );
}
try {
UINFO ( "Flashing camera with calibration from %s with camera name %s" , calibrationFolder . c_str (), cameraName . c_str ());
if ( ULogger :: level () <= ULogger :: kInfo )
{
std :: cout << "K left: " << stereoModel_ . left (). K_raw () << std :: endl ;
std :: cout << "K right: " << stereoModel_ . right (). K_raw () << std :: endl ;
std :: cout << "D left: " << stereoModel_ . left (). D_raw () << std :: endl ;
std :: cout << "D right: " << stereoModel_ . right (). D_raw () << std :: endl ;
std :: cout << "Extrinsics: " << stereoModel_ . stereoTransform () << std :: endl ;
std :: cout << "Expected K with rectification_alpha=0: " << stereoModel_ . left (). K () * ( double ( targetSize_ . width ) / double ( stereoModel_ . left (). imageWidth ())) << std :: endl ;
}
device_ -> flashCalibration2 ( calibHandler );
}
catch ( const std :: runtime_error & e ) {
UERROR ( "Failed flashing calibration: %s" , e . what ());
}
}
else
{
UERROR ( "Failed loading calibration from %s with camera name %s" , calibrationFolder . c_str (), cameraName . c_str ());
}
//Reload calibration
calibHandler = device_ -> readCalibration ();
}
2025-03-09 03:30:11 +08:00
auto cameraId = outputMode_ == 2 ? dai :: CameraBoardSocket :: CAM_A : dai :: CameraBoardSocket :: CAM_B ;
2023-12-15 01:59:35 +08:00
cv :: Mat cameraMatrix , distCoeffs , newCameraMatrix ;
2023-05-30 18:16:28 +08:00
2023-12-15 01:59:35 +08:00
std :: vector < std :: vector < float > > matrix = calibHandler . getCameraIntrinsics ( cameraId , targetSize_ . width , targetSize_ . height );
2023-05-30 18:16:28 +08:00
cameraMatrix = ( cv :: Mat_ < double > ( 3 , 3 ) <<
matrix [ 0 ][ 0 ], matrix [ 0 ][ 1 ], matrix [ 0 ][ 2 ],
matrix [ 1 ][ 0 ], matrix [ 1 ][ 1 ], matrix [ 1 ][ 2 ],
matrix [ 2 ][ 0 ], matrix [ 2 ][ 1 ], matrix [ 2 ][ 2 ]);
2023-12-15 01:59:35 +08:00
std :: vector < float > coeffs = calibHandler . getDistortionCoefficients ( cameraId );
if ( calibHandler . getDistortionModel ( cameraId ) == dai :: CameraModel :: Perspective )
2023-05-30 18:16:28 +08:00
distCoeffs = ( cv :: Mat_ < double > ( 1 , 8 ) << coeffs [ 0 ], coeffs [ 1 ], coeffs [ 2 ], coeffs [ 3 ], coeffs [ 4 ], coeffs [ 5 ], coeffs [ 6 ], coeffs [ 7 ]);
2023-07-17 03:32:18 +08:00
if ( alphaScaling_ >- 1.0f )
2023-12-15 01:59:35 +08:00
newCameraMatrix = cv :: getOptimalNewCameraMatrix ( cameraMatrix , distCoeffs , targetSize_ , alphaScaling_ );
2023-07-17 03:32:18 +08:00
else
2023-12-15 01:59:35 +08:00
newCameraMatrix = cameraMatrix ;
2023-06-05 18:59:59 -07:00
2023-12-15 01:59:35 +08:00
double fx = newCameraMatrix . at < double > ( 0 , 0 );
double fy = newCameraMatrix . at < double > ( 1 , 1 );
double cx = newCameraMatrix . at < double > ( 0 , 2 );
double cy = newCameraMatrix . at < double > ( 1 , 2 );
2024-06-30 17:11:37 -07:00
UINFO ( "fx=%f fy=%f cx=%f cy=%f (target size = %dx%d)" , fx , fy , cx , cy , targetSize_ . width , targetSize_ . height );
if ( outputMode_ == 2 ) {
2025-03-09 03:30:11 +08:00
stereoModel_ = StereoCameraModel ( deviceName , fx , fy , cx , cy , 0 , this -> getLocalTransform (), targetSize_ );
2024-06-30 17:11:37 -07:00
}
else {
double baseline = calibHandler . getBaselineDistance ( dai :: CameraBoardSocket :: CAM_C , dai :: CameraBoardSocket :: CAM_B , false ) / 100.0 ;
UINFO ( "baseline=%f" , baseline );
2025-03-09 03:30:11 +08:00
stereoModel_ = StereoCameraModel ( deviceName , fx , fy , cx , cy , outputMode_ == 0 ? baseline : 0 , this -> getLocalTransform () * Transform ( - calibHandler . getBaselineDistance ( dai :: CameraBoardSocket :: CAM_A ) / 100.0 , 0 , 0 ), targetSize_ );
2024-06-30 17:11:37 -07:00
}
2021-03-07 12:27:21 -05:00
2025-03-09 03:30:11 +08:00
if ( imuPublished_ || imuType . empty ())
2022-10-23 18:15:23 -07:00
{
// Cannot test the following, I get "IMU calibration data is not available on device yet." with my camera
// Update: now (as March 6, 2022) it crashes in "dai::CalibrationHandler::getImuToCameraExtrinsics(dai::CameraBoardSocket, bool)"
2023-06-14 17:50:12 +08:00
//matrix = calibHandler.getImuToCameraExtrinsics(dai::CameraBoardSocket::CAM_B);
2022-10-23 18:15:23 -07:00
//imuLocalTransform_ = Transform(
// matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
// matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
// matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3]);
2025-03-09 03:30:11 +08:00
if ( deviceName == "OAK-D" )
2023-05-25 00:01:55 +08:00
{
imuLocalTransform_ = Transform (
2023-05-25 12:19:07 +08:00
0 , - 1 , 0 , 0.0525 ,
2023-12-15 01:59:35 +08:00
1 , 0 , 0 , 0.013662 ,
2023-05-25 12:19:07 +08:00
0 , 0 , 1 , 0 );
2023-05-25 00:01:55 +08:00
}
2025-03-09 03:30:11 +08:00
else if ( boardName == "BC2087" ) // OAK-D LR
{
imuLocalTransform_ = Transform (
1 , 0 , 0 , 0.021425 ,
0 , 1 , 0 , 0.009925 ,
0 , 0 , 1 , 0 );
}
else if ( boardName == "DM2080" ) // OAK-D SR
{
imuLocalTransform_ = Transform (
- 1 , 0 , 0 , 0 ,
0 , - 1 , 0 , - 0.0024 ,
0 , 0 , 1 , 0 );
}
else if ( boardName == "DM9098" ) // OAK-D S2, OAK-D W, OAK-D Pro, OAK-D Pro W
2023-05-25 00:01:55 +08:00
{
imuLocalTransform_ = Transform (
2023-12-15 01:59:35 +08:00
0 , 1 , 0 , 0.037945 ,
2023-07-14 20:18:48 +08:00
1 , 0 , 0 , 0.00079 ,
2023-12-15 01:59:35 +08:00
0 , 0 , - 1 , 0 );
}
2025-03-09 03:30:11 +08:00
else if ( boardName == "NG2094" ) // OAK-D Pro W Dev
2023-12-15 01:59:35 +08:00
{
imuLocalTransform_ = Transform (
0 , 1 , 0 , 0.0374 ,
1 , 0 , 0 , 0.00176 ,
0 , 0 , - 1 , 0 );
2023-07-14 20:18:48 +08:00
}
2025-03-09 03:30:11 +08:00
else if ( boardName == "NG9097" ) // OAK-D S2 PoE, OAK-D W PoE, OAK-D Pro PoE, OAK-D Pro W PoE
2023-07-14 20:18:48 +08:00
{
2025-03-09 03:30:11 +08:00
if ( imuType == "BMI270" )
{
imuLocalTransform_ = Transform (
0 , 1 , 0 , 0.04 ,
1 , 0 , 0 , 0.020265 ,
0 , 0 , - 1 , 0 );
}
else // BNO085/086
{
imuLocalTransform_ = Transform (
0 , - 1 , 0 , 0.04 ,
- 1 , 0 , 0 , 0.020265 ,
0 , 0 , - 1 , 0 );
}
2023-05-25 00:01:55 +08:00
}
else
{
2025-03-09 03:30:11 +08:00
UWARN ( "Unsupported boardName (%s)! Disabling IMU!" , boardName . c_str ());
2023-05-25 00:01:55 +08:00
imuPublished_ = false ;
}
2022-10-23 18:15:23 -07:00
}
else
{
UINFO ( "IMU disabled" );
2025-03-09 03:30:11 +08:00
imuPublished_ = false ;
}
dai :: Pipeline pipeline ;
auto sync = pipeline . create < dai :: node :: Sync > ();
sync -> setSyncThreshold ( std :: chrono :: milliseconds ( int ( 500 / this -> getImageRate ())));
if ( outputMode_ == 2 )
{
auto rgbCamera = pipeline . create < dai :: node :: Camera > ();
rgbCamera -> setCamera ( "color" );
if ( boardName == "BC2087" )
rgbCamera -> setSize ( 1920 , 1200 );
else if ( boardName == "NG2094" )
rgbCamera -> setSize ( 1280 , 720 );
else
rgbCamera -> setSize ( 1920 , 1080 );
rgbCamera -> setSize ( 1920 , 1200 );
rgbCamera -> setVideoSize ( targetSize_ . width , targetSize_ . height );
rgbCamera -> setPreviewSize ( targetSize_ . width , targetSize_ . height );
rgbCamera -> setFps ( this -> getImageRate ());
rgbCamera -> setMeshSource ( imagesRectified_ ? dai :: CameraProperties :: WarpMeshSource :: CALIBRATION : dai :: CameraProperties :: WarpMeshSource :: NONE );
if ( imagesRectified_ && alphaScaling_ >- 1.0f )
rgbCamera -> setCalibrationAlpha ( alphaScaling_ );
rgbCamera -> properties . ispScale . horizNumerator = rgbCamera -> properties . ispScale . vertNumerator = imageWidth_ / 640 ;
rgbCamera -> properties . ispScale . horizDenominator = rgbCamera -> properties . ispScale . vertDenominator = boardName == "NG2094" ? 2 : 3 ;
auto rgbEncoder = pipeline . create < dai :: node :: VideoEncoder > ();
rgbEncoder -> setDefaultProfilePreset ( this -> getImageRate (), dai :: VideoEncoderProperties :: Profile :: MJPEG );
rgbCamera -> video . link ( rgbEncoder -> input );
rgbEncoder -> bitstream . link ( sync -> inputs [ "rgb" ]);
}
auto stereoDepth = pipeline . create < dai :: node :: StereoDepth > ();
if ( outputMode_ == 2 )
stereoDepth -> setDepthAlign ( dai :: CameraBoardSocket :: CAM_A );
else
stereoDepth -> setDepthAlign ( dai :: StereoDepthProperties :: DepthAlign :: RECTIFIED_LEFT );
if ( subpixelFractionalBits_ >= 3 && subpixelFractionalBits_ <= 5 )
{
stereoDepth -> setSubpixel ( true );
stereoDepth -> setSubpixelFractionalBits ( subpixelFractionalBits_ );
}
stereoDepth -> setExtendedDisparity ( extendedDisparity_ );
stereoDepth -> enableDistortionCorrection ( true );
stereoDepth -> setDisparityToDepthUseSpecTranslation ( useSpecTranslation_ );
stereoDepth -> setDepthAlignmentUseSpecTranslation ( useSpecTranslation_ );
if ( alphaScaling_ > - 1.0f )
stereoDepth -> setAlphaScaling ( alphaScaling_ );
stereoDepth -> initialConfig . setConfidenceThreshold ( confThreshold_ );
stereoDepth -> initialConfig . setLeftRightCheck ( lrcThreshold_ >= 0 );
if ( lrcThreshold_ >= 0 )
stereoDepth -> initialConfig . setLeftRightCheckThreshold ( lrcThreshold_ );
stereoDepth -> initialConfig . setMedianFilter ( dai :: MedianFilter ( medianFilter_ ));
auto config = stereoDepth -> initialConfig . get ();
config . censusTransform . kernelSize = dai :: StereoDepthConfig :: CensusTransform :: KernelSize :: KERNEL_7x9 ;
config . censusTransform . kernelMask = 0X5092A28C5152428 ;
config . costMatching . disparityWidth = disparityWidth_ == 64 ? dai :: StereoDepthConfig :: CostMatching :: DisparityWidth :: DISPARITY_64 : dai :: StereoDepthConfig :: CostMatching :: DisparityWidth :: DISPARITY_96 ;
config . costMatching . enableCompanding = enableCompanding_ ;
config . costMatching . linearEquationParameters . alpha = 2 ;
config . costMatching . linearEquationParameters . beta = 4 ;
config . costAggregation . horizontalPenaltyCostP1 = 100 ;
config . costAggregation . horizontalPenaltyCostP2 = 500 ;
config . costAggregation . verticalPenaltyCostP1 = 100 ;
config . costAggregation . verticalPenaltyCostP2 = 500 ;
config . postProcessing . brightnessFilter . maxBrightness = 255 ;
stereoDepth -> initialConfig . set ( config );
stereoDepth -> depth . link ( sync -> inputs [ "depth" ]);
if ( outputMode_ < 2 )
{
auto leftEncoder = pipeline . create < dai :: node :: VideoEncoder > ();
leftEncoder -> setDefaultProfilePreset ( this -> getImageRate (), dai :: VideoEncoderProperties :: Profile :: MJPEG );
if ( imagesRectified_ )
stereoDepth -> rectifiedLeft . link ( leftEncoder -> input );
else
stereoDepth -> syncedLeft . link ( leftEncoder -> input );
leftEncoder -> bitstream . link ( sync -> inputs [ "left" ]);
}
if ( ! outputMode_ )
{
auto rightEncoder = pipeline . create < dai :: node :: VideoEncoder > ();
rightEncoder -> setDefaultProfilePreset ( this -> getImageRate (), dai :: VideoEncoderProperties :: Profile :: MJPEG );
if ( imagesRectified_ )
stereoDepth -> rectifiedRight . link ( rightEncoder -> input );
else
stereoDepth -> syncedRight . link ( rightEncoder -> input );
rightEncoder -> bitstream . link ( sync -> inputs [ "right" ]);
}
if ( boardName == "BC2087" )
{
auto leftCamera = pipeline . create < dai :: node :: ColorCamera > ();
leftCamera -> setCamera ( "left" );
leftCamera -> setResolution ( dai :: ColorCameraProperties :: SensorResolution :: THE_1200_P );
leftCamera -> setIspScale ( imageWidth_ / 640 , 3 );
leftCamera -> setFps ( this -> getImageRate ());
auto rightCamera = pipeline . create < dai :: node :: ColorCamera > ();
rightCamera -> setCamera ( "right" );
rightCamera -> setResolution ( dai :: ColorCameraProperties :: SensorResolution :: THE_1200_P );
rightCamera -> setIspScale ( imageWidth_ / 640 , 3 );
rightCamera -> setFps ( this -> getImageRate ());
leftCamera -> isp . link ( stereoDepth -> left );
rightCamera -> isp . link ( stereoDepth -> right );
}
else
{
auto leftCamera = pipeline . create < dai :: node :: MonoCamera > ();
leftCamera -> setCamera ( "left" );
leftCamera -> setResolution ( imageWidth_ == 640 ? dai :: MonoCameraProperties :: SensorResolution :: THE_400_P : dai :: MonoCameraProperties :: SensorResolution :: THE_800_P );
leftCamera -> setFps ( this -> getImageRate ());
auto rightCamera = pipeline . create < dai :: node :: MonoCamera > ();
rightCamera -> setCamera ( "right" );
rightCamera -> setResolution ( imageWidth_ == 640 ? dai :: MonoCameraProperties :: SensorResolution :: THE_400_P : dai :: MonoCameraProperties :: SensorResolution :: THE_800_P );
rightCamera -> setFps ( this -> getImageRate ());
leftCamera -> out . link ( stereoDepth -> left );
rightCamera -> out . link ( stereoDepth -> right );
}
if ( detectFeatures_ == 1 )
{
auto gfttDetector = pipeline . create < dai :: node :: FeatureTracker > ();
gfttDetector -> setHardwareResources ( 2 , 2 );
gfttDetector -> initialConfig . setCornerDetector (
useHarrisDetector_ ? dai :: FeatureTrackerConfig :: CornerDetector :: Type :: HARRIS : dai :: FeatureTrackerConfig :: CornerDetector :: Type :: SHI_THOMASI );
gfttDetector -> initialConfig . setNumTargetFeatures ( numTargetFeatures_ );
gfttDetector -> initialConfig . setMotionEstimator ( false );
auto cfg = gfttDetector -> initialConfig . get ();
cfg . featureMaintainer . minimumDistanceBetweenFeatures = minDistance_ * minDistance_ ;
gfttDetector -> initialConfig . set ( cfg );
if ( imagesRectified_ )
stereoDepth -> rectifiedLeft . link ( gfttDetector -> inputImage );
else
stereoDepth -> syncedLeft . link ( gfttDetector -> inputImage );
gfttDetector -> outputFeatures . link ( sync -> inputs [ "feat" ]);
}
else if ( detectFeatures_ >= 2 )
{
auto imageManip = pipeline . create < dai :: node :: ImageManip > ();
imageManip -> setKeepAspectRatio ( false );
imageManip -> setMaxOutputFrameSize ( 320 * 200 );
imageManip -> initialConfig . setResize ( 320 , 200 );
auto neuralNetwork = pipeline . create < dai :: node :: NeuralNetwork > ();
neuralNetwork -> setBlobPath ( blobPath_ );
neuralNetwork -> setNumInferenceThreads ( 2 );
neuralNetwork -> setNumNCEPerInferenceThread ( 1 );
neuralNetwork -> input . setBlocking ( false );
if ( imagesRectified_ )
stereoDepth -> rectifiedLeft . link ( imageManip -> inputImage );
else
stereoDepth -> syncedLeft . link ( imageManip -> inputImage );
imageManip -> out . link ( neuralNetwork -> input );
neuralNetwork -> out . link ( sync -> inputs [ "feat" ]);
}
auto xoutCamera = pipeline . create < dai :: node :: XLinkOut > ();
xoutCamera -> setStreamName ( "camera" );
sync -> out . link ( xoutCamera -> input );
if ( imuPublished_ )
{
auto imu = pipeline . create < dai :: node :: IMU > ();
if ( imuType == "BMI270" )
imu -> enableIMUSensor ({ dai :: IMUSensor :: ACCELEROMETER_RAW , dai :: IMUSensor :: GYROSCOPE_RAW }, 200 );
else // BNO085/086
imu -> enableIMUSensor ({ dai :: IMUSensor :: ACCELEROMETER , dai :: IMUSensor :: GYROSCOPE_UNCALIBRATED }, 200 );
imu -> setBatchReportThreshold ( boardName == "NG9097" ? 4 : 1 );
imu -> setMaxBatchReports ( 10 );
auto xoutIMU = pipeline . create < dai :: node :: XLinkOut > ();
xoutIMU -> setStreamName ( "imu" );
imu -> out . link ( xoutIMU -> input );
}
device_ -> startPipeline ( pipeline );
if ( ! device_ -> getIrDrivers (). empty ())
{
UINFO ( "Setting IR intensity" );
device_ -> setIrLaserDotProjectorIntensity ( dotIntensity_ );
device_ -> setIrFloodLightIntensity ( floodIntensity_ );
}
else if ( dotIntensity_ > 0 || floodIntensity_ > 0 )
{
UWARN ( "No IR drivers were detected! IR intensity cannot be set." );
2022-10-23 18:15:23 -07:00
}
2021-07-28 14:19:30 -04:00
2024-03-28 03:29:06 +08:00
cameraQueue_ = device_ -> getOutputQueue ( "camera" , 8 , false );
2022-10-23 18:15:23 -07:00
if ( imuPublished_ )
{
2023-05-25 12:19:07 +08:00
imuLocalTransform_ = this -> getLocalTransform () * imuLocalTransform_ ;
2023-05-25 00:01:55 +08:00
UINFO ( "IMU local transform = %s" , imuLocalTransform_ . prettyPrint (). c_str ());
2023-07-17 23:35:03 +08:00
device_ -> getOutputQueue ( "imu" , 50 , false ) -> addCallback ([ this ]( const std :: shared_ptr < dai :: ADatatype > data ) {
auto imuData = std :: dynamic_pointer_cast < dai :: IMUData > ( data );
auto imuPackets = imuData -> packets ;
for ( auto & imuPacket : imuPackets )
2023-05-27 21:28:43 +08:00
{
2023-07-17 23:35:03 +08:00
auto & acceleroValues = imuPacket . acceleroMeter ;
auto & gyroValues = imuPacket . gyroscope ;
double accStamp = std :: chrono :: duration < double > ( acceleroValues . getTimestampDevice (). time_since_epoch ()). count ();
double gyroStamp = std :: chrono :: duration < double > ( gyroValues . getTimestampDevice (). time_since_epoch ()). count ();
2023-05-27 21:28:43 +08:00
2023-07-17 23:35:03 +08:00
if ( publishInterIMU_ )
2023-05-27 21:28:43 +08:00
{
2023-07-17 23:35:03 +08:00
IMU imu ( cv :: Vec3f ( gyroValues . x , gyroValues . y , gyroValues . z ), cv :: Mat :: eye ( 3 , 3 , CV_64FC1 ),
cv :: Vec3f ( acceleroValues . x , acceleroValues . y , acceleroValues . z ), cv :: Mat :: eye ( 3 , 3 , CV_64FC1 ),
imuLocalTransform_ );
UEventsManager :: post ( new IMUEvent ( imu , ( accStamp + gyroStamp ) / 2 ));
}
else
{
UScopeMutex lock ( imuMutex_ );
2023-11-16 11:50:07 +08:00
accBuffer_ . emplace_hint ( accBuffer_ . end (), accStamp , cv :: Vec3f ( acceleroValues . x , acceleroValues . y , acceleroValues . z ));
gyroBuffer_ . emplace_hint ( gyroBuffer_ . end (), gyroStamp , cv :: Vec3f ( gyroValues . x , gyroValues . y , gyroValues . z ));
2023-05-27 21:28:43 +08:00
}
}
});
2022-10-23 18:15:23 -07:00
}
2021-03-07 12:27:21 -05:00
uSleep ( 2000 ); // avoid bad frames on start
return true ;
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
return false ;
}
bool CameraDepthAI :: isCalibrated () const
{
#ifdef RTABMAP_DEPTHAI
2024-06-30 17:11:37 -07:00
return outputMode_ == 0 ? stereoModel_ . isValidForProjection () : stereoModel_ . left (). isValidForProjection ();
2021-03-07 12:27:21 -05:00
#else
return false ;
#endif
}
std :: string CameraDepthAI :: getSerial () const
{
#ifdef RTABMAP_DEPTHAI
2023-07-15 20:58:00 +08:00
return device_ -> getMxId ();
2021-03-07 12:27:21 -05:00
#endif
return "" ;
}
2024-04-14 19:06:04 -07:00
SensorData CameraDepthAI :: captureImage ( SensorCaptureInfo * info )
2021-03-07 12:27:21 -05:00
{
SensorData data ;
#ifdef RTABMAP_DEPTHAI
2024-03-28 03:29:06 +08:00
auto messageGroup = cameraQueue_ -> get < dai :: MessageGroup > ();
2025-03-09 03:30:11 +08:00
auto rgbOrLeft = messageGroup -> get < dai :: ImgFrame > ( outputMode_ == 2 ? "rgb" : "left" );
auto depthOrRight = messageGroup -> get < dai :: ImgFrame > ( outputMode_ ? "depth" : "right" );
2024-03-28 03:29:06 +08:00
2025-03-09 03:30:11 +08:00
double stamp = std :: chrono :: duration < double > ( depthOrRight -> getTimestampDevice ( dai :: CameraExposureOffset :: MIDDLE ). time_since_epoch ()). count ();
if ( outputMode_ )
data = SensorData ( cv :: imdecode ( rgbOrLeft -> getData (), cv :: IMREAD_ANYCOLOR ), depthOrRight -> getCvFrame (), stereoModel_ . left (), this -> getNextSeqID (), stamp );
2021-03-07 12:27:21 -05:00
else
2025-03-09 03:30:11 +08:00
data = SensorData ( cv :: imdecode ( rgbOrLeft -> getData (), cv :: IMREAD_GRAYSCALE ), cv :: imdecode ( depthOrRight -> getData (), cv :: IMREAD_GRAYSCALE ), stereoModel_ , this -> getNextSeqID (), stamp );
2023-05-27 21:28:43 +08:00
if ( imuPublished_ && ! publishInterIMU_ )
2021-03-07 12:27:21 -05:00
{
2023-05-27 21:28:43 +08:00
cv :: Vec3d acc , gyro ;
std :: map < double , cv :: Vec3f >:: const_iterator iterA , iterB ;
imuMutex_ . lock ();
while ( accBuffer_ . empty () || gyroBuffer_ . empty () || accBuffer_ . rbegin () -> first < stamp || gyroBuffer_ . rbegin () -> first < stamp )
{
imuMutex_ . unlock ();
uSleep ( 1 );
imuMutex_ . lock ();
}
//acc
iterB = accBuffer_ . lower_bound ( stamp );
iterA = iterB ;
if ( iterA != accBuffer_ . begin ())
iterA = -- iterA ;
if ( iterA == iterB || stamp == iterB -> first )
{
acc = iterB -> second ;
}
else if ( stamp > iterA -> first && stamp < iterB -> first )
{
float t = ( stamp - iterA -> first ) / ( iterB -> first - iterA -> first );
acc = iterA -> second + t * ( iterB -> second - iterA -> second );
}
accBuffer_ . erase ( accBuffer_ . begin (), iterB );
//gyro
iterB = gyroBuffer_ . lower_bound ( stamp );
iterA = iterB ;
if ( iterA != gyroBuffer_ . begin ())
iterA = -- iterA ;
if ( iterA == iterB || stamp == iterB -> first )
{
gyro = iterB -> second ;
}
else if ( stamp > iterA -> first && stamp < iterB -> first )
{
float t = ( stamp - iterA -> first ) / ( iterB -> first - iterA -> first );
gyro = iterA -> second + t * ( iterB -> second - iterA -> second );
}
gyroBuffer_ . erase ( gyroBuffer_ . begin (), iterB );
imuMutex_ . unlock ();
data . setIMU ( IMU ( gyro , cv :: Mat :: eye ( 3 , 3 , CV_64FC1 ), acc , cv :: Mat :: eye ( 3 , 3 , CV_64FC1 ), imuLocalTransform_ ));
2021-03-07 12:27:21 -05:00
}
2023-06-12 03:57:26 +08:00
if ( detectFeatures_ == 1 )
{
2024-03-28 03:29:06 +08:00
auto features = messageGroup -> get < dai :: TrackedFeatures > ( "feat" ) -> trackedFeatures ;
2023-06-12 03:57:26 +08:00
std :: vector < cv :: KeyPoint > keypoints ;
2024-03-28 03:29:06 +08:00
for ( auto & feature : features )
2023-06-12 03:57:26 +08:00
keypoints . emplace_back ( cv :: KeyPoint ( feature . position . x , feature . position . y , 3 ));
data . setFeatures ( keypoints , std :: vector < cv :: Point3f > (), cv :: Mat ());
}
2024-03-28 03:29:06 +08:00
else if ( detectFeatures_ >= 2 )
2023-06-17 16:53:25 +08:00
{
2024-03-28 03:29:06 +08:00
auto features = messageGroup -> get < dai :: NNData > ( "feat" );
std :: vector < float > scores_dense , local_descriptor_map , global_descriptor ;
if ( detectFeatures_ == 2 )
{
scores_dense = features -> getLayerFp16 ( "heatmap" );
local_descriptor_map = features -> getLayerFp16 ( "desc" );
}
else if ( detectFeatures_ == 3 )
{
scores_dense = features -> getLayerFp16 ( "pred/local_head/detector/Squeeze" );
local_descriptor_map = features -> getLayerFp16 ( "pred/local_head/descriptor/transpose" );
global_descriptor = features -> getLayerFp16 ( "pred/global_head/l2_normalize_1" );
}
2024-01-03 07:38:39 +08:00
2024-03-28 03:29:06 +08:00
cv :: Mat scores ( 200 , 320 , CV_32FC1 , scores_dense . data ());
cv :: resize ( scores , scores , targetSize_ , 0 , 0 , cv :: INTER_CUBIC );
2024-01-03 07:38:39 +08:00
if ( nms_ )
2023-06-17 16:53:25 +08:00
{
2024-01-03 07:38:39 +08:00
cv :: Mat dilated_scores ( targetSize_ , CV_32FC1 );
cv :: dilate ( scores , dilated_scores , cv :: getStructuringElement ( cv :: MORPH_RECT , cv :: Size ( nmsRadius_ * 2 + 1 , nmsRadius_ * 2 + 1 )));
cv :: Mat max_mask = scores == dilated_scores ;
cv :: dilate ( scores , dilated_scores , cv :: Mat ());
cv :: Mat max_mask_r1 = scores == dilated_scores ;
cv :: Mat supp_mask ( targetSize_ , CV_8UC1 );
for ( size_t i = 0 ; i < 2 ; i ++ )
{
cv :: dilate ( max_mask , supp_mask , cv :: getStructuringElement ( cv :: MORPH_RECT , cv :: Size ( nmsRadius_ * 2 + 1 , nmsRadius_ * 2 + 1 )));
cv :: Mat supp_scores = scores . clone ();
supp_scores . setTo ( 0 , supp_mask );
cv :: dilate ( supp_scores , dilated_scores , cv :: getStructuringElement ( cv :: MORPH_RECT , cv :: Size ( nmsRadius_ * 2 + 1 , nmsRadius_ * 2 + 1 )));
cv :: Mat new_max_mask = cv :: Mat :: zeros ( targetSize_ , CV_8UC1 );
cv :: bitwise_not ( supp_mask , supp_mask );
cv :: bitwise_and ( supp_scores == dilated_scores , supp_mask , new_max_mask , max_mask_r1 );
cv :: bitwise_or ( max_mask , new_max_mask , max_mask );
}
cv :: bitwise_not ( max_mask , supp_mask );
scores . setTo ( 0 , supp_mask );
2023-06-17 16:53:25 +08:00
}
2024-01-03 07:38:39 +08:00
std :: vector < cv :: Point > kpts ;
cv :: findNonZero ( scores > threshold_ , kpts );
std :: vector < cv :: KeyPoint > keypoints ;
for ( auto & kpt : kpts )
2023-06-17 16:53:25 +08:00
{
2024-01-03 07:38:39 +08:00
float response = scores . at < float > ( kpt );
keypoints . emplace_back ( cv :: KeyPoint ( kpt , 8 , - 1 , response ));
2023-06-17 16:53:25 +08:00
}
2024-03-28 03:29:06 +08:00
cv :: Mat coarse_desc ( 25 , 40 , CV_32FC ( 256 ), local_descriptor_map . data ());
if ( detectFeatures_ == 2 )
coarse_desc . forEach < cv :: Vec < float , 256 >> ([ & ]( cv :: Vec < float , 256 >& descriptor , const int position []) -> void {
cv :: normalize ( descriptor , descriptor );
});
2023-06-19 14:31:13 +08:00
cv :: Mat mapX ( keypoints . size (), 1 , CV_32FC1 );
cv :: Mat mapY ( keypoints . size (), 1 , CV_32FC1 );
for ( size_t i = 0 ; i < keypoints . size (); ++ i )
{
mapX . at < float > ( i ) = ( keypoints [ i ]. pt . x - ( targetSize_ . width - 1 ) / 2 ) * 40 / targetSize_ . width + ( 40 - 1 ) / 2 ;
mapY . at < float > ( i ) = ( keypoints [ i ]. pt . y - ( targetSize_ . height - 1 ) / 2 ) * 25 / targetSize_ . height + ( 25 - 1 ) / 2 ;
}
cv :: Mat map1 , map2 , descriptors ;
cv :: convertMaps ( mapX , mapY , map1 , map2 , CV_16SC2 );
cv :: remap ( coarse_desc , descriptors , map1 , map2 , cv :: INTER_LINEAR );
descriptors . forEach < cv :: Vec < float , 256 >> ([ & ]( cv :: Vec < float , 256 >& descriptor , const int position []) -> void {
cv :: normalize ( descriptor , descriptor );
});
descriptors = descriptors . reshape ( 1 );
data . setFeatures ( keypoints , std :: vector < cv :: Point3f > (), descriptors );
2024-03-28 03:29:06 +08:00
if ( detectFeatures_ == 3 )
2024-04-14 05:56:28 +08:00
data . addGlobalDescriptor ( GlobalDescriptor ( 1 , cv :: Mat ( 1 , global_descriptor . size (), CV_32FC1 , global_descriptor . data ()). clone ()));
2023-06-17 16:53:25 +08:00
}
2023-06-12 03:57:26 +08:00
2021-03-07 12:27:21 -05:00
#else
UERROR ( "CameraDepthAI: RTAB-Map is not built with depthai-core support!" );
#endif
return data ;
}
} // namespace rtabmap