Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect semicircle in OpenCV

I am trying to detect full circles and semicircles in an image.enter image description here

I am following the below mentioned procedure: Process image (including Canny edge detection). Find contours and draw them on an empty image, so that I can eliminate unwanted components (The processed image is exactly what I want). Detect circles using HoughCircles. And, this is what I get:

enter image description here

I tried varying the parameters in HoughCircles but the results are not consistent as it varies based on lighting and the position of circles in the image. I accept or reject a circle based on its size. So, the result is not acceptable. Also, I have a long list of "acceptable" circles. So, I need some allowance in the HoughCircle params. As for the full circles, it's easy - I can simply find the "roundness" of the contour. The problem is semicircles!

Please find the edited image before Hough transformenter image description here

like image 539
harsh Avatar asked Dec 20 '13 07:12

harsh


People also ask

How do I find circles in Opencv?

HoughCircles() function. Finds circles in a grayscale image using the Hough transform. In the below example we will take an image as input. Then make a copy of it and apply this transform function to identify the circle in the output.

Can Hough transform Detect circles?

The circle Hough Transform (CHT) is a basic feature extraction technique used in digital image processing for detecting circles in imperfect images. The circle candidates are produced by “voting” in the Hough parameter space and then selecting local maxima in an accumulator matrix.


1 Answers

Use houghCircle directly on your image, don't extract edges first. Then test for each detected circle, how much percentage is really present in the image:

int main() {     cv::Mat color = cv::imread("../houghCircles.png");     cv::namedWindow("input"); cv::imshow("input", color);      cv::Mat canny;      cv::Mat gray;     /// Convert it to gray     cv::cvtColor( color, gray, CV_BGR2GRAY );      // compute canny (don't blur with that image quality!!)     cv::Canny(gray, canny, 200,20);     cv::namedWindow("canny2"); cv::imshow("canny2", canny>0);      std::vector<cv::Vec3f> circles;      /// Apply the Hough Transform to find the circles     cv::HoughCircles( gray, circles, CV_HOUGH_GRADIENT, 1, 60, 200, 20, 0, 0 );      /// Draw the circles detected     for( size_t i = 0; i < circles.size(); i++ )      {         Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));         int radius = cvRound(circles[i][2]);         cv::circle( color, center, 3, Scalar(0,255,255), -1);         cv::circle( color, center, radius, Scalar(0,0,255), 1 );     }      //compute distance transform:     cv::Mat dt;     cv::distanceTransform(255-(canny>0), dt, CV_DIST_L2 ,3);     cv::namedWindow("distance transform"); cv::imshow("distance transform", dt/255.0f);      // test for semi-circles:     float minInlierDist = 2.0f;     for( size_t i = 0; i < circles.size(); i++ )      {         // test inlier percentage:         // sample the circle and check for distance to the next edge         unsigned int counter = 0;         unsigned int inlier = 0;          cv::Point2f center((circles[i][0]), (circles[i][1]));         float radius = (circles[i][2]);          // maximal distance of inlier might depend on the size of the circle         float maxInlierDist = radius/25.0f;         if(maxInlierDist<minInlierDist) maxInlierDist = minInlierDist;          //TODO: maybe paramter incrementation might depend on circle size!         for(float t =0; t<2*3.14159265359f; t+= 0.1f)          {             counter++;             float cX = radius*cos(t) + circles[i][0];             float cY = radius*sin(t) + circles[i][1];              if(dt.at<float>(cY,cX) < maxInlierDist)              {                 inlier++;                 cv::circle(color, cv::Point2i(cX,cY),3, cv::Scalar(0,255,0));             }             else                 cv::circle(color, cv::Point2i(cX,cY),3, cv::Scalar(255,0,0));         }         std::cout << 100.0f*(float)inlier/(float)counter << " % of a circle with radius " << radius << " detected" << std::endl;     }      cv::namedWindow("output"); cv::imshow("output", color);     cv::imwrite("houghLinesComputed.png", color);      cv::waitKey(-1);     return 0; } 

For this input:

enter image description here

It gives this output:

enter image description here

The red circles are Hough results.

The green sampled dots on the circle are inliers.

The blue dots are outliers.

Console output:

100 % of a circle with radius 27.5045 detected 100 % of a circle with radius 25.3476 detected 58.7302 % of a circle with radius 194.639 detected 50.7937 % of a circle with radius 23.1625 detected 79.3651 % of a circle with radius 7.64853 detected 

If you want to test RANSAC instead of Hough, have a look at this.

like image 83
Micka Avatar answered Sep 19 '22 12:09

Micka