Skip to content

Commit 36ae17b

Browse files
committed
Clarified use of Hough functions, and added example program comparing Hough and Radon for circles.
1 parent a609e6c commit 36ae17b

3 files changed

Lines changed: 102 additions & 8 deletions

File tree

‎examples/CMakeLists.txt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ if(DIP_BUILD_DIPVIEWER)
136136
target_compile_definitions(blend_images PRIVATE DIP_EXAMPLES_DIR="${CMAKE_CURRENT_LIST_DIR}")
137137
target_link_libraries(blend_images DIP DIPviewer)
138138

139+
# An example program that shows how to use dip::FindHoughCircles and dip::RadonTransformCircles, and use dip::viewer::Show
140+
add_executable(detect_circles cpp/detect_circles.cpp)
141+
target_link_libraries(detect_circles DIP DIPviewer)
142+
139143
add_dependencies(examples
140144
viewer
141145
display

‎examples/cpp/detect_circles.cpp‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* This program shows how to use dip::FindHoughCircles and dip::RadonTransformCircles.
3+
* It displays some images using dip::viewer::Show, and sets display properties.
4+
*/
5+
6+
#include "diplib.h"
7+
#include "diplib/analysis.h"
8+
#include "diplib/detection.h"
9+
#include "diplib/generation.h"
10+
#include "diplib/linear.h"
11+
#include "diplib/mapping.h"
12+
#include "diplib/math.h"
13+
14+
#include "dipviewer.h"
15+
#include "diplib/viewer/slice.h"
16+
#include "diplib/viewer/viewer.h"
17+
18+
19+
int main() {
20+
// Create a test image
21+
dip::Image img = dip::Image( { 256, 256 }, 1 );
22+
std::cout << "Ground-truth:\n";
23+
dip::FloatArray center = { 117.73, 133.10 };
24+
double radius = 100.72;
25+
std::cout << " - circle at (" << center[ 0 ] << ", " << center[ 1 ] << "), radius " << radius << '\n';
26+
dip::DrawBandlimitedBall( img, radius * 2, center, { 255 } );
27+
dip::Random rng;
28+
dip::GaussianNoise( img, img, rng, 5 ); // A small amount of noise
29+
dip::viewer::Show( img, "input image" );
30+
31+
// Compute gradient and mask
32+
dip::Image gv = dip::Gradient( img );
33+
dip::viewer::Show( gv, "gradient image" );
34+
dip::Image gm = dip::Norm( gv );
35+
dip::Image mask = gm > 40;
36+
dip::viewer::Show( mask, "mask image" );
37+
38+
// Compute Hough circles
39+
auto hough = dip::FindHoughCircles( mask, gv, { 50, 150 } );
40+
41+
// Compose output
42+
dip::Image out = img.Similar();
43+
out.Fill( 0 );
44+
std::cout << "Detected by Hough:\n";
45+
for( auto v : hough ) {
46+
std::cout << " - circle at (" << v[ 0 ] << ", " << v[ 1 ] << "), radius " << v[ 2 ] << '\n';
47+
dip::DrawBandlimitedBall( out, v[ 2 ] * 2, { v[ 0 ], v[ 1 ] }, { 255 } );
48+
}
49+
dip::viewer::Show( out, "Hough detected circles" );
50+
auto h = dip::viewer::Show( out - img, "difference Hough - input" );
51+
h->options().lut_ = dip::viewer::ViewingOptions::LookupTable::Divergent;
52+
h->options().mapping_range_ = { -100, 100 };
53+
54+
// Compute Radon circles
55+
// NOTE! `out` is not used in the call below because we added "no parameter space" to the options.
56+
auto radon = dip::RadonTransformCircles( gm, out, { 50, 150, 1 }, 1.0, 100.0, "full", { "normalize", "correct", "no parameter space" } );
57+
58+
// Compose output
59+
out.Fill( 0 );
60+
std::cout << "Detected by Radon:\n";
61+
for( auto v : radon ) {
62+
std::cout << " - circle at (" << v.origin[ 0 ] << ", " << v.origin[ 1 ] << "), radius " << v.radius << '\n';
63+
dip::DrawBandlimitedBall( out, v.radius * 2, v.origin, { 255 } );
64+
}
65+
dip::viewer::Show( out, "Radon detected circles" );
66+
h = dip::viewer::Show( out - img, "difference Radon - input" );
67+
h->options().lut_ = dip::viewer::ViewingOptions::LookupTable::Divergent;
68+
h->options().mapping_range_ = { -100, 100 };
69+
70+
dip::viewer::Spin();
71+
}

‎include/diplib/detection.h‎

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
2-
* (c)2018-2021, Cris Luengo.
2+
* (c)2017, Wouter Caarls.
3+
* (c)2018-2025, Cris Luengo.
34
* Based on original DIPlib code: (c)1995-2014, Delft University of Technology.
45
*
56
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -53,12 +54,19 @@ namespace dip {
5354

5455
/// \brief Hough transform for circles in 2D binary images.
5556
///
56-
/// Computes the Hough parameter space for circles in 2D images, with the radius dimension collapsed.
57-
/// The parameter space `out` has the same sizes as the binary input image `in`. `gv` is a vector image
58-
/// of the same sizes as `in`, with the gradient vector for each pixel of `in`.
57+
/// Computes the Hough parameter space for circles in 2D binary images, with the radius dimension collapsed.
58+
/// The parameter space `out` has the same sizes as the input image `in`.
59+
///
60+
/// `gv` is a vector image of the same sizes as `in`, with 2D vectors that point normal to the circle at
61+
/// each pixel in `in`.
62+
/// This version of the algorithm does not draw a full cone in a 3D parameter space (x, y, r) for each
63+
/// set pixel in the input, but draws a line along the normal in a 2D parameter space (x, y).
64+
/// The magnitude of the vector is used as weight, meaning that the length of the vector can be used
65+
/// to encode confidence in the direction. See \ref dip::FindHoughCircles for an example how to generate
66+
/// the input images.
5967
///
6068
/// `range` must be empty, or have exactly two elements representing the minimum and maximum radius to
61-
/// be considered. If empty, the minimum radius is 0, and the maximum is the length of the image diagonal.
69+
//. be considered. If empty, the minimum radius is 0, and the maximum is the length of the image diagonal.
6270
DIP_EXPORT void HoughTransformCircleCenters(
6371
Image const& in,
6472
Image const& gv,
@@ -106,14 +114,24 @@ DIP_EXPORT Distribution PointDistanceDistribution(
106114
/// using \ref dip::HoughTransformCircleCenters, and then a radius is calculated for each center. Note that
107115
/// only a single radius is returned per center coordinates.
108116
///
109-
/// `gv` is a vector image of the same sizes as `in`, with the gradient vector for each pixel of `in`.
117+
/// `gv` is a vector image of the same sizes as `in`, with 2D vectors that point normal to the circle at
118+
/// each pixel in `in`. See \ref dip::HoughTransformCircleCenters for details.
110119
///
111120
/// `range` must be empty, or have exactly two elements representing the minimum and maximum radius to
112121
/// be considered. If empty, the minimum radius is 0, and the maximum is the length of the image diagonal.
113122
///
114123
/// `distance` is the minimum distance between centers, used to suppress noisy results.
115124
/// `fraction` is the minimum height of a peak in the Hough transform, with respect to the largest peak,
116125
/// that should be considered, again to suppress noisy results.
126+
///
127+
/// The output array contains three values per circle found: the x and y coordinates, and the radius.
128+
///
129+
/// Example usage:
130+
/// ```cpp
131+
/// dip::Image gv = dip::Gradient( img );
132+
/// dip::Image mask = dip::Norm( gv ) > 10; // Some threshold that removes irrelevant gradients, keeping only significant edges
133+
/// auto hough = dip::FindHoughCircles( mask, gv, { 50, 150 } );
134+
/// ```
117135
DIP_EXPORT FloatCoordinateArray FindHoughCircles(
118136
Image const& in,
119137
Image const& gv,
@@ -122,6 +140,7 @@ DIP_EXPORT FloatCoordinateArray FindHoughCircles(
122140
dfloat fraction = 0.1
123141
);
124142

143+
125144
/// \brief Stores the parameters for one hypersphere (circle, sphere).
126145
struct RadonCircleParameters{
127146
FloatArray origin; ///< Coordinates of the origin of the hypersphere
@@ -184,7 +203,7 @@ using RadonCircleParametersArray = std::vector< RadonCircleParameters >;
184203
/// - C.L. Luengo Hendriks, M. van Ginkel and L.J. van Vliet,
185204
/// "Underestimation of the radius in the Radon transform for circles and spheres",
186205
/// Technical Report PH-2003-02, Pattern Recognition Group, Delft University of Technology, The Netherlands, 2003.
187-
// TODO: If `mode` is `"full"`, then the parameter space is computed chunks to save memory.
206+
// TODO: If `mode` is `"full"`, then the parameter space is computed in chunks to save memory.
188207
DIP_EXPORT RadonCircleParametersArray RadonTransformCircles(
189208
Image const& in,
190209
Image& out,
@@ -209,9 +228,9 @@ DIP_NODISCARD inline Image RadonTransformCircles(
209228
return out;
210229
}
211230

212-
213231
/// \endgroup
214232

233+
215234
/// \group detection_corners Corner detectors
216235
/// \ingroup detection
217236
/// \brief Corner detection algorithms

0 commit comments

Comments
 (0)