我正在檢測由激光束照射的圓形孔徑的中心和半徑。該算法將從我沒有物理控制的系統(即,調暗光源或調整激光位置)饋送圖像。我需要使用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