Kiretu
|
00001 /* This file is part of the Kiretu, a Kinect reconstruction tutor. 00002 * 00003 * http://pille.iwr.uni-heidelberg.de/~kinect01/ 00004 * 00005 * The code ist licensed to you under the terms of the GNU General Public 00006 * License, version 2.0. See the GPL2 file for the text of the license or the 00007 * following URL: 00008 * 00009 * http://www.gnu.org/licenses/gpl-2.0.txt 00010 * 00011 * If you redistribute this file in source form, modified or unmodified, you 00012 * have to leave this header intact and distribute it under the same terms with 00013 * the GPL2 file. 00014 * 00015 * Binary distributions must follow the binary distribution requirements of 00016 * the License. 00017 * 00018 */ 00019 00020 /** \file KinectCloud.h 00021 * 00022 * Header file of the KinectCloud-class. 00023 * 00024 * \author Daniel Wunderlich (d.wunderlich@stud.uni-heidelberg.de) 00025 * \version 0.8 00026 * \date 2011-01-26 00027 * 00028 * \see KinectCloud 00029 */ 00030 00031 #include <vector> 00032 #include <iostream> 00033 #include <cmath> 00034 00035 //~ #include <vcg/simplex/vertex/base.h> 00036 //~ #include <vcg/simplex/vertex/component.h> 00037 //~ #include <vcg/space/normal_extrapolation.h> 00038 //~ #include <vcg/complex/used_types.h> 00039 00040 #include "Util.h" 00041 //~ #include "NormalReconstruction.h" 00042 00043 /** \class KinectCloud 00044 * \brief C++-class which represents a point-cloud of Microsoft's Kinect and 00045 * allows the reconstruction of a point-cloud applying the steps 00046 * explained at the documentation. 00047 * 00048 * \author Daniel Wunderlich (d.wunderlich@stud.uni-heidelberg.de) 00049 * \version 0.8 00050 * \date 2011-01-26 00051 * \see \ref reconstruction and \ref kinectcloud-section 00052 */ 00053 class KinectCloud { 00054 00055 public: 00056 00057 /** \brief Constructor of the KinectCloud-class. 00058 */ 00059 KinectCloud(); 00060 00061 00062 /** \brief Destructor of the KinectCloud-class. 00063 */ 00064 ~KinectCloud(); 00065 00066 00067 /** \brief Adds the z-values of a Kinect depth-image grabbed by FrameGrabber 00068 * and stores them as a point-cloud (std::vector< std::vector<float> >). 00069 * 00070 * \param zValues Pointer to a \f$640 \times 480\f$-dimensional array of 00071 * z-values. 00072 */ 00073 void addZValues(int* zValues); 00074 00075 00076 /** \brief Adds the RGB-values of a Kinect RGB-image grabbed by FrameGrabber 00077 * and stores them as a point-cloud (std::vector< std::vector<float> >). 00078 * 00079 * \param rgbValues Pointer to a \f$640 \times 480\f$-dimensional array of 00080 * RGB-values. 00081 */ 00082 void addRgbValues(int* rgbValues); 00083 00084 //~ void undistortDepthImage(std::vector<float> depthDist); 00085 //~ void undistortRgbImage(std::vector<float> rgbDist); 00086 00087 00088 /** \brief Converts the added depth-values of the Kinect (\f$ Z_\mathrm{raw} \in 00089 * [0, 2047) \f$) into meter using the formula 00090 * \f[ 00091 * Z_\mathrm{meter} = \frac{1}{Z_\mathrm{raw} \cdot (-0.0030711016) + 3.3309495161}, 00092 * \f] 00093 * which was experimentaly determined (http://nicolas.burrus.name/index.php/Research/KinectCalibration). 00094 * 00095 * Consider that the z-values must be added (addZValues(int* zValues)) 00096 * before before calling this function. 00097 * 00098 * \see \ref kinectcloud-step1 00099 */ 00100 void rawToMeter(); 00101 00102 00103 /** \brief Applies the intrinsic camera-parameters to the point-cloud. The 00104 * parameters should be imported using YMLParser. With the help of 00105 * these parameters, each point \f$ (x,y)^T \f$ of the depth-image with 00106 * its depth-value \f$Z\f$ is projected on its equivalent point 00107 * \f$ (X,Y,Z)^T \f$ in 3D-space regarding its z-value and the 00108 * depth-camera-parameters. 00109 * This is done with the following formula: 00110 * \f{align*} 00111 * \begin{pmatrix} 00112 * x_\mathsf{d} \\ y_\mathsf{d}\\ 1 00113 * \end{pmatrix} 00114 * &= 00115 * \begin{pmatrix} 00116 * & & & 0 \\ 00117 * & \mathbf{C} & & 0 \\ 00118 * & & & 0 00119 * \end{pmatrix} 00120 * \begin{pmatrix} 00121 * X_\mathsf{d} \\ Y_\mathsf{d} \\ Z_\mathsf{d} \\ 1 00122 * \end{pmatrix} 00123 * = 00124 * \begin{pmatrix} 00125 * f_x & 0 & c_x & 0 \\ 00126 * 0 & f_y & c_y & 0 \\ 00127 * 0 & 0 & 1 & 0 00128 * \end{pmatrix} 00129 * \cdot 00130 * \begin{pmatrix} 00131 * X_\mathsf{d} \\ Y_\mathsf{d} \\ Z_\mathsf{d} \\ 1 00132 * \end{pmatrix} \\ 00133 * &= 00134 * \begin{pmatrix} 00135 * f_x \cdot X_\mathsf{d} + c_x \cdot Z_\mathsf{d} \\ 00136 * f_y \cdot Y_\mathsf{d} + c_y \cdot Z_\mathsf{d} \\ 00137 * Z 00138 * \end{pmatrix} 00139 * = 00140 * \begin{pmatrix} 00141 * f_x \cdot X_\mathsf{d} / Z_\mathsf{d} + c_x \\ 00142 * f_y \cdot Y_\mathsf{d} / Z_\mathsf{d} + c_y \\ 00143 * 1 00144 * \end{pmatrix} \\ 00145 * &\Rightarrow\quad 00146 * \begin{cases} 00147 * X_\mathsf{d} = (x_\mathsf{d} - c_x) \cdot Z_\mathsf{d} / f_x \\ 00148 * Y_\mathsf{d} = (y_\mathsf{d} - c_y) \cdot Z_\mathsf{d} / f_y 00149 * \end{cases}, 00150 * \f} 00151 * where \f$\mathbf{C}\f$ contains the intrinsic parameters of the 00152 * depth-camera. Notice that the z-value doesn't change during this 00153 * procedure and is already available at the depth-image. 00154 * 00155 * Consider that the extrinsic parameters should already be applied to 00156 * the point-cloud (applyExtrinsics(std::vector< std::vector<float> > rot, std::vector<float> trans)) 00157 * before calling this function. 00158 * 00159 * \param depthCam Intrisic parameters of the depth-cam as a 00160 * \f$ 3 \times 3 \f$-matrix as written in the specific 00161 * yml-file and imported using YMLParser. 00162 * 00163 * \see \ref kinectcloud-step2 00164 */ 00165 void depthToCloud(std::vector< std::vector<float> > depthCam); 00166 00167 00168 /** \brief Applies the extrinsic camera-parameters to the point-cloud. The 00169 * parameters should be imported using YMLParser. This is done with a 00170 * rotation and translation of each point: 00171 * \f[ 00172 * \begin{pmatrix} 00173 * x_\mathrm{rgb} \\ y_\mathrm{rgb} \\ z_\mathrm{rgb} 00174 * \end{pmatrix} 00175 * = 00176 * R \cdot 00177 * \begin{pmatrix} 00178 * x_\mathrm{d} \\ y_\mathrm{d} \\ z_\mathrm{d} 00179 * \end{pmatrix} 00180 * + T 00181 * = 00182 * \begin{pmatrix} 00183 * r_{11} & r_{12} & r_{13} \\ 00184 * r_{21} & r_{22} & r_{23} \\ 00185 * r_{31} & r_{32} & r_{33} 00186 * \end{pmatrix} 00187 * \cdot 00188 * \begin{pmatrix} 00189 * x_\mathrm{d} \\ y_\mathrm{d} \\ z_\mathrm{d} 00190 * \end{pmatrix} 00191 * + 00192 * \begin{pmatrix} 00193 * t_1 \\ t_2 \\ t_3 00194 * \end{pmatrix}, 00195 * \f] 00196 * where \f$R\f$ and \f$T\f$ are the extrinsic parameters of the Kinect 00197 * and describe a rotation and translation. 00198 * 00199 * Consider that the z-values should be converted into meters 00200 * (rawToMeter()) before calling this function for a correct 00201 * reconstruction. 00202 * 00203 * \param rot Rotation-matrix (\f$ 3 \times 3 \f$) of the Kinect as 00204 * written in the specific yml-file and imported using 00205 * YMLParser. 00206 * \param trans Translation-vector (3-dimensional) of the Kinect as 00207 * written in the specific yml-file and imported using 00208 * YMLParser. 00209 * 00210 * \see \ref kinectcloud-step3 00211 */ 00212 void applyExtrinsics(std::vector< std::vector<float> > rot, std::vector<float> trans); 00213 00214 00215 /** \brief Computes the mapping between the point-cloud and the equivalent 00216 * points of the RGB-image by reprojecting the point 00217 * \f$ (X_\mathsf{rgb},Y_\mathsf{rgb},Z_\mathsf{rgb}) \f$ 00218 * of the point-cloud to its equivalent point 00219 * \f$ (x_\mathsf{rgb},y_\mathsf{rgb}) \f$ in the plane 00220 * using the intrinsics of the RGB-camera imported by YMLParser. The 00221 * projection is done with the following formula: 00222 * \f{align*} 00223 * \begin{pmatrix} 00224 * x_\mathsf{rgb} \\ y_\mathsf{rgb} \\ 1 00225 * \end{pmatrix} 00226 * &= 00227 * \begin{pmatrix} 00228 * & & & 0 \\ 00229 * & \mathbf{C} & & 0 \\ 00230 * & & & 0 00231 * \end{pmatrix} 00232 * \begin{pmatrix} 00233 * X_\mathsf{rgb} \\ Y_\mathsf{rgb} \\ Z_\mathsf{rgb} \\ 1 00234 * \end{pmatrix} 00235 * = 00236 * \begin{pmatrix} 00237 * f_x & 0 & c_x & 0 \\ 00238 * 0 & f_y & c_y & 0 \\ 00239 * 0 & 0 & 1 & 0 00240 * \end{pmatrix} 00241 * \cdot 00242 * \begin{pmatrix} 00243 * X_\mathsf{rgb} \\ Y_\mathsf{rgb} \\ Z_\mathsf{rgb} \\ 1 00244 * \end{pmatrix} \\ 00245 * &= 00246 * \begin{pmatrix} 00247 * f_x \cdot X_\mathsf{rgb} + c_x \cdot Z_\mathsf{rgb} \\ 00248 * f_y \cdot Y_\mathsf{rgb} + c_y \cdot Z_\mathsf{rgb} \\ 00249 * Z 00250 * \end{pmatrix} 00251 * = 00252 * \begin{pmatrix} 00253 * f_x \cdot X_\mathsf{rgb} / Z + c_x \\ 00254 * f_y \cdot Y_\mathsf{rgb} / Z + c_y \\ 00255 * 1 00256 * \end{pmatrix} \\ 00257 * &\Rightarrow 00258 * \begin{cases} 00259 * x_\mathsf{rgb} = (f_x \cdot X_\mathsf{rgb} / Z_\mathsf{rgb}) + c_x \\ 00260 * y_\mathsf{rgb} = (f_y \cdot Y_\mathsf{rgb} / Z_\mathsf{rgb}) + c_y 00261 * \end{cases}, 00262 * \f} 00263 * where \f$C\f$ contains the intrinsic parameters of the RGB-camera. 00264 * 00265 * Consider that the depth-image needs to be projected into the 00266 * 3D-space using (depthToCloud(std::vector< std::vector<float> > depthCam)) 00267 * before calling this function for correct reconstruction. 00268 * 00269 * \param rgbCam Intrisic parameters of the RGB-cam as a 00270 * \f$ 3 \times 3 \f$-matrix as written in the specific 00271 * yml-file and imported using YMLParser. 00272 * 00273 * \see \ref kinectcloud-step4 00274 */ 00275 void computeRgbMapping(std::vector< std::vector<float> > rgbCam); 00276 00277 //~ void computeNormals(); 00278 00279 00280 /** \brief Get the cloud. 00281 * 00282 * \return Vector of 3-dimensional points. 00283 */ 00284 std::vector< std::vector<float> > getCloud(); 00285 00286 00287 /** \brief Get the RGB-cloud. 00288 * 00289 * \return Vector of 3-dimensional vectors containing the RGB-values of the 00290 * cloud. 00291 */ 00292 std::vector< std::vector<int> > getCloudRgb(); 00293 00294 00295 /** \brief Get the cloud-RGB-mapping. 00296 * 00297 * \return Vector of 2-dimensional vectors, which contain the x- and y-value of 00298 * the pixel at the RGB-image of every point at the point-cloud. It is 00299 * used to find the corresponding color of every point of the 00300 * point-cloud at the RGB-image. 00301 */ 00302 std::vector< std::vector<int> > getCloudRgbMapping(); 00303 00304 //~ std::vector< std::vector<float> > getNormals(); 00305 00306 00307 /** \brief Get a vector which indicates if a point of the point-cloud is valid 00308 * (\f$depth < 2047\f$). 00309 * 00310 * \return Indicates for every of the \f$640 \times 480\f$ points if it is 00311 * valid (\f$depth < 2047\f$). 00312 */ 00313 std::vector<bool> getValidValues(); 00314 00315 00316 /** \brief Get the reconstruction-steps. 00317 * 00318 * \return Vector boolean values indicating if the reconstruction step was 00319 * done. The values of a returned vector \c recon indicate: 00320 * \li \c recon[0]: Raw depth-values of the Kinect converted into 00321 * meters using rawToMeter(). 00322 * \li \c recon[1]: The intrinsic parameters of the depth-camera were 00323 * applied using 00324 * depthToCloud(std::vector< std::vector<float> > depthCam). 00325 * \li \c recon[2]: The extrinsic camera-parameters were applied using 00326 * applyExtrinsics(std::vector< std::vector<float> > rot, std::vector<float> trans). 00327 * \li \c recon[3]: The intrinsic parameters of the RGB-camera were 00328 * applied using 00329 * computeRgbMapping(std::vector< std::vector<float> > rgbCam). 00330 * \li (\c recon[4]: Normals were reconstructed using 00331 * computeNormals() – not implemented yet.) 00332 * 00333 */ 00334 std::vector<bool> getReconstructionSteps(); 00335 00336 private: 00337 std::vector< std::vector<float> > cloud; /**< The point-cloud */ 00338 std::vector< std::vector<int> > cloudRgb; /**< The RGB-values */ 00339 std::vector< std::vector<int> > cloudRgbMapping; /**< Coordinates of a point's corresponding color at the RGB-image */ 00340 //~ std::vector< std::vector<float> > normals; /**< Normals */ 00341 std::vector<bool> validValues; /**< Valid flags for each point */ 00342 std::vector<bool> reconstructionSteps; /**< Reconstruction flags */ 00343 00344 }; 00345 00346 00347 00348 //~ class VCGVertex; 00349 //~ class VCGUsedTypes : public vcg::UsedTypes<vcg::Use<VCGVertex>::AsVertexType> {}; 00350 //~ class VCGVertex : public vcg::Vertex<VCGUsedTypes, vcg::vertex::Coord3d, vcg::vertex::Normal3d> {};