我正试图在我的图像中间检测到一个圆形物体。这是一个示例图像:
左半部分是灰度和高斯模糊输入图像;在Otsu阈值处理后,右半部分是相同的图像。左下角的微小银色阴影导致Otsu门槛误入歧途。有没有办法设置一个感兴趣的圆形区域,以避免角落噪音?
答案 0 :(得分:5)
直接在良好的阈值图像上使用Hough Circle Transform 可以适用于这种特定情况,即使检测到的圆圈有点偏移:
cv::Mat thres;
cv::threshold(gray, thres, 110, 255, cv::THRESH_BINARY);
std::vector<cv::Vec3f> circles;
cv::HoughCircles(thres, circles, cv::HOUGH_GRADIENT, 1, thres.rows/2, 20, 15);
for (size_t i = 0; i < circles.size(); i++)
{
cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
cv::circle(input, center, 3, cv::Scalar(0, 255, 255), -1);
cv::circle(input, center, radius, cv::Scalar(0, 0, 255), 1);
}
⇨
⇨
在更复杂的情况下,您可能需要尝试其他阈值方法,以及fill the internal parts (holes) of the segments将它们重建为椭圆形式。
下面说明的处理流程执行以下操作以改进硬币的检测:
cv::HoughCircles()
来检测圆形。 ⇨
⇨
⇨
⇨
通过这种方法可以注意到硬币检测更加集中。无论如何,这里是魔术的C ++示例代码:
// Load input image
cv::Mat input = cv::imread("coin.jpg");
if (input.empty())
{
std::cout << "!!! Failed to open image" << std::endl;
return -1;
}
// Convert it to grayscale
cv::Mat gray;
cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
// Threshold the grayscale image for segmentation purposes
cv::Mat thres;
cv::threshold(gray, thres, 110, 255, cv::THRESH_BINARY);
//cv::imwrite("threhsold.jpg", thres);
// Dirty trick to join nearby segments
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(15, 15));
cv::morphologyEx(thres, thres, cv::MORPH_OPEN, element);
//cv::imwrite("morph.jpg", thres);
// Fill the holes inside the segments
fillHoles(thres);
//cv::imwrite("filled.jpg", thres);
// Apply the Hough Circle Transform to detect circles
std::vector<cv::Vec3f> circles;
cv::HoughCircles(thres, circles, cv::HOUGH_GRADIENT, 1, thres.rows/2, 20, 15);
std::cout << "* Number of detected circles: " << circles.size() << std::endl;
for (size_t i = 0; i < circles.size(); i++)
{
cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
cv::circle(input, center, 3, cv::Scalar(0,255,255), -1);
cv::circle(input, center, radius, cv::Scalar(0,0,255), 1);
}
cv::imshow("Output", input);
//cv::imwrite("output.jpg", input);
cv::waitKey(0);
void fillHoles(cv::Mat& img)
{
if (img.channels() > 1)
{
std::cout << "fillHoles !!! Image must be single channel" << std::endl;
return;
}
cv::Mat holes = img.clone();
cv::floodFill(holes, cv::Point2i(0,0), cv::Scalar(1));
for (int i = 0; i < (img.rows * img.cols); i++)
if (holes.data[i] == 255)
img.data[i] = 0;
}
答案 1 :(得分:1)
您可以将Hough用于finding circles:
/// Apply the Hough Transform to find the circles
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
找到最大的圆圈后,您可以将所有像素设置为0