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