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
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
00068
00069
00070
00071
00072
00073
00074
00075
00076
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
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
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
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
00141 uint16_t z_raw = depth_img.at<uint16_t>(v, u);
00142
00143
00144 z_mean = z_raw * 0.001;
00145
00146
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
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
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
00183 mean_sum += weight * z_neighbor;
00184
00185
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;
00200
00202 double s_u = 1.0;
00203 double s_v = 1.0;
00204
00205 n_valid_keypoints = 0;
00206
00207
00208 double cx = intr.at<double>(0, 2);
00209 double cy = intr.at<double>(1, 2);
00210
00211
00212 double fx = intr.at<double>(0, 0);
00213 double fy = intr.at<double>(1, 1);
00214
00215
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
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
00233 double u = keypoints[kp_idx].pt.x;
00234 double v = keypoints[kp_idx].pt.y;
00235
00236
00237 uint16_t z_raw = depth_img.at<uint16_t>((int)v, (int)u);
00238
00239
00240 if (z_raw == 0)
00241 {
00242 kp_valid[kp_idx] = false;
00243 continue;
00244 }
00245
00246
00247 double z, var_z;
00248
00249 getGaussianMixtureDistribution(u, v, z, var_z);
00250
00251
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
00261 double z_2 = z * z;
00262 double umcx = u - cx;
00263 double vmcy = v - cy;
00264
00265
00266 double x = z * umcx / fx;
00267 double y = z * vmcy / fy;
00268
00269
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
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
00292 Matrix3f& kp_covariance = kp_covariances[kp_idx];
00293
00294 kp_covariance(0,0) = s_xx;
00295 kp_covariance(0,1) = s_xy;
00296 kp_covariance(0,2) = s_xz;
00297
00298 kp_covariance(1,0) = s_yx;
00299 kp_covariance(1,1) = s_yy;
00300 kp_covariance(1,2) = s_yz;
00301
00302 kp_covariance(2,0) = s_zx;
00303 kp_covariance(2,1) = s_zy;
00304 kp_covariance(2,2) = s_zz;
00305 }
00306 }
00307
00308 void RGBDFrame::constructFeaturePointCloud(
00309 PointCloudFeature& cloud)
00310 {
00311
00312 Vector3fVector means_f;
00313 removeInvalidMeans(kp_means, kp_valid, means_f);
00314
00315
00316 pointCloudFromMeans(means_f, cloud);
00317
00318
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
00327 double cx = intr.at<double>(0, 2);
00328 double cy = intr.at<double>(1, 2);
00329
00330
00331 double fx = intr.at<double>(0, 0);
00332 double fy = intr.at<double>(1, 1);
00333
00334
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;
00344
00345
00346 if (z_raw != 0)
00347 {
00348 std::vector<double> point;
00349
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;
00363
00364
00365 double cx = intr.at<double>(0, 2);
00366 double cy = intr.at<double>(1, 2);
00367
00368
00369 double fx = intr.at<double>(0, 0);
00370 double fy = intr.at<double>(1, 1);
00371
00372
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;
00388
00389 PointT& p = cloud.points[index];
00390
00391 double z_mean, z_var;
00392
00393
00394 if (z_raw != 0)
00395 {
00396 getGaussianMixtureDistribution(u, v, z_mean, z_var);
00397
00398
00399 if (z_var < max_var_z && z_mean < max_z)
00400 {
00401
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
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
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
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
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
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
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 cv::imwrite(rgb_filename, frame.rgb_img);
00477 cv::imwrite(depth_filename, frame.depth_img);
00478
00479
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
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
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
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
00520 frame.rgb_img = cv::imread(rgb_filename);
00521 frame.depth_img = cv::imread(depth_filename, -1);
00522
00523
00524 cv::FileStorage fs_mat(intr_filename, cv::FileStorage::READ);
00525 fs_mat["intr"] >> frame.intr;
00526
00527 return true;
00528 }
00529
00530 }