如何隔离我认为最合适但排名低得多的霍夫圆?

信息处理 图像处理 opencv 霍夫变换
2022-01-28 19:25:08

我正在寻找激光光斑的中心和半径,我计划通过在 Visual C++ 的 opencv 3.2 中使用 HoughCircle 算法来完成。

我的一个示例图像是一个定义非常明确的点,但返回的霍夫圆与我的预期大不相同。下面是原始图像和处理后的图像的截图,紫色圆圈是我的期望值,红色圆圈是计算出的霍夫。我有控制 Hough 调用的 dp、param1 和 param2 的轨迹栏。在第一对图像中,我只对处理后的图像进行了模糊和阈值处理,在第二对图像中,我使用 5x5 椭圆蒙版膨胀了一次。

原始图像 第一张图片 第一张图片 第一张图片 第一张图片

我已经移动了霍夫参数的滑块,但这两个圆圈是我得到的最佳近似值,而且都不正确。使用的参数是:Hough1 = 100, Hough2= 21, dp= 1。我认为我不需要调整模糊、阈值或膨胀参数,因为我认为当前的圆应该足够好,可以更好地估计. 下面是没有膨胀的点的 Canny 视图:

精明的

当我将膨胀迭代增加到 7 并调整我的霍夫参数时,我得到了许多看起来不准确的圆圈。当我减小霍夫参数 2 时,最终会出现一些看起来最合适的圆圈,但可能是第 10 个出现的圆圈。下面是一张带有额外膨胀和较低 dp/param2 值的图像,绿色圆圈代表一个 Hough 圆圈,它与我手动估计的紫色圆圈相当接近。

我可以采取哪些步骤来自动抓取和隔离人类用户会接受为合理的最佳拟合的圆圈?

图片 图片 图片

代码:

int houghParam1 = 100;
int houghParam2 = 100;
int dp = 10; //divided by 10 later
int x=616;
int y=444;
int radius = 398;
int iterations = 0;

int main()
{
namedWindow("Circled Orig");
namedWindow("Processed", 1);
namedWindow("Circles");
namedWindow("Parameters");
namedWindow("Canny");
createTrackbar("Param1", "Parameters", &houghParam1, 200);
createTrackbar("Param2", "Parameters", &houghParam2, 200);
createTrackbar("dp", "Parameters", &dp, 20);
createTrackbar("x", "Parameters", &x, 1200);
createTrackbar("y", "Parameters", &y, 1200);
createTrackbar("radius", "Parameters", &radius, 900);
createTrackbar("dilate #", "Parameters", &iterations, 20);
std::string directory = "Secret";
std::string suffix = ".pgm";
Mat processedImage;
Mat origImg;
for (int fileCounter = 2; fileCounter < 3; fileCounter++) //1, 12
{
    std::string numString = std::to_string(static_cast<long long>(fileCounter));
    std::string imageFile = directory + numString + suffix;
    testImage = imread(imageFile);
    Mat bwImage;
    cvtColor(testImage, bwImage, CV_BGR2GRAY);
    GaussianBlur(bwImage, processedImage, Size(9, 9), 9);
    threshold(processedImage, processedImage, 25, 255, THRESH_BINARY); //THRESH_OTSU
    int numberContours = -1;
    int iterations = 1;
    imshow("Processed", processedImage);
}

vector<Vec3f> circles;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
float dp2 = dp;
while (true)
{
    float dp2 = dp;
    Mat circleImage = processedImage.clone();
    origImg = testImage.clone();
    if (iterations > 0) dilate(circleImage, circleImage, element, Point(-1, -1), iterations);
    Mat cannyImage;
    Canny(circleImage, cannyImage, 100, 20);
    imshow("Canny", cannyImage);
    HoughCircles(circleImage, circles, HOUGH_GRADIENT, dp2/10, 5, houghParam1, houghParam2, 300, 5000);
    cvtColor(circleImage, circleImage, CV_GRAY2BGR);
    for (size_t i = 0; i < circles.size(); i++)
    {
        Scalar color = Scalar(0, 0, 255);
        Point center2(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius2 = cvRound(circles[i][2]);
        if (abs(center2.x - x) < 10 && abs((center2.y - y) < 10) && abs(radius - radius2) < 20)  color = Scalar(0, 255, 0);
        circle(circleImage, center2, 3, color, -1, 8, 0);
        circle(circleImage, center2, radius2, color, 3, 8, 0);
        circle(origImg, center2, 3, color, -1, 8, 0);
        circle(origImg, center2, radius2,color, 3, 8, 0);
    }

    //Manual circles
    circle(circleImage, Point(x, y), 3, Scalar(128, 0, 128), -1, 8, 0);
    circle(circleImage, Point(x, y), radius, Scalar(128, 0, 128), 3, 8, 0);
    circle(origImg, Point(x, y), 3, Scalar(128, 0, 128), -1, 8, 0);
    circle(origImg, Point(x, y), radius, Scalar(128, 0, 128), 3, 8, 0);
    imshow("Circles", circleImage);
    imshow("Circled Orig", origImg);

    int x = waitKey(50);


}
Mat drawnImage;
cvtColor(processedImage, drawnImage, CV_GRAY2BGR);
return 1;
}
1个回答

霍夫变换是“正确的”。因为它在给定累积值的情况下搜索最一致的“形状”。如果您只想找到点的中心,那么您可以使用其他技术(从简单到...不太简单)。

霍夫变换产生另一幅图像,该图像由图像在其输入处以不同角度累积的“投影”组成。综合结果是:

  1. 点映射到弧

    • 因为从旋转中心偏移的一个点在旋转投影看来是和谐地“移动”。
  2. 线映射到点

    • 因为,一条线实际上是一个“移动”点,一旦旋转投影垂直于它,它就会产生最大和。
  3. 多边形映射到空间中具有不同配置的点。

    • 因为上面的#1,#2。多边形在这里被“插入”为由一组直线段组成的形状。因此,要检测一个矩形(一个由 4 条标记其周长的线定义的空心矩形),您所要做的就是寻找它们之间特定距离处的 4 个点。同样,要检测一个,您需要在霍夫空间中寻找特定点。

当您将“blob”的阈值版本呈现给 Hough 变换时,它会看到一大块直线,在旋转过程中是一致的。每一条“线”都是从白色填充的圆圈中挑选出来的和弦。

因此,霍夫变换“看到”的是一组与大累积相关的角度指数,以及围绕该累积的“方差”,代表斑点的不均匀性。

这可能是因为它无法检测到它正在寻找的“点”,所以圆形检测部分被抛弃了。

通过在将 blob 发送到 Hough 变换之前对 blob 运行边缘检测,可以获得更好的结果。

但是,更一般地说,为什么在这种情况下使用 Hough 变换来检测 blob 的中心?以下是一些替代方案:

  • 对图像设置阈值,然后找到白色像素坐标的“边界框”(极值点,X、Y 方向上所有白色像素的最小值、最大值),然后找到该边界框的中心。

  • 对图像设置阈值,应用线检测或卷积矩阵来隔离外围点​​,然后找到这些点的凸包事实上,即使您没有进行线检测或外围点检测,凸包仍然可以工作(但您会使用大量冗余数据增加计算复杂度)。凸包会给你你正在寻找的外围,它也不是一个糟糕的“概括”,因为它使用背后的基本假设是激光点肯定是凸的......这是一个合理的假设使其出现在屏幕上的形状(不一定是激光的孔径)。

希望这可以帮助。