9 #ifndef CObservation3DRangeScan_project3D_impl_H 10 #define CObservation3DRangeScan_project3D_impl_H 18 template <
class POINTMAP>
void do_project_3d_pointcloud(
const int H,
const int W,
const float *kys,
const float *kzs,
mrpt::math::CMatrix &rangeImage,
mrpt::utils::PointCloudAdapter<POINTMAP> &pca, std::vector<uint16_t> &idxs_x, std::vector<uint16_t> &idxs_y,
const mrpt::obs::TRangeImageFilterParams &fp,
bool MAKE_DENSE,
const int DECIM);
21 template <
typename POINTMAP,
bool isDepth>
41 for (
int r = 0;
r < H;
r++)
42 for (
int c = 0;
c < W;
c++)
47 const float Ky = (r_cx -
c) * r_fx_inv;
48 const float Kz = (r_cy -
r) * r_fy_inv;
51 isDepth ? D : D / std::sqrt(1 + Ky * Ky + Kz * Kz),
68 template <
typename POINTMAP,
bool isDepth>
76 const size_t WH = W * H;
91 for (
int r = 0;
r < H;
r++)
92 for (
int c = 0;
c < W;
c++)
94 *kys++ = (r_cx -
c) * r_fx_inv;
95 *kzs++ = (r_cy -
r) * r_fy_inv;
116 if ((W & 0x07) == 0 && pp.
USE_SSE2 && DECIM == 1)
127 template <
class POINTMAP>
145 const size_t WH = W * H;
162 range2XYZ_LUT<POINTMAP, true>(pca, src_obs, pp, fp, H, W);
164 range2XYZ<POINTMAP, true>(pca, src_obs, fp, H, W);
167 range2XYZ<POINTMAP, false>(pca, src_obs, fp, H, W);
174 (W % DECIM) == 0 && (H % DECIM == 0),
175 "Width/Height are not an exact multiple of decimation");
176 const int Wd = W / DECIM;
177 const int Hd = H / DECIM;
179 const size_t WHd = Wd * Hd;
186 "Decimation only available if range_is_depth && PROJ3D_USE_LUT");
187 range2XYZ_LUT<POINTMAP, true>(pca, src_obs, pp, fp, H, W, DECIM);
210 if (!isDirectCorresp)
219 T_inv.block<3,3>(0,0)=R_inv.cast<
float>();
220 T_inv.block<3,1>(0,3)=t_inv.cast<
float>();
223 Eigen::Matrix<float,4,1> pt_wrt_color, pt_wrt_depth;
229 const size_t nPts = pca.size();
230 for (
size_t i=0;i<nPts;i++)
232 int img_idx_x, img_idx_y;
233 bool pointWithinImage =
false;
236 pointWithinImage=
true;
243 pca.getPointXYZ(i,pt_wrt_depth[0],pt_wrt_depth[1],pt_wrt_depth[2]);
244 pt_wrt_color.noalias() = T_inv*pt_wrt_depth;
247 if (pt_wrt_color[2]) {
251 img_idx_x>=0 && img_idx_x<imgW &&
252 img_idx_y>=0 && img_idx_y<imgH;
256 if (pointWithinImage)
258 if (hasColorIntensityImg) {
266 pCol.
R = pCol.
G = pCol.
B =
c;
271 pCol.
R = pCol.
G = pCol.
B = 255;
274 pca.setPointRGBu8(i,pCol.
R,pCol.
G,pCol.
B);
292 Eigen::Matrix<float,4,1> pt, pt_transf;
295 const size_t nPts = pca.size();
296 for (
size_t i=0;i<nPts;i++)
298 pca.getPointXYZ(i,pt[0],pt[1],pt[2]);
299 pt_transf.noalias() = HM*pt;
300 pca.setPointXYZ(i,pt_transf[0],pt_transf[1],pt_transf[2]);
306 template <
class POINTMAP>
308 const int H,
const int W,
const float* kys,
const float* kzs,
311 std::vector<uint16_t>& idxs_x, std::vector<uint16_t>& idxs_y,
320 for (
int r = 0;
r < H;
r++)
321 for (
int c = 0;
c < W;
c++)
323 const float D = rangeImage.coeff(
r,
c);
325 const auto ky = *kys++, kz = *kzs++;
328 if (!MAKE_DENSE) pca.setInvalidPoint(idx++);
332 pca.setPointXYZ(idx, D , ky * D , kz * D );
340 const int Hd = H / DECIM, Wd = W / DECIM;
342 for (
int rd = 0; rd < Hd; rd++)
343 for (
int cd = 0; cd < Wd; cd++)
345 bool valid_pt =
false;
346 float min_d = std::numeric_limits<float>::max();
347 for (
int rb = 0; rb < DECIM; rb++)
348 for (
int cb = 0; cb < DECIM; cb++)
350 const auto r = rd * DECIM + rb,
c = cd * DECIM + cb;
351 const float D = rangeImage.coeff(
r,
c);
355 if (D < min_d) min_d = D;
360 rangeImage.coeffRef(
r,
c) = 0;
365 if (!MAKE_DENSE) pca.setInvalidPoint(idx++);
368 const auto eq_r = rd * DECIM + DECIM / 2,
369 eq_c = cd * DECIM + DECIM / 2;
370 const auto ky = kys[eq_c + eq_r * W], kz = kzs[eq_c + eq_r * W];
372 idx, min_d , ky * min_d , kz * min_d );
386 template <
class POINTMAP>
392 const int W_4 = W >> 2;
395 const __m128 D_zeros = _mm_set_ps(.0f,.0f,.0f,.0f);
397 _mm_cmpneq_ps(D_zeros,D_zeros) :
398 _mm_cmpeq_ps(D_zeros,D_zeros);
399 for (
int r=0;
r<H;
r++)
401 const float *D_ptr = &rangeImage.coeffRef(
r,0);
405 for (
int c=0;
c<W_4;
c++)
407 const __m128 D = _mm_load_ps(D_ptr);
408 const __m128 nz_mask = _mm_cmpgt_ps(D, D_zeros);
409 __m128 valid_range_mask;
412 valid_range_mask = nz_mask;
420 const __m128 Dmin = _mm_load_ps(Dgt_ptr);
421 valid_range_mask = _mm_or_ps(
422 _mm_cmpgt_ps(D, Dmin), _mm_cmpeq_ps(Dmin, D_zeros));
426 const __m128 Dmax = _mm_load_ps(Dlt_ptr);
427 valid_range_mask = _mm_or_ps(
428 _mm_cmplt_ps(D, Dmax), _mm_cmpeq_ps(Dmax, D_zeros));
430 valid_range_mask = _mm_and_ps(
431 valid_range_mask, nz_mask);
437 const __m128 Dmin = _mm_load_ps(Dgt_ptr);
438 const __m128 Dmax = _mm_load_ps(Dlt_ptr);
440 const __m128 gt_mask = _mm_or_ps(
441 _mm_cmpgt_ps(D, Dmin), _mm_cmpeq_ps(Dmin, D_zeros));
442 const __m128 lt_mask = _mm_or_ps(
443 _mm_cmplt_ps(D, Dmax), _mm_cmpeq_ps(Dmax, D_zeros));
446 _mm_and_ps(nz_mask, _mm_and_ps(gt_mask, lt_mask));
447 valid_range_mask = _mm_xor_ps(valid_range_mask, xormask);
449 valid_range_mask = _mm_or_ps(
450 valid_range_mask, _mm_and_ps(
451 _mm_cmpeq_ps(Dmin, D_zeros),
452 _mm_cmpeq_ps(Dmax, D_zeros)));
454 valid_range_mask = _mm_and_ps(valid_range_mask, nz_mask);
457 const int valid_range_maski = _mm_movemask_epi8(_mm_castps_si128(valid_range_mask));
458 if (valid_range_maski!=0)
460 const __m128 KY = _mm_load_ps(kys);
461 const __m128 KZ = _mm_load_ps(kzs);
463 _mm_storeu_ps(xs , D);
464 _mm_storeu_ps(ys , _mm_mul_ps(KY,D));
465 _mm_storeu_ps(zs , _mm_mul_ps(KZ,D));
467 for (
int q=0;
q<4;
q++)
469 const int actual_c = (
c << 2) +
q;
470 if ((valid_range_maski & (1<<(
q*4))) !=0) {
471 pca.setPointXYZ(idx,xs[
q],ys[
q],zs[
q]);
472 idxs_x[idx]=actual_c;
480 pca.setInvalidPoint(idx);
484 rangeImage.coeffRef(
r, actual_c) = 0;
488 else if (!MAKE_DENSE)
490 for(
int q=0;
q<4;
q++)
492 pca.setInvalidPoint(idx);
494 const int actual_c = (
c << 2) +
q;
496 rangeImage.coeffRef(
r, actual_c) = 0;
500 if (Dgt_ptr) Dgt_ptr+=4;
501 if (Dlt_ptr) Dlt_ptr+=4;
#define ASSERT_EQUAL_(__A, __B)
void range2XYZ_LUT(mrpt::utils::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=1)
Mainly for internal use within CObservation3DRangeScan::project3DPointsFromDepthImageInto() ...
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: NULL) Read takeIntoAccountSensorPoseOnRobot
void range2XYZ(mrpt::utils::PointCloudAdapter< POINTMAP > &pca, mrpt::obs::CObservation3DRangeScan &src_obs, const mrpt::obs::TRangeImageFilterParams &fp, const int H, const int W)
mrpt::utils::TCamera cameraParamsIntensity
Projection parameters of the intensity (graylevel or RGB) camera.
mrpt::math::CVectorFloat Kzs
GLdouble GLdouble GLdouble GLdouble q
std::vector< uint16_t > points3D_idxs_x
double cy() const
Get the value of the principal point y-coordinate (in pixels).
Declares a class derived from "CObservation" that encapsules a 3D range scan measurement, as from a time-of-flight range camera or any other RGBD sensor.
const mrpt::math::CMatrix * rangeMask_min
(Default: NULL) If provided, each data range will be tested to be greater-than (rangeMask_min) or les...
Used in CObservation3DRangeScan::project3DPointsFromDepthImageInto()
mrpt::math::CMatrix rangeImage
If hasRangeImage=true, a matrix of floats with the range data as captured by the camera (in meters) ...
mrpt::utils::TCamera cameraParams
Projection parameters of the depth camera.
double fx() const
Get the value of the focal length x-value (in pixels).
double fy() const
Get the value of the focal length y-value (in pixels).
A numeric matrix of compile-time fixed size.
This base provides a set of functions for maths stuff.
mrpt::poses::CPose3D relativePoseIntensityWRTDepth
Relative pose of the intensity camera wrt the depth camera (which is the coordinates origin for this ...
std::vector< uint16_t > points3D_idxs_y
//!< If hasPoints3D=true, the (x,y) pixel coordinates for each (X,Y,Z) point in points3D_x, points3D_y, points3D_z
mrpt::math::CArrayDouble< 3 > m_coords
The translation vector [x,y,z] access directly or with x(), y(), z() setter/getter methods...
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...
mrpt::math::CMatrixDouble44 getHomogeneousMatrixVal() const
void project3DPointsFromDepthImageInto(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
void do_project_3d_pointcloud(const int H, const int W, const float *kys, const float *kzs, mrpt::math::CMatrix &rangeImage, mrpt::utils::PointCloudAdapter< POINTMAP > &pca, std::vector< uint16_t > &idxs_x, std::vector< uint16_t > &idxs_y, const mrpt::obs::TRangeImageFilterParams &fp, bool MAKE_DENSE, const int DECIM)
An adapter to different kinds of point cloud object.
mrpt::math::CVectorFloat Kys
double cx() const
Get the value of the principal point x-coordinate (in pixels).
static TCached3DProjTables m_3dproj_lut
3D point cloud projection look-up-table
bool mark_invalid_ranges
If enabled, the range pixels of points that do NOT pass the mask filter will be marked as invalid ran...
bool USE_SSE2
(Default:true) If possible, use SSE2 optimized code.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
GLdouble GLdouble GLdouble r
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot.
const mrpt::math::CMatrix * rangeMask_max
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...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
void do_project_3d_pointcloud_SSE2(const int H, const int W, const float *kys, const float *kzs, mrpt::math::CMatrix &rangeImage, mrpt::utils::PointCloudAdapter< POINTMAP > &pca, std::vector< uint16_t > &idxs_x, std::vector< uint16_t > &idxs_y, const mrpt::obs::TRangeImageFilterParams &fp, bool MAKE_DENSE)
Used in CObservation3DRangeScan::project3DPointsFromDepthImageInto()
bool hasIntensityImage
true means the field intensityImage contains valid data
int round(const T value)
Returns the closer integer (int) to x.
bool PROJ3D_USE_LUT
(Default:true) [Only used when range_is_depth=true] Whether to use a Look-up-table (LUT) to speed up ...
bool doDepthAndIntensityCamerasCoincide() const
Return true if relativePoseIntensityWRTDepth equals the pure rotation (0,0,0,-90deg,0,-90deg) (with a small comparison epsilon)
bool isColor() const
Returns true if the image is RGB, false if it is grayscale.
unsigned char * get_unsafe(unsigned int col, unsigned int row, unsigned int channel=0) const
Access to pixels without checking boundaries - Use normally the () operator better, which checks the coordinates.
An adapter to different kinds of point cloud object.
void getRotationMatrix(mrpt::math::CMatrixDouble33 &ROT) const
Get the 3x3 rotation matrix.
bool MAKE_DENSE
(Default:true) set to false if you want to preserve the organization of the point cloud ...
mrpt::utils::CImage intensityImage
If hasIntensityImage=true, a color or gray-level intensity image of the same size than "rangeImage"...
This class is a "CSerializable" wrapper for "CMatrixFloat".
bool range_is_depth
true: Kinect-like ranges: entries of rangeImage are distances along the +X axis; false: Ranges in ran...
#define ASSERTMSG_(f, __ERROR_MSG)
size_t getWidth() const MRPT_OVERRIDE
Returns the width of the image in pixels.
bool takeIntoAccountSensorPoseOnRobot
(Default: false) If false, local (sensor-centric) coordinates of points are generated. Otherwise, points are transformed with sensorPose. Furthermore, if provided, those coordinates are transformed with robotPoseInTheWorld
size_t getHeight() const MRPT_OVERRIDE
Returns the height of the image in pixels.
mrpt::utils::TCamera prev_camParams
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.