检测图像上的硬币(并拟合椭圆)
我目前正在开展一个项目,试图检测平坦表面(即桌子)上的一些硬币。硬币不会重叠,也不会被其他物体隐藏。但可能还有其他可见的物体,并且照明条件可能并不完美......基本上,想象一下自己正在拍摄桌上有一些硬币的桌子。
所以每个点都应该是可见的椭圆。由于我不知道相机的位置,椭圆的形状可能会有所不同,从圆形(从顶部看)到扁平椭圆,具体取决于拍摄硬币的角度。
我的问题是,我不确定如何提取硬币并最终在它们上添加椭圆(我正在寻找进行进一步的计算)。
目前,我刚刚进行了第一次尝试,在 OpenCV 中设置阈值,使用 findContours() 获取轮廓线并拟合椭圆。不幸的是,轮廓线很少给出硬币的形状(反射、光线不好……),而且这种方式也不是首选,因为我不希望用户设置任何阈值。
另一个想法是在该图像上使用椭圆的模板匹配方法,但由于我不知道相机的角度也不知道椭圆的大小,我认为这不会很好地工作......
所以我想询问是否有人可以告诉我一种适合我的情况的方法。
有没有快速的方法从图像中提取三个硬币?计算应该在移动设备上实时进行,并且该方法不应该对不同或变化的灯光或背景颜色太敏感。
如果有人能给我任何关于哪种方法适用的提示,那就太好了我。
I am currently working on a project where I am trying to detect a few coins lying on a flat surface (i.e. a desk). The coins do not overlap and are not hidden by other objects. But there might be other objects visible and the lighting conditions may not be perfect... Basically, consider yourself filming your desk which has some coins on it.
So each point should be visible as an Ellipse. Since I don't know the position of the camera the shape of the ellipses may vary, from a circle (view from top) to flat ellipses depending on the angle the coins are filmed from.
My problem is that I am not sure how to extract the coins and finally fit ellipses over them (which I am looking for to do further calculations).
For now, I have just made the first attempt by setting a threshold value in OpenCV, using findContours() to get the contour lines and fitting an ellipse. Unfortunately, the contour lines only rarely give me the shape of the coins (reflections, bad lighting, ...) and this way is also not preferred since I don't want the user to set any threshold.
Another idea was to use a template matching method of an ellipse on that image, but since I don't know the angle of the camera nor the size of the ellipses I don't think this would work well...
So I wanted to ask if anybody could tell me a method that would work in my case.
Is there a fast way to extract the three coins from the image? The calculations should be made in realtime on mobile devices and the method should not be too sensitive for different or changing lights or the color of the background.
Would be great if anybody could give me any tips on which method could work for me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一些实现传统方法的 C99 源代码(基于 OpenCV doco):
给定 Carnieri 提供的二进制图像,这是输出:
这是输出图像:
您可以改进的地方:
cvConvexityDefects
)区分硬币和其他物体的最佳方法可能是通过形状。我想不出任何其他低级图像特征(颜色显然已经过时了)。因此,我可以想到两种方法:
传统的对象检测
您的第一个任务是将对象(硬币和非硬币)与背景分开。正如 Carnieri 所建议的,Ohtsu 的方法在这里很有效。您似乎担心图像是二分的,但我认为这不会成为问题。只要有大量可见的桌子,就一定会在直方图中出现一个峰值。只要桌子上有一些视觉上可区分的物体,你就一定会获得第二个高峰。
膨胀您的二值图像几次,以消除阈值处理留下的噪声。这些硬币相对较大,因此它们应该能够经受住这种形态操作。
使用区域生长将白色像素分组为对象 - 只需迭代连接相邻的前景像素即可。在此操作结束时,您将得到一个不相交对象的列表,并且您将知道每个对象占用哪些像素。
从这些信息中,您将知道对象的宽度和高度(来自上一步)。因此,现在您可以估计围绕该对象的椭圆的大小,然后查看该特定对象与椭圆的匹配程度。仅使用宽度与高度之比可能会更容易。
或者,您可以使用 时刻 以更精确的方式确定对象的形状。
Here's some C99 source implementing the traditional approach (based on OpenCV doco):
Given the binary image that Carnieri provided, this is the output:
And this is the output image:
What you could improve on:
cvConvexityDefects
)Your best way of distinguishing coins from other objects is probably going to be by shape. I can't think of any other low-level image features (color is obviously out). So, I can think of two approaches:
Traditional object detection
Your first task is to separate the objects (coins and non-coins) from the background. Ohtsu's method, as suggested by Carnieri, will work well here. You seem to worry about the images being bipartite but I don't think this will be a problem. As long as there is a significant amount of desk visible, you're guaranteed to have one peak in your histogram. And as long as there are a couple of visually distinguishable objects on the desk, you are guaranteed your second peak.
Dilate your binary image a couple of times to get rid of noise left by thresholding. The coins are relatively big so they should survive this morphological operation.
Group the white pixels into objects using region growing -- just iteratively connect adjacent foreground pixels. At the end of this operation you will have a list of disjoint objects, and you will know which pixels each object occupies.
From this information, you will know the width and the height of the object (from the previous step). So, now you can estimate the size of the ellipse that would surround the object, and then see how well this particular object matches the ellipse. It may be easier just to use width vs height ratio.
Alternatively, you can then use moments to determine the shape of the object in a more precise way.
我不知道解决你的问题的最佳方法是什么。不过,具体而言,关于阈值处理,您可以使用大津方法,该方法根据图像直方图的分析自动找到最佳阈值。使用 OpenCV 的 threshold 方法以及参数
ThresholdType 等于
THRESH_OTSU
。但请注意,大津的方法仅适用于具有双峰直方图的图像(例如,深色背景上具有明亮物体的图像)。
您可能已经看到过这个,但是还有一种用于 拟合椭圆的方法 围绕一组 2D 点(例如,连接的组件)。
编辑:大津的方法应用于示例图像:
灰度图像:

应用大津方法的结果:

I don't know what the best method for your problem is. About thresholding specifically, however, you can use Otsu's method, which automatically finds the optimal threshold value based on an analysis of the image histogram. Use OpenCV's threshold method with the parameter
ThresholdType
equal toTHRESH_OTSU
.Be aware, though, that Otsu's method work well only in images with bimodal histograms (for instance, images with bright objects on a dark background).
You've probably seen this, but there is also a method for fitting an ellipse around a set of 2D points (for instance, a connected component).
EDIT: Otsu's method applied to a sample image:
Grayscale image:

Result of applying Otsu's method:

如果其他人将来像我一样遇到这个问题,但是使用 C++:
一旦您使用
findContours
来查找轮廓(如上面 Misha 的答案),您可以使用 <代码>fitEllipse,例如If anyone else comes along with this problem in the future as I did, but using C++:
Once you have used
findContours
to find the contours (as in Misha's answer above), you can easily fit ellipses usingfitEllipse
, eg