Python 在numpy数组中提取非零值组

Python 在numpy数组中提取非零值组,python,numpy,Python,Numpy,我试图从numpy数组中提取非零值的矩形组。 阵列可能如下所示(但要大得多): a=np.array([ [0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,0], [0,0,0,0,6,1,1,1,3,1,0], [0,0,0,0,0,1,1,1,1,1,0], [0,0,0,0,2,2,2,0,1,0,0], [0,0,0,0,2,2,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,0,0,0,0,0,0,0

我试图从numpy数组中提取非零值的矩形组。 阵列可能如下所示(但要大得多):

a=np.array([
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,1,1,1,1,1,0],
[0,0,0,0,6,1,1,1,3,1,0],
[0,0,0,0,0,1,1,1,1,1,0],
[0,0,0,0,2,2,2,0,1,0,0],
[0,0,0,0,2,2,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[1,1,1,1,0,0,0,0,0,0,0],
[1,1,1,1,0,0,0,0,7,2,0],
[1,1,1,1,0,0,0,0,0,0,0]])
我想提取大于给定大小(例如大于3x3)的非零值组/块,即这些块的最小角和最大角的坐标。 在本例中,我应该得到以下信息:

res=[(7,0),(10,4)],
[(1,5), (4,10)]]
所以

[12]中的
xmin,ymin=res[0][0]
在[13]中:xmax,ymax=res[0][1]
In[14]:a[xmin:xmax,ymin:ymax]
出[14]:
数组([[1,1,1,1],
[1, 1, 1, 1],
[1, 1, 1, 1]])
In[15]:xmin,ymin=res[1][0]
在[16]中:xmax,ymax=res[1][1]
In[17]:a[xmin:xmax,ymin:ymax]
出[17]:
数组([[1,1,1,1,1],
[1, 1, 1, 3, 1],
[1, 1, 1, 1, 1]])
我试着查看数组中的每个非零值,并从这一点开始增长所需大小的形状,直到它包含一个零。 它能工作,但速度很慢。 对于这个示例阵列,大约需要1.17毫秒, 在实际应用程序(即600x1000阵列)中大约需要18秒,这太慢了。
是否有numpy或OpenCV函数或技巧可以更快地执行此操作?

您的问题似乎是典型的计算机视觉问题。您要查找的区域不是背景,并且具有特定的形状(矩形)和大小(最小3x3)

对于此类问题,我们使用水滴分析

我不想写一个具体的例子,因为有更多的功能,包括可能也是有趣的你的工作。blob分析有很多例子。以下是一个很好的起点:

对我的信息的简短扩展: 该网站的示例基于较旧版本的opencv。以下代码是新版本上的实现。康达目前提供的最新版本是OpenCV 3.4.2:

#标准导入
进口cv2
输入numpy作为np;
#读取图像
im=cv2.imread(“blob.png”,cv2.imread\u灰度)
#使用默认参数设置检测器。
detector=cv2.SimpleBlobDetector_create()
#检测斑点。
关键点=检测器。检测(im)
#将检测到的斑点绘制为红色圆圈。
#cv2.DRAW_匹配_标志_DRAW_RICH_关键点确保圆的大小与水滴的大小相对应
带关键点的im\u=cv2.drawKeypoints(im,keypoints,np.array([]),(0,0255),cv2.DRAW\u匹配标志\u DRAW\u RICH\u关键点)
#显示关键点
cv2.imshow(“关键点”,带关键点的im)
cv2.等待键(0)

重要的变化是探测器的创建。

您的问题似乎是典型的计算机视觉问题。您要查找的区域不是背景,并且具有特定的形状(矩形)和大小(最小3x3)

对于此类问题,我们使用水滴分析

我不想写一个具体的例子,因为有更多的功能,包括可能也是有趣的你的工作。blob分析有很多例子。以下是一个很好的起点:

对我的信息的简短扩展: 该网站的示例基于较旧版本的opencv。以下代码是新版本上的实现。康达目前提供的最新版本是OpenCV 3.4.2:

#标准导入
进口cv2
输入numpy作为np;
#读取图像
im=cv2.imread(“blob.png”,cv2.imread\u灰度)
#使用默认参数设置检测器。
detector=cv2.SimpleBlobDetector_create()
#检测斑点。
关键点=检测器。检测(im)
#将检测到的斑点绘制为红色圆圈。
#cv2.DRAW_匹配_标志_DRAW_RICH_关键点确保圆的大小与水滴的大小相对应
带关键点的im\u=cv2.drawKeypoints(im,keypoints,np.array([]),(0,0255),cv2.DRAW\u匹配标志\u DRAW\u RICH\u关键点)
#显示关键点
cv2.imshow(“关键点”,带关键点的im)
cv2.等待键(0)

重要的变化是探测器的创建。

我认为有一个非常简单的解决方案。一个
开口
(一个
侵蚀
,然后是一个
扩张
)将简单地缩小小于所需大小(3x3)的区域,然后恢复其余区域。以下是将
a
转换为
uint8
后的视图:

现在我将在其上应用
打开

out = cv2.morphologyEx(a, cv2.MORPH_OPEN, np.ones((3,3), dtype=np.uint8))
可视化
输出

如您所见,只需一行代码即可识别矩形区域。您也可以将此输出用作位掩码来过滤掉原始图像

a_ = a.copy()
a_[np.logical_not(out.astype('bool'))] = 0
现在更具挑战性的部分是,如果你需要计算出矩形的角坐标。你可以突破大炮,应用轮廓检测,但我觉得一个更简单的分析也可以

from skimage.measure import label
out_ = label(out, connectivity=1)

现在,
out
数组中的每个区域都用一个单独的数字标记,从0到N_regions-1(其中0是背景区域)。剩下的工作很简单。您可以遍历每个数字并进行一些简单的numpy比较,以计算出每个编号区域的坐标

利用skimage的
regionprops
,我们可以更快地完成工作。我们将在前面计算的标签图像上应用它

from skimage.measure import regionprops

for r in regionprops(out_):
  print('({},{}), ({},{})'.format(*r.bbox))
输出:


我认为有一个非常简单的解决方法。一个
开口
(一个
侵蚀
,然后是一个
扩张
)将简单地缩小小于所需大小(3x3)的区域,然后恢复其余区域。这是转换后的
a
视图
(1,5), (4,10)
(7,0), (10,4)