Main MRPT website > C++ reference
MRPT logo
CKinect.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 mrpt_CKinect_H
00029 #define mrpt_CKinect_H
00030 
00031 #include <mrpt/hwdrivers/CGenericSensor.h>
00032 #include <mrpt/slam/CObservation3DRangeScan.h>
00033 #include <mrpt/slam/CObservationIMU.h>
00034 #include <mrpt/utils/TEnumType.h>
00035 #include <mrpt/gui/CDisplayWindow.h>
00036 
00037 #include <mrpt/hwdrivers/link_pragmas.h>
00038 
00039 // MRPT implements a common interface to Kinect disregarding the
00040 //  actual underlying library. These macros defined in "mrpt/config.h"
00041 //  let us know which library is actually used:
00042 //   - MRPT_HAS_KINECT_CL_NUI     = 0 or 1
00043 //   - MRPT_HAS_KINECT_FREENECT   = 0 or 1
00044 
00045 // Depth of Kinect ranges:
00046 #if MRPT_HAS_KINECT_FREENECT
00047 #       define MRPT_KINECT_DEPTH_10BIT
00048 #       define KINECT_RANGES_TABLE_LEN    1024
00049 #       define KINECT_RANGES_TABLE_MASK   0x03FF
00050 #else //  MRPT_HAS_KINECT_CL_NUI or none:
00051 #       define MRPT_KINECT_DEPTH_11BIT
00052 #       define KINECT_RANGES_TABLE_LEN    2048
00053 #       define KINECT_RANGES_TABLE_MASK   0x07FF
00054 #endif
00055 
00056 
00057 namespace mrpt
00058 {
00059         namespace hwdrivers
00060         {
00061                 /** A class for grabing "range images", intensity images (either RGB or IR) and other information from an Xbox Kinect sensor.
00062                   *
00063                   *  <h2>Configuration and usage:</h2> <hr>
00064                   * Data is returned as observations of type mrpt::slam::CObservation3DRangeScan (and mrpt::slam::CObservationIMU for accelerometers data).
00065                   *  See those classes for documentation on their fields.
00066                   *
00067                   * As with any other CGenericSensor class, the normal sequence of methods to be called is:
00068                   *   - CGenericSensor::loadConfig() - Or calls to the individual setXXX() to configure the sensor parameters.
00069                   *   - CKinect::initialize() - to start the communication with the sensor.
00070                   *   - call CKinect::getNextObservation() for getting the data.
00071                   *
00072                   * <h2>Calibration parameters</h2><hr>
00073                   *  For an accurate transformation of depth images to 3D points, you'll have to calibrate your Kinect, and supply
00074                   *   the following <b>threee pieces of information</b> (default calibration data will be used otherwise, but they'll be not optimal for all sensors!):
00075                   *    - Camera parameters for the RGB camera. See CKinect::setCameraParamsIntensity()
00076                   *    - Camera parameters for the depth camera. See CKinect::setCameraParamsDepth()
00077                   *    - The 3D relative pose of the two cameras. See CKinect::setRelativePoseIntensityWrtDepth()
00078                   *
00079                   * <h2>Coordinates convention</h2><hr>
00080                   *   The origin of coordinates is the focal point of the depth camera, with the axes oriented as in the
00081                   *   diagram shown in mrpt::slam::CObservation3DRangeScan. Notice in that picture that the RGB camera is
00082                   *   assumed to have axes as usual in computer vision, which differ from those for the depth camera.
00083                   *
00084                   *   The X,Y,Z axes used to report the data from accelerometers coincide with those of the depth camera
00085                   *    (e.g. the camera standing on a table would have an ACC_Z=-9.8m/s2).
00086                   *
00087                   * <h2>Some general comments</h2><hr>
00088                   *             - Depth is grabbed in 10bit depth, and a range N it's converted to meters as: range(m) = 0.1236 * tan(N/2842.5 + 1.1863)
00089                   *             - This sensor can be also used from within rawlog-grabber to grab datasets within a robot with more sensors.
00090                   *             - There is no built-in threading support, so if you use this class manually (not with-in rawlog-grabber),
00091                   *                     the ideal would be to create a thread and continuously request data from that thread (see mrpt::system::createThread ).
00092                   *             - The intensity channel default to the RGB images, but it can be changed with setVideoChannel() to read the IR camera images (useful for calibrating).
00093                   *             - There is a built-in support for an optional preview of the data on a window, so you don't need to even worry on creating a window to show them.
00094                   *             - This class relies on an embedded version of libfreenect (you do NOT need to install it in your system). Thanks guys for the great job!
00095                   *
00096                   * <h2>Converting to 3D point cloud </h2><hr>
00097                   *   You can convert the 3D observation into a 3D point cloud with this piece of code:
00098                   *
00099                   * \code
00100                   * mrpt::slam::CObservation3DRangeScan  obs3D;
00101                   * mrpt::slam::CColouredPointsMap       pntsMap;
00102                   * pntsMap.colorScheme.scheme = CColouredPointsMap::cmFromIntensityImage;
00103                   * pntsMap.loadFromRangeScan(obs3D);
00104                   * \endcode
00105                   *
00106                   *   Then the point cloud mrpt::slam::CColouredPointsMap can be converted into an OpenGL object for
00107                   *    rendering with mrpt::slam::CMetricMap::getAs3DObject() or alternatively with:
00108                   *
00109                   *  \code
00110                   *    mrpt::opengl::CPointCloudColouredPtr gl_points = mrpt::opengl::CPointCloudColoured::Create();
00111                   *    gl_points->loadFromPointsMap(&pntsMap);
00112                   *  \endcode
00113                   *
00114                   *
00115                   * <h2>Raw depth to range conversion</h2><hr>
00116                   *  At construction, this class builds an internal array for converting raw 10 or 11bit depths into ranges in meters.
00117                   *   Users can read that array or modify it (if you have a better calibration, for example) by calling CKinect::getRawDepth2RangeConversion().
00118                   *   If you replace it, remember to set the first and last entries (index 0 and KINECT_RANGES_TABLE_LEN-1) to zero, to indicate that those are invalid ranges.
00119                   *
00120                   *  <table width="100%" >
00121                   *  <tr>
00122                   *  <td align="center" >
00123                   *   <img src="kinect_depth2range_10bit.png" > <br>
00124                   *    R(d) = k3 * tan(d/k2 + k1); <br>
00125                   *    k1 = 1.1863,  k2 = 2842.5, k3 = 0.1236 <br>
00126                   *  </td>
00127                   *  <td align="center" >
00128                   *  </td>
00129                   *  </tr>
00130                   *  </table>
00131                   *
00132                   *
00133                   * <h2>Platform-specific comments</h2><hr>
00134                   *   For more details, refer to <a href="http://openkinect.org/wiki/Main_Page" >libfreenect</a> documentation:
00135                   *             - Linux: You'll need root privileges to access Kinect. Or, install <code> MRPT/scripts/51-kinect.rules </code> in <code>/etc/udev/rules.d/</code> to allow access to all users.
00136                   *             - Windows:
00137                   *                     - Since MRPT 0.9.4 you'll only need to install <a href="http://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/" >libusb-win32</a>: download and extract the latest libusb-win32-bin-x.x.x.x.zip
00138                   *                     - To install the drivers, read this: http://openkinect.org/wiki/Getting_Started#Windows
00139                   *             - MacOS: (write me!)
00140                   *
00141                   *
00142                   * <h2>Format of parameters for loading from a .ini file</h2><hr>
00143                   *
00144                   *  \code
00145                   *  PARAMETERS IN THE ".INI"-LIKE CONFIGURATION STRINGS:
00146                   * -------------------------------------------------------
00147                   *   [supplied_section_name]
00148                   *    sensorLabel     = KINECT       // A text description
00149                   *    preview_window  = false        // Show a window with a preview of the grabbed data in real-time
00150                   *
00151                   *    device_number   = 0           // Device index to open (0:first Kinect, 1:second Kinect,...)
00152                   *
00153                   *    grab_image      = true        // Grab the RGB image channel? (Default=true)
00154                   *    grab_depth      = true        // Grab the depth channel? (Default=true)
00155                   *    grab_3D_points  = true        // Grab the 3D point cloud? (Default=true) If disabled, points can be generated later on.
00156                   *    grab_IMU        = true        // Grab the accelerometers? (Default=true)
00157                   *
00158                   *    video_channel   = VIDEO_CHANNEL_RGB // Optional. Can be: VIDEO_CHANNEL_RGB (default) or VIDEO_CHANNEL_IR
00159                   *
00160                   *    // Calibration matrix of the RGB camera:
00161                   *    rgb_cx        = 328.9427     // (cx,cy): Optical center, pixels
00162                   *    rgb_cy        = 267.4807
00163                   *    rgb_fx        = 529.2151     // (fx,fy): Focal distance, pixels
00164                   *    rgb_fy        = 525.5639
00165                   *
00166                   *    // Calibration matrix of the Depth camera:
00167                   *    d_cx          = 339.3078     // (cx,cy): Optical center, pixels
00168                   *    d_cy          = 242.7391
00169                   *    d_fx          = 594.2143     // (fx,fy): Focal distance, pixels
00170                   *    d_fy          = 591.0405
00171                   *
00172                   *    // The relative pose of the RGB camera wrt the depth camera.
00173                   *    //  (See mrpt::slam::CObservation3DRangeScan for a 3D diagram of this pose)
00174                   *    relativePoseIntensityWRTDepth  =  [0 -0.02 0 -90 0 -90]   //  [x(m) y(m) z(m) yaw(deg) pitch(deg) roll(deg)]
00175                   *
00176                   *    pose_x=0 // Camera position in the robot (meters)
00177                   *    pose_y=0
00178                   *    pose_z=0
00179                   *    pose_yaw=0       // Angles in degrees
00180                   *    pose_pitch=0
00181                   *    pose_roll=0
00182                   *
00183                   *  \endcode
00184                   *
00185                   *  More references to read:
00186                   *             - http://openkinect.org/wiki/Imaging_Information
00187                   *             - http://nicolas.burrus.name/index.php/Research/KinectCalibration
00188                   * \ingroup mrpt_hwdrivers_grp
00189                   */
00190                 class HWDRIVERS_IMPEXP  CKinect : public mrpt::hwdrivers::CGenericSensor
00191                 {
00192                         DEFINE_GENERIC_SENSOR(CKinect)
00193 
00194                 public:
00195                         typedef float TDepth2RangeArray[KINECT_RANGES_TABLE_LEN]; //!< A typedef for an array that converts raw depth to ranges in meters.
00196 
00197                         /** RGB or IR video channel identifiers \sa setVideoChannel */
00198                         enum TVideoChannel {
00199                                 VIDEO_CHANNEL_RGB=0,
00200                                 VIDEO_CHANNEL_IR
00201                         };
00202 
00203                         CKinect();       //!< Default ctor
00204                         ~CKinect();      //!< Default ctor
00205 
00206                         /** Initializes the 3D camera - should be invoked after calling loadConfig() or setting the different parameters with the set*() methods.
00207                           *  \exception This method must throw an exception with a descriptive message if some critical error is found.
00208                           */
00209                         virtual void initialize();
00210 
00211                         /** To be called  at a high rate (>XX Hz), this method populates the internal buffer of received observations.
00212                           *  This method is mainly intended for usage within rawlog-grabber or similar programs.
00213                           *  For an alternative, see getNextObservation()
00214                           *  \exception This method must throw an exception with a descriptive message if some critical error is found.
00215                           * \sa getNextObservation
00216                           */
00217                         virtual void doProcess();
00218 
00219                         /** The main data retrieving function, to be called after calling loadConfig() and initialize().
00220                           *  \param out_obs The output retrieved observation (only if there_is_obs=true).
00221                           *  \param there_is_obs If set to false, there was no new observation.
00222                           *  \param hardware_error True on hardware/comms error.
00223                           *
00224                           * \sa doProcess
00225                           */
00226                         void getNextObservation(
00227                                 mrpt::slam::CObservation3DRangeScan &out_obs,
00228                                 bool &there_is_obs,
00229                                 bool &hardware_error );
00230 
00231                         /** \overload
00232                           * \note This method also grabs data from the accelerometers, returning them in out_obs_imu
00233                           */
00234                         void getNextObservation(
00235                                 mrpt::slam::CObservation3DRangeScan &out_obs,
00236                                 mrpt::slam::CObservationIMU         &out_obs_imu,
00237                                 bool &there_is_obs,
00238                                 bool &hardware_error );
00239 
00240                         /**  Set the path where to save off-rawlog image files (this class DOES take into account this path).
00241                           *  An  empty string (the default value at construction) means to save images embedded in the rawlog, instead of on separate files.
00242                           * \exception std::exception If the directory doesn't exists and cannot be created.
00243                           */
00244                         virtual void setPathForExternalImages( const std::string &directory );
00245 
00246 
00247                         /** @name Sensor parameters (alternative to \a loadConfig ) and manual control
00248                             @{ */
00249 
00250                         /** Try to open the camera (set all the parameters before calling this) - users may also call initialize(), which in turn calls this method.
00251                           *  Raises an exception upon error.
00252                           * \exception std::exception A textual description of the error.
00253                           */
00254                         void open();
00255 
00256                         bool isOpen() const; //!< Whether there is a working connection to the sensor
00257 
00258                         /** Close the conection to the sensor (not need to call it manually unless desired for some reason,
00259                           * since it's called at destructor) */
00260                         void close();
00261 
00262                         /** Changes the video channel to open (RGB or IR) - you can call this method before start grabbing or in the middle of streaming and the video source will change on the fly.
00263                             Default is RGB channel. */
00264                         void          setVideoChannel(const TVideoChannel vch);
00265                         /** Return the current video channel (RGB or IR) \sa setVideoChannel */
00266                         inline TVideoChannel getVideoChannel() const { return m_video_channel; }
00267 
00268                         /** Set the sensor index to open (if there're several sensors attached to the computer); default=0 -> the first one. */
00269                         inline void setDeviceIndexToOpen(int index) { m_user_device_number=index; }
00270                         inline int getDeviceIndexToOpen() const { return m_user_device_number; }
00271 
00272                         /** Change tilt angle \note Sensor must be open first. */
00273                         void setTiltAngleDegrees(double angle);
00274                         double getTiltAngleDegrees();
00275 
00276                         /** Default: disabled */
00277                         inline void enablePreviewRGB(bool enable=true) { m_preview_window = enable; }
00278                         inline void disablePreviewRGB() { m_preview_window = false; }
00279                         inline bool isPreviewRGBEnabled() const { return m_preview_window; }
00280 
00281                         /** If preview is enabled, show only one image out of N (default: 1=show all) */
00282                         inline void setPreviewDecimation(size_t decimation_factor ) { m_preview_window_decimation = decimation_factor; }
00283                         inline size_t getPreviewDecimation() const { return m_preview_window_decimation; }
00284 
00285                         /** Get the maximum range (meters) that can be read in the observation field "rangeImage" */
00286                         inline double getMaxRange() const { return m_maxRange; }
00287 
00288                         /** Get the row count in the camera images, loaded automatically upon camera open(). */
00289                         inline size_t getRowCount() const { return m_cameraParamsRGB.nrows; }
00290                         /** Get the col count in the camera images, loaded automatically upon camera open(). */
00291                         inline size_t getColCount() const { return m_cameraParamsRGB.ncols; }
00292 
00293                         /** Get a const reference to the depth camera calibration parameters */
00294                         inline const mrpt::utils::TCamera  & getCameraParamsIntensity() const { return m_cameraParamsRGB; }
00295                         inline void setCameraParamsIntensity(const mrpt::utils::TCamera  &p) { m_cameraParamsRGB=p; }
00296 
00297                         /** Get a const reference to the depth camera calibration parameters */
00298                         inline const mrpt::utils::TCamera  & getCameraParamsDepth() const { return m_cameraParamsDepth; }
00299                         inline void setCameraParamsDepth(const mrpt::utils::TCamera  &p) { m_cameraParamsDepth=p; }
00300 
00301                         /** Set the pose of the intensity camera wrt the depth camera \sa See mrpt::slam::CObservation3DRangeScan for a 3D diagram of this pose */
00302                         inline void setRelativePoseIntensityWrtDepth(const mrpt::poses::CPose3D &p) { m_relativePoseIntensityWRTDepth=p; }
00303                         inline const mrpt::poses::CPose3D &getRelativePoseIntensityWrtDepth() const { return m_relativePoseIntensityWRTDepth; }
00304 
00305                         /** Get a reference to the array that convert raw depth values (10 or 11 bit) into ranges in meters, so it can be read or replaced by the user.
00306                           *  If you replace it, remember to set the first and last entries (index 0 and KINECT_RANGES_TABLE_LEN-1) to zero, to indicate that those are invalid ranges.
00307                           */
00308                         inline       TDepth2RangeArray & getRawDepth2RangeConversion()       { return m_range2meters; }
00309                         inline const TDepth2RangeArray & getRawDepth2RangeConversion() const { return m_range2meters; }
00310 
00311                         /** Enable/disable the grabbing of the RGB channel */
00312                         inline void enableGrabRGB(bool enable=true) { m_grab_image=enable; }
00313                         inline bool isGrabRGBEnabled() const { return m_grab_image; }
00314 
00315                         /** Enable/disable the grabbing of the depth channel */
00316                         inline void enableGrabDepth(bool enable=true) { m_grab_depth=enable; }
00317                         inline bool isGrabDepthEnabled() const { return m_grab_depth; }
00318 
00319                         /** Enable/disable the grabbing of the inertial data */
00320                         inline void enableGrabAccelerometers(bool enable=true) { m_grab_IMU=enable; }
00321                         inline bool isGrabAccelerometersEnabled() const { return m_grab_IMU; }
00322 
00323                         /** Enable/disable the grabbing of the 3D point clouds */
00324                         inline void enableGrab3DPoints(bool enable=true) { m_grab_3D_points=enable; }
00325                         inline bool isGrab3DPointsEnabled() const { return m_grab_3D_points; }
00326 
00327                         /** @} */
00328 
00329 
00330 #if MRPT_HAS_KINECT_FREENECT
00331                         // Auxiliary getters/setters (we can't declare the libfreenect callback as friend since we
00332                         //   want to avoid including the API headers here).
00333                         inline mrpt::slam::CObservation3DRangeScan & internal_latest_obs() { return m_latest_obs; }
00334                         inline volatile uint32_t & internal_tim_latest_depth() { return m_tim_latest_depth; }
00335                         inline volatile uint32_t & internal_tim_latest_rgb()   { return m_tim_latest_rgb; }
00336                         inline mrpt::synch::CCriticalSection & internal_latest_obs_cs() { return m_latest_obs_cs; }
00337 #endif
00338 
00339                 protected:
00340                         /** Loads specific configuration for the device from a given source of configuration parameters, for example, an ".ini" file, loading from the section "[iniSection]" (see utils::CConfigFileBase and derived classes)
00341                           *  \exception This method must throw an exception with a descriptive message if some critical parameter is missing or has an invalid value.
00342                           */
00343                         virtual void  loadConfig_sensorSpecific(
00344                                 const mrpt::utils::CConfigFileBase &configSource,
00345                                 const std::string                       &section );
00346 
00347                         mrpt::poses::CPose3D    m_sensorPoseOnRobot;
00348 
00349                         bool            m_preview_window; //!< Show preview window while grabbing
00350                         size_t          m_preview_window_decimation; //!< If preview is enabled, only show 1 out of N images.
00351                         size_t      m_preview_decim_counter_range, m_preview_decim_counter_rgb;
00352                         mrpt::gui::CDisplayWindowPtr  m_win_range, m_win_int;
00353 
00354 #if MRPT_HAS_KINECT_FREENECT
00355                         void *m_f_ctx;  //!< The "freenect_context", or NULL if closed
00356                         void *m_f_dev;  //!< The "freenect_device", or NULL if closed
00357 
00358                         // Data fields for use with the callback function:
00359                         mrpt::slam::CObservation3DRangeScan  m_latest_obs;
00360                         volatile uint32_t                 m_tim_latest_depth, m_tim_latest_rgb; // 0 = not updated
00361                         mrpt::synch::CCriticalSection     m_latest_obs_cs;
00362 #endif
00363 
00364 #if MRPT_HAS_KINECT_CL_NUI
00365                         void *m_clnui_cam;   //!< The "CLNUICamera" or NULL if closed
00366                         void *m_clnui_motor; //!< The "CLNUIMotor" or NULL if closed
00367 #endif
00368 
00369                         mrpt::utils::TCamera    m_cameraParamsRGB;  //!< Params for the RGB camera
00370                         mrpt::utils::TCamera    m_cameraParamsDepth;  //!< Params for the Depth camera
00371                         mrpt::poses::CPose3D    m_relativePoseIntensityWRTDepth; //!< See mrpt::slam::CObservation3DRangeScan for a diagram of this pose
00372 
00373                         double  m_maxRange; //!< Sensor max range (meters)
00374 
00375                         int  m_user_device_number; //!< Number of device to open (0:first,...)
00376 
00377                         bool  m_grab_image, m_grab_depth, m_grab_3D_points, m_grab_IMU ; //!< Default: all true
00378 
00379                         TVideoChannel  m_video_channel; //!< The video channel to open: RGB or IR
00380 
00381                 private:
00382                         std::vector<uint8_t> m_buf_depth, m_buf_rgb; //!< Temporary buffers for image grabbing.
00383                         TDepth2RangeArray   m_range2meters; //!< The table raw depth -> range in meters
00384 
00385                         void calculate_range2meters(); //!< Compute m_range2meters at construction
00386 
00387                 public:
00388                         EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00389 
00390                 };      // End of class
00391         } // End of NS
00392 
00393         // Specializations MUST occur at the same namespace:
00394         namespace utils
00395         {
00396                 template <>
00397                 struct TEnumTypeFiller<hwdrivers::CKinect::TVideoChannel>
00398                 {
00399                         typedef hwdrivers::CKinect::TVideoChannel enum_t;
00400                         static void fill(bimap<enum_t,std::string>  &m_map)
00401                         {
00402                                 m_map.insert(hwdrivers::CKinect::VIDEO_CHANNEL_RGB, "VIDEO_CHANNEL_RGB");
00403                                 m_map.insert(hwdrivers::CKinect::VIDEO_CHANNEL_IR,  "VIDEO_CHANNEL_IR");
00404                         }
00405                 };
00406         } // End of namespace
00407 
00408 } // End of NS
00409 
00410 
00411 #endif



Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011