更新:这篇 StackOverflow 帖子(包括一些漂亮的示例图片)似乎已经解决了圆圈检测- 至少是您问题的一部分。他指向的优秀文章的参考可以在这个wiki 页面上找到(不幸的是只能通过回程机器)。
如果新链接也不存在,这里是相关部分:
检测图像:
要检测图像中的圆圈,需要注意一些繁琐的部分。在使用 - 圆形检测功能处理图像之前cvHoughCircles
,您可能希望先将其转换为灰度图像并对其进行平滑处理。以下是您需要使用的函数的一般过程以及它们的用法示例。
创建图像
假设您有一个名为“img”的初始图像进行处理,首先您要创建一个名为“gray”的图像变量,其尺寸与 img 使用相同cvCreateImage
。
IplImage* gray = cvCreateImage( cvGetSize(img), 8, 1 );
// allocate a 1 channel byte image
CvMemStorage* storage = cvCreateMemStorage(0);
IplImage* cvCreateImage(CvSize size, int depth, int channels);
size: cvSize(width,height);
depth: pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,
IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F, IPL_DEPTH_64F
channels: Number of channels per pixel. Can be 1, 2, 3 or 4. The channels
are interleaved. The usual data layout of a color image is
b0 g0 r0 b1 g1 r1 ...
转换为灰色
现在您需要使用cvCvtColor
在颜色空间之间转换的方法将其转换为灰色。
cvCvtColor( img, gray, CV_BGR2GRAY );
cvCvtColor(src,dst,code); // src -> dst
code = CV_<X>2<Y>
<X>/<Y> = RGB, BGR, GRAY, HSV, YCrCb, XYZ, Lab, Luv, HLS
e.g.: CV_BGR2GRAY, CV_BGR2HSV, CV_BGR2Lab
平滑图像
这样做是为了防止检测到很多错误的圆圈。您可能需要使用最后两个参数,注意它们需要乘以奇数。
cvSmooth( gray, gray, CV_GAUSSIAN, 9, 9 );
// smooth it, otherwise a lot of false circles may be detected
void cvSmooth( const CvArr* src, CvArr* dst,
int smoothtype=CV_GAUSSIAN,
int param1, int param2);
源代码
夏令时
平滑型
平滑类型:
- CV_BLUR_NO_SCALE(没有缩放的简单模糊)- 对像素 param1×param2 邻域求和。如果邻域大小不固定,可以使用 cvIntegral 函数。
- CV_BLUR(简单模糊)- 在像素 param1×param2 邻域上求和,随后按 1/(param1•param2) 缩放。
- CV_GAUSSIAN(高斯模糊)- 使用 param1×param2 高斯卷积图像。
- CV_MEDIAN (median blur) - 找到 param1×param1 邻域的中值(即邻域是正方形的)。
- CV_BILATERAL(双边过滤器) - 使用
color sigma=param1
和应用双边 3x3 过滤space sigma=param2
参数1
参数2
在简单缩放/非缩放和高斯模糊的情况下,如果param2
为零,则设置为param1
使用霍夫圆检测
该函数cvHoughCircles
用于检测灰度图像上的圆圈。最后两个参数可能需要再摆弄一下。
CvSeq* circles =
cvHoughCircles( gray, storage, CV_HOUGH_GRADIENT, 2, gray->height/4, 200, 100 );
CvSeq* cvHoughCircles( CvArr* image, void* circle_storage,
int method, double dp, double min_dist,
double param1=100, double param2=100,
int min_radius=0, int max_radius=0 );
======= 相关部分结束 =========
该 wiki 页面的其余部分实际上非常好(尽管我不会在此处重新复制它,因为其余部分与原始问题无关,而且 StackOverflow 对答案有大小限制)。希望该链接到 Wayback 机器上的缓存副本将无限期地继续工作。
我更新前的上一个答案:
伟大的!现在您发布了一些示例,我可以看到您不仅追求矩形、方形矩形和圆形,还希望在 3D 环境中找到这些形状,因此可能会从视频中寻找平行四边形和椭圆形的特殊情况帧到视频帧最终会显示为矩形、正方形和/或圆形(取决于您如何平移相机)。
就个人而言,我发现自己解决问题比尝试了解如何使用现有(通常非常成熟)库更容易。这并不是说我自己的工作会比一个成熟的库更好,它肯定不会。只是一旦我可以自己解决问题,那么我就更容易理解和使用库(库本身通常会比我自己的解决方案运行得更快、更智能)。
所以下一步我将把位图的颜色空间更改为灰度。彩色位图,我很难理解,也很难操作,特别是因为它有很多不同的表示方式,但是灰度位图更容易理解和操作。对于灰度位图,只需想象一个值网格,每个值代表不同的光强度。
现在,让我们将问题的范围限制为在静态 2D 环境中寻找平行四边形和椭圆(我们稍后会担心处理 3D 环境和移动视频帧,或者我应该说,你自己会担心那部分,因为这个问题对我来说已经变得太复杂了)。
现在,我们也不必担心您使用什么工具或语言。只需使用最简单和最快捷的方法。例如,假设时间没有问题,几乎可以编写任何脚本来自动将图像转换为灰度。ImageMagick、Gimp、Marvin、Processing、Python、Ruby、Java 等。
使用这些工具中的任何一个,都应该很容易对具有足够相似强度的像素进行分组(以使计算更易于管理),并为每个光强度桶在不同的阵列中对每个像素坐标进行排序。换句话说,排列某种粗略的阵列直方图应该不难,这些直方图按包含每个像素的 x 和 y 位置的强度排序。
在那之后,这个问题就变成了一个更像这个的问题(可以在 StackOverflow 上找到),因此可以使用其建议的解决方案来解决。
一旦您能够以这种方式解决问题,那么将您提出的解决方案转换为更适合该任务的语言应该不会太困难。并且它也应该更容易理解和使用您最终为任务选择的任何现有库的底层功能。至少,这就是我所希望的,因为我还不够熟悉,而且我无法真正帮助您处理 OpenCV 库本身。