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
00041
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
00068 uint16_t z_raw = depth_img.at<uint16_t>(v, u);
00069
00070
00071 z_mean = z_raw * 0.001;
00072
00073
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
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
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
00110 mean_sum += weight * z_neighbor;
00111
00112
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;
00127
00129 double s_u = 1.0;
00130 double s_v = 1.0;
00131
00132 n_valid_keypoints = 0;
00133
00134
00135 double cx = model.cx();
00136 double cy = model.cy();
00137
00138
00139 double fx = model.fx();
00140 double fy = model.fy();
00141
00142
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
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
00160 double u = keypoints[kp_idx].pt.x;
00161 double v = keypoints[kp_idx].pt.y;
00162
00163
00164 uint16_t z_raw = depth_img.at<uint16_t>((int)v, (int)u);
00165
00166
00167 if (z_raw == 0)
00168 {
00169 kp_valid[kp_idx] = false;
00170 continue;
00171 }
00172
00173
00174 double z, var_z;
00175
00176 getGaussianMixtureDistribution(u, v, z, var_z);
00177
00178
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
00188 double z_2 = z * z;
00189 double umcx = u - cx;
00190 double vmcy = v - cy;
00191
00192
00193 double x = z * umcx / fx;
00194 double y = z * vmcy / fy;
00195
00196
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
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
00219 Matrix3f& kp_covariance = kp_covariances[kp_idx];
00220
00221 kp_covariance(0,0) = s_xx;
00222 kp_covariance(0,1) = s_xy;
00223 kp_covariance(0,2) = s_xz;
00224
00225 kp_covariance(1,0) = s_yx;
00226 kp_covariance(1,1) = s_yy;
00227 kp_covariance(1,2) = s_yz;
00228
00229 kp_covariance(2,0) = s_zx;
00230 kp_covariance(2,1) = s_zy;
00231 kp_covariance(2,2) = s_zz;
00232 }
00233 }
00234
00235 void RGBDFrame::constructFeaturePointCloud(
00236 PointCloudFeature& cloud)
00237 {
00238
00239 Vector3fVector means_f;
00240 removeInvalidMeans(kp_means, kp_valid, means_f);
00241
00242
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;
00253
00254
00255 float cx = model.cx();
00256 float cy = model.cy();
00257
00258
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;
00273
00274 PointT& p = cloud.points[index];
00275
00276 double z_mean, z_var;
00277
00278
00279 if (z_raw != 0)
00280 {
00281 getGaussianMixtureDistribution(u, v, z_mean, z_var);
00282
00283
00284 if (z_var < max_var_z && z_mean < max_z)
00285 {
00286
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
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
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
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
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
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
00362 cv::imwrite(rgb_filename, frame.rgb_img);
00363 cv::imwrite(depth_filename, frame.depth_img);
00364
00365
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
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
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
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
00405 frame.rgb_img = cv::imread(rgb_filename);
00406 frame.depth_img = cv::imread(depth_filename, -1);
00407
00408
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 }