我有一个包含从.png创建的灰度图像的2D数组,如下所示:

import cv2

img = cv2.imread("./images/test.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

我想做的是提取一个仅包含包含数据的矩形的子数组-,而忽略图片周围的所有零。

例如,如果输入为:

  0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0
  0   0 175   0   0   0  71   0
  0   0   0  12   8  54   0   0
  0   0   0   0 255   0   0   0
  0   0   0   2   0   0   0   0
  0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0

然后输出应为:

175   0   0   0  71
  0  12   8  54   0
  0   0 255   0   0
  0   2   0   0   0

我可以向前遍历行以找到第一个非零行,然后向后遍历行以找到记住索引的最后一个非零行-然后对各列重复相同的操作,然后使用该数据提取一个子数组,但是我确保有更合适的做同样的方法,甚至可能有为此目的设计的NumPy函数。

如果要在最短的代码还是最快的执行之间进行选择,那么我会对更快的代码执行更感兴趣。

编辑:
我没有提供最佳示例,因为中间的行/列可能为零,如下所示:

输入:

  0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0
  0   0 175   0   0   0  71   0
  0   0   0  12   8  54   0   0
  0   0   0   0 255   0   0   0
  0   0   0   0   0   0   0   0
  0   0   0   2   0   0   0   0
  0   0   0   0   0   0   0   0

输出:

175   0   0   0  71
  0  12   8  54   0
  0   0 255   0   0
  0   0   0   0   0
  0   2   0   0   0

最佳答案

更新
使用opencv函数的这种更简单的方法实际上更快,并且可能比此处其他答案中介绍的其他方法更快。

def crop_fastest(arr):
    return cv2.boundingRect(cv2.findNonZero(arr))

这将返回边界框的x,y,宽度和高度。在台式机上,输入旧代码1000 loops, best of 3: 562 µs per loop,输入新代码10000 loops, best of 3: 179 µs per loop

另一个更新

正如Chupo_cro指出的那样,简单地调用cv2.boundingRect(arr)会返回相同的结果,这似乎是由于the code in this function在内部进行了转换。

上一个答案

可能有更快的方法。此较简单的功能稍快一些。
from scipy import ndimage
def crop_fast(arr):
    slice_x, slice_y = ndimage.find_objects(arr>0)[0]
    return arr[slice_x, slice_y]

为了比较droooze和本代码的速度,
arr = np.zeros(shape=(50000,6), dtype=np.uint8)
arr[2] = [9,8,0,0,1,1]
arr[1] = [0,3,0,0,1,1]

然后%timeit crop(arr)返回1000 loops, best of 3: 1.62 ms per loop,而%timeit crop_fast(arr)返回便携式计算机上的1000 loops, best of 3: 979 µs per loop。也就是说,crop_fast()花费crop()约60%的时间。

关于python - 从表示图像的数组中排除周围零的最快方法?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49472962/

10-11 20:30
查看更多