gpt4 book ai didi

opencv - 阈值化之前 Opencv 中的圆形感兴趣区域

转载 作者:太空宇宙 更新时间:2023-11-03 21:02:35 26 4
gpt4 key购买 nike

我正在尝试检测图像中间的圆形物体。这是一个示例图片:

左半部分是灰度化和高斯模糊的输入图像;右半部分是经过 Otsu 阈值处理后的相同图像。左下角的细小银色阴影将大津阈值引入歧途。有什么办法可以设置一个圆形的感兴趣区域来避免角噪声?

最佳答案

使用 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);

Helper function :

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;
}

关于opencv - 阈值化之前 Opencv 中的圆形感兴趣区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26595715/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com