frame.cpp
Go to the documentation of this file.
00001 #include <stdio.h>
00002 
00003 #include <iostream>
00004 
00005 #include <emmintrin.h>
00006 
00007 #include "visual_odometry.hpp"
00008 #include "frame.hpp"
00009 #include "fast.hpp"
00010 #include "gauss_pyramid.h"
00011 #include "camera_intrinsics.hpp"
00012 #include "rectification.hpp"
00013 #include "depth_source.hpp"
00014 #include "internal_utils.hpp"
00015 #include "normalize_image.hpp"
00016 
00017 #include "tictoc.hpp"
00018 
00019 #ifndef ALIGNMENT
00020 #define ALIGNMENT 16
00021 #endif
00022 
00023 using namespace std;
00024 
00025 // ========================= OdometryFrame =========================
00026 
00027 namespace fovis
00028 {
00029 
00030 OdometryFrame::OdometryFrame(const Rectification* rectification,
00031                              const VisualOdometryOptions& options)
00032 {
00033   const CameraIntrinsicsParameters& input_camera = rectification->getInputCameraParameters();
00034   _rectification = rectification;
00035   _orig_width = input_camera.width;
00036   _orig_height = input_camera.height;
00037 
00038 
00039   const VisualOdometryOptions& defaults(VisualOdometry::getDefaultOptions());
00040   _num_levels = optionsGetIntOrFromDefault(options, "max-pyramid-level", defaults);
00041   _feature_window_size = optionsGetIntOrFromDefault(options, "feature-window-size", defaults);
00042   _use_image_normalization = optionsGetBoolOrFromDefault(options, "use-image-normalization", defaults);
00043 
00044   _use_bucketing = optionsGetBoolOrFromDefault(options, "use-bucketing", defaults);
00045   int bucket_width = optionsGetIntOrFromDefault(options, "bucket-width", defaults);
00046   int bucket_height = optionsGetIntOrFromDefault(options, "bucket-height", defaults);
00047   int max_keypoints_per_bucket = optionsGetIntOrFromDefault(options, "max-keypoints-per-bucket", defaults);
00048 
00049   for (int level_num=0; level_num<_num_levels; level_num++) {
00050     int level_width = _orig_width >> level_num;
00051     int level_height = _orig_height >> level_num;
00052     // hard code parameters for now
00053     GridKeyPointFilter grid_filter(level_width, level_height, bucket_width,
00054                                    bucket_height, max_keypoints_per_bucket);
00055 
00056     PyramidLevel* level = new PyramidLevel(level_width, level_height,
00057                                            level_num, _feature_window_size,
00058                                            grid_filter);
00059     _levels.push_back(level);
00060   }
00061 }
00062 
00063 OdometryFrame::~OdometryFrame()
00064 {
00065   for (unsigned i=0; i<_levels.size(); i++)
00066     delete _levels[i];
00067   _levels.clear();
00068   _num_levels = 0;
00069 }
00070 
00071 void
00072 OdometryFrame::prepareFrame(const uint8_t* raw_gray,
00073                             int fast_threshold,
00074                             DepthSource* depth_source)
00075 {
00076   // copy raw image to first pyramid level
00077   assert(_num_levels);
00078   PyramidLevel* first_level = _levels[0];
00079   int src_stride = _orig_width;
00080   for (int row=0; row<_orig_height; row++) {
00081     memcpy(first_level->_raw_gray + row * first_level->_raw_gray_stride,
00082            raw_gray + row * src_stride, _orig_width);
00083   }
00084 
00085   if (_use_image_normalization) {
00086     normalize_image(first_level->_raw_gray, first_level->_raw_gray_stride,
00087                     _orig_width, _orig_height);
00088 
00089   }
00090 
00091   // compute image pyramid and detect initial features
00092   for (int level_num=0; level_num<_num_levels; level_num++) {
00093     PyramidLevel* level = _levels[level_num];
00094 
00095     if (level_num > 0) {
00096       // resize the image from the previous level
00097       PyramidLevel* prev_level = _levels[level_num-1];
00098       int prev_width = prev_level->getWidth();
00099       int prev_height = prev_level->getHeight();
00100       gauss_pyr_down_8u_C1R(prev_level->_raw_gray, prev_level->_raw_gray_stride,
00101           prev_width, prev_height,
00102           level->_raw_gray, level->_raw_gray_stride,
00103           prev_level->_pyrbuf);
00104     }
00105 
00106     level->_initial_keypoints.clear();
00107     FAST(level->_raw_gray, level->_width, level->_height, level->_raw_gray_stride,
00108         &level->_initial_keypoints, fast_threshold, 1);
00109 
00110     // Keep track of this number before filtering out keyoints with the
00111     // grid bucketing, to use it as a signal for FAST threshold adjustment.
00112     level->_num_detected_keypoints = static_cast<int>(level->_initial_keypoints.size());
00113 
00114     if (_use_bucketing) {
00115       tictoc("bucketing");
00116       level->_grid_filter.filter(&level->_initial_keypoints);
00117       tictoc("bucketing");
00118     }
00119 
00120     level->_num_keypoints = 0;
00121 
00122     int num_kp_candidates = level->_initial_keypoints.size();
00123 
00124     // increase buffer size if needed
00125     if (num_kp_candidates > level->_keypoints_capacity) {
00126       level->increase_capacity(static_cast<int>(num_kp_candidates*1.2));
00127     }
00128 
00129     int min_dist_from_edge = (_feature_window_size - 1) / 2 + 1;
00130     int min_x = min_dist_from_edge;
00131     int min_y = min_dist_from_edge;
00132     int max_x = level->_width - (min_dist_from_edge + 1);
00133     int max_y = level->_height - (min_dist_from_edge + 1);
00134 
00135     // filter the keypoint candidates, and compute derived data
00136     for (int kp_ind=0; kp_ind<num_kp_candidates; kp_ind++) {
00137       KeyPoint& kp_cand = level->_initial_keypoints[kp_ind];
00138 
00139       // ignore features too close to border
00140       if(kp_cand.u < min_x || kp_cand.u > max_x || kp_cand.v < min_y ||
00141          kp_cand.v > max_y)
00142         continue;
00143 
00144       KeypointData kpdata;
00145       kpdata.kp = kp_cand;
00146       kpdata.base_uv(0) = kp_cand.u * (1 << level_num);
00147       kpdata.base_uv(1) = kp_cand.v * (1 << level_num);
00148       kpdata.pyramid_level = level_num;
00149 
00150       assert(kpdata.base_uv(0) >= 0);
00151       assert(kpdata.base_uv(1) < _orig_width);
00152       assert(kpdata.base_uv(0) >= 0);
00153       assert(kpdata.base_uv(1) < _orig_height);
00154 
00155       // lookup rectified pixel coordinates
00156       int pixel_index = static_cast<int>(kpdata.base_uv(1) * _orig_width + kpdata.base_uv(0));
00157       _rectification->rectifyLookupByIndex(pixel_index, &kpdata.rect_base_uv);
00158 
00159       // Ignore the points that fall
00160       // outside the original image region when undistorted.
00161       if (kpdata.rect_base_uv(0) < 0 || kpdata.rect_base_uv(0) >= _orig_width ||
00162           kpdata.rect_base_uv(1) < 0 || kpdata.rect_base_uv(1) >= _orig_height) {
00163         continue;
00164       }
00165 
00166       // ignore features with unknown depth
00167       int du = static_cast<int>(kpdata.rect_base_uv(0)+0.5);
00168       int dv = static_cast<int>(kpdata.rect_base_uv(1)+0.5);
00169       if (!depth_source->haveXyz(du, dv)) { continue; }
00170 
00171       // We will calculate depth of all the keypoints later
00172       kpdata.xyzw = Eigen::Vector4d(NAN, NAN, NAN, NAN);
00173       kpdata.has_depth = false;
00174       kpdata.keypoint_index = level->_num_keypoints;
00175 
00176       kpdata.track_id = -1; //hasn't been associated with a track yet
00177 
00178       level->_keypoints[level->_num_keypoints] = kpdata;
00179       level->_num_keypoints++;
00180     }
00181 
00182     // extract features
00183     level->populateDescriptorsAligned(level->_keypoints, level->_num_keypoints,
00184                                       level->_descriptors);
00185   }
00186 
00187   // populate 3D position for descriptors. Depth calculation may fail for some
00188   // of these keypoints.
00189   depth_source->getXyz(this);
00190 
00191   // Get rid of keypoints with no depth.
00192   purgeBadKeypoints();
00193 
00194 }
00195 
00199 void
00200 OdometryFrame::purgeBadKeypoints() {
00201   tictoc("purge_bad_keypoints");
00202   for(int level_num=0; level_num<_num_levels; ++level_num) {
00203     PyramidLevel* level = _levels[level_num];
00204     int desc_stride = level->getDescriptorStride();
00205     // Invariant: kp_data_end and descriptors_end point at end
00206     // of arrays with 'good' keypoints and descriptors respectively
00207     KeypointData* kp_data_end = &(level->_keypoints[0]);
00208     uint8_t* descriptors_end = &(level->_descriptors[0]);
00209     for (int kp_ind=0; kp_ind < level->_num_keypoints; ++kp_ind) {
00210       KeypointData * kp_data = &(level->_keypoints[kp_ind]);
00211       uint8_t *desc = level->_descriptors + kp_ind * desc_stride;
00212       if (kp_data->has_depth) {
00213         // Keep this keypoint - copy it to end of 'good' keypoint array
00214         // Avoid redundant copying
00215         if (kp_data_end != kp_data) {
00216           *kp_data_end = *kp_data;
00217           memcpy(descriptors_end, desc, desc_stride);
00218         }
00219         ++kp_data_end;
00220         descriptors_end += desc_stride;
00221       }
00222     }
00223     int new_num_keypoints = kp_data_end - &(level->_keypoints[0]);
00224     level->_num_keypoints = new_num_keypoints;
00225     // Re-index keypoints to keep things consistent
00226     for (int kp_ind=0; kp_ind < level->_num_keypoints; ++kp_ind) {
00227       KeypointData& kp_data(level->_keypoints[kp_ind]);
00228       assert (kp_data.has_depth);
00229       kp_data.keypoint_index = kp_ind;
00230     }
00231   }
00232   tictoc("purge_bad_keypoints");
00233 }
00234 
00235 void
00236 OdometryFrame::sanityCheck() const
00237 {
00238 #ifndef NDEBUG
00239   for(int level_ind=0; level_ind<_num_levels; level_ind++) {
00240     const PyramidLevel* level = _levels[level_ind];
00241     int num_keypoints = level->_num_keypoints;
00242     for(int f_ind=0; f_ind<num_keypoints; f_ind++) {
00243       const KeypointData& kp = level->_keypoints[f_ind];
00244 
00245       assert(kp.kp.u >= 0 && kp.kp.v >= 0 &&
00246           kp.kp.u < level->_width && kp.kp.v < level->_height);
00247     }
00248   }
00249 #endif
00250 }
00251 
00252 }


libfovis
Author(s): Albert Huang, Maurice Fallon
autogenerated on Thu Jun 6 2019 20:16:12