【问题标题】:Extract groups of nonzero values in a numpy array在 numpy 数组中提取非零值组
【发布时间】:2020-07-14 10:26:14
【问题描述】:

我正在尝试从 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)]]

这样

In [12]: xmin, ymin = res[0][0]

In [13]: xmax, ymax = res[0][1]

In [14]: a[xmin:xmax, ymin:ymax]
Out[14]:
array([[1, 1, 1, 1],
       [1, 1, 1, 1],
       [1, 1, 1, 1]])

In [15]: xmin, ymin = res[1][0]

In [16]: xmax, ymax = res[1][1]

In [17]: a[xmin:xmax, ymin:ymax]
Out[17]:
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 3, 1],
       [1, 1, 1, 1, 1]])

我尝试查看数组的每个非零值,并从此时开始增长所需大小的形状,直到它包含零。 它可以工作,但速度很慢。 对于这个示例数组,大约需要 1.17 毫秒, 在实际应用程序(即 600x1000 阵列)中大约需要 18 秒,这太慢了。 是否有 numpy 或 OpenCV 函数或技巧可以更快地执行此操作?

【问题讨论】:

  • 你的数组是什么数据?
  • 它们是深度图像,包含每个像素从相机到现实生活对象的距离(以米为单位)

标签: python numpy


【解决方案1】:

我认为使用morpholical transforms 有一个非常简单的解决方案。 openingerosion 后跟 dilation)只会缩小小于所需大小 (3x3) 的区域,然后恢复剩余的区域。这是a 转换为uint8 后的视图:

现在我将在上面申请opening

out = cv2.morphologyEx(a, cv2.MORPH_OPEN, np.ones((3,3), dtype=np.uint8))

可视化out

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

a_ = a.copy()
a_[np.logical_not(out.astype('bool'))] = 0

现在,如果您需要计算矩形的角坐标,则更具挑战性。您可以打破大炮并应用轮廓检测​​,但我觉得更简单的connected components 分析应该也可以工作。

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

现在out_ 数组中的每个区域都标有一个单独的数字,从 0 到 N_regions-1(其中 0 是背景区域)。其余的工作非常简单。您可以遍历每个数字并进行一些简单的 numpy 比较以找出每个编号区域的坐标。

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

from skimage.measure import regionprops

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

输出:

(1,5), (4,10)
(7,0), (10,4)

【讨论】:

    【解决方案2】:

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

    对于这类问题,我们使用blob 分析

    我不想写一个具体的例子,因为其中包含更多可能对您的工作也很有趣的功能。有许多用于斑点分析的示例。这是一个很好的起点:https://www.learnopencv.com/blob-detection-using-opencv-python-c/

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

    # Standard imports
    import cv2
    import numpy as np;
    
    # Read image
    im = cv2.imread("blob.png", cv2.IMREAD_GRAYSCALE)
    
    # Set up the detector with default parameters.
    detector = cv2.SimpleBlobDetector_create()
    
    # Detect blobs.
    keypoints = detector.detect(im)
    
    # Draw detected blobs as red circles.
    # cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
    im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    
    # Show keypoints
    cv2.imshow("Keypoints", im_with_keypoints)
    cv2.waitKey(0)
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-04
      • 1970-01-01
      • 2014-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-09
      • 1970-01-01
      相关资源
      最近更新 更多