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
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
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
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
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
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
00111
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
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
00136 for (int kp_ind=0; kp_ind<num_kp_candidates; kp_ind++) {
00137 KeyPoint& kp_cand = level->_initial_keypoints[kp_ind];
00138
00139
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
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
00160
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
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
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;
00177
00178 level->_keypoints[level->_num_keypoints] = kpdata;
00179 level->_num_keypoints++;
00180 }
00181
00182
00183 level->populateDescriptorsAligned(level->_keypoints, level->_num_keypoints,
00184 level->_descriptors);
00185 }
00186
00187
00188
00189 depth_source->getXyz(this);
00190
00191
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
00206
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
00214
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
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 }