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


lib_rgbdtools
Author(s): Ivan Dryanovski
autogenerated on Tue Aug 27 2013 10:33:54