我想在下面的图像中分别检测红色和绿色圆圈(以及一些其他类似的图像)
我使用的是opencv和python。
我尝试过使用houghcircles,但即使更改了params之后也没有任何帮助。
任何建议如何做到这一点真的会有很大帮助。 如果有人发送代码,我将不胜感激
答案 0 :(得分:7)
您在评论中提到圈子的大小始终相同。 让我们利用这个事实。我的代码片段是用C ++语言编写的,但这不应该是一个问题,因为它们只是为了显示要使用的OpenCV函数(以及如何)...
<强> TL; DR 执行此操作:
现在,让我们开始吧!
第1步 - 模板图片
您需要一张图片,显示与背景明显分开的圆圈。你有两个选择(两者都同样好):
圆圈可以是任何颜色 - 重要的是它与背景不同。
第2步 - 模板匹配
加载图片和模板图片并将其转换为HSV color space。然后拆分通道,以便您只能使用饱和通道:
using namespace std;
using namespace cv;
Mat im_rgb = imread("circles.jpg");
Mat tm_rgb = imread("template.jpg");
Mat im_hsv, tm_hsv;
cvtColor(im_rgb, im_hsv, CV_RGB2HSV);
cvtColor(tm_rgb, tm_hsv, CV_RGB2HSV);
vector<Mat> im_channels, tm_channels;
split(im_hsv, im_channels);
split(tm_hsv, tm_channels);
这就是圈子和模板现在的样子:
接下来,您必须获取包含圈子边框信息的图片。无论您如何实现这一目标,都必须在图像和模板饱和度通道上应用完全相同的操作。 我用sobel算子来完成工作。代码示例仅显示我在图像饱和通道上执行的操作;模板饱和通道经历了完全相同的过程:
Mat im_f;
im_channels[1].convertTo(im_f, CV_32FC1);
GaussianBlur(im_f, im_f, Size(3, 3), 1, 1);
Mat sx, sy;
Sobel(im_f, sx, -1, 1, 0);
Sobel(im_f, sy, -1, 0, 1);
Mat image_input = abs(sx) + abs(sy);
现在,执行模板匹配。我建议您选择模板匹配的类型来计算归一化的相关系数:
Mat match_result;
matchTemplate(image_input, template_input, match_result, CV_TM_CCOEFF_NORMED);
这是模板匹配结果:
如果将模板放置在图像上的不同位置,此图像会告诉您模板与基础图像的关联程度。例如,像素(0,0)处的结果值对应于放置在输入图像上的(0,0)处的模板。
当模板放置在与底层图像匹配良好的位置时,相关系数很高。使用阈值方法丢弃除信号峰值以外的所有内容(模板匹配的值将位于[-1,1]区间内,并且您只对接近1的值感兴趣):
Mat thresholded;
threshold(match_result, thresholded, 0.8, 1.0, CV_THRESH_BINARY);
接下来,确定每个隔离区域内模板结果最大值的位置。为此,我建议您使用阈值图像作为掩码。每个区域内只需要选择一个最大值。
这些位置会告诉您必须放置模板的位置,以使其与圆圈最匹配。我绘制了从这些点开始并具有与模板图像相同的宽度/高度的矩形:
第3步:圆圈的颜色
现在你知道模板应该放在哪里,以便它们很好地覆盖圆圈。但您仍需要找出圆心位于模板图像上的位置。您可以通过计算模板饱和度通道的质量中心来实现:
在图像上,圆心位于以下点:
Point circ_center_on_image = template_position + circ_center_on_template;
现在您只需要检查这些点的红色通道强度是否大于绿色通道强度。如果是,则圆圈为红色,否则为绿色: