I am using Visual Studio 2015, OpenCV.3 and EmguCV.3. My code represented below and the result is shown in the picture. I know that the problem is the input values of HoughCircles function, but I don't know which inputs are suitable for this picture. I appreciate any help.
Image<Gray, byte> OriginalImage = new Image<Gray, byte>(Openfile.FileName);
Image<Gray, byte> ResizedImage = OriginalImage.Resize(OriginalImage.Width / 2, OriginalImage.Height / 2, Emgu.CV.CvEnum.Inter.Cubic);
//********** Convert Image to Binary
Image<Gray, byte> smoothImg =
ResizedImage.SmoothGaussian(5);
smoothImg._Erode(5);
smoothImg._Dilate(5);
Image<Gray, byte> BinaryImage =
smoothImg.ThresholdBinary(new Gray(20), new Gray(255));
//********** Find Circles
Image<Rgb, byte> ROIImgScaledCircles = ROIImgScaled.Convert<Rgb, byte>();
CircleF[] circles = smoothImg.HoughCircles(
new Gray(180),//cannyThreshold
new Gray(60),//circleAccumulatorThreshold
2.0, //dp:Resolution of the accumulator used to detect centers of the circles
10.0, //min distance
10, //min radius
128 //max radius
)[0]; //Get the circles from the first channel
foreach (CircleF cir in circles)
{
ROIImgScaledCircles.Draw(cir, new Rgb(235, 20, 30), 1);
}
pbxCircles.Image = ROIImgScaledCircles.ToBitmap();
Original Image:
Founded Circles:
HoughCircles function in OpenCV to detect circles in images. Unlike detecting squares or rectangles in images, detecting circles is substantially harder since we cannot reply on approximating the number of points in a contour. To help us detect circles in images, OpenCV has supplied the cv2. HoughCircles function.
Syntax. cv2. HoughCircles(image, method, dp, minDist) Where Image is the image file converted to grey scale Method is the algorithm used to detct the circles. Dp is the inverse ratio of the accumulator resolution to the image resolution.
Edge detection. In order to detect the circles, or any other geometric shape, we first need to detect the edges of the objects present in the image. The edges in an image are the points for which there is a sharp change of color. For instance, the edge of a red ball on a white background is a circle.
Working with complete shapes, you may find it easier to work detect edges and then find contours. Here's an example:
Image<Bgr, byte> original = new Image<Bgr, byte>(@"E:\Downloads\original.jpg");
UMat grayscale = new UMat();
UMat pyrdown = new UMat();
UMat canny = new UMat();
double cannyThreshold = 128;
CvInvoke.CvtColor(original, grayscale, ColorConversion.Bgr2Gray);
// remove noise and run edge detection
CvInvoke.PyrDown(grayscale, pyrdown);
CvInvoke.PyrUp(pyrdown, grayscale);
CvInvoke.Canny(grayscale, canny, cannyThreshold, cannyThreshold * 2);
Image<Bgr, byte> result = original.Copy();
// find and draw circles
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(canny, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
//CvInvoke.DrawContours(result, contours, -1, new MCvScalar(0, 0, 255));
for (int i = 0; i < contours.Size; i++)
{
Ellipse ellipse = new Ellipse(CvInvoke.FitEllipse(contours[i]));
result.Draw(ellipse, new Bgr(Color.Red), 1);
}
result.Save(@"E:\Downloads\circles.jpg");
Here's the result, from left to right:
Here is a solution (based on OpenCvSharp, not on emgucv, which allows C# code to be very close to all OpenCV code that you can find in C++ or Python, but you can easily convert it back to emgucv).
I've removed the Erode and Dilate step (which in this case just destroy the original image too much).
What I used is a loop on hough circle calls (varying the inverse ratio to accumulator resolution) to ensure that I detect more than one circle, and not the circles I'm not interested in.
int blurSize = 5;
using (var src = new Mat("2Okrv.jpg"))
using (var gray = src.CvtColor(ColorConversionCodes.BGR2GRAY))
using (var blur = gray.GaussianBlur(new Size(blurSize, blurSize), 0))
using (var dst = src.Clone())
{
// this hashset will automatically store all "unique" detected circles
// circles are stored modulo some "espilon" value, set to 5 here (half of min size of hough circles below)
var allCircles = new HashSet<CircleSegment>(new CircleEqualityComparer { Epsilon = 5 });
// vary inverse ratio of accumulator resolution
// depending on image, you may vary start/end/step
for (double dp = 1; dp < 5; dp += 0.2)
{
// we use min dist = 1, to make sure we can detect concentric circles
// we use standard values for other parameters (canny, ...)
// we use your min max values (the max may be important when dp varies)
var circles = Cv2.HoughCircles(blur, HoughMethods.Gradient, dp, 1, 100, 100, 10, 128);
foreach (var circle in circles)
{
allCircles.Add(circle);
}
}
// draw final list of unique circles
foreach (var circle in allCircles)
{
Cv2.Circle(dst, circle.Center, (int)circle.Radius, Scalar.FromRgb(235, 20, 30), 1);
}
// display images
using (new Window("src image", src))
using (new Window("dst image", dst))
{
Cv2.WaitKey();
}
}
public class CircleEqualityComparer : IEqualityComparer<CircleSegment>
{
public double Epsilon { get; set; }
public bool Equals(CircleSegment x, CircleSegment y) => x.Center.DistanceTo(y.Center) <= Epsilon && Math.Abs(x.Radius - y.Radius) <= Epsilon;
// bit of a hack... we return a constant so only Equals is used to compare two circles
// since we have only few circles that's ok, we don't play with millions...
public int GetHashCode(CircleSegment obj) => 0;
}
Here is the result:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With