From be0f5095a4f7e084c23b4dcd13e2cefc431562de Mon Sep 17 00:00:00 2001 From: sashichandra Date: Wed, 8 Nov 2017 02:27:18 +0000 Subject: [PATCH 1/2] Adds Dense SIFT feature type. http://www.vlfeat.org/overview/dsift.html --- config.yaml | 8 ++++++- opensfm/config.py | 8 ++++++- opensfm/features.py | 26 +++++++++++++++++++++- opensfm/src/csfm.cc | 8 +++++++ opensfm/src/dsift.cc | 52 ++++++++++++++++++++++++++++++++++++++++++++ opensfm/src/dsift.h | 15 +++++++++++++ 6 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 opensfm/src/dsift.cc create mode 100644 opensfm/src/dsift.h diff --git a/config.yaml b/config.yaml index 62c135604..4a5b17916 100644 --- a/config.yaml +++ b/config.yaml @@ -10,9 +10,15 @@ feature_process_size: 2048 # Resize the image if its size is larger than spec feature_use_adaptive_suppression: no # Params for SIFT -sift_peak_threshold: 0.1 # Smaller value -> more features +sift_peak_threshold: 0.1 # Smaller value -> more features sift_edge_threshold: 10 # See OpenCV doc +# Params for DSIFT +dsift_step: 16 # Sampling step, smaller value -> more features +dsift_bin_size: 8 +dsift_use_flat_window: yes # See VLFeat DSIFT doc +dsift_gaussian_blur: no # Smooth image using CV2 Gaussian Blur + # Params for SURF surf_hessian_threshold: 3000 # Smaller value -> more features surf_n_octaves: 4 # See OpenCV doc diff --git a/opensfm/config.py b/opensfm/config.py index 8432c845c..85ffad1dc 100644 --- a/opensfm/config.py +++ b/opensfm/config.py @@ -14,9 +14,15 @@ feature_use_adaptive_suppression: no # Params for SIFT -sift_peak_threshold: 0.1 # Smaller value -> more features +sift_peak_threshold: 0.1 # Smaller value -> more features sift_edge_threshold: 10 # See OpenCV doc +# Params for DSIFT +dsift_step: 16 # Sampling step, smaller value -> more features +dsift_bin_size: 8 +dsift_use_flat_window: yes # See VLFeat DSIFT doc +dsift_gaussian_blur: no # Smooth image using CV2 Gaussian Blur + # Params for SURF surf_hessian_threshold: 3000 # Smaller value -> more features surf_n_octaves: 4 # See OpenCV doc diff --git a/opensfm/features.py b/opensfm/features.py index 1c323c847..a2db448fe 100644 --- a/opensfm/features.py +++ b/opensfm/features.py @@ -130,6 +130,28 @@ def extract_features_sift(image, config): return points, desc +def extract_features_dsift(image, config): + t = time.time() + + if config.get('dsift_gaussian_blur', False): image = cv2.GaussianBlur(image, (5,5), 0) + points, desc = csfm.dsift(image.astype(np.float32) / 255, # VlFeat expects pixel values between 0, 1 + step = config.get('dsift_step', 16), + bin_size = config.get('dsift_bin_size', 8), + use_flat_window = config.get('dsift_use_flat_window', True)) + + if config.get('feature_root', False): + desc = np.sqrt(desc) + uchar_scaling = 362 # x * 512 < 256 => sqrt(x) * 362 < 256 + else: + uchar_scaling = 512 + + if config.get('dsift_normalize_to_uchar', False): + desc = (uchar_scaling * desc).clip(0, 255).round() + + logger.debug('Found {0} points in {1}s'.format( len(points), time.time()-t )) + return points, desc + + def extract_features_surf(image, config): surf_hessian_threshold = config.get('surf_hessian_threshold', 3000) if context.OPENCV3: @@ -260,6 +282,8 @@ def extract_features(color_image, config, mask=None): feature_type = config['feature_type'].upper() if feature_type == 'SIFT': points, desc = extract_features_sift(image, config) + elif feature_type == 'DSIFT': + points, desc = extract_features_dsift(image, config) elif feature_type == 'SURF': points, desc = extract_features_surf(image, config) elif feature_type == 'AKAZE': @@ -269,7 +293,7 @@ def extract_features(color_image, config, mask=None): elif feature_type == 'ORB': points, desc = extract_features_orb(image, config) else: - raise ValueError('Unknown feature type (must be SURF, SIFT, AKAZE, HAHOG or ORB)') + raise ValueError('Unknown feature type (must be SURF, SIFT, DSIFT, AKAZE, HAHOG or ORB)') xs = points[:, 0].round().astype(int) ys = points[:, 1].round().astype(int) diff --git a/opensfm/src/csfm.cc b/opensfm/src/csfm.cc index 545e3ee97..721cacb67 100644 --- a/opensfm/src/csfm.cc +++ b/opensfm/src/csfm.cc @@ -7,6 +7,7 @@ #include "types.h" #include "hahog.cc" +#include "dsift.cc" #include "multiview.cc" #include "akaze.cc" #include "bundle.h" @@ -78,6 +79,13 @@ BOOST_PYTHON_MODULE(csfm) { ) ); + def("dsift", csfm::dsift, + (boost::python::arg("step") = 16, + boost::python::arg("bin_size") = 8, + boost::python::arg("use_flat_window") = false + ) + ); + def("triangulate_bearings_dlt", csfm::TriangulateBearingsDLT); def("triangulate_bearings_midpoint", csfm::TriangulateBearingsMidpoint); diff --git a/opensfm/src/dsift.cc b/opensfm/src/dsift.cc new file mode 100644 index 000000000..38b3c12b0 --- /dev/null +++ b/opensfm/src/dsift.cc @@ -0,0 +1,52 @@ +#include "types.h" +#include "dsift.h" + +#include +#include + +extern "C" { + #include "vl/dsift.h" + #include "vl/imopv.h" + #include +} + + +namespace csfm { + +bp::object dsift(PyObject *image, + int step, + int bin_size, + bool use_flat_window) { + PyArrayContiguousView im((PyArrayObject *)image); + + if (im.valid()) { + VlDsiftFilter *dsift = vl_dsift_new_basic(im.shape(1), im.shape(0), step, bin_size); + vl_dsift_set_flat_window(dsift, use_flat_window); + vl_dsift_process(dsift, im.data()); + int const numkp = vl_dsift_get_keypoint_num(dsift); + VlDsiftKeypoint const * keypoints = vl_dsift_get_keypoints(dsift); + std::vector points(4 * numkp); + for (int i = 0; i < numkp; ++i) { + VlDsiftKeypoint const & kp = keypoints[i]; + points[4 * i + 0] = (float) kp.x; + points[4 * i + 1] = (float) kp.y; + points[4 * i + 2] = (float) kp.s; + points[4 * i + 3] = (float) kp.norm; + } + // Get the descriptors: size is descsize * numkp: + int const descsize = vl_dsift_get_descriptor_size(dsift); + std::vector desc(descsize * numkp); + float const *descriptors = vl_dsift_get_descriptors(dsift); + bp::list retn; + npy_intp points_shape[2] = {npy_intp(numkp), 4}; + retn.append(bpn_array_from_data(2, points_shape, &points[0])); + npy_intp desc_shape[2] = {npy_intp(numkp), npy_intp(descsize)}; + retn.append(bpn_array_from_data(2, desc_shape, descriptors)); + + vl_dsift_delete(dsift); + return retn; + } + return bp::object(); +} + +} diff --git a/opensfm/src/dsift.h b/opensfm/src/dsift.h new file mode 100644 index 000000000..eb9e80b44 --- /dev/null +++ b/opensfm/src/dsift.h @@ -0,0 +1,15 @@ +#ifndef __DSIFT_H__ +#define __DSIFT_H__ + +#include "types.h" + +namespace csfm { + +bp::object dsift(PyObject *image, + int step, + int bin_size, + bool use_flat_window); + +} + +#endif // __DSIFT_H__ From 40604b7741a5ebde2321955bebc370f348b10586 Mon Sep 17 00:00:00 2001 From: sashichandra Date: Wed, 8 Nov 2017 18:00:55 +0000 Subject: [PATCH 2/2] removes normalize_to_uchar option. --- opensfm/features.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/opensfm/features.py b/opensfm/features.py index a2db448fe..d21d95ebb 100644 --- a/opensfm/features.py +++ b/opensfm/features.py @@ -139,14 +139,7 @@ def extract_features_dsift(image, config): bin_size = config.get('dsift_bin_size', 8), use_flat_window = config.get('dsift_use_flat_window', True)) - if config.get('feature_root', False): - desc = np.sqrt(desc) - uchar_scaling = 362 # x * 512 < 256 => sqrt(x) * 362 < 256 - else: - uchar_scaling = 512 - - if config.get('dsift_normalize_to_uchar', False): - desc = (uchar_scaling * desc).clip(0, 255).round() + if config.get('feature_root', False): desc = np.sqrt(desc) logger.debug('Found {0} points in {1}s'.format( len(points), time.time()-t )) return points, desc