【问题标题】:get non zero ROI from numpy array从 numpy 数组中获得非零 ROI
【发布时间】:2021-03-02 13:07:42
【问题描述】:

我想从图像中提取矩形 ROI。 图像包含单个连接的非零部分。

我需要它在运行时高效。

我在想也许:

  1. 沿每个方向求和。
  2. 查找第一个非零和最后一个非零。
  3. 相应地对图像进行切片。

有没有更好的办法?

我的代码:

First 是一个查找第一个和最后一个非零的函数:

import numpy as np

from PIL import Image

def first_last_nonzero(boolean_vector):
    first = last = -1
    for idx,val in enumerate(boolean_vector):
        if val == True and first == -1:
            first = idx
        if val == False and first != -1:
            last = idx
            return first , last

然后创建一个图像:

np_im = np.array([[  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0 255 154 251  60   0   0   0]
 [  0   0   0   0   4  66   0   0 255   0   0   0]
 [  0   0   0   0   0   0   0 134  48   0   0   0]
 [  0   0   0   0   0   0 236  70   0   0   0   0]
 [  0   0   0   0   1 255   0   0   0   0   0   0]
 [  0   0   0   0 255  24  24  24   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0]])

然后在每个轴的总和上运行我们的函数:

y_start, y_end = first_last_nonzero(np.sum(np_im, 1)>0)
x_start, x_end = first_last_nonzero(np.sum(np_im, 0)>0)
cropped_np_im = np_im[y_start:y_end, x_start:x_end]

# show the cropped image
Image.fromarray(cropped_np_im).show()

这可行,但可能有很多不必要的计算。 有一个更好的方法吗?或者更 Pythonic 的方式?

【问题讨论】:

    标签: python arrays numpy indexing roi


    【解决方案1】:

    您可以使用这篇文章中的功能: Numpy: How to find first non-zero value in every column of a numpy array?

    def first_nonzero(arr, axis, invalid_val=-1):
        mask = arr!=0
        return np.where(mask.any(axis=axis), mask.argmax(axis=axis), invalid_val)
    
    def last_nonzero(arr, axis, invalid_val=-1):
        mask = arr!=0
        val = arr.shape[axis] - np.flip(mask, axis=axis).argmax(axis=axis) - 1
        return np.where(mask.any(axis=axis), val, invalid_val)
    
    
    arr = np.array([
        [0, 0, 0, 0, 1, 1],
        [0, 0, 1, 1, 0, 0],
        [0, 1, 0, 0, 0, 0],
        [0, 0, 0, 1, 0, 0],
        [0, 0, 1, 0, 1, 0],
        [0, 0, 0, 0, 0, 0] ])
    
    y_Min, y_Max, x_Min, x_Max = (0, 0, 0, 0) 
    y_Min = first_nonzero(arr, axis = 0, invalid_val = -1) 
    y_Min = (y_Min[y_Min >= 0]).min() 
    x_Min = first_nonzero(arr, axis = 1, invalid_val = -1) 
    x_Min = (x_Min[x_Min >= 0]).min() 
    y_Max = last_nonzero(arr, axis = 0, invalid_val = -1) 
    y_Max = (y_Max[y_Max >= 0]).max() 
    x_Max = last_nonzero(arr, axis = 1, invalid_val = -1) 
    x_Max = (x_Max[x_Max >= 0]).max() 
    print(x_Min) 
    print(y_Min) 
    print(x_Max) 
    print(y_Max)
    

    对于我的这个例子,代码将返回 1、0、5、4。 作为 python 的一般经验法则:不惜一切代价尽量避免循环。根据我自己的经验,这句话在 100 个案例中有 99 个是正确的

    【讨论】:

    • 我的例子是连接空间。每个示例中只有一个。难道不能以某种方式使用它吗?
    • 您应该可以使用此代码。它应该适用于您的输入数据
    • 我希望某种算法能够: 随机选取像素。如果不是 0,则标记所有连接的像素。返回此范围内的正方形
    • 我不明白您所说的“随机选择像素”是什么意思。我发布的脚本当前返回包围所有大于 0 的像素的正方形。您只需在图像上绘制它即可完成。
    • 非常感谢您的耐心等待。谢谢!!问题是我不想检查所有像素。想象一下,左下角只有一个 9 像素的正方形是 255,其余的都是 0。如果我必须检查一个大图像,我将需要检查很多像素。如果我在这个角落找到一个像素,我可以检查它的所有邻居,然后检查他们的邻居等,并在第一个大于 0 的像素之后的 9 步中找到矩形。这可能会更快
    猜你喜欢
    • 1970-01-01
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多