HoughCircles 在 OpenCV 中无法正确检测圆
Posted
技术标签:
【中文标题】HoughCircles 在 OpenCV 中无法正确检测圆【英文标题】:HoughCircles Doesn't detect circles correctly in OpenCV 【发布时间】:2017-12-12 18:16:10 【问题描述】:我正在使用 Visual Studio 2015、OpenCV.3 和 EmguCV.3。 我的代码如下所示,结果如图所示。我知道问题是 HoughCircles 函数的输入值,但我不知道哪些输入适合这张图片。感谢您的帮助。
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();
原图:
创建的圈子:
【问题讨论】:
可以提供原图吗?我猜你希望有 2 个圈子? @SimonMourier 我编辑了问题并添加了原始图像。实际上是的,我希望有 2 个圆圈。 我使用 opencvsharp(与 c++/python 示例非常接近),而不是 emgucv,你可以吗? 【参考方案1】:使用完整的形状,您可能会发现检测边缘然后找到轮廓更容易。这是一个例子:
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");
这是结果,从左到右:
-
原图
模糊图像(使用 pyrdown/pyrup)
canny 边缘检测结果
从轮廓重建圆
【讨论】:
【参考方案2】:这是一个解决方案(基于OpenCvSharp,而不是基于 emgucv,它允许 C# 代码非常接近您可以在 C++ 或 Python 中找到的所有 OpenCV 代码,但您可以轻松地将其转换回 emgucv)。
我删除了 Erode 和 Dilate 步骤(在这种情况下,这只会过多地破坏原始图像)。
我使用的是一个关于霍夫圆调用的循环(改变累加器分辨率的反比),以确保我检测到多个圆,而不是我不感兴趣的圆。
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;
结果如下:
【讨论】:
以上是关于HoughCircles 在 OpenCV 中无法正确检测圆的主要内容,如果未能解决你的问题,请参考以下文章
使用opencv和python进行HoughCircles圆检测-
#私藏项目实操分享#教你用OpenCV 和 Python实现圆物检测《-》HoughCircles
从 onCameraFrame、OpenCV、Android/Java 调用 HoughCircles() 方法时改变慢帧速率
Python,OpenCV中的霍夫圆变换——cv2.HoughCircles()