这是图像类型的裁剪示例(大约11x9
像素),图像最终实际上都是28x28
大小,但存储在作为784
组件展平的内存中数组),我将尝试将算法应用于:
基本上,我希望能够识别出何时出现此形状(红线用于强调像素的分离,而周围的黑色边框用于在StackOverflow的白色背景上更好地勾勒图像的轮廓) :
它的方向无关紧要:必须沿水平轴和垂直轴以任何可能的表示形式(旋转和对称)对其进行检测(例如,不应考虑旋转45°,也不应对角线对称:例如仅考虑90°,180°和270°旋转。
虽然我只需要找到一个解决方案,但我只需要在图像上找到两种解决方案(忽略白色区域周围的灰色模糊):
以另一个示例为例(这也表明图像中的白色数字并不总是被黑色像素完全包围):
该函数应返回True ,因为存在形状:
现在,显然有一个简单的解决方案:
使用诸如pattern = [[1,0,0,0],[1,1,1,1]]
之类的变量,产生其变体,然后沿图像滑动所有变体,直到找到完全匹配为止,此时整个过程停止并返回True
。
但是,在最坏的情况下,单个图像最多需要8*(28-2)*(28-4)*(2*4)
个操作,大约需要进行 40000次操作,这似乎有些过分了(如果我很快计算正确。)
我猜想使这种幼稚的方法更好的一种方法是,首先扫描图像,直到找到第一个白色像素,然后再在该点之前寻找4行4列的图案,但这似乎还不够好。
有什么想法吗?也许这种功能已经在某些库中实现了? 我正在寻找一种超越我幼稚方法的实现或算法。
作为一个附带说明,虽然有点hack,但我猜想这是可以卸载到GPU的问题,但是我对此没有太多经验。 虽然这不是我要寻找的主要内容,但如果您提供答案,请随时添加与GPU相关的注释。
答案 0 :(得分:5)
如果您进行的操作过多,请考虑减少操作量。
对于这个问题,我将使用图像积分。
如果在图像上对求和内核进行卷积(这在fft域中只有conv2
,imfilter
来说是非常快的操作),那么您会知道只有积分等于5的位置(在您的情况下)可能是模式匹配的地方。检查这些(即使是4次旋转)应该在计算上非常快。您的示例图片中最多不能有50个适合此模式的位置。
我的python不太流畅,但这是您在MATLAB中的第一张图片的概念证明,我相信翻译此代码应该不会有问题。
% get the same image you have (imgur upscaled it and made it RGB)
I=rgb2gray(imread('https://i.stack.imgur.com/l3u4A.png'));
I=imresize(I,[9 11]);
I=double(I>50);
% Integral filter definition (with your desired size)
h=ones(3,4);
% horizontal and vertical filter (because your filter is not square)
Ifiltv=imfilter(I,h);
Ifilth=imfilter(I,h');
% find the locations where integral is exactly the value you want
[xh,yh]=find(Ifilth==5);
[xv,yv]=find(Ifiltv==5);
% this is just plotting, for completeness
figure()
imshow(I,[]);
hold on
plot(yh,xh,'r.');
plot(yv,xv,'r.');
这将在14个位置进行检查。我的标准计算机在计算两个图像积分上平均需要230ns,我称之为 fast 。
GPU计算也不是hack:D。由于它们具有强大的计算能力,因此它是解决大量问题的方法。例如。 GPU中的卷积速度非常快。
答案 1 :(得分:3)
您要实现的操作是数学形态学中称为hit and miss的运算符。
它可以非常有效地实现为两个侵蚀的组合。如果您要检测的形状可以分解为几个简单的几何形状(尤其是矩形,可以快速计算出),那么操作员将更加高效。
您会在大多数图像处理库中找到非常有效的腐蚀方式,例如尝试OpenCV。 OpenCV也有一个命中率运算符here is a tutorial for how to use it。
作为一个预期输出的示例,我生成了一个简单的测试图像(左),使用了hit and miss运算符,该模板的模板恰好匹配图像中的一个位置(中间),然后再次使用与任何地方都不匹配(正确):
我是在MATLAB而不是Python中执行此操作的,因为我已将其打开并且最容易使用。这是代码:
Lambda
上面的代码使用了我在DIPimage中实现的hit和miss运算符。相同的实现在PyDIP中与return [post, ...state];
在Python中可用(还没有PyDIP的二进制版本,您需要自己编译):
se = [1,1,1,1 % Defines the template
0,0,0,1];
img = [0,0,0,0,0,0 % Defines the test image
0,1,1,1,1,0
0,0,0,0,1,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0];
img = dip_image(img,'bin');
res1 = hitmiss(img,se);
res2 = hitmiss(img,rot90(se,2));
% Quick-and-dirty display
h = dipshow([img,res1,res2]);
diptruesize(h,'tight',3000)
hold on
plot([5.5,5.5],[-0.5,5.5],'r-')
plot([11.5,11.5],[-0.5,5.5],'r-')