rgbd_frame.cpp
Go to the documentation of this file.
00001 
00024 #include "ccny_rgbd/structures/rgbd_frame.h"
00025 
00026 namespace ccny_rgbd {
00027 
00028 RGBDFrame::RGBDFrame()
00029 {
00030 
00031 }
00032 
00033 RGBDFrame::RGBDFrame(
00034   const ImageMsg::ConstPtr& rgb_msg,
00035   const ImageMsg::ConstPtr& depth_msg,
00036   const CameraInfoMsg::ConstPtr& info_msg)
00037 { 
00038   rgb_img = cv_bridge::toCvShare(rgb_msg)->image;
00039   
00040   // handles 16UC1 natively
00041   // 32FC1 need to be converted into 16UC1
00042   const std::string& enc = depth_msg->encoding; 
00043   if (enc.compare("16UC1") == 0)
00044     depth_img = cv_bridge::toCvShare(depth_msg)->image;
00045   else if (enc.compare("32FC1") == 0)
00046     depthImageFloatTo16bit(cv_bridge::toCvShare(depth_msg)->image, depth_img);
00047       
00048   header = rgb_msg->header;
00049 
00050   model.fromCameraInfo(info_msg);
00051 }
00052 
00053 double RGBDFrame::getStdDevZ(double z) const
00054 {
00055   return Z_STDEV_CONSTANT * z * z;
00056 }
00057 
00058 double RGBDFrame::getVarZ(double z) const
00059 {
00060   double std_dev_z = getStdDevZ(z);
00061   return std_dev_z * std_dev_z;
00062 }
00063 
00064 void RGBDFrame::getGaussianDistribution(
00065   int u, int v, double& z_mean, double& z_var) const
00066 {
00067   // get raw z value (in mm)
00068   uint16_t z_raw = depth_img.at<uint16_t>(v, u);
00069 
00070   // z [meters]
00071   z_mean = z_raw * 0.001;
00072 
00073   // var_z [meters]
00074   z_var = getVarZ(z_mean);
00075 }
00076 
00077 void RGBDFrame::getGaussianMixtureDistribution(
00078   int u, int v, double& z_mean, double& z_var) const
00079 {
00081   int w = 1;
00082 
00083   int u_start = std::max(u - w, 0);
00084   int v_start = std::max(v - w, 0);
00085   int u_end   = std::min(u + w, depth_img.cols - 1);
00086   int v_end   = std::min(v + w, depth_img.rows - 1);
00087 
00088   // iterate accross window - find mean
00089   double weight_sum = 0.0;
00090   double mean_sum   = 0.0;
00091   double alpha_sum  = 0.0;
00092 
00093   for (int uu = u_start; uu <= u_end; ++uu)
00094   for (int vv = v_start; vv <= v_end; ++vv)
00095   {
00096     uint16_t z_neighbor_raw = depth_img.at<uint16_t>(vv, uu);
00097  
00098     if (z_neighbor_raw != 0)
00099     {
00100       double z_neighbor = z_neighbor_raw * 0.001;
00101 
00102       // determine and aggregate weight
00103       double weight;
00104       if       (u==uu && v==vv) weight = 4.0;
00105       else if  (u==uu || v==vv) weight = 2.0;
00106       else                      weight = 1.0; 
00107       weight_sum += weight;
00108 
00109       // aggregate mean
00110       mean_sum += weight * z_neighbor;
00111 
00112       // aggregate var
00113       double var_z_neighbor = getVarZ(z_neighbor);
00114       alpha_sum += weight * (var_z_neighbor + z_neighbor * z_neighbor);
00115     }
00116   }
00117 
00118   z_mean = mean_sum  / weight_sum;
00119   z_var  = alpha_sum / weight_sum - z_mean * z_mean;
00120 }
00121 
00122 void RGBDFrame::computeDistributions(
00123   double max_z,
00124   double max_stdev_z)
00125 {
00126   double max_var_z = max_stdev_z * max_stdev_z; // maximum allowed z variance
00127 
00129   double s_u = 1.0;            // uncertainty in pixels
00130   double s_v = 1.0;            // uncertainty in pixels
00131 
00132   n_valid_keypoints = 0;
00133 
00134   // center point
00135   double cx = model.cx();
00136   double cy = model.cy();
00137 
00138   // focus length
00139   double fx = model.fx();
00140   double fy = model.fy();
00141 
00142   // precompute for convenience
00143   double var_u = s_u * s_u;
00144   double var_v = s_v * s_v;
00145   double fx2 = fx*fx;
00146   double fy2 = fy*fy;
00147 
00148   // allocate space
00149   kp_valid.clear();
00150   kp_means.clear();
00151   kp_covariances.clear();
00152 
00153   kp_valid.resize(keypoints.size());
00154   kp_means.resize(keypoints.size());
00155   kp_covariances.resize(keypoints.size());
00156 
00157   for (unsigned int kp_idx = 0; kp_idx < keypoints.size(); ++kp_idx)
00158   {
00159     // calculate pixel coordinates
00160     double u = keypoints[kp_idx].pt.x;
00161     double v = keypoints[kp_idx].pt.y;  
00162 
00163     // get raw z value
00164     uint16_t z_raw = depth_img.at<uint16_t>((int)v, (int)u);
00165 
00166     // skip bad values  
00167     if (z_raw == 0)
00168     {
00169       kp_valid[kp_idx] = false;
00170       continue;
00171     }
00172   
00173     // get z: mean and variance
00174     double z, var_z;
00175     //getGaussianDistribution(u, v, z, var_z);
00176     getGaussianMixtureDistribution(u, v, z, var_z);
00177 
00178     // skip bad values - too far away, or z-variance too big
00179     if (z > max_z || var_z > max_var_z)
00180     {
00181       kp_valid[kp_idx] = false;
00182       continue;
00183     }
00184     kp_valid[kp_idx] = true;
00185     n_valid_keypoints++;
00186 
00187     // precompute for convenience
00188     double z_2  = z * z;
00189     double umcx = u - cx;
00190     double vmcy = v - cy;
00191 
00192     // calculate x and y
00193     double x = z * umcx / fx;
00194     double y = z * vmcy / fy;
00195   
00196     // calculate covariances
00197     double s_xz = var_z * umcx / fx;
00198     double s_yz = var_z * vmcy / fy;
00199 
00200     double s_xx = (var_z * umcx * umcx + var_u * (z_2 + var_z))/fx2;
00201     double s_yy = (var_z * vmcy * vmcy + var_v * (z_2 + var_z))/fy2;
00202 
00203     double s_xy = umcx * vmcy * var_z / (fx * fy);
00204     double s_yx = s_xy;
00205 
00206     double s_zz = var_z; 
00207 
00208     double s_zy = s_yz;
00209     double s_zx = s_xz;
00210    
00211     // fill out mean matrix
00212     Vector3f& kp_mean = kp_means[kp_idx];
00213 
00214     kp_mean(0,0) = x;
00215     kp_mean(1,0) = y;
00216     kp_mean(2,0) = z;
00217 
00218     // fill out covariance matrix
00219     Matrix3f& kp_covariance = kp_covariances[kp_idx];
00220 
00221     kp_covariance(0,0) = s_xx; // xx
00222     kp_covariance(0,1) = s_xy; // xy
00223     kp_covariance(0,2) = s_xz; // xz
00224 
00225     kp_covariance(1,0) = s_yx; // xy
00226     kp_covariance(1,1) = s_yy; // yy
00227     kp_covariance(1,2) = s_yz; // yz
00228 
00229     kp_covariance(2,0) = s_zx; // xz-
00230     kp_covariance(2,1) = s_zy; // yz
00231     kp_covariance(2,2) = s_zz; // zz
00232   }
00233 }
00234 
00235 void RGBDFrame::constructFeaturePointCloud(
00236   PointCloudFeature& cloud)
00237 {
00238   // filter invalid
00239   Vector3fVector means_f;
00240   removeInvalidMeans(kp_means, kp_valid, means_f);
00241 
00242   // create point cloud
00243   pointCloudFromMeans(means_f, cloud);
00244   cloud.header = header;    
00245 }
00246 
00247 void RGBDFrame::constructDensePointCloud(
00248   PointCloudT& cloud,
00249   double max_z,
00250   double max_stdev_z) const
00251 {
00252   double max_var_z = max_stdev_z * max_stdev_z; // maximum allowed z variance
00253 
00254   // Use correct principal point from calibration
00255   float cx = model.cx();
00256   float cy = model.cy();
00257 
00258   // Scale by focal length for computing (X,Y)
00259   float constant_x = 1.0 / model.fx();
00260   float constant_y = 1.0 / model.fy();
00261 
00262   float bad_point = std::numeric_limits<float>::quiet_NaN();
00263 
00264   cloud.points.clear();
00265   cloud.points.resize(rgb_img.rows * rgb_img.cols);
00266   for (int v = 0; v < rgb_img.rows; ++v)
00267   for (int u = 0; u < rgb_img.cols; ++u)
00268   {
00269     unsigned int index = v * rgb_img.cols + u;
00270 
00271     uint16_t z_raw = depth_img.at<uint16_t>(v, u);
00272     float z = z_raw * 0.001; //convert to meters
00273 
00274     PointT& p = cloud.points[index];
00275 
00276     double z_mean, z_var; 
00277 
00278     // check for out of range or bad measurements
00279     if (z_raw != 0)
00280     {
00281       getGaussianMixtureDistribution(u, v, z_mean, z_var);
00282 
00283       // check for variance and z limits     
00284       if (z_var < max_var_z && z_mean < max_z)
00285       {
00286         // fill in XYZ
00287         p.x = z * (u - cx) * constant_x;
00288         p.y = z * (v - cy) * constant_y;
00289         p.z = z;
00290       }
00291       else
00292       {
00293         p.x = p.y = p.z = bad_point;
00294       }
00295     }
00296     else
00297     {
00298       p.x = p.y = p.z = bad_point;
00299     }
00300  
00301     // fill out color
00302     const cv::Vec3b& color = rgb_img.at<cv::Vec3b>(v,u);
00303     p.r = color[2];
00304     p.g = color[1];
00305     p.b = color[0];
00306   }
00307 
00308   cloud.header = header;
00309   cloud.height = rgb_img.rows;
00310   cloud.width  = rgb_img.cols;
00311   cloud.is_dense = false;
00312 }
00313 
00314 bool RGBDFrame::save(
00315   const RGBDFrame& frame, 
00316   const std::string& path)
00317 {
00318   // set the filenames
00319   std::string rgb_filename    = path + "/rgb.png";
00320   std::string depth_filename  = path + "/depth.png";
00321   std::string header_filename = path + "/header.yml";
00322   std::string intr_filename   = path + "/intr.yml"; 
00323   std::string cloud_filename  = path + "/cloud.pcd";
00324   
00325   // create the directory
00326   bool directory_result = boost::filesystem::create_directory(path); 
00327 
00328   if (!directory_result)    
00329   {
00330     ROS_ERROR("Could not create directory: %s", path.c_str());
00331     return false;
00332   }
00333 
00334 /*
00335   // save cloud
00336   if (save_cloud)
00337   {
00338     pcl::PCDWriter writer;
00339     int result_pcd;
00340 
00341     PointCloudT cloud;
00342     frame.constructDensePointCloud(cloud);
00343     
00344     result_pcd = writer.writeBinary<PointT>(cloud_filename, cloud);  
00345 
00346     if (result_pcd != 0) 
00347     {
00348       ROS_ERROR("Error saving point cloud");
00349       return false;
00350     }
00351   }
00352 */
00353 
00354   // save header
00355   cv::FileStorage fs_h(header_filename, cv::FileStorage::WRITE);
00356   fs_h << "frame_id"   << frame.header.frame_id;
00357   fs_h << "seq"        << (int)frame.header.seq;
00358   fs_h << "stamp_sec"  << (int)frame.header.stamp.sec;
00359   fs_h << "stamp_nsec" << (int)frame.header.stamp.nsec;
00360 
00361   // save images 
00362   cv::imwrite(rgb_filename,   frame.rgb_img);
00363   cv::imwrite(depth_filename, frame.depth_img);
00364   
00365   // save intrinsic matrix
00366   cv::FileStorage fs_mat(intr_filename, cv::FileStorage::WRITE);
00367   cv::Mat intr = frame.model.intrinsicMatrix();
00368   fs_mat << "intr" << intr;
00369 
00370   return true;
00371 }
00372 
00373 bool RGBDFrame::load(RGBDFrame& frame, const std::string& path)
00374 {
00375   // set the filenames
00376   std::string rgb_filename    = path + "/rgb.png";
00377   std::string depth_filename  = path + "/depth.png";
00378   std::string header_filename = path + "/header.yml";
00379   std::string intr_filename   = path + "/intr.yml"; 
00380 
00381   // check if files exist
00382   if (!boost::filesystem::exists(rgb_filename)    ||
00383       !boost::filesystem::exists(depth_filename)  ||
00384       !boost::filesystem::exists(header_filename) ||
00385       !boost::filesystem::exists(intr_filename) )
00386   {
00387     ROS_ERROR("files for loading frame not found");
00388     return false;
00389   }
00390 
00391   // load header
00392   cv::FileStorage fs_h(header_filename, cv::FileStorage::READ);
00393   int seq, sec, nsec;
00394 
00395   fs_h["frame_id"]   >> frame.header.frame_id;
00396   fs_h["seq"]        >> seq;
00397   fs_h["stamp_sec"]  >> sec;
00398   fs_h["stamp_nsec"] >> nsec;
00399 
00400   frame.header.seq = seq;
00401   frame.header.stamp.sec = sec;
00402   frame.header.stamp.nsec = nsec;
00403 
00404   // load images
00405   frame.rgb_img = cv::imread(rgb_filename);
00406   frame.depth_img = cv::imread(depth_filename, -1);
00407 
00408   // load intrinsic matrix
00409   cv::FileStorage fs_mat(intr_filename, cv::FileStorage::READ);
00410 
00411   cv::Mat intr;
00412   CameraInfoMsg info_msg;
00413   fs_mat["intr"] >> intr;
00414   convertMatToCameraInfo(intr, info_msg);
00415   frame.model.fromCameraInfo(info_msg);
00416 
00417   return true;
00418 }
00419 
00420 } // namespace ccny_rgbd
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends


ccny_rgbd
Author(s): Ivan Dryanovski
autogenerated on Fri Apr 12 2013 20:38:48