diff options
Diffstat (limited to 'ml/dlib/dlib/image_keypoint/surf.h')
-rw-r--r-- | ml/dlib/dlib/image_keypoint/surf.h | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/ml/dlib/dlib/image_keypoint/surf.h b/ml/dlib/dlib/image_keypoint/surf.h new file mode 100644 index 000000000..d12b30840 --- /dev/null +++ b/ml/dlib/dlib/image_keypoint/surf.h @@ -0,0 +1,295 @@ +// Copyright (C) 2009 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SURf_H_ +#define DLIB_SURf_H_ + +#include "surf_abstract.h" +#include "hessian_pyramid.h" +#include "../matrix.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct surf_point + { + interest_point p; + matrix<double,64,1> des; + double angle; + }; + +// ---------------------------------------------------------------------------------------- + + inline void serialize( + const surf_point& item, + std::ostream& out + ) + { + try + { + serialize(item.p,out); + serialize(item.des,out); + serialize(item.angle,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type surf_point"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void deserialize( + surf_point& item, + std::istream& in + ) + { + try + { + deserialize(item.p,in); + deserialize(item.des,in); + deserialize(item.angle,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type surf_point"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline double gaussian (double x, double y, double sig) + { + DLIB_ASSERT(sig > 0, + "\tdouble gaussian()" + << "\n\t sig must be bigger than 0" + << "\n\t sig: " << sig + ); + const double sqrt_2_pi = 2.5066282746310002416123552393401041626930; + return 1.0/(sig*sqrt_2_pi) * std::exp( -(x*x + y*y)/(2*sig*sig)); + } + +// ---------------------------------------------------------------------------------------- + + template <typename integral_image_type, typename T> + double compute_dominant_angle ( + const integral_image_type& img, + const dlib::vector<T,2>& center, + const double& scale + ) + { + DLIB_ASSERT(get_rect(img).contains(centered_rect(center, (unsigned long)(17*scale),(unsigned long)(17*scale))) == true && + scale > 0, + "\tdouble compute_dominant_angle(img, center, scale)" + << "\n\tAll arguments to this function must be > 0" + << "\n\t get_rect(img): " << get_rect(img) + << "\n\t center: " << center + << "\n\t scale: " << scale + ); + + + std::vector<double> ang; + std::vector<dlib::vector<double,2> > samples; + + const long sc = static_cast<long>(scale+0.5); + + // accumulate a bunch of angle and vector samples + dlib::vector<double,2> vect; + for (long r = -6; r <= 6; ++r) + { + for (long c = -6; c <= 6; ++c) + { + if (r*r + c*c < 36) + { + // compute a Gaussian weighted gradient and the gradient's angle. + const double gauss = gaussian(c,r, 2.5); + vect.x() = gauss*haar_x(img, sc*point(c,r)+center, 4*sc); + vect.y() = gauss*haar_y(img, sc*point(c,r)+center, 4*sc); + samples.push_back(vect); + ang.push_back(atan2(vect.y(), vect.x())); + } + } + } + + + // now find the dominant direction + double max_length = 0; + double best_ang = 0; + // look at a bunch of pie shaped slices of a circle + const long slices = 45; + const double ang_step = (2*pi)/slices; + for (long ang_i = 0; ang_i < slices; ++ang_i) + { + // compute the bounding angles + double ang1 = ang_step*ang_i - pi; + double ang2 = ang1 + pi/3; + + + // compute sum of all vectors that are within the above two angles + vect.x() = 0; + vect.y() = 0; + for (unsigned long i = 0; i < ang.size(); ++i) + { + if (ang1 <= ang[i] && ang[i] <= ang2) + { + vect += samples[i]; + } + else if (ang2 > pi && (ang[i] >= ang1 || ang[i] <= (-2*pi+ang2))) + { + vect += samples[i]; + } + } + + + // record the angle of the best vectors + if (length_squared(vect) > max_length) + { + max_length = length_squared(vect); + best_ang = atan2(vect.y(), vect.x()); + } + } + + return best_ang; + } + +// ---------------------------------------------------------------------------------------- + + template <typename integral_image_type, typename T, typename MM, typename L> + void compute_surf_descriptor ( + const integral_image_type& img, + const dlib::vector<T,2>& center, + const double scale, + const double angle, + matrix<double,64,1,MM,L>& des + ) + { + DLIB_ASSERT(get_rect(img).contains(centered_rect(center, (unsigned long)(32*scale),(unsigned long)(32*scale))) == true && + scale > 0, + "\tvoid compute_surf_descriptor(img, center, scale, angle)" + << "\n\tAll arguments to this function must be > 0" + << "\n\t get_rect(img): " << get_rect(img) + << "\n\t center: " << center + << "\n\t scale: " << scale + ); + + point_rotator rot(angle); + point_rotator inv_rot(-angle); + + const long sc = static_cast<long>(scale+0.5); + long count = 0; + + // loop over the 4x4 grid of histogram buckets + for (long r = -10; r < 10; r += 5) + { + for (long c = -10; c < 10; c += 5) + { + dlib::vector<double,2> vect, abs_vect, temp; + + // now loop over 25 points in this bucket and sum their features. Note + // that we include 1 pixels worth of padding around the outside of each 5x5 + // cell. This is to help neighboring cells interpolate their counts into + // each other a little bit. + for (long y = r-1; y < r+5+1; ++y) + { + if (y < -10 || y >= 10) + continue; + for (long x = c-1; x < c+5+1; ++x) + { + if (x < -10 || x >= 10) + continue; + + // get the rotated point for this extraction point + point p(rot(point(x,y)*scale) + center); + + // Give points farther from the center of the bucket a lower weight. + const long center_r = r+2; + const long center_c = c+2; + const double weight = 1.0/(4+std::abs(center_r-y) + std::abs(center_c-x)); + + temp.x() = weight*haar_x(img, p, 2*sc); + temp.y() = weight*haar_y(img, p, 2*sc); + + // rotate this vector into alignment with the surf descriptor box + temp = inv_rot(temp); + + vect += temp; + abs_vect += abs(temp); + } + } + + des(count++) = vect.x(); + des(count++) = vect.y(); + des(count++) = abs_vect.x(); + des(count++) = abs_vect.y(); + } + } + + // Return the length normalized descriptor. Add a small number + // to guard against division by zero. + const double len = length(des) + 1e-7; + des = des/len; + } + +// ---------------------------------------------------------------------------------------- + + template <typename image_type> + const std::vector<surf_point> get_surf_points ( + const image_type& img, + long max_points = 10000, + double detection_threshold = 30.0 + ) + { + DLIB_ASSERT(max_points > 0 && detection_threshold >= 0, + "\t std::vector<surf_point> get_surf_points()" + << "\n\t Invalid arguments were given to this function." + << "\n\t max_points: " << max_points + << "\n\t detection_threshold: " << detection_threshold + ); + + // Figure out the proper scalar type we should use to work with these pixels. + typedef typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type bp_type; + typedef typename promote<bp_type>::type working_pixel_type; + + // make an integral image first + integral_image_generic<working_pixel_type> int_img; + int_img.load(img); + + // now make a hessian pyramid + hessian_pyramid pyr; + pyr.build_pyramid(int_img, 4, 6, 2); + + // now get all the interest points from the hessian pyramid + std::vector<interest_point> points; + get_interest_points(pyr, detection_threshold, points); + std::vector<surf_point> spoints; + + // sort all the points by how strong their detect is + std::sort(points.rbegin(), points.rend()); + + // now extract SURF descriptors for the points + surf_point sp; + for (unsigned long i = 0; i < std::min((size_t)max_points,points.size()); ++i) + { + // ignore points that are close to the edge of the image + const double border = 32; + const unsigned long border_size = static_cast<unsigned long>(border*points[i].scale); + if (get_rect(int_img).contains(centered_rect(points[i].center, border_size, border_size))) + { + sp.angle = compute_dominant_angle(int_img, points[i].center, points[i].scale); + compute_surf_descriptor(int_img, points[i].center, points[i].scale, sp.angle, sp.des); + sp.p = points[i]; + + spoints.push_back(sp); + } + } + + return spoints; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SURf_H_ + |