К сожалению, вы не показали свои шаги предварительной обработки.В моем подходе я сделаю следующее:
- Преобразование входного изображения в оттенки серого (см.
cvtColor
). - Среднее размытие, поддерживает "ребра "(см.
medianBlur
). - Адаптивный порог (см.
adaptiveTreshold
). - Морфологическое отверстие, чтобы избавиться от небольшого шума(см.
morphologyEx
). - Найти круги по
HoughCircles
. - Здесь не сделано: Возможные уточнения найденных кругов.Исключите слишком маленькие или слишком большие круги.Используйте всю имеющуюся у вас информацию об этом!Например, насколько большими могут быть круги?
Вот весь мой код:
// Read image.
cv::Mat img = cv::imread("images/i7aJJ.jpg", cv::IMREAD_COLOR);
// Convert to grayscale for processing.
cv::Mat blk;
cv::cvtColor(img, blk, cv::COLOR_BGR2GRAY);
// Median blurring to improve following thresholding.
cv::medianBlur(blk, blk, 11);
// Adaptive thresholding.
cv::adaptiveThreshold(blk, blk, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 51, -2);
// Morphological opening to get rid of small noise.
cv::morphologyEx(blk, blk, cv::MORPH_OPEN, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3)));
// Find circles using Hough transform.
std::vector<cv::Vec4f> circles;
cv::HoughCircles(blk, circles, cv::HOUGH_GRADIENT, 1.0, 300, 50, 25, 100);
// TODO: Refinement of found circles, if there are more than two.
// For example, calculate areas: Neglect too small or too large areas.
// Compare all areas, and keep the two with nearly matching areas and
// suitable areas.
// Draw circles in input image.
for (Vec4f& circle : circles) {
cv::circle(img, cv::Point(circle[0], circle[1]), circle[2], cv::Scalar(0, 0, 255), 4);
cv::circle(img, cv::Point(circle[0], circle[1]), 5, cv::Scalar(0, 255, 0), cv::FILLED);
}
// --- Assuming there are only the two right circles left from here. --- //
// Draw some debug output in input image.
const cv::Point c1 = cv::Point(circles[0][0], circles[0][1]);
const cv::Point c2 = cv::Point(circles[1][0], circles[1][1]);
cv::line(img, c1, c2, cv::Scalar(255, 0, 0), 2);
// Calculate distance, and put in input image.
double dist = cv::norm(c1 - c2);
cv::putText(img, std::to_string(dist), cv::Point((c1.x + c2.x) / 2 + 20, (c1.y + c2.y) / 2 + 20), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255, 0, 0));
Окончательный результат выглядит следующим образом:
Промежуточное изображение прямо перед операцией HoughCircles
выглядит следующим образом:
В общемЯ не так скептически отношусь к HoughCircles
.Вы просто должны обратить внимание на свою предварительную обработку.
Надеюсь, это поможет!