Main MRPT website > C++ reference
MRPT logo
CObservation3DRangeScan_project3D_impl.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
00026    |                                                                           |
00027    +---------------------------------------------------------------------------+ */
00028 #ifndef CObservation3DRangeScan_project3D_impl_H
00029 #define CObservation3DRangeScan_project3D_impl_H
00030 
00031 namespace mrpt {
00032 namespace slam {
00033 namespace detail {
00034         // Auxiliary functions which implement SSE-optimized proyection of 3D point cloud:
00035         template <class POINTMAP> void do_project_3d_pointcloud(const int H,const int W,const float *kys,const float *kzs,const mrpt::math::CMatrix &rangeImage, mrpt::utils::PointCloudAdapter<POINTMAP> &pca);
00036         template <class POINTMAP> void do_project_3d_pointcloud_SSE2(const int H,const int W,const float *kys,const float *kzs,const mrpt::math::CMatrix &rangeImage, mrpt::utils::PointCloudAdapter<POINTMAP> &pca);
00037 
00038         template <class POINTMAP>
00039         void project3DPointsFromDepthImageInto(
00040                         CObservation3DRangeScan    & src_obs,
00041                         POINTMAP                   & dest_pointcloud,
00042                         const bool                   takeIntoAccountSensorPoseOnRobot,
00043                         const mrpt::poses::CPose3D * robotPoseInTheWorld,
00044                         const bool                   PROJ3D_USE_LUT)
00045         {
00046                 using namespace mrpt::math;
00047 
00048                 if (!src_obs.hasRangeImage) return;
00049 
00050                 mrpt::utils::PointCloudAdapter<POINTMAP> pca(dest_pointcloud);
00051 
00052                 // ------------------------------------------------------------
00053                 // Stage 1/3: Create 3D point cloud local coordinates
00054                 // ------------------------------------------------------------
00055                 const int W = src_obs.rangeImage.cols();
00056                 const int H = src_obs.rangeImage.rows();
00057                 const size_t WH = W*H;
00058 
00059                 // Reserve memory for 3D points:
00060                 pca.resize(WH);
00061 
00062                 if (src_obs.range_is_depth)
00063                 {
00064                         // range_is_depth = true
00065 
00066                         // Use cached tables?
00067                         if (PROJ3D_USE_LUT)
00068                         {
00069                                 // Use LUT:
00070                                 if (src_obs.m_3dproj_lut.prev_camParams!=src_obs.cameraParams || WH!=size_t(src_obs.m_3dproj_lut.Kys.size()))
00071                                 {
00072                                         src_obs.m_3dproj_lut.prev_camParams = src_obs.cameraParams;
00073                                         src_obs.m_3dproj_lut.Kys.resize(WH);
00074                                         src_obs.m_3dproj_lut.Kzs.resize(WH);
00075 
00076                                         const float r_cx = src_obs.cameraParams.cx();
00077                                         const float r_cy = src_obs.cameraParams.cy();
00078                                         const float r_fx_inv = 1.0f/src_obs.cameraParams.fx();
00079                                         const float r_fy_inv = 1.0f/src_obs.cameraParams.fy();
00080 
00081                                         float *kys = &src_obs.m_3dproj_lut.Kys[0];
00082                                         float *kzs = &src_obs.m_3dproj_lut.Kzs[0];
00083                                         for (int r=0;r<H;r++)
00084                                                 for (int c=0;c<W;c++)
00085                                                 {
00086                                                         *kys++ = (r_cx - c) * r_fx_inv;
00087                                                         *kzs++ = (r_cy - r) * r_fy_inv;
00088                                                 }
00089                                 } // end update LUT.
00090 
00091                                 ASSERT_EQUAL_(WH,size_t(src_obs.m_3dproj_lut.Kys.size()))
00092                                 ASSERT_EQUAL_(WH,size_t(src_obs.m_3dproj_lut.Kzs.size()))
00093                                 float *kys = &src_obs.m_3dproj_lut.Kys[0];
00094                                 float *kzs = &src_obs.m_3dproj_lut.Kzs[0];
00095 
00096         #if MRPT_HAS_SSE2
00097                                 if ((W & 0x07)==0)
00098                                                 do_project_3d_pointcloud_SSE2(H,W,kys,kzs,src_obs.rangeImage,pca);
00099                                 else    do_project_3d_pointcloud(H,W,kys,kzs,src_obs.rangeImage,pca);  // if image width is not 8*N, use standard method
00100         #else
00101                                 do_project_3d_pointcloud(H,W,kys,kzs,src_obs.rangeImage,pca);
00102         #endif
00103                         }
00104                         else
00105                         {
00106                                 // Without LUT:
00107                                 const float r_cx =  src_obs.cameraParams.cx();
00108                                 const float r_cy = src_obs.cameraParams.cy();
00109                                 const float r_fx_inv = 1.0f/src_obs.cameraParams.fx();
00110                                 const float r_fy_inv = 1.0f/src_obs.cameraParams.fy();
00111                                 size_t idx=0;
00112                                 for (int r=0;r<H;r++)
00113                                         for (int c=0;c<W;c++)
00114                                         {
00115                                                 const float Kz = (r_cy - r) * r_fy_inv;
00116                                                 const float Ky = (r_cx - c) * r_fx_inv;
00117                                                 const float D = src_obs.rangeImage.coeff(r,c);
00118                                                 pca.setPointXYZ(idx++,
00119                                                         D,        // x
00120                                                         Ky * D,   // y
00121                                                         Kz * D    // z
00122                                                         );
00123                                         }
00124                         }
00125                 }
00126                 else
00127                 {
00128                         /* range_is_depth = false :
00129                           *   Ky = (r_cx - c)/r_fx
00130                           *   Kz = (r_cy - r)/r_fy
00131                           *
00132                           *   x(i) = rangeImage(r,c) / sqrt( 1 + Ky^2 + Kz^2 )
00133                           *   y(i) = Ky * x(i)
00134                           *   z(i) = Kz * x(i)
00135                           */
00136                         const float r_cx = src_obs.cameraParams.cx();
00137                         const float r_cy = src_obs.cameraParams.cy();
00138                         const float r_fx_inv = 1.0f/src_obs.cameraParams.fx();
00139                         const float r_fy_inv = 1.0f/src_obs.cameraParams.fy();
00140                         size_t idx=0;
00141                         for (int r=0;r<H;r++)
00142                                 for (int c=0;c<W;c++)
00143                                 {
00144                                         const float Ky = (r_cx - c) * r_fx_inv;
00145                                         const float Kz = (r_cy - r) * r_fy_inv;
00146                                         const float D = src_obs.rangeImage.coeff(r,c);
00147                                         pca.setPointXYZ(idx++,
00148                                                 D / std::sqrt(1+Ky*Ky+Kz*Kz), // x
00149                                                 Ky * D,   // y
00150                                                 Kz * D    // z
00151                                                 );
00152                                 }
00153                 }
00154 
00155                 // -------------------------------------------------------------
00156                 // Stage 2/3: Project local points into RGB image to get colors
00157                 // -------------------------------------------------------------
00158                 if (src_obs.hasIntensityImage)
00159                 {
00160                         const int imgW = src_obs.intensityImage.getWidth();
00161                         const int imgH = src_obs.intensityImage.getHeight();
00162                         const bool hasColorIntensityImg = src_obs.intensityImage.isColor();
00163 
00164                         const float cx = src_obs.cameraParamsIntensity.cx();
00165                         const float cy = src_obs.cameraParamsIntensity.cy();
00166                         const float fx = src_obs.cameraParamsIntensity.fx();
00167                         const float fy = src_obs.cameraParamsIntensity.fy();
00168 
00169                         // Unless we are in a special case (both depth & RGB images coincide)...
00170                         const bool isDirectCorresp = src_obs.doDepthAndIntensityCamerasCoincide();
00171 
00172                         // ...precompute the inverse of the pose transformation out of the loop,
00173                         //  store as a 4x4 homogeneous matrix to exploit SSE optimizations below:
00174                         CMatrixFixedNumeric<float,4,4> T_inv;
00175                         if (!isDirectCorresp)
00176                         {
00177                                 CMatrixFixedNumeric<double,3,3> R_inv;
00178                                 CMatrixFixedNumeric<double,3,1> t_inv;
00179                                 mrpt::math::homogeneousMatrixInverse(
00180                                         src_obs.relativePoseIntensityWRTDepth.m_ROT,src_obs.relativePoseIntensityWRTDepth.m_coords,
00181                                         R_inv,t_inv);
00182 
00183                                 T_inv(3,3)=1;
00184                                 T_inv.block<3,3>(0,0)=R_inv.cast<float>();
00185                                 T_inv.block<3,1>(3,0)=t_inv.cast<float>();
00186                         }
00187 
00188                         Eigen::Matrix<float,4,1>  pt_wrt_color, pt_wrt_depth;
00189                         pt_wrt_depth[3]=1;
00190 
00191                         int img_idx_x=0, img_idx_y=0; // projected pixel coordinates, in the RGB image plane
00192                         mrpt::utils::TColor pCol;
00193 
00194                         // For each local point:
00195                         for (size_t i=0;i<WH;i++)
00196                         {
00197                                 bool pointWithinImage = false;
00198                                 if (isDirectCorresp)
00199                                 {
00200                                         pointWithinImage=true;
00201                                         img_idx_x++;
00202                                         if (img_idx_x>=imgW) {
00203                                                 img_idx_x=0;
00204                                                 img_idx_y++;
00205                                         }
00206                                 }
00207                                 else
00208                                 {
00209                                         // Project point, which is now in "pca" in local coordinates wrt the depth camera, into the intensity camera:
00210                                         pca.getPointXYZ(i,pt_wrt_depth[0],pt_wrt_depth[1],pt_wrt_depth[2]);
00211                                         pt_wrt_color.noalias() = T_inv*pt_wrt_depth;
00212 
00213                                         // Project to image plane:
00214                                         if (pt_wrt_color[2]) {
00215                                                 img_idx_x = mrpt::utils::round( cx + fx * pt_wrt_color[0]/pt_wrt_color[2] );
00216                                                 img_idx_y = mrpt::utils::round( cy + fy * pt_wrt_color[1]/pt_wrt_color[2] );
00217                                                 pointWithinImage=
00218                                                         img_idx_x>=0 && img_idx_x<imgW &&
00219                                                         img_idx_y>=0 && img_idx_y<imgH;
00220                                         }
00221                                 }
00222 
00223                                 if (pointWithinImage)
00224                                 {
00225                                         if (hasColorIntensityImg)  {
00226                                                 const uint8_t *c= src_obs.intensityImage.get_unsafe(img_idx_x, img_idx_y, 0);
00227                                                 pCol.R = c[2];
00228                                                 pCol.G = c[1];
00229                                                 pCol.B = c[0];
00230                                         }
00231                                         else{
00232                                                 uint8_t c= *src_obs.intensityImage.get_unsafe(img_idx_x, img_idx_y, 0);
00233                                                 pCol.R = pCol.G = pCol.B = c;
00234                                         }
00235                                 }
00236                                 else
00237                                 {
00238                                         pCol.R = pCol.G = pCol.B = 255;
00239                                 }
00240                                 // Set color:
00241                                 pca.setPointRGBu8(i,pCol.R,pCol.G,pCol.B);
00242                         } // end for each point
00243                 } // end if src_obs has intensity image
00244 
00245                 // ...
00246 
00247                 // ------------------------------------------------------------
00248                 // Stage 3/3: Apply 6D transformations
00249                 // ------------------------------------------------------------
00250                 if (takeIntoAccountSensorPoseOnRobot || robotPoseInTheWorld)
00251                 {
00252                         mrpt::poses::CPose3D  transf_to_apply; // Either ROBOTPOSE or ROBOTPOSE(+)SENSORPOSE or SENSORPOSE
00253                         if (takeIntoAccountSensorPoseOnRobot)
00254                                 transf_to_apply = src_obs.sensorPose;
00255                         if (robotPoseInTheWorld)
00256                                 transf_to_apply.composeFrom(*robotPoseInTheWorld, CPose3D(transf_to_apply));
00257 
00258                         const CMatrixFixedNumeric<float,4,4> HM = transf_to_apply.getHomogeneousMatrixVal().cast<float>();
00259                         Eigen::Matrix<float,4,1>  pt, pt_transf;
00260                         pt[3]=1;
00261 
00262                         for (size_t i=0;i<WH;i++)
00263                         {
00264                                 pca.getPointXYZ(i,pt[0],pt[1],pt[2]);
00265                                 pt_transf.noalias() = HM*pt;
00266                                 pca.setPointXYZ(i,pt_transf[0],pt_transf[1],pt_transf[2]);
00267                         }
00268                 }
00269         } // end of project3DPointsFromDepthImageInto
00270 
00271         // Auxiliary functions which implement proyection of 3D point clouds:
00272         template <class POINTMAP>
00273         inline void do_project_3d_pointcloud(const int H,const int W,const float *kys,const float *kzs,const mrpt::math::CMatrix &rangeImage, mrpt::utils::PointCloudAdapter<POINTMAP> &pca)
00274         {
00275                 size_t idx=0;
00276                 for (int r=0;r<H;r++)
00277                         for (int c=0;c<W;c++)
00278                         {
00279                                 const float D = rangeImage.coeff(r,c);
00280                                 pca.setPointXYZ(idx++,
00281                                         D,          // x
00282                                         *kys++ * D, // y
00283                                         *kzs++ * D  // z
00284                                         );
00285                         }
00286         }
00287 
00288         // Auxiliary functions which implement proyection of 3D point clouds:
00289         template <class POINTMAP>
00290         inline void do_project_3d_pointcloud_SSE2(const int H,const int W,const float *kys,const float *kzs,const mrpt::math::CMatrix &rangeImage, mrpt::utils::PointCloudAdapter<POINTMAP> &pca)
00291         {
00292         #if MRPT_HAS_SSE2
00293                         // Use optimized version:
00294                         const int W_4 = W >> 2;  // /=4 , since we process 4 values at a time.
00295                         size_t idx=0;
00296                         EIGEN_ALIGN16 float xs[4],ys[4],zs[4];
00297                         for (int r=0;r<H;r++)
00298                         {
00299                                 const float *D_ptr = &rangeImage.coeffRef(r,0);  // Matrices are 16-aligned
00300 
00301                                 for (int c=0;c<W_4;c++)
00302                                 {
00303                                         const __m128 D = _mm_load_ps(D_ptr);
00304 
00305                                         const __m128 KY = _mm_load_ps(kys);
00306                                         const __m128 KZ = _mm_load_ps(kzs);
00307 
00308                                         _mm_storeu_ps(xs , D);
00309                                         _mm_storeu_ps(ys , _mm_mul_ps(KY,D));
00310                                         _mm_storeu_ps(zs , _mm_mul_ps(KZ,D));
00311 
00312                                         D_ptr+=4;
00313                                         kys+=4;
00314                                         kzs+=4;
00315                                         pca.setPointXYZ(idx++,xs[0],ys[0],zs[0]);
00316                                         pca.setPointXYZ(idx++,xs[1],ys[1],zs[1]);
00317                                         pca.setPointXYZ(idx++,xs[2],ys[2],zs[2]);
00318                                         pca.setPointXYZ(idx++,xs[3],ys[3],zs[3]);
00319                                 }
00320                         }
00321         #endif
00322         }
00323 
00324 
00325 } // End of namespace
00326 } // End of namespace
00327 } // End of namespace
00328 
00329 #endif



Page generated by Doxygen 1.7.4 for MRPT 0.9.5 SVN:2717 at Sun Oct 16 16:08:03 PDT 2011 Hosted on:
SourceForge.net Logo