mirror of
https://github.com/introlab/rtabmap_ros.git
synced 2026-10-05 09:17:47 +08:00
0.13.3: scan2d with normals support/registration
This commit is contained in:
@@ -85,7 +85,8 @@ public:
|
||||
int maxScanPts = 0,
|
||||
int downsampleStep = 1,
|
||||
float voxelSize = 0.0f,
|
||||
int normalsK = 0, // compute normals if > 0
|
||||
int normalsK = 0, // compute normals if > 0
|
||||
float normalsRadius = 0, // compute normals if > 0
|
||||
const Transform & localTransform=Transform::getIdentity())
|
||||
{
|
||||
_scanPath = dir;
|
||||
@@ -93,6 +94,7 @@ public:
|
||||
_scanMaxPts = maxScanPts;
|
||||
_scanDownsampleStep = downsampleStep;
|
||||
_scanNormalsK = normalsK;
|
||||
_scanNormalsRadius = normalsRadius;
|
||||
_scanVoxelSize = voxelSize;
|
||||
if(_scanDownsampleStep>1)
|
||||
{
|
||||
@@ -158,6 +160,7 @@ private:
|
||||
int _scanDownsampleStep;
|
||||
float _scanVoxelSize;
|
||||
int _scanNormalsK;
|
||||
float _scanNormalsRadius;
|
||||
|
||||
bool _depthFromScan;
|
||||
int _depthFromScanFillHoles; // <0:horizontal 0:disabled >0:vertical
|
||||
|
||||
@@ -73,13 +73,15 @@ public:
|
||||
int decimation=4,
|
||||
float maxDepth=4.0f,
|
||||
float voxelSize = 0.0f,
|
||||
int normalsK = 0)
|
||||
int normalsK = 0,
|
||||
int normalsRadius = 0.0f)
|
||||
{
|
||||
_scanFromDepth = enabled;
|
||||
_scanDecimation=decimation;
|
||||
_scanMaxDepth = maxDepth;
|
||||
_scanVoxelSize = voxelSize;
|
||||
_scanNormalsK = normalsK;
|
||||
_scanNormalsRadius = normalsRadius;
|
||||
}
|
||||
|
||||
void postUpdate(SensorData * data, CameraInfo * info = 0) const;
|
||||
@@ -107,6 +109,7 @@ private:
|
||||
float _scanMinDepth;
|
||||
float _scanVoxelSize;
|
||||
int _scanNormalsK;
|
||||
float _scanNormalsRadius;
|
||||
StereoDense * _stereoDense;
|
||||
clams::DiscreteDepthDistortionModel * _distortionModel;
|
||||
bool _bilateralFiltering;
|
||||
|
||||
@@ -283,6 +283,7 @@ private:
|
||||
bool _compressionParallelized;
|
||||
float _laserScanDownsampleStepSize;
|
||||
int _laserScanNormalK;
|
||||
int _laserScanNormalRadius;
|
||||
bool _reextractLoopClosureFeatures;
|
||||
float _rehearsalMaxDistance;
|
||||
float _rehearsalMaxAngle;
|
||||
|
||||
@@ -211,7 +211,8 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Mem, ImagePostDecimation, int, 1, "Image decimation (>=1) of saved data in created signatures (after features extraction). Decimation is done from the original image. Negative decimation is done from RGB size instead of depth size (if depth is smaller than RGB, it may be interpolated depending of the decimation value).");
|
||||
RTABMAP_PARAM(Mem, CompressionParallelized, bool, true, "Compression of sensor data is multi-threaded.");
|
||||
RTABMAP_PARAM(Mem, LaserScanDownsampleStepSize, int, 1, "If > 1, downsample the laser scans when creating a signature.");
|
||||
RTABMAP_PARAM(Mem, LaserScanNormalK, int, 0, "If > 0 and laser scans are 3D without normals, normals will be computed with K search neighbors when creating a signature.");
|
||||
RTABMAP_PARAM(Mem, LaserScanNormalK, int, 0, "If > 0 and laser scans don't have normals, normals will be computed with K search neighbors when creating a signature.");
|
||||
RTABMAP_PARAM(Mem, LaserScanNormalRadius, int, 0, "If > 0 and laser scans don't have normals, normals will be computed with radius search neighbors when creating a signature.");
|
||||
RTABMAP_PARAM(Mem, UseOdomFeatures, bool, false, "Use odometry features.");
|
||||
|
||||
// KeypointMemory (Keypoint-based)
|
||||
@@ -510,7 +511,8 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Icp, Epsilon, float, 0, "Set the transformation epsilon (maximum allowable difference between two consecutive transformations) in order for an optimization to be considered as having converged to the final solution.");
|
||||
RTABMAP_PARAM(Icp, CorrespondenceRatio, float, 0.2, "Ratio of matching correspondences to accept the transform.");
|
||||
RTABMAP_PARAM(Icp, PointToPlane, bool, false, "Use point to plane ICP.");
|
||||
RTABMAP_PARAM(Icp, PointToPlaneNormalNeighbors, int, 20, "Number of neighbors to compute normals for point to plane.");
|
||||
RTABMAP_PARAM(Icp, PointToPlaneK, int, 20, "Number of neighbors to compute normals for point to plane if the cloud doesn't have already normals.");
|
||||
RTABMAP_PARAM(Icp, PointToPlaneRadius, float, 0.0, "Search radius to compute normals for point to plane if the cloud doesn't have already normals.");
|
||||
|
||||
// libpointmatcher
|
||||
RTABMAP_PARAM(Icp, PM, bool, false, "Use libpointmatcher for ICP registration instead of PCL's implementation.");
|
||||
|
||||
@@ -64,7 +64,8 @@ private:
|
||||
float _epsilon;
|
||||
float _correspondenceRatio;
|
||||
bool _pointToPlane;
|
||||
int _pointToPlaneNormalNeighbors;
|
||||
int _pointToPlaneK;
|
||||
float _pointToPlaneRadius;
|
||||
bool _libpointmatcher;
|
||||
std::string _libpointmatcherConfig;
|
||||
float _libpointmatcherOutlierRatio;
|
||||
|
||||
@@ -198,6 +198,8 @@ cv::Mat RTABMAP_EXP laserScanFromPointCloud(const pcl::PointCloud<pcl::PointXYZ>
|
||||
// return CV_32FC4 (x,y,z,rgb)
|
||||
cv::Mat RTABMAP_EXP laserScanFromPointCloud(const pcl::PointCloud<pcl::PointXYZRGB> & cloud, const Transform & transform = Transform());
|
||||
// return CV_32FC7 (x,y,z,rgb,normal_z,normal_y,normalz)
|
||||
cv::Mat RTABMAP_EXP laserScanFromPointCloud(const pcl::PointCloud<pcl::PointXYZRGB> & cloud, const pcl::PointCloud<pcl::Normal> & normals, const Transform & transform = Transform());
|
||||
// return CV_32FC7 (x,y,z,rgb,normal_z,normal_y,normalz)
|
||||
cv::Mat RTABMAP_EXP laserScanFromPointCloud(const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud, const Transform & transform = Transform());
|
||||
// return CV_32FC2 (x,y)
|
||||
cv::Mat RTABMAP_EXP laserScan2dFromPointCloud(const pcl::PointCloud<pcl::PointXYZ> & cloud, const Transform & transform = Transform());
|
||||
|
||||
@@ -141,6 +141,12 @@ pcl::PointCloud<pcl::PointNormal>::Ptr RTABMAP_EXP passThrough(
|
||||
float min,
|
||||
float max,
|
||||
bool negative = false);
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP passThrough(
|
||||
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
||||
const std::string & axis,
|
||||
float min,
|
||||
float max,
|
||||
bool negative = false);
|
||||
|
||||
pcl::IndicesPtr RTABMAP_EXP cropBox(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
|
||||
@@ -212,32 +212,50 @@ cv::Mat RTABMAP_EXP mergeTextures(
|
||||
bool exposureFusion = false, //Exposure fusion can be used only with OpenCV3
|
||||
const ProgressState * state = 0);
|
||||
|
||||
|
||||
cv::Mat RTABMAP_EXP computeNormals(
|
||||
const cv::Mat & laserScan,
|
||||
int searchK,
|
||||
float searchRadius);
|
||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
int normalKSearch = 20,
|
||||
int searchK = 20,
|
||||
float searchRadius = 0.0f,
|
||||
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||
int normalKSearch = 20,
|
||||
int searchK = 20,
|
||||
float searchRadius = 0.0f,
|
||||
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
const pcl::IndicesPtr & indices,
|
||||
int normalKSearch = 20,
|
||||
int searchK = 20,
|
||||
float searchRadius = 0.0f,
|
||||
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||
const pcl::IndicesPtr & indices,
|
||||
int normalKSearch = 20,
|
||||
int searchK = 20,
|
||||
float searchRadius = 0.0f,
|
||||
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
|
||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeNormals2D(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
int searchK = 5,
|
||||
float searchRadius = 0.0f,
|
||||
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeFastOrganizedNormals2D(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
int searchK = 5,
|
||||
float searchRadius = 0.0f,
|
||||
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeFastOrganizedNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||
float maxDepthChangeFactor = 0.02f,
|
||||
float normalSmoothingSize = 10.0f,
|
||||
const Eigen::Vector3f & viewPoint = Eigen::Vector3f(0,0,0));
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
|
||||
pcl::PointCloud<pcl::Normal>::Ptr RTABMAP_EXP computeFastOrganizedNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||
const pcl::IndicesPtr & indices,
|
||||
float maxDepthChangeFactor = 0.02f,
|
||||
|
||||
@@ -70,6 +70,7 @@ CameraImages::CameraImages() :
|
||||
_scanDownsampleStep(1),
|
||||
_scanVoxelSize(0.0f),
|
||||
_scanNormalsK(0),
|
||||
_scanNormalsRadius(0),
|
||||
_depthFromScan(false),
|
||||
_depthFromScanFillHoles(1),
|
||||
_depthFromScanFillHolesFromBorder(false),
|
||||
@@ -99,6 +100,7 @@ CameraImages::CameraImages(const std::string & path,
|
||||
_scanDownsampleStep(1),
|
||||
_scanVoxelSize(0.0f),
|
||||
_scanNormalsK(0),
|
||||
_scanNormalsRadius(0),
|
||||
_depthFromScan(false),
|
||||
_depthFromScanFillHoles(1),
|
||||
_depthFromScanFillHolesFromBorder(false),
|
||||
@@ -685,9 +687,9 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
cloud = util3d::voxelize(cloud, _scanVoxelSize);
|
||||
UDEBUG("Voxel filtering scan (voxel=%f m): %d -> %d", _scanVoxelSize, previousSize, (int)cloud->size());
|
||||
}
|
||||
if(_scanNormalsK > 0 && cloud->size())
|
||||
if((_scanNormalsK > 0 || _scanNormalsRadius) && cloud->size())
|
||||
{
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, _scanNormalsK);
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, _scanNormalsK, _scanNormalsRadius);
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr cloudNormals(new pcl::PointCloud<pcl::PointNormal>);
|
||||
pcl::concatenateFields(*cloud, *normals, *cloudNormals);
|
||||
scan = util3d::laserScanFromPointCloud(*cloudNormals, _scanLocalTransform.inverse());
|
||||
|
||||
@@ -58,6 +58,7 @@ CameraThread::CameraThread(Camera * camera, const ParametersMap & parameters) :
|
||||
_scanMinDepth(0.0f),
|
||||
_scanVoxelSize(0.0f),
|
||||
_scanNormalsK(0),
|
||||
_scanNormalsRadius(0.0f),
|
||||
_stereoDense(new StereoBM(parameters)),
|
||||
_distortionModel(0),
|
||||
_bilateralFiltering(false),
|
||||
@@ -323,10 +324,10 @@ void CameraThread::postUpdate(SensorData * dataPtr, CameraInfo * info) const
|
||||
|
||||
if(cloud->size())
|
||||
{
|
||||
if(_scanNormalsK>0)
|
||||
if(_scanNormalsK>0 || _scanNormalsRadius>0.0f)
|
||||
{
|
||||
Eigen::Vector3f viewPoint(baseToScan.x(), baseToScan.y(), baseToScan.z());
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, _scanNormalsK, viewPoint);
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, _scanNormalsK, _scanNormalsRadius, viewPoint);
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr cloudNormals(new pcl::PointCloud<pcl::PointNormal>);
|
||||
pcl::concatenateFields(*cloud, *normals, *cloudNormals);
|
||||
scan = util3d::laserScanFromPointCloud(*cloudNormals, baseToScan.inverse());
|
||||
|
||||
@@ -89,6 +89,7 @@ Memory::Memory(const ParametersMap & parameters) :
|
||||
_compressionParallelized(Parameters::defaultMemCompressionParallelized()),
|
||||
_laserScanDownsampleStepSize(Parameters::defaultMemLaserScanDownsampleStepSize()),
|
||||
_laserScanNormalK(Parameters::defaultMemLaserScanNormalK()),
|
||||
_laserScanNormalRadius(Parameters::defaultMemLaserScanNormalRadius()),
|
||||
_reextractLoopClosureFeatures(Parameters::defaultRGBDLoopClosureReextractFeatures()),
|
||||
_rehearsalMaxDistance(Parameters::defaultRGBDLinearUpdate()),
|
||||
_rehearsalMaxAngle(Parameters::defaultRGBDAngularUpdate()),
|
||||
@@ -440,6 +441,7 @@ void Memory::parseParameters(const ParametersMap & parameters)
|
||||
Parameters::parse(parameters, Parameters::kMemCompressionParallelized(), _compressionParallelized);
|
||||
Parameters::parse(parameters, Parameters::kMemLaserScanDownsampleStepSize(), _laserScanDownsampleStepSize);
|
||||
Parameters::parse(parameters, Parameters::kMemLaserScanNormalK(), _laserScanNormalK);
|
||||
Parameters::parse(parameters, Parameters::kMemLaserScanNormalRadius(), _laserScanNormalRadius);
|
||||
Parameters::parse(parameters, Parameters::kRGBDLoopClosureReextractFeatures(), _reextractLoopClosureFeatures);
|
||||
Parameters::parse(parameters, Parameters::kRGBDLinearUpdate(), _rehearsalMaxDistance);
|
||||
Parameters::parse(parameters, Parameters::kRGBDAngularUpdate(), _rehearsalMaxAngle);
|
||||
@@ -3718,13 +3720,12 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
|
||||
if(stats) stats->addStatistic(Statistics::kTimingMemScan_downsampling(), t*1000.0f);
|
||||
UDEBUG("time downsampling scan = %fs", t);
|
||||
}
|
||||
if(!laserScan.empty() && _laserScanNormalK > 0 && laserScan.channels() == 3 && !isIntermediateNode)
|
||||
if(!laserScan.empty() &&
|
||||
(_laserScanNormalK > 0 || _laserScanNormalRadius>0.0f) &&
|
||||
laserScan.channels() > 1 && laserScan.channels() < 5 &&
|
||||
!isIntermediateNode)
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = util3d::laserScanToPointCloud(laserScan);
|
||||
float x,y,z;
|
||||
data.laserScanInfo().localTransform().getTranslation(x,y,z);
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, _laserScanNormalK, Eigen::Vector3f(x,y,z));
|
||||
laserScan = util3d::laserScanFromPointCloud(*cloud, *normals);
|
||||
laserScan = util3d::computeNormals(laserScan, _laserScanNormalK, _laserScanNormalRadius);
|
||||
t = timer.ticks();
|
||||
if(stats) stats->addStatistic(Statistics::kTimingMemScan_normals(), t*1000.0f);
|
||||
UDEBUG("time normals scan = %fs", t);
|
||||
|
||||
@@ -225,6 +225,10 @@ const std::map<std::string, std::pair<bool, std::string> > & Parameters::getRemo
|
||||
{
|
||||
// removed parameters
|
||||
|
||||
// 0.13.3
|
||||
removedParameters_.insert(std::make_pair("Icp/PointToPlaneNormalNeighbors", std::make_pair(true, Parameters::kIcpPointToPlaneK())));
|
||||
|
||||
|
||||
// 0.13.1
|
||||
removedParameters_.insert(std::make_pair("Rtabmap/VhStrategy", std::make_pair(true, Parameters::kVhEpEnabled())));
|
||||
|
||||
@@ -326,7 +330,7 @@ const std::map<std::string, std::pair<bool, std::string> > & Parameters::getRemo
|
||||
removedParameters_.insert(std::make_pair("LccIcp3/Iterations", std::make_pair(false, Parameters::kIcpIterations())));
|
||||
removedParameters_.insert(std::make_pair("LccIcp3/CorrespondenceRatio", std::make_pair(false, Parameters::kIcpCorrespondenceRatio())));
|
||||
removedParameters_.insert(std::make_pair("LccIcp3/PointToPlane", std::make_pair(true, Parameters::kIcpPointToPlane())));
|
||||
removedParameters_.insert(std::make_pair("LccIcp3/PointToPlaneNormalNeighbors", std::make_pair(true, Parameters::kIcpPointToPlaneNormalNeighbors())));
|
||||
removedParameters_.insert(std::make_pair("LccIcp3/PointToPlaneNormalNeighbors", std::make_pair(true, Parameters::kIcpPointToPlaneK())));
|
||||
|
||||
removedParameters_.insert(std::make_pair("LccIcp2/MaxCorrespondenceDistance", std::make_pair(true, Parameters::kIcpMaxCorrespondenceDistance())));
|
||||
removedParameters_.insert(std::make_pair("LccIcp2/Iterations", std::make_pair(true, Parameters::kIcpIterations())));
|
||||
|
||||
@@ -36,8 +36,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <rtabmap/utilite/UConversion.h>
|
||||
#include <rtabmap/utilite/UMath.h>
|
||||
#include <rtabmap/utilite/UTimer.h>
|
||||
#include <pcl/io/pcd_io.h>
|
||||
#include <pcl/io/vtk_io.h>
|
||||
#include <pcl/conversions.h>
|
||||
|
||||
#ifdef RTABMAP_POINTMATCHER
|
||||
@@ -225,7 +223,8 @@ RegistrationIcp::RegistrationIcp(const ParametersMap & parameters, Registration
|
||||
_epsilon(Parameters::defaultIcpEpsilon()),
|
||||
_correspondenceRatio(Parameters::defaultIcpCorrespondenceRatio()),
|
||||
_pointToPlane(Parameters::defaultIcpPointToPlane()),
|
||||
_pointToPlaneNormalNeighbors(Parameters::defaultIcpPointToPlaneNormalNeighbors()),
|
||||
_pointToPlaneK(Parameters::defaultIcpPointToPlaneK()),
|
||||
_pointToPlaneRadius(Parameters::defaultIcpPointToPlaneRadius()),
|
||||
_libpointmatcher(Parameters::defaultIcpPM()),
|
||||
_libpointmatcherConfig(Parameters::defaultIcpPMConfig()),
|
||||
_libpointmatcherOutlierRatio(Parameters::defaultIcpPMOutlierRatio()),
|
||||
@@ -257,7 +256,8 @@ void RegistrationIcp::parseParameters(const ParametersMap & parameters)
|
||||
Parameters::parse(parameters, Parameters::kIcpEpsilon(), _epsilon);
|
||||
Parameters::parse(parameters, Parameters::kIcpCorrespondenceRatio(), _correspondenceRatio);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlane(), _pointToPlane);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlaneNormalNeighbors(), _pointToPlaneNormalNeighbors);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlaneK(), _pointToPlaneK);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlaneRadius(), _pointToPlaneRadius);
|
||||
|
||||
Parameters::parse(parameters, Parameters::kIcpPM(), _libpointmatcher);
|
||||
Parameters::parse(parameters, Parameters::kIcpPMConfig(), _libpointmatcherConfig);
|
||||
@@ -342,7 +342,7 @@ void RegistrationIcp::parseParameters(const ParametersMap & parameters)
|
||||
UASSERT_MSG(_maxIterations > 0, uFormat("value=%d", _maxIterations).c_str());
|
||||
UASSERT(_epsilon >= 0.0f);
|
||||
UASSERT_MSG(_correspondenceRatio >=0.0f && _correspondenceRatio <=1.0f, uFormat("value=%f", _correspondenceRatio).c_str());
|
||||
UASSERT_MSG(_pointToPlaneNormalNeighbors > 0, uFormat("value=%d", _pointToPlaneNormalNeighbors).c_str());
|
||||
UASSERT_MSG(!_pointToPlane || (_pointToPlane && (_pointToPlaneK > 0 || _pointToPlaneRadius > 0.0f)), uFormat("_pointToPlaneK=%d _pointToPlaneRadius=%f", _pointToPlaneK, _pointToPlaneRadius).c_str());
|
||||
}
|
||||
|
||||
Transform RegistrationIcp::computeTransformationImpl(
|
||||
@@ -354,7 +354,8 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
UDEBUG("Guess transform = %s", guess.prettyPrint().c_str());
|
||||
UDEBUG("Voxel size=%f", _voxelSize);
|
||||
UDEBUG("PointToPlane=%d", _pointToPlane?1:0);
|
||||
UDEBUG("Normal neighborhood=%d", _pointToPlaneNormalNeighbors);
|
||||
UDEBUG("Normal neighborhood=%d", _pointToPlaneK);
|
||||
UDEBUG("Normal radius=%d", _pointToPlaneRadius);
|
||||
UDEBUG("Max correspondence distance=%f", _maxCorrespondenceDistance);
|
||||
UDEBUG("Max Iterations=%d", _maxIterations);
|
||||
UDEBUG("Correspondence Ratio=%f", _correspondenceRatio);
|
||||
@@ -406,8 +407,8 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
|
||||
if( _pointToPlane &&
|
||||
_voxelSize == 0.0f &&
|
||||
fromScan.channels() == 6 &&
|
||||
toScan.channels() == 6)
|
||||
fromScan.channels() >= 6 &&
|
||||
toScan.channels() >= 6)
|
||||
{
|
||||
//special case if we have already normals computed and there is no filtering
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr fromCloudNormals = util3d::laserScanToPointCloudNormal(fromScan, fromLocalTransform);
|
||||
@@ -450,6 +451,9 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fromCloudNormals = util3d::removeNaNNormalsFromPointCloud(fromCloudNormals);
|
||||
toCloudNormals = util3d::removeNaNNormalsFromPointCloud(toCloudNormals);
|
||||
|
||||
icpT = util3d::icpPointToPlane(
|
||||
fromCloudNormals,
|
||||
toCloudNormals,
|
||||
@@ -497,15 +501,41 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr fromCloudRegistered(new pcl::PointCloud<pcl::PointXYZ>());
|
||||
if(_pointToPlane) // ICP Point To Plane, only in 3D
|
||||
if(_pointToPlane && // ICP Point To Plane
|
||||
!((fromScan.channels() == 2 || toScan.channels() == 2) && !_libpointmatcher)) // PCL crashes if 2D
|
||||
{
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals;
|
||||
Eigen::Vector3f viewpointFrom(fromLocalTransform.x(), fromLocalTransform.y(), fromLocalTransform.z());
|
||||
Transform toT = guess * toLocalTransform;
|
||||
Eigen::Vector3f viewpointTo(toT.x(), toT.y(), toT.z());
|
||||
|
||||
normals = util3d::computeNormals(fromCloudFiltered, _pointToPlaneNormalNeighbors);
|
||||
if(fromScan.channels() == 2)
|
||||
{
|
||||
normals = util3d::computeFastOrganizedNormals2D(
|
||||
fromCloudFiltered,
|
||||
_pointToPlaneK,
|
||||
_pointToPlaneRadius,
|
||||
viewpointFrom);
|
||||
}
|
||||
else
|
||||
{
|
||||
normals = util3d::computeNormals(fromCloudFiltered, _pointToPlaneK, _pointToPlaneRadius, viewpointFrom);
|
||||
}
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr fromCloudNormals(new pcl::PointCloud<pcl::PointNormal>);
|
||||
pcl::concatenateFields(*fromCloudFiltered, *normals, *fromCloudNormals);
|
||||
|
||||
normals = util3d::computeNormals(toCloudFiltered, _pointToPlaneNormalNeighbors);
|
||||
if(toScan.channels() == 2)
|
||||
{
|
||||
normals = util3d::computeFastOrganizedNormals2D(
|
||||
toCloudFiltered,
|
||||
_pointToPlaneK,
|
||||
_pointToPlaneRadius,
|
||||
viewpointTo);
|
||||
}
|
||||
else
|
||||
{
|
||||
normals = util3d::computeNormals(toCloudFiltered, _pointToPlaneK, _pointToPlaneRadius, viewpointTo);
|
||||
}
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr toCloudNormals(new pcl::PointCloud<pcl::PointNormal>);
|
||||
pcl::concatenateFields(*toCloudFiltered, *normals, *toCloudNormals);
|
||||
|
||||
@@ -517,7 +547,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
fromSignature.sensorData().setLaserScanRaw(util3d::laserScanFromPointCloud(*fromCloudNormals, fromLocalTransform.inverse()), LaserScanInfo(maxLaserScansFrom, fromSignature.sensorData().laserScanInfo().maxRange(), fromLocalTransform));
|
||||
toSignature.sensorData().setLaserScanRaw(util3d::laserScanFromPointCloud(*toCloudNormals, (guess*toLocalTransform).inverse()), LaserScanInfo(maxLaserScansTo, toSignature.sensorData().laserScanInfo().maxRange(), toLocalTransform));
|
||||
|
||||
UDEBUG("Compute normals time = %f s", timer.ticks());
|
||||
UDEBUG("Compute normals (%d,%d) time = %f s", (int)fromCloudNormals->size(), (int)toCloudNormals->size(), timer.ticks());
|
||||
|
||||
if(toCloudNormals->size() && fromCloudNormals->size())
|
||||
{
|
||||
@@ -569,7 +599,6 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
this->force3DoF());
|
||||
}
|
||||
|
||||
|
||||
if(!icpT.isNull() && hasConverged)
|
||||
{
|
||||
util3d::computeVarianceAndCorrespondences(
|
||||
@@ -583,6 +612,11 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
}
|
||||
else // ICP Point to Point
|
||||
{
|
||||
if(_pointToPlane && ((fromScan.channels() == 2 || toScan.channels() == 2) && !_libpointmatcher))
|
||||
{
|
||||
UWARN("ICP PointToPlane ignored for 2d scans with PCL registration (some crash issues). Use libpointmatcher (%s) or disable %s to avoid this warning.", Parameters::kIcpPM().c_str(), Parameters::kIcpPointToPlane().c_str());
|
||||
}
|
||||
|
||||
if(_voxelSize > 0.0f)
|
||||
{
|
||||
// update output scans
|
||||
|
||||
@@ -1363,6 +1363,46 @@ cv::Mat laserScanFromPointCloud(const pcl::PointCloud<pcl::PointXYZRGB> & cloud,
|
||||
return laserScan;
|
||||
}
|
||||
|
||||
cv::Mat laserScanFromPointCloud(const pcl::PointCloud<pcl::PointXYZRGB> & cloud, const pcl::PointCloud<pcl::Normal> & normals, const Transform & transform)
|
||||
{
|
||||
UASSERT(cloud.size() == normals.size());
|
||||
cv::Mat laserScan(1, (int)cloud.size(), CV_32FC(7));
|
||||
bool nullTransform = transform.isNull() || transform.isIdentity();
|
||||
for(unsigned int i=0; i<cloud.size(); ++i)
|
||||
{
|
||||
float * ptr = laserScan.ptr<float>(0, i);
|
||||
if(!nullTransform)
|
||||
{
|
||||
pcl::PointXYZRGBNormal pt;
|
||||
pt.x = cloud.at(i).x;
|
||||
pt.y = cloud.at(i).y;
|
||||
pt.z = cloud.at(i).z;
|
||||
pt.normal_x = normals.at(i).normal_x;
|
||||
pt.normal_y = normals.at(i).normal_y;
|
||||
pt.normal_z = normals.at(i).normal_z;
|
||||
pt = util3d::transformPoint(pt, transform);
|
||||
ptr[0] = pt.x;
|
||||
ptr[1] = pt.y;
|
||||
ptr[2] = pt.z;
|
||||
ptr[4] = pt.normal_x;
|
||||
ptr[5] = pt.normal_y;
|
||||
ptr[6] = pt.normal_z;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr[0] = cloud.at(i).x;
|
||||
ptr[1] = cloud.at(i).y;
|
||||
ptr[2] = cloud.at(i).z;
|
||||
ptr[4] = normals.at(i).normal_x;
|
||||
ptr[5] = normals.at(i).normal_y;
|
||||
ptr[6] = normals.at(i).normal_z;
|
||||
}
|
||||
int * ptrInt = (int*)ptr;
|
||||
ptrInt[3] = int(cloud.at(i).b) | (int(cloud.at(i).g) << 8) | (int(cloud.at(i).r) << 16);
|
||||
}
|
||||
return laserScan;
|
||||
}
|
||||
|
||||
cv::Mat laserScanFromPointCloud(const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud, const Transform & transform)
|
||||
{
|
||||
cv::Mat laserScan(1, (int)cloud.size(), CV_32FC(7));
|
||||
|
||||
@@ -369,6 +369,26 @@ pcl::PointCloud<pcl::PointNormal>::Ptr passThrough(
|
||||
return output;
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr passThrough(
|
||||
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
||||
const std::string & axis,
|
||||
float min,
|
||||
float max,
|
||||
bool negative)
|
||||
{
|
||||
UASSERT_MSG(max > min, uFormat("cloud=%d, max=%f min=%f axis=%s", (int)cloud->size(), max, min, axis.c_str()).c_str());
|
||||
UASSERT(axis.compare("x") == 0 || axis.compare("y") == 0 || axis.compare("z") == 0);
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr output(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
|
||||
pcl::PassThrough<pcl::PointXYZRGBNormal> filter;
|
||||
filter.setNegative(negative);
|
||||
filter.setFilterFieldName(axis);
|
||||
filter.setFilterLimits(min, max);
|
||||
filter.setInputCloud(cloud);
|
||||
filter.filter(*output);
|
||||
return output;
|
||||
}
|
||||
|
||||
pcl::IndicesPtr cropBox(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
const pcl::IndicesPtr & indices,
|
||||
|
||||
@@ -1994,18 +1994,51 @@ cv::Mat mergeTextures(
|
||||
return globalTextures;
|
||||
}
|
||||
|
||||
cv::Mat computeNormals(
|
||||
const cv::Mat & laserScan,
|
||||
int searchK,
|
||||
float searchRadius)
|
||||
{
|
||||
if(laserScan.empty() || laserScan.channels()<2 || laserScan.channels()>4)
|
||||
{
|
||||
return laserScan;
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals;
|
||||
if(laserScan.channels() < 4)
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = util3d::laserScanToPointCloud(laserScan);
|
||||
if(laserScan.channels() == 2)
|
||||
{
|
||||
normals = util3d::computeNormals2D(cloud, searchK, searchRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
normals = util3d::computeNormals(cloud, searchK, searchRadius);
|
||||
}
|
||||
return util3d::laserScanFromPointCloud(*cloud, *normals);
|
||||
}
|
||||
else // 4 channels
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = util3d::laserScanToPointCloudRGB(laserScan);
|
||||
normals = util3d::computeNormals(cloud, searchK, searchRadius);
|
||||
return util3d::laserScanFromPointCloud(*cloud, *normals);
|
||||
}
|
||||
}
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
int normalKSearch,
|
||||
int searchK,
|
||||
float searchRadius,
|
||||
const Eigen::Vector3f & viewPoint)
|
||||
{
|
||||
pcl::IndicesPtr indices(new std::vector<int>);
|
||||
return computeNormals(cloud, indices, normalKSearch, viewPoint);
|
||||
return computeNormals(cloud, indices, searchK, searchRadius, viewPoint);
|
||||
}
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
const pcl::IndicesPtr & indices,
|
||||
int normalKSearch,
|
||||
int searchK,
|
||||
float searchRadius,
|
||||
const Eigen::Vector3f & viewPoint)
|
||||
{
|
||||
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
|
||||
@@ -2032,7 +2065,8 @@ pcl::PointCloud<pcl::Normal>::Ptr computeNormals(
|
||||
// n.setIndices(indices);
|
||||
//}
|
||||
n.setSearchMethod (tree);
|
||||
n.setKSearch (normalKSearch);
|
||||
n.setKSearch (searchK);
|
||||
n.setRadiusSearch (searchRadius);
|
||||
n.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
|
||||
n.compute (*normals);
|
||||
|
||||
@@ -2041,16 +2075,18 @@ pcl::PointCloud<pcl::Normal>::Ptr computeNormals(
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||
int normalKSearch,
|
||||
int searchK,
|
||||
float searchRadius,
|
||||
const Eigen::Vector3f & viewPoint)
|
||||
{
|
||||
pcl::IndicesPtr indices(new std::vector<int>);
|
||||
return computeNormals(cloud, indices, normalKSearch, viewPoint);
|
||||
return computeNormals(cloud, indices, searchK, searchRadius, viewPoint);
|
||||
}
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||
const pcl::IndicesPtr & indices,
|
||||
int normalKSearch,
|
||||
int searchK,
|
||||
float searchRadius,
|
||||
const Eigen::Vector3f & viewPoint)
|
||||
{
|
||||
pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>);
|
||||
@@ -2077,13 +2113,182 @@ pcl::PointCloud<pcl::Normal>::Ptr computeNormals(
|
||||
// n.setIndices(indices);
|
||||
//}
|
||||
n.setSearchMethod (tree);
|
||||
n.setKSearch (normalKSearch);
|
||||
n.setKSearch (searchK);
|
||||
n.setRadiusSearch(searchRadius);
|
||||
n.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
|
||||
n.compute (*normals);
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeNormals2D(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
int searchK,
|
||||
float searchRadius,
|
||||
const Eigen::Vector3f & viewPoint)
|
||||
{
|
||||
UASSERT(searchK>0 || searchRadius>0.0f);
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
|
||||
|
||||
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
|
||||
tree->setInputCloud (cloud);
|
||||
|
||||
normals->resize(cloud->size());
|
||||
|
||||
float bad_point = std::numeric_limits<float>::quiet_NaN ();
|
||||
|
||||
// assuming that points are ordered
|
||||
for(unsigned int i=0; i<cloud->size(); ++i)
|
||||
{
|
||||
const pcl::PointXYZ & pt = cloud->at(i);
|
||||
std::vector<Eigen::Vector3f> neighborNormals;
|
||||
Eigen::Vector3f direction;
|
||||
direction[0] = viewPoint[0] - pt.x;
|
||||
direction[1] = viewPoint[1] - pt.y;
|
||||
direction[2] = viewPoint[2] - pt.z;
|
||||
|
||||
std::vector<int> k_indices;
|
||||
std::vector<float> k_sqr_distances;
|
||||
if(searchRadius>0.0f)
|
||||
{
|
||||
tree->radiusSearch(cloud->at(i), searchRadius, k_indices, k_sqr_distances, searchK);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree->nearestKSearch(cloud->at(i), searchK, k_indices, k_sqr_distances);
|
||||
}
|
||||
|
||||
for(unsigned int j=0; j<k_indices.size(); ++j)
|
||||
{
|
||||
if(k_indices.at(j) != (int)i)
|
||||
{
|
||||
const pcl::PointXYZ & pt2 = cloud->at(k_indices.at(j));
|
||||
Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
|
||||
Eigen::Vector3f up = v.cross(direction);
|
||||
Eigen::Vector3f n = up.cross(v);
|
||||
n.normalize();
|
||||
neighborNormals.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
if(neighborNormals.empty())
|
||||
{
|
||||
normals->at(i).normal_x = bad_point;
|
||||
normals->at(i).normal_y = bad_point;
|
||||
normals->at(i).normal_z = bad_point;
|
||||
}
|
||||
else
|
||||
{
|
||||
Eigen::Vector3f meanNormal(0,0,0);
|
||||
for(unsigned int j=0; j<neighborNormals.size(); ++j)
|
||||
{
|
||||
meanNormal+=neighborNormals[j];
|
||||
}
|
||||
meanNormal /= (float)neighborNormals.size();
|
||||
meanNormal.normalize();
|
||||
normals->at(i).normal_x = meanNormal[0];
|
||||
normals->at(i).normal_y = meanNormal[1];
|
||||
normals->at(i).normal_z = meanNormal[2];
|
||||
}
|
||||
}
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals2D(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||
int searchK,
|
||||
float searchRadius,
|
||||
const Eigen::Vector3f & viewPoint)
|
||||
{
|
||||
UASSERT(searchK>0);
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
|
||||
|
||||
normals->resize(cloud->size());
|
||||
searchRadius *= searchRadius; // squared distance
|
||||
|
||||
float bad_point = std::numeric_limits<float>::quiet_NaN ();
|
||||
|
||||
// assuming that points are ordered
|
||||
for(int i=0; i<(int)cloud->size(); ++i)
|
||||
{
|
||||
int li = i-searchK;
|
||||
if(li<0)
|
||||
{
|
||||
li=0;
|
||||
}
|
||||
int hi = i+searchK;
|
||||
if(hi>=(int)cloud->size())
|
||||
{
|
||||
hi=(int)cloud->size()-1;
|
||||
}
|
||||
|
||||
// get points before not too far
|
||||
const pcl::PointXYZ & pt = cloud->at(i);
|
||||
std::vector<Eigen::Vector3f> neighborNormals;
|
||||
Eigen::Vector3f direction;
|
||||
direction[0] = viewPoint[0] - cloud->at(i).x;
|
||||
direction[1] = viewPoint[1] - cloud->at(i).y;
|
||||
direction[2] = viewPoint[2] - cloud->at(i).z;
|
||||
for(int j=i-1; j>=li; --j)
|
||||
{
|
||||
const pcl::PointXYZ & pt2 = cloud->at(j);
|
||||
Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
|
||||
if(searchRadius<=0.0f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
|
||||
{
|
||||
Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
|
||||
Eigen::Vector3f up = v.cross(direction);
|
||||
Eigen::Vector3f n = up.cross(v);
|
||||
n.normalize();
|
||||
neighborNormals.push_back(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(int j=i+1; j<=hi; ++j)
|
||||
{
|
||||
const pcl::PointXYZ & pt2 = cloud->at(j);
|
||||
Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
|
||||
if(searchRadius<=0.0f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
|
||||
{
|
||||
Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
|
||||
Eigen::Vector3f up = v[2]==0.0f?Eigen::Vector3f(0,0,1):v.cross(direction);
|
||||
Eigen::Vector3f n = up.cross(v);
|
||||
n.normalize();
|
||||
neighborNormals.push_back(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(neighborNormals.empty())
|
||||
{
|
||||
normals->at(i).normal_x = bad_point;
|
||||
normals->at(i).normal_y = bad_point;
|
||||
normals->at(i).normal_z = bad_point;
|
||||
}
|
||||
else
|
||||
{
|
||||
Eigen::Vector3f meanNormal(0,0,0);
|
||||
for(unsigned int j=0; j<neighborNormals.size(); ++j)
|
||||
{
|
||||
meanNormal+=neighborNormals[j];
|
||||
}
|
||||
meanNormal /= (float)neighborNormals.size();
|
||||
meanNormal.normalize();
|
||||
normals->at(i).normal_x = meanNormal[0];
|
||||
normals->at(i).normal_y = meanNormal[1];
|
||||
normals->at(i).normal_z = meanNormal[2];
|
||||
}
|
||||
}
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::Ptr computeFastOrganizedNormals(
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||
float maxDepthChangeFactor,
|
||||
|
||||
Reference in New Issue
Block a user