HoughCircles detecting arches.
Greetings!
With the below C-code I'm detecting arches within an image with 2 arches. I'm using opencv-4.1.0 on a windows-10 machine, if this matters.
Using the parameters
int dp = 3; // The inverse ratio of resolution;
int min_dist = 1000; // Minimum distance between detected centers
int upper_canny = 65; // Upper threshold for the internal Canny edge detector
int th_center = 85; // Threshold for center detection
int min_radius = 1000;
int max_radius = 0;
I find 5 circles and they outline more or less accurately the arc.
Playing with dp, and th_center I get different results.
What wolud be an appropriate approach to get unambiguous results?
Thanks for hints
Wolf
#include <windows.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
int main(int argc, char** argv) {
char ImageName[256]={0};
int big_h=1024*8;
int big_w=1280, h=550;
int cx=(1280/2)-(big_w/2);
int cy=big_h-h;
cv::Rect roi(cx, 0, big_w, h);
cv::Mat input, filter, gray, canny;
cv::Mat big_gray(big_h, big_w, CV_8U);
strcpy(ImageName, "D:/CircleTestImage03.jpg");
// Read image
input = cv::imread(ImageName, cv::IMREAD_COLOR);
if (!input.data ) {
printf("Image '%s' not found\n", ImageName);
return(-1);
}
// Convert to gray
cv::cvtColor(input(roi), gray, cv::COLOR_BGR2GRAY);
cv::imshow("gray", gray);
// Reduce the noise avoiding false circle detection
cv::GaussianBlur(gray, gray, cv::Size(9, 9), 2, 2);
cv::imshow("Blur", gray);
// Place gray to bottom of big_gray allowing center finding of bog circeles.
// Otherwise no arc will be found.
gray.copyTo(big_gray(cv::Rect(0,cy, big_w, gray.rows)));
int dp = 3; // The inverse ratio of resolution;
int min_dist = 1000; // Minimum distance between detected centers
int upper_canny = 65; // Upper threshold for the internal Canny edge detector
int th_center = 85; // Threshold for center detection
int min_radius = 1000;
int max_radius = 0;
// Compute canny, info only
cv::Canny(gray, canny, upper_canny, upper_canny/2);
cv::imshow("canny", canny);
std::vector<cv::Vec3f> circles; // x, y, r
HoughCircles(big_gray, circles, cv::HOUGH_GRADIENT,
dp, min_dist, upper_canny, th_center, min_radius, max_radius);
// Draw circles
for (int i = 0; i < (int)circles.size(); i++ ) {
// coordinates of outline within input framre
circles[i][0] += cx;
circles[i][1] -= cy;
cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
printf("Circle #%d dp=%d x=%d y=%d r=%d\n", i, dp, center.x, center.y, radius);
cv::circle(input, center, radius, CV_RGB(255,0,0), 2, 8, 0 );
}
cv::imshow("input", input); cv::waitKey(1);
printf("Push key to finish.\n");
cv::waitKey(-1);
return 0;
}
We have found hough circles to be unreliable and sensitive to its input parameters. Our preferred method is to use OpenCV's line iterator. Normally we set up radial line iterators from some assumed or detected center and look for pixel intensity transitions from light to dark or dark to light. In your case, you could use vertical line iterators and look for 2 intensity transitions.
I can concur that the hough circles is highly sensitive to the input parameters for each specific situation. Unless you have a very constrained setup and want to spent time in the optimal configuration, I would look for alternative solutions as proposed above by @Chris.