我正在检测由激光束照射的圆形孔径的中心和半径。该算法将从我没有物理控制的系统(即,调暗光源或调整激光位置)馈送图像。我需要使用C++执行此操作,并选择使用openCV。如何过滤边缘检测的极其嘈杂的圆点?
在一些地区,光圈的边缘是明确的,但在其他地区是非常嘈杂。我目前正试图隔离“好”点来做RANSAC,但我一直采取其他步骤。以下是参考两个原始图像:
我第一次开始试图做霍夫配合。我执行了一个中值模糊来去除盐和胡椒噪声,然后进行高斯模糊,然后将图像提供给openCV中的HoughCircle函数,其中滑块控制Hough参数1和2,定义为here。结果是灾难性的:
然后我决定尝试处理图像,然后再发送到HoughCircle。我从原始图像开始,模糊中值,高斯模糊,阈值化,扩张,Canny边缘检测,然后将Canny图像提供给函数。
我最终能够对我的圆圈进行合理的估计,但它是在手动降低Hough参数时出现的第15个圆圈。我手动绘制了紫色轮廓,绿色圆圈表示Hough输出,这些输出接近我的手动估计。以下图像是:
- 而不扩张
- 坎尼输出的Canny输出与扩张
- 扩张的Canny算子图像的霍夫输出绘制的原始图像上。
正如你所看到的,无效的圈数大大租税正确的一圈,我不太清楚如何好圆鉴于Hough变换回报隔离很多其他参数更加严格的无效圆圈。
我目前有一些我实现的代码,对于我给出的所有测试图像都可以正常工作,但代码与许多可调参数似乎非常脆弱。我所做的背后的驱动逻辑是从注意到激光良好照明的光圈边缘区域在几个阈值水平上相对恒定(如下图所示)。
我没有边缘检测在两个阈值电平,并且在两个图像重叠存储的点。目前,结果也存在一些不准确的结果,因为光圈边缘在不同的阈值水平下仍然稍微变化。我可以张贴了很长的代码,如果有必要对于这一点,但它背后的伪代码:
1. Perform a median blur, followed by a Gaussian blur. Kernels are 9x9.
2. Threshold the image until 35% of the image is white. (~intensities > 30)
3. Take the Canny edges of this thresholded image and store (Canny1)
4. Take the original image, perform the same median and Gaussian blurs, but threshold with a 50% larger value, giving a smaller spot (~intensities > 45)
5. Perform the "Closing" morphology operation to further erode the spot and remove any smaller contours.
6. Perform another Canny to get the edges, and store this image (Canny2)
7. Blur both the Canny images with a 7x7 Gaussian blur.
8. Take the regions where the two Canny images overlap and say that these points are likely to be good points.
9. Do a RANSAC circle fit with these points.
我注意到,有边缘的区域中检测到循环,是通过人眼分辨的漂亮作为最佳圈子的一部分。有没有办法将这些区域分离出来以适合RANSAC?
代码霍夫:
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;
}
请问激光曾经相对于光圈移动?光圈的大小是否会改变,或者您的程序是否已知? –
如果您认为这有帮助,请考虑接受答案。 – m3h0w