18 #include <Eigen/Dense>      24 template <
class POINTMAP>
    26     const int H, 
const int W, 
const float* kxs, 
const float* kys,
    29     std::vector<uint16_t>& idxs_x, std::vector<uint16_t>& idxs_y,
    32 template <
class POINTMAP>
    34     const int H, 
const int W, 
const float* kxs, 
const float* kys,
    37     std::vector<uint16_t>& idxs_x, std::vector<uint16_t>& idxs_y,
    40 template <
typename POINTMAP>
    46     const int DECIM, 
const bool use_rotated_LUT)
    48     const size_t WH = W * H;
    52     const auto& Kxs = use_rotated_LUT ? lut.
Kxs_rot : lut.Kxs;
    53     const auto& Kys = use_rotated_LUT ? lut.Kys_rot : lut.Kys;
    54     const auto& Kzs = use_rotated_LUT ? lut.Kzs_rot : lut.Kzs;
    59     const float* kxs = &Kxs[0];
    60     const float* kys = &Kys[0];
    61     const float* kzs = &Kzs[0];
    80     if ((W & 0x07) == 0 && pp.
USE_SSE2 && DECIM == 1 &&
    83             H, W, kxs, kys, kzs, *ri, src_obs.
rangeUnits, pca,
    89             H, W, kxs, kys, kzs, *ri, src_obs.
rangeUnits, pca,
    96         const size_t nPts = pca.size();
   100         for (
size_t i = 0; i < nPts; i++)
   103             pca.getPointXYZ(i, pt.
x, pt.
y, pt.
z);
   105             pca.setPointXYZ(i, pt.
x, pt.
y, pt.
z);
   110 template <
class POINTMAP>
   125     if (!pp.
layer.empty())
   136     const bool use_rotated_LUT =
   150     const size_t WH = W * H;
   168             (W % DECIM) == 0 && (H % DECIM == 0),
   169             "Width/Height are not an exact multiple of decimation");
   170         const int Wd = W / DECIM;
   171         const int Hd = H / DECIM;
   173         const size_t WHd = Wd * Hd;
   179     range2XYZ_LUT<POINTMAP>(pca, src_obs, pp, fp, H, W, DECIM, use_rotated_LUT);
   184     if constexpr (pca.HAS_RGB)
   186         if (src_obs.hasIntensityImage)
   188             const int imgW = src_obs.intensityImage.getWidth();
   189             const int imgH = src_obs.intensityImage.getHeight();
   190             const bool hasColorIntensityImg = src_obs.intensityImage.isColor();
   192             const float cx = src_obs.cameraParamsIntensity.cx();
   193             const float cy = src_obs.cameraParamsIntensity.cy();
   194             const float fx = src_obs.cameraParamsIntensity.fx();
   195             const float fy = src_obs.cameraParamsIntensity.fy();
   199             const bool isDirectCorresp =
   200                 src_obs.doDepthAndIntensityCamerasCoincide();
   209             if (!isDirectCorresp)
   214                     src_obs.relativePoseIntensityWRTDepth.getRotationMatrix(),
   215                     src_obs.relativePoseIntensityWRTDepth.m_coords, R_inv,
   228             const size_t nPts = pca.size();
   229             const auto& iimg = src_obs.intensityImage;
   230             const uint8_t* img_data = iimg.ptrLine<uint8_t>(0);
   231             const auto img_stride = iimg.getRowStride();
   232             for (
size_t i = 0; i < nPts; i++)
   237                 bool pointWithinImage = 
false;
   240                     pointWithinImage = 
true;
   241                     img_idx_x = src_obs.points3D_idxs_x[i];
   242                     img_idx_y = src_obs.points3D_idxs_y[i];
   250                         i, pt_wrt_depth[0], pt_wrt_depth[1], pt_wrt_depth[2]);
   251                     pt_wrt_color = T_inv * pt_wrt_depth;
   257                             cx + fx * pt_wrt_color[0] / pt_wrt_color[2]);
   259                             cy + fy * pt_wrt_color[1] / pt_wrt_color[2]);
   260                         pointWithinImage = img_idx_x >= 0 && img_idx_x < imgW &&
   261                                            img_idx_y >= 0 && img_idx_y < imgH;
   265                 if (pointWithinImage)
   267                     if (hasColorIntensityImg)
   270                             img_stride * img_idx_y + 3 * img_idx_x;
   271                         pCol.
R = img_data[px_idx + 2];
   272                         pCol.
G = img_data[px_idx + 1];
   273                         pCol.
B = img_data[px_idx + 0];
   277                         const auto px_idx = img_stride * img_idx_y + img_idx_x;
   278                         pCol.
R = pCol.
G = pCol.
B = img_data[px_idx];
   283                     pCol.
R = pCol.
G = pCol.
B = 255;
   286                 pca.setPointRGBu8(i, pCol.
R, pCol.
G, pCol.
B);
   295     if (!use_rotated_LUT &&
   296         (pp.takeIntoAccountSensorPoseOnRobot || pp.robotPoseInTheWorld))
   301         if (pp.takeIntoAccountSensorPoseOnRobot)
   302             transf_to_apply = src_obs.sensorPose;
   303         if (pp.robotPoseInTheWorld)
   314         const size_t nPts = pca.
size();
   315         for (
size_t i = 0; i < nPts; i++)
   317             pca.getPointXYZ(i, pt[0], pt[1], pt[2]);
   319             pca.setPointXYZ(i, pt_transf[0], pt_transf[1], pt_transf[2]);
   325 template <
class POINTMAP>
   327     const int H, 
const int W, 
const float* kxs, 
const float* kys,
   330     std::vector<uint16_t>& idxs_x, std::vector<uint16_t>& idxs_y,
   339         for (
int r = 0; r < H; r++)
   340             for (
int c = 0; c < W; c++)
   342                 const float D = rangeImage.
coeff(r, c) * rangeUnits;
   344                 const auto kx = *kxs++, ky = *kys++, kz = *kzs++;
   347                     if (MAKE_ORGANIZED) pca.setInvalidPoint(idx++);
   351                 pca.setPointXYZ(idx, kx * D, ky * D , kz * D );
   359         const int Hd = H / DECIM, Wd = W / DECIM;
   361         for (
int rd = 0; rd < Hd; rd++)
   362             for (
int cd = 0; cd < Wd; cd++)
   364                 bool valid_pt = 
false;
   365                 float min_d = std::numeric_limits<float>::max();
   366                 for (
int rb = 0; rb < DECIM; rb++)
   367                     for (
int cb = 0; cb < DECIM; cb++)
   369                         const auto r = rd * DECIM + rb, c = cd * DECIM + cb;
   370                         const float D = rangeImage.
coeff(r, c) * rangeUnits;
   374                             if (D < min_d) min_d = D;
   384                     if (MAKE_ORGANIZED) pca.setInvalidPoint(idx++);
   387                 const auto eq_r = rd * DECIM + DECIM / 2,
   388                            eq_c = cd * DECIM + DECIM / 2;
   389                 const auto eq_idx = eq_c + eq_r * W;
   390                 const auto kx = kxs[eq_idx], ky = kys[eq_idx], kz = kzs[eq_idx];
   392                     idx, kx * min_d , ky * min_d , kz * min_d );
   406 template <
class POINTMAP>
   408     const int H, 
const int W, 
const float* kxs, 
const float* kys,
   411     std::vector<uint16_t>& idxs_x, std::vector<uint16_t>& idxs_y,
   417     const int W_4 = W >> 2;  
   419     alignas(MRPT_MAX_STATIC_ALIGN_BYTES) 
float xs[4], ys[4], zs[4];
   420     const __m128 D_zeros = _mm_set_ps(.0f, .0f, .0f, .0f);
   421     const __m128 xormask =
   427     for (
int r = 0; r < H; r++)
   429         const uint16_t* Du16_ptr = &rangeImage(r, 0);
   430         const float* Dgt_ptr =
   432         const float* Dlt_ptr =
   435         for (
int c = 0; c < W_4; c++)
   439             alignas(16) 
float tmp[4];
   440             for (
int b = 0; b < 4; b++) tmp[b] = Du16_ptr[b] * rangeUnits;
   442             const __m128 D = _mm_load_ps(&tmp[0]);
   443             const __m128 nz_mask = _mm_cmpgt_ps(D, D_zeros);
   444             __m128 valid_range_mask;
   447                 valid_range_mask = nz_mask;
   455                         const __m128 Dmin = _mm_load_ps(Dgt_ptr);
   456                         valid_range_mask = _mm_or_ps(
   457                             _mm_cmpgt_ps(D, Dmin), _mm_cmpeq_ps(Dmin, D_zeros));
   461                         const __m128 Dmax = _mm_load_ps(Dlt_ptr);
   462                         valid_range_mask = _mm_or_ps(
   463                             _mm_cmplt_ps(D, Dmax), _mm_cmpeq_ps(Dmax, D_zeros));
   465                     valid_range_mask = _mm_and_ps(
   466                         valid_range_mask, nz_mask);  
   472                     const __m128 Dmin = _mm_load_ps(Dgt_ptr);
   473                     const __m128 Dmax = _mm_load_ps(Dlt_ptr);
   475                     const __m128 gt_mask = _mm_or_ps(
   476                         _mm_cmpgt_ps(D, Dmin), _mm_cmpeq_ps(Dmin, D_zeros));
   477                     const __m128 lt_mask = _mm_or_ps(
   478                         _mm_cmplt_ps(D, Dmax), _mm_cmpeq_ps(Dmax, D_zeros));
   481                         _mm_and_ps(nz_mask, _mm_and_ps(gt_mask, lt_mask));
   482                     valid_range_mask = _mm_xor_ps(valid_range_mask, xormask);
   484                     valid_range_mask = _mm_or_ps(
   485                         valid_range_mask, _mm_and_ps(
   486                                               _mm_cmpeq_ps(Dmin, D_zeros),
   487                                               _mm_cmpeq_ps(Dmax, D_zeros)));
   489                     valid_range_mask = _mm_and_ps(valid_range_mask, nz_mask);
   492             const int valid_range_maski = _mm_movemask_epi8(
   493                 _mm_castps_si128(valid_range_mask));  
   494             if (valid_range_maski != 0)  
   496                 const __m128 KX = _mm_load_ps(kxs);
   497                 const __m128 KY = _mm_load_ps(kys);
   498                 const __m128 KZ = _mm_load_ps(kzs);
   500                 _mm_storeu_ps(xs, _mm_mul_ps(KX, D));
   501                 _mm_storeu_ps(ys, _mm_mul_ps(KY, D));
   502                 _mm_storeu_ps(zs, _mm_mul_ps(KZ, D));
   504                 for (
int q = 0; q < 4; q++)
   506                     const int actual_c = (c << 2) + q;
   507                     if ((valid_range_maski & (1 << (q * 4))) != 0)
   509                         pca.setPointXYZ(idx, xs[q], ys[q], zs[q]);
   510                         idxs_x[idx] = actual_c;
   518                             pca.setInvalidPoint(idx);
   522                             rangeImage.
coeffRef(r, actual_c) = 0;
   526             else if (MAKE_ORGANIZED)
   528                 for (
int q = 0; q < 4; q++)
   530                     pca.setInvalidPoint(idx);
   532                     const int actual_c = (c << 2) + q;
   534                         rangeImage.
coeffRef(r, actual_c) = 0;
   538             if (Dgt_ptr) Dgt_ptr += 4;
   539             if (Dlt_ptr) Dlt_ptr += 4;
 
std::map< std::string, mrpt::math::CMatrix_u16 > rangeImageOtherLayers
Additional layer range/depth images. 
 
Mainly for internal use within CObservation3DRangeScan::unprojectInto() 
 
constexpr matrix_size_t size() const
Get a 2-vector with [NROWS NCOLS] (as in MATLAB command size(x)) 
 
uint8_t decimation
(Default:1) If !=1, split the range image in blocks of DxD (D=decimation), and only generates one poi...
 
void resizePoints3DVectors(const size_t nPoints)
Use this method instead of resizing all three points3D_x, points3D_y & points3D_z to allow the usage ...
 
const mrpt::poses::CPose3D * robotPoseInTheWorld
(Default: nullptr) Read takeIntoAccountSensorPoseOnRobot 
 
An adapter to different kinds of point cloud object. 
 
std::vector< uint16_t > points3D_idxs_x
If hasPoints3D=true, the (x,y) pixel coordinates for each (X,Y,Z) point in points3D_x, points3D_y, points3D_z. 
 
void insertMatrix(const int row_start, const int col_start, const OTHERMATVEC &submat)
Copies the given input submatrix/vector into this matrix/vector, starting at the given top-left coord...
 
A range or depth 3D scan measurement, as from a time-of-flight range camera or a structured-light dep...
 
Used in CObservation3DRangeScan::unprojectInto() 
 
bool supports(feature f) noexcept
Returns true if the current CPU (and OS) supports the given CPU feature. 
 
const mrpt::math::CMatrixF * rangeMask_max
 
#define ASSERT_(f)
Defines an assertion mechanism. 
 
This base provides a set of functions for maths stuff. 
 
An adapter to different kinds of point cloud object. 
 
std::vector< uint16_t > points3D_idxs_y
 
void composeFrom(const CPose3D &A, const CPose3D &B)
Makes "this = A (+) B"; this method is slightly more efficient than "this= A + B;" since it avoids th...
 
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure. 
 
mrpt::aligned_std_vector< float > Kxs_rot
x,y,z: in the rotated frame of coordinates of the sensorPose. 
 
void unprojectInto(mrpt::obs::CObservation3DRangeScan &src_obs, POINTMAP &dest_pointcloud, const mrpt::obs::T3DPointsProjectionParams &projectParams, const mrpt::obs::TRangeImageFilterParams &filterParams)
 
bool hasRangeImage
true means the field rangeImage contains valid data 
 
mrpt::math::CMatrix_u16 rangeImage
If hasRangeImage=true, a matrix of floats with the range data as captured by the camera (in meters)...
 
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism. 
 
double x() const
Common members of all points & poses classes. 
 
const mrpt::math::CMatrixF * rangeMask_min
(Default: nullptr) If provided, each data range will be tested to be greater-than (rangeMask_min) or ...
 
size_type rows() const
Number of rows in the matrix. 
 
size_type cols() const
Number of columns in the matrix. 
 
bool mark_invalid_ranges
If enabled, the range pixels of points that do NOT pass the mask filter will be marked as invalid ran...
 
const Scalar & coeff(int r, int c) const
 
bool USE_SSE2
(Default:true) If possible, use SSE2 optimized code. 
 
bool MAKE_ORGANIZED
(Default:false) set to true if you want an organized point cloud 
 
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot. 
 
void range2XYZ_LUT(mrpt::opengl::PointCloudAdapter< POINTMAP > &pca, mrpt::obs::CObservation3DRangeScan &src_obs, const mrpt::obs::T3DPointsProjectionParams &pp, const mrpt::obs::TRangeImageFilterParams &fp, const int H, const int W, const int DECIM, const bool use_rotated_LUT)
 
void homogeneousMatrixInverse(const MATRIXLIKE1 &M, MATRIXLIKE2 &out_inverse_M)
Efficiently compute the inverse of a 4x4 homogeneous matrix by only transposing the rotation 3x3 part...
 
CMatrixFixed< float, ROWS, COLS > cast_float() const
 
A class used to store a 3D pose (a 3D translation + a rotation in 3D). 
 
Used in CObservation3DRangeScan::unprojectInto() 
 
bool hasIntensityImage
true means the field intensityImage contains valid data 
 
MATRIX44 getHomogeneousMatrixVal() const
Returns the corresponding 4x4 homogeneous transformation matrix for the point(translation) or pose (t...
 
TPoint3D_< float > TPoint3Df
 
void do_project_3d_pointcloud(const int H, const int W, const float *kxs, const float *kys, const float *kzs, mrpt::math::CMatrix_u16 &rangeImage, const float rangeUnits, mrpt::opengl::PointCloudAdapter< POINTMAP > &pca, std::vector< uint16_t > &idxs_x, std::vector< uint16_t > &idxs_y, const mrpt::obs::TRangeImageFilterParams &fp, bool MAKE_ORGANIZED, const int DECIM)
 
std::string layer
If empty, the main rangeImage layer will be unprojected. 
 
void do_project_3d_pointcloud_SSE2(const int H, const int W, const float *kxs, const float *kys, const float *kzs, mrpt::math::CMatrix_u16 &rangeImage, const float rangeUnits, mrpt::opengl::PointCloudAdapter< POINTMAP > &pca, std::vector< uint16_t > &idxs_x, std::vector< uint16_t > &idxs_y, const mrpt::obs::TRangeImageFilterParams &fp, bool MAKE_ORGANIZED)
 
float rangeUnits
The conversion factor from integer units in rangeImage and actual distances in meters. 
 
bool takeIntoAccountSensorPoseOnRobot
(Default: false) If false, local (sensor-centric) coordinates of points are generated. 
 
const unproject_LUT_t & get_unproj_lut() const
Gets (or generates upon first request) the 3D point cloud projection look-up-table for the current de...
 
Scalar & coeffRef(int r, int c)
 
bool do_range_filter(size_t r, size_t c, const float D) const
Returns true if the point (r,c) with depth D passes all filters. 
 
bool rangeCheckBetween
Only used if both rangeMask_min and rangeMask_max are present. 
 
int round(const T value)
Returns the closer integer (int) to x.