in opensfm/src/features/src/hahog.cc [123:202]
py::tuple hahog(foundation::pyarray_f image, float peak_threshold,
float edge_threshold, int target_num_features) {
if (!image.size()) {
return py::none();
}
std::vector<float> points;
std::vector<float> desc;
vl_size numFeatures;
vl_size dimension = 128;
{
py::gil_scoped_release release;
// create a detector object
VlCovDet *covdet = vl_covdet_new(VL_COVDET_METHOD_HESSIAN);
// set various parameters (optional)
vl_covdet_set_first_octave(covdet, 0);
vl_covdet_set_peak_threshold(covdet, peak_threshold);
vl_covdet_set_edge_threshold(covdet, edge_threshold);
// process the image and run the detector
vl_covdet_put_image(covdet, image.data(), image.shape(1), image.shape(0));
vl_covdet_set_non_extrema_suppression_threshold(covdet, 0);
vl_covdet_detect(covdet, std::numeric_limits<vl_size>::max());
// select the best features to keep
numFeatures = run_features_selection(covdet, target_num_features);
// compute the orientation of the features (optional)
std::vector<VlCovDetFeature> vecFeatures =
vlfeat_covdet_extract_orientations(covdet, numFeatures);
numFeatures = vecFeatures.size();
// get feature descriptors
VlSiftFilt *sift = vl_sift_new(16, 16, 1, 3, 0);
vl_index i;
vl_index patchResolution = 15;
double patchRelativeExtent = 7.5;
double patchRelativeSmoothing = 1;
vl_size patchSide = 2 * patchResolution + 1;
double patchStep = (double)patchRelativeExtent / patchResolution;
points.resize(4 * numFeatures);
desc.resize(dimension * numFeatures);
std::vector<float> patch(patchSide * patchSide);
std::vector<float> patchXY(2 * patchSide * patchSide);
vl_sift_set_magnif(sift, 3.0);
for (i = 0; i < (signed)numFeatures; ++i) {
const VlFrameOrientedEllipse &frame = vecFeatures.at(i).frame;
float det = frame.a11 * frame.a22 - frame.a12 * frame.a21;
float size = sqrt(fabs(det));
float angle = atan2(frame.a21, frame.a11) * 180.0f / M_PI;
points[4 * i + 0] = frame.x;
points[4 * i + 1] = frame.y;
points[4 * i + 2] = size;
points[4 * i + 3] = angle;
vl_covdet_extract_patch_for_frame(covdet, &patch[0], patchResolution,
patchRelativeExtent,
patchRelativeSmoothing, frame);
vl_imgradient_polar_f(&patchXY[0], &patchXY[1], 2, 2 * patchSide,
&patch[0], patchSide, patchSide, patchSide);
vl_sift_calc_raw_descriptor(
sift, &patchXY[0], &desc[dimension * i], (int)patchSide,
(int)patchSide, (double)(patchSide - 1) / 2,
(double)(patchSide - 1) / 2,
(double)patchRelativeExtent / (3.0 * (4 + 1) / 2) / patchStep,
VL_PI / 2);
}
vl_sift_delete(sift);
vl_covdet_delete(covdet);
}
return py::make_tuple(
foundation::py_array_from_data(points.data(), numFeatures, 4),
foundation::py_array_from_data(desc.data(), numFeatures, dimension));
}