mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
Added some utility routines to the hough_transform object.
This commit is contained in:
parent
26c2cc4e49
commit
4d793ddd8a
@ -81,17 +81,15 @@ namespace dlib
|
||||
|
||||
// First we compute the radius measured in pixels from the center and the theta
|
||||
// angle in radians.
|
||||
typedef dlib::vector<double,2> vect;
|
||||
const rectangle box(0,0,size()-1,size()-1);
|
||||
const vect cent = center(box);
|
||||
double theta = p.x()-cent.x();
|
||||
double radius = p.y()-cent.y();
|
||||
theta = theta*pi/even_size;
|
||||
radius = radius*sqrt_2 + 0.5;
|
||||
double theta, radius;
|
||||
get_line_properties(p, theta, radius);
|
||||
theta *= pi/180;
|
||||
|
||||
// now make a line segment on the line.
|
||||
vect v1 = cent + vect(size()+1000,0) + vect(0,radius);
|
||||
vect v2 = cent - vect(size()+1000,0) + vect(0,radius);
|
||||
const rectangle box = get_rect(*this);
|
||||
const dpoint cent = center(box);
|
||||
dpoint v1 = cent + dpoint(size()+1000,0) + dpoint(0,radius);
|
||||
dpoint v2 = cent - dpoint(size()+1000,0) + dpoint(0,radius);
|
||||
point p1 = rotate_point(cent, v1, theta);
|
||||
point p2 = rotate_point(cent, v2, theta);
|
||||
|
||||
@ -100,6 +98,28 @@ namespace dlib
|
||||
return std::make_pair(p1,p2);
|
||||
}
|
||||
|
||||
double get_line_angle_in_degrees (
|
||||
const point& p
|
||||
) const
|
||||
{
|
||||
double angle, radius;
|
||||
get_line_properties(p, angle, radius);
|
||||
return angle;
|
||||
}
|
||||
|
||||
void get_line_properties (
|
||||
const point& p,
|
||||
double& angle_in_degrees,
|
||||
double& radius
|
||||
) const
|
||||
{
|
||||
const dpoint cent = center(get_rect(*this));
|
||||
double theta = p.x()-cent.x();
|
||||
radius = p.y()-cent.y();
|
||||
angle_in_degrees = 180*theta/even_size;
|
||||
radius = radius*sqrt_2 + 0.5;
|
||||
}
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
@ -274,7 +294,7 @@ namespace dlib
|
||||
{
|
||||
himg[hough_point.y()][hough_point.x()] += val;
|
||||
};
|
||||
perform_hough_transform(img_, box, record_hit);
|
||||
perform_generic_hough_transform(img_, box, record_hit);
|
||||
}
|
||||
|
||||
template <
|
||||
@ -296,12 +316,16 @@ namespace dlib
|
||||
std::vector<std::vector<point>> find_pixels_voting_for_lines (
|
||||
const in_image_type& img,
|
||||
const rectangle& box,
|
||||
const std::vector<point>& hough_points
|
||||
const std::vector<point>& hough_points,
|
||||
const unsigned long angle_window_size = 1,
|
||||
const unsigned long radius_window_size = 1
|
||||
) const
|
||||
{
|
||||
|
||||
typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
|
||||
|
||||
DLIB_CASSERT(angle_window_size >= 1);
|
||||
DLIB_CASSERT(radius_window_size >= 1);
|
||||
DLIB_CASSERT(box.width() == size() && box.height() == size(),
|
||||
"\t std::vector<std::vector<point>> hough_transform::find_pixels_voting_for_lines()"
|
||||
<< "\n\t Invalid arguments given to this function."
|
||||
@ -325,7 +349,16 @@ namespace dlib
|
||||
matrix<uint32> hmap(size(),size());
|
||||
hmap = hough_points.size();
|
||||
for (size_t i = 0; i < hough_points.size(); ++i)
|
||||
hmap(hough_points[i].y(),hough_points[i].x()) = i;
|
||||
{
|
||||
rectangle area = centered_rect(hough_points[i],angle_window_size,radius_window_size).intersect(get_rect(hmap));
|
||||
for (long r = area.top(); r <= area.bottom(); ++r)
|
||||
{
|
||||
for (long c = area.left(); c <= area.right(); ++c)
|
||||
{
|
||||
hmap(r,c) = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// record that this image point voted for this Hough point
|
||||
auto record_hit = [&](const point& hough_point, const point& img_point, in_pixel_type)
|
||||
@ -335,7 +368,7 @@ namespace dlib
|
||||
constituent_points[idx].push_back(img_point);
|
||||
};
|
||||
|
||||
perform_hough_transform(img, box, record_hit);
|
||||
perform_generic_hough_transform(img, box, record_hit);
|
||||
|
||||
return constituent_points;
|
||||
}
|
||||
@ -345,20 +378,90 @@ namespace dlib
|
||||
>
|
||||
std::vector<std::vector<point>> find_pixels_voting_for_lines (
|
||||
const in_image_type& img,
|
||||
const std::vector<point>& hough_points
|
||||
const std::vector<point>& hough_points,
|
||||
const unsigned long angle_window_size = 1,
|
||||
const unsigned long radius_window_size = 1
|
||||
) const
|
||||
{
|
||||
rectangle box(0,0, num_columns(img)-1, num_rows(img)-1);
|
||||
return find_pixels_voting_for_lines(img, box, hough_points);
|
||||
return find_pixels_voting_for_lines(img, box, hough_points, angle_window_size, radius_window_size);
|
||||
}
|
||||
|
||||
template <
|
||||
typename image_type,
|
||||
typename thresh_type
|
||||
>
|
||||
std::vector<point> find_strong_hough_points(
|
||||
const image_type& himg_,
|
||||
const thresh_type hough_count_threshold,
|
||||
const double angle_nms_thresh,
|
||||
const double radius_nms_thresh
|
||||
)
|
||||
{
|
||||
const_image_view<image_type> himg(himg_);
|
||||
|
||||
DLIB_CASSERT(himg.nr() == size());
|
||||
DLIB_CASSERT(himg.nc() == size());
|
||||
DLIB_CASSERT(angle_nms_thresh >= 0)
|
||||
DLIB_CASSERT(radius_nms_thresh >= 0)
|
||||
|
||||
std::vector<std::pair<double,point>> initial_lines;
|
||||
for (long r = 0; r < himg.nr(); ++r)
|
||||
{
|
||||
for (long c = 0; c < himg.nc(); ++c)
|
||||
{
|
||||
if (himg[r][c] >= hough_count_threshold)
|
||||
initial_lines.emplace_back(himg[r][c], point(c,r));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<point> final_lines;
|
||||
std::vector<std::pair<double,double>> final_angle_and_radius;
|
||||
|
||||
// Now do non-max suppression. First, sort the initial_lines so the best lines come first.
|
||||
std::sort(initial_lines.rbegin(), initial_lines.rend(),
|
||||
[](const std::pair<double,point>& a, const std::pair<double,point>& b){ return a.first<b.first;});
|
||||
for (auto& r : initial_lines)
|
||||
{
|
||||
double angle, radius;
|
||||
get_line_properties(r.second, angle, radius);
|
||||
|
||||
// check if anything in final_lines is too close to r.second. If
|
||||
// something is found then discard r.second.
|
||||
auto too_close = false;
|
||||
for (auto& ref : final_angle_and_radius)
|
||||
{
|
||||
auto& ref_angle = ref.first;
|
||||
auto& ref_radius = ref.second;
|
||||
|
||||
// We need to check for wrap around in angle since, for instance, a
|
||||
// line with angle and radius of 90 and 10 is the same line as one with
|
||||
// angle -90 and radius -10.
|
||||
if ((std::abs(ref_angle - angle) < angle_nms_thresh && std::abs(ref_radius-radius) < radius_nms_thresh) ||
|
||||
(180 - std::abs(ref_angle - angle) < angle_nms_thresh && std::abs(ref_radius+radius) < radius_nms_thresh))
|
||||
{
|
||||
too_close = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!too_close)
|
||||
{
|
||||
final_lines.emplace_back(r.second);
|
||||
final_angle_and_radius.emplace_back(angle, radius);
|
||||
}
|
||||
}
|
||||
|
||||
return final_lines;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename record_hit_function_type
|
||||
>
|
||||
void perform_hough_transform (
|
||||
void perform_generic_hough_transform (
|
||||
const in_image_type& img_,
|
||||
const rectangle& box,
|
||||
record_hit_function_type record_hit
|
||||
@ -368,7 +471,7 @@ namespace dlib
|
||||
typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
|
||||
|
||||
DLIB_ASSERT(box.width() == size() && box.height() == size(),
|
||||
"\t void hough_transform::perform_hough_transform()"
|
||||
"\t void hough_transform::perform_generic_hough_transform()"
|
||||
<< "\n\t Invalid arguments given to this function."
|
||||
<< "\n\t box.width(): " << box.width()
|
||||
<< "\n\t box.height(): " << box.height()
|
||||
@ -458,6 +561,21 @@ namespace dlib
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename record_hit_function_type
|
||||
>
|
||||
void perform_generic_hough_transform (
|
||||
const in_image_type& img_,
|
||||
record_hit_function_type record_hit
|
||||
) const
|
||||
{
|
||||
rectangle box(0,0, num_columns(img_)-1, num_rows(img_)-1);
|
||||
perform_generic_hough_transform(img_, box, record_hit);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
unsigned long _size;
|
||||
unsigned long even_size; // equal to _size if _size is even, otherwise equal to _size-1.
|
||||
matrix<int32> xcos_theta, ysin_theta;
|
||||
|
@ -78,6 +78,37 @@ namespace dlib
|
||||
- The returned points are inside rectangle(0,0,size()-1,size()-1).
|
||||
!*/
|
||||
|
||||
double get_line_angle_in_degrees (
|
||||
const point& p
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
- rectangle(0,0,size()-1,size()-1).contains(p) == true
|
||||
(i.e. p must be a point inside the Hough accumulator array)
|
||||
ensures
|
||||
- returns the angle, in degrees, of the line corresponding to the Hough
|
||||
transform point p.
|
||||
!*/
|
||||
|
||||
void get_line_properties (
|
||||
const point& p,
|
||||
double& angle_in_degrees,
|
||||
double& radius
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
- rectangle(0,0,size()-1,size()-1).contains(p) == true
|
||||
(i.e. p must be a point inside the Hough accumulator array)
|
||||
ensures
|
||||
- Converts a point in the Hough transform space into an angle, in degrees,
|
||||
and a radius, measured in pixels from the center of the input image.
|
||||
- #angle_in_degrees == the angle of the line corresponding to the Hough
|
||||
transform point p. Moreover: -90 <= #angle_in_degrees < 90.
|
||||
- #radius == the distance from the center of the input image, measured in
|
||||
pixels, and the line corresponding to the Hough transform point p.
|
||||
Moreover: -sqrt(size()*size()/2) <= #radius <= sqrt(size()*size()/2)
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
@ -134,7 +165,9 @@ namespace dlib
|
||||
point in #himg corresponds to a line in the input box. In particular,
|
||||
the line for #himg[y][x] is given by get_line(point(x,y)). Also, when
|
||||
viewing the #himg image, the x-axis gives the angle of the line and the
|
||||
y-axis the distance of the line from the center of the box.
|
||||
y-axis the distance of the line from the center of the box. The
|
||||
conversion between Hough coordinates and angle and pixel distance can be
|
||||
obtained by calling get_line_properties().
|
||||
!*/
|
||||
|
||||
template <
|
||||
@ -164,7 +197,9 @@ namespace dlib
|
||||
std::vector<std::vector<point>> find_pixels_voting_for_lines (
|
||||
const in_image_type& img,
|
||||
const rectangle& box,
|
||||
const std::vector<point>& hough_points
|
||||
const std::vector<point>& hough_points,
|
||||
const unsigned long angle_window_size = 1,
|
||||
const unsigned long radius_window_size = 1
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
@ -176,9 +211,11 @@ namespace dlib
|
||||
- get_rect(*this).contains(hough_points[i]) == true
|
||||
(i.e. hough_points must contain points in the output Hough transform
|
||||
space generated by this object.)
|
||||
- angle_window_size >= 1
|
||||
- radius_window_size >= 1
|
||||
ensures
|
||||
- This function computes the Hough transform of the part of img contained
|
||||
within box. It does the same computation as operator() define above,
|
||||
within box. It does the same computation as operator() defined above,
|
||||
except instead of accumulating into an image we create an explicit list
|
||||
of all the points in img that contributed to each line (i.e each point in
|
||||
the Hough image). To do this we take a list of Hough points as input and
|
||||
@ -191,13 +228,19 @@ namespace dlib
|
||||
It has the following properties:
|
||||
- #CONSTITUENT_POINTS.size() == hough_points.size()
|
||||
- for all valid i:
|
||||
- Any point in img with a non-zero value that lies on the line
|
||||
corresponding to the Hough point hough_points[i] is added to
|
||||
- Let HP[i] = centered_rect(hough_points[i], angle_window_size, radius_window_size)
|
||||
- Any point in img with a non-zero value that lies on a line
|
||||
corresponding to one of the Hough points in HP[i] is added to
|
||||
CONSTITUENT_POINTS[i]. Therefore, when this routine finishes,
|
||||
#CONSTITUENT_POINTS[i] will contain all the points in img that voted
|
||||
for the line hough_points[i].
|
||||
- #CONSTITUENT_POINTS[i].size() == the number of points in img that voted for
|
||||
the line hough_points[i].
|
||||
for the lines associated with the Hough accumulator bins in HP[i].
|
||||
- #CONSTITUENT_POINTS[i].size() == the number of points in img that
|
||||
voted for any of the lines HP[i] in Hough space. Note, however, that if
|
||||
angle_window_size or radius_window_size are made so large that HP[i]
|
||||
overlaps HP[j] for i!=j then the overlapping regions of Hough space
|
||||
are assign to HP[i] or HP[j] arbitrarily. Therefore, all points in
|
||||
CONSTITUENT_POINTS are unique, that is, there is no overlap in points
|
||||
between any element of CONSTITUENT_POINTS.
|
||||
!*/
|
||||
|
||||
template <
|
||||
@ -205,7 +248,9 @@ namespace dlib
|
||||
>
|
||||
std::vector<std::vector<point>> find_pixels_voting_for_lines (
|
||||
const in_image_type& img,
|
||||
const std::vector<point>& hough_points
|
||||
const std::vector<point>& hough_points,
|
||||
const unsigned long angle_window_size = 1,
|
||||
const unsigned long radius_window_size = 1
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
@ -217,9 +262,97 @@ namespace dlib
|
||||
- get_rect(*this).contains(hough_points[i]) == true
|
||||
(i.e. hough_points must contain points in the output Hough transform
|
||||
space generated by this object.)
|
||||
- angle_window_size >= 1
|
||||
- radius_window_size >= 1
|
||||
ensures
|
||||
- performs: return find_pixels_voting_for_lines(img, get_rect(img), hough_points);
|
||||
That is, just runs the hough transform on the whole input image.
|
||||
- performs: return find_pixels_voting_for_lines(img, get_rect(img), hough_points, angle_window_size, radius_window_size);
|
||||
That is, just runs the routine on the whole input image.
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename image_type,
|
||||
typename thresh_type
|
||||
>
|
||||
std::vector<point> find_strong_hough_points(
|
||||
const image_type& himg,
|
||||
const thresh_type hough_count_threshold,
|
||||
const double angle_nms_thresh,
|
||||
const double radius_nms_thresh
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h and it must contain grayscale pixels.
|
||||
- himg.nr() == size()
|
||||
- himg.nc() == size()
|
||||
- angle_nms_thresh >= 0
|
||||
- radius_nms_thresh >= 0
|
||||
ensures
|
||||
- This routine finds strong lines in a Hough transform and performs
|
||||
non-maximum suppression on the detected lines. Recall that each point in
|
||||
Hough space is associated with a line. Therefore, this routine finds all
|
||||
the pixels in himg (a Hough transform image) with values >=
|
||||
hough_count_threshold and performs non-maximum suppression on the
|
||||
identified list of pixels. It does this by discarding lines that are
|
||||
within angle_nms_thresh degrees of a stronger line or within
|
||||
radius_nms_thresh distance (in terms of radius as defined by
|
||||
get_line_properties()) to a stronger Hough point.
|
||||
- The identified lines is returned as a list of coordinates in himg.
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename record_hit_function_type
|
||||
>
|
||||
void perform_generic_hough_transform (
|
||||
const in_image_type& img,
|
||||
const rectangle& box,
|
||||
record_hit_function_type record_hit
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
- in_image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h and it must contain grayscale pixels.
|
||||
- box.width() == size()
|
||||
- box.height() == size()
|
||||
- record_hit is a function object with the signature:
|
||||
void record_hit(const point& hough_point, const point& img_point, in_image_pixel_type value)
|
||||
ensures
|
||||
- Computes the Hough transform of the part of img contained within box.
|
||||
This routine is very general and allows you to implement a wide variety
|
||||
of Hough transforms, in fact, the operator() and
|
||||
find_pixels_voting_for_lines() routines defined above are implemented in
|
||||
terms of perform_generic_hough_transform(). The behavior is described by
|
||||
the following pseudo-code:
|
||||
for (image_coordinate : all_coordinates_in_img)
|
||||
for (hough_point : all_Hough_space_coordinates_for_lines_passing_through_image_coordinate)
|
||||
record_hit(hough_point, image_coordinate, img[image_coordinate.y][image_coordinate.x()]);
|
||||
That is, we perform the Hough transform, but rather than accumulating
|
||||
into a Hough accumulator image, we call record_hit() and record_hit()
|
||||
does whatever it wants. For example, in the operator() method defined
|
||||
above record_hit() simply accumulates into an image, and therefor
|
||||
performs the classic Hough transform. But there are many other options.
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename record_hit_function_type
|
||||
>
|
||||
void perform_generic_hough_transform (
|
||||
const in_image_type& img,
|
||||
record_hit_function_type record_hit
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
- in_image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h and it must contain grayscale pixels.
|
||||
- record_hit is a function object with the signature:
|
||||
void record_hit(const point& hough_point, const point& img_point, in_image_pixel_type value)
|
||||
- num_rows(img) == size()
|
||||
- num_columns(img) == size()
|
||||
ensures
|
||||
- performs: perform_generic_hough_transform(img, get_rect(img), record_hit);
|
||||
That is, just runs the routine on the whole input image.
|
||||
!*/
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user