00001 #include "stereo_frame.hpp"
00002
00003 #include <stdio.h>
00004
00005 #include <iostream>
00006
00007 #include "visual_odometry.hpp"
00008 #include "internal_utils.hpp"
00009 #include "gauss_pyramid.h"
00010 #include "fast.hpp"
00011 #include "tictoc.hpp"
00012 #include "rectification.hpp"
00013 #include "normalize_image.hpp"
00014
00015 #ifndef ALIGNMENT
00016 #define ALIGNMENT 16
00017 #endif
00018
00019 namespace fovis
00020 {
00021
00022 static bool
00023 keypoint_rect_v_comparator(const KeypointData& a,
00024 const KeypointData& b) {
00025 return (a.rect_base_uv(1) < b.rect_base_uv(1));
00026 }
00027
00028 StereoFrame::StereoFrame(int width, int height,
00029 const Rectification* rectify_map,
00030 const VisualOdometryOptions& options) :
00031 _base_width(width), _base_height(height)
00032 {
00033
00034 const VisualOdometryOptions& defaults(VisualOdometry::getDefaultOptions());
00035
00036 _num_levels = optionsGetIntOrFromDefault(options, "max-pyramid-level", defaults);
00037 _feature_window_size = optionsGetIntOrFromDefault(options, "feature-window-size", defaults);
00038 _use_bucketing = optionsGetBoolOrFromDefault(options, "use-bucketing", defaults);
00039 _use_image_normalization = optionsGetBoolOrFromDefault(options, "use-image-normalization", defaults);
00040
00041 int bucket_width = optionsGetIntOrFromDefault(options, "bucket-width", defaults);
00042 int bucket_height = optionsGetIntOrFromDefault(options, "bucket-height", defaults);
00043 int max_keypoints_per_bucket = optionsGetIntOrFromDefault(options, "max-keypoints-per-bucket", defaults);
00044
00045 _rectify_map = rectify_map->makeCopy();
00046 initialize(bucket_width, bucket_height, max_keypoints_per_bucket);
00047 }
00048
00049 StereoFrame::~StereoFrame() {
00050 for (std::vector<PyramidLevel *>::iterator itr = _levels.begin();
00051 itr != _levels.end();
00052 ++itr) {
00053 delete *itr;
00054 }
00055 delete _rectify_map;
00056 }
00057
00058 void
00059 StereoFrame::initialize(int bucket_width,
00060 int bucket_height,
00061 int max_keypoints_per_bucket) {
00062 for(int level_num=0; level_num < _num_levels; ++level_num) {
00063
00064 int level_width = _base_width >> level_num;
00065 int level_height = _base_height >> level_num;
00066
00067 GridKeyPointFilter grid_filter(level_width, level_height, bucket_width,
00068 bucket_height, max_keypoints_per_bucket);
00069
00070 PyramidLevel* level = new PyramidLevel(level_width, level_height,
00071 level_num, _feature_window_size,
00072 grid_filter);
00073 _levels.push_back(level);
00074 }
00075 }
00076
00077 void
00078 StereoFrame::prepareFrame(const uint8_t* raw_gray, int fast_threshold) {
00079
00080
00081 assert(_num_levels);
00082 PyramidLevel* first_level = _levels[0];
00083 int src_stride = _base_width;
00084 for(int row=0; row<_base_height; row++) {
00085 memcpy(first_level->_raw_gray + row * first_level->_raw_gray_stride,
00086 raw_gray + row * src_stride, _base_width);
00087 }
00088
00089 if (_use_image_normalization) {
00090 normalize_image(first_level->_raw_gray, first_level->_raw_gray_stride,
00091 _base_width, _base_height);
00092 }
00093
00094
00095 for(int level_num=0; level_num<_num_levels; ++level_num) {
00096 PyramidLevel* level = _levels[level_num];
00097 if(level_num > 0) {
00098
00099 PyramidLevel* prev_level = _levels[level_num-1];
00100 int prev_width = prev_level->getWidth();
00101 int prev_height = prev_level->getHeight();
00102 gauss_pyr_down_8u_C1R(prev_level->_raw_gray, prev_level->_raw_gray_stride,
00103 prev_width, prev_height, level->_raw_gray, level->_raw_gray_stride,
00104 prev_level->_pyrbuf);
00105 }
00106
00107 level->_initial_keypoints.clear();
00108 FAST(level->_raw_gray, level->_width, level->_height, level->_raw_gray_stride,
00109 &level->_initial_keypoints, fast_threshold, 1);
00110
00111
00112
00113 level->_num_detected_keypoints = static_cast<int>(level->_initial_keypoints.size());
00114
00115 if (_use_bucketing) {
00116 tictoc("bucketing");
00117 level->_grid_filter.filter(&level->_initial_keypoints);
00118 tictoc("bucketing");
00119 }
00120
00121 level->_num_keypoints = 0;
00122
00123 int num_kp_candidates = level->_initial_keypoints.size();
00124
00125
00126 if(num_kp_candidates > level->_keypoints_capacity) {
00127 level->increase_capacity((int)(num_kp_candidates * 1.2));
00128 }
00129
00130 int num_features = 0;
00131 for(int kp_ind=0; kp_ind<num_kp_candidates; ++kp_ind) {
00132
00133 KeyPoint& kp_cand = level->_initial_keypoints[kp_ind];
00134
00135 if (!level->isLegalKeypointCoordinate(kp_cand.u, kp_cand.v)) {
00136 continue;
00137 }
00138
00139
00140 KeypointData kpdata;
00141 kpdata.kp = kp_cand;
00142 kpdata.base_uv(0) = kp_cand.u * (1 << level_num);
00143 kpdata.base_uv(1) = kp_cand.v * (1 << level_num);
00144
00145 int pixel_index = (int)(kpdata.base_uv(1) * _base_width + kpdata.base_uv(0));
00146 _rectify_map->rectifyLookupByIndex(pixel_index, &kpdata.rect_base_uv);
00147 if(kpdata.rect_base_uv(0) < 0 || kpdata.rect_base_uv(0) >= _base_width ||
00148 kpdata.rect_base_uv(1) < 0 || kpdata.rect_base_uv(1) >= _base_height) {
00149 continue;
00150 }
00151 kpdata.pyramid_level = level_num;
00152 kpdata.has_depth = false;
00153 kpdata.xyzw = Eigen::Vector4d(NAN, NAN, NAN, NAN);
00154 kpdata.keypoint_index = num_features;
00155 kpdata.track_id = -1;
00156
00157 num_features++;
00158
00159 level->_keypoints[level->_num_keypoints] = kpdata;
00160 level->_num_keypoints++;
00161 }
00162
00163
00164 std::sort(&(level->_keypoints[0]),
00165 &(level->_keypoints[level->_num_keypoints]),
00166 keypoint_rect_v_comparator);
00167
00168
00169 level->populateDescriptorsAligned(level->_keypoints, level->_num_keypoints,
00170 level->_descriptors);
00171
00172 }
00173 }
00174
00175 }