Python:获取数组所有掩码的最快方法

时间:2019-08-13 22:57:14

标签: python numpy opencv numpy-broadcasting

有没有比遍历2d数组的所有组件来获得特定范围内所有可能的蒙版更快的方法了,

import numpy as np
numOfLabels = 80
array2D = np.random.choice(255,(512,512))
for i in range(1,numOfLabels):
    mask = array2D==i

也许可以广播并创建带有所有蒙版的3d阵列

编辑:

感谢您已经写好的答案。 为了更好的解释。我想做什么:

我有一个带有组件的二维标签矩阵。组件标有数字,例如1到80。我有两个图像。现在,我想为所有80个组件分别计算这两个图像的平均值,最大值,最小值。也许我有完全错误的想法去做。

EDIT2:

根据评论,我找到了一种使用以下代码的方法:

from scipy import ndimage
import numpy as np

def calculateMeanMaxMin(val):
    return np.array([np.mean(val),np.max(val),np.min(val)])

def getTheStatsForComponents(array1,array2):
    ret, thresholded= cv2.threshold(array2, 50, 255, cv2.THRESH_BINARY)
    thresholded= thresholded.astype(np.uint8)
    numLabels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresholded, 8, cv2.CV_8UC1)
    allComponentStats=[]
    meanmaxminArray2 = ndimage.labeled_comprehension(array2, labels, np.arange(1, numLabels+1), calculateMeanMaxMin, np.ndarray, 0)
    meanmaxminArray1 = ndimage.labeled_comprehension(array1, labels, np.arange(1, numLabels+1), calculateMeanMaxMin, np.ndarray, 0)
    for position, label in enumerate(range(1, numLabels)):
        currentLabel = np.uint8(labels== label)
        _, contour, _ = cv2.findContours(currentLabel, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
        (side1,side2)=cv2.minAreaRect(contour[0])[1]
        componentStat = stats[label]
        allstats = {'position':centroids[label,:],'area':componentStat[4],'height':componentStat[3],
                              'width':componentStat[2],'meanArray1':meanmaxminArray1[position][0],'maxArray1':meanmaxminArray1[position][1],
                              'minArray1':meanmaxminArray1[position][2],'meanArray2':meanmaxminArray2[position][0],'maxArray2':meanmaxminArray2[position][1],
                              'minArray2':meanmaxminArray2[position][2]}
        allComponentStats.append(allstats)
    return allComponentStats

但是我想知道是否有一种更快的方法来获取写入字典的所有组件的所有统计信息,因为我不知道ndimage.measurements.labeled_comprehension是否很快,并且是否可以避免这种循环? / strong>

3 个答案:

答案 0 :(得分:2)

您可以使用np.put_along_axis一次创建所有遮罩。所有未标记的点都到达平面零:

all_masks = np.zeros((numOfLabels, *array2D.shape), bool)
np.put_along_axis(all_masks, array2D*(array2D<numOfLabels)[None], True, axis=0)

# check
for i in range(1,numOfLabels):
    assert (all_masks[i] == (array2D==i)).all()

答案 1 :(得分:1)

这将使用广播创建3D蒙版阵列:

mask = array2D == np.arange(1, numOfLabels)[:, None, None]

例如

In [26]: numOfLabels = 80                                                                                          

In [27]: array2D = np.random.choice(255, (512, 512))                                                               

In [28]: mask = array2D == np.arange(1, numOfLabels)[:, None, None]                                                

In [29]: mask.shape                                                                                                
Out[29]: (79, 512, 512)

In [30]: array2D[:10, :13]                                                                                         
Out[30]: 
array([[111, 161, 109, 235, 193, 224,  63,  78, 106, 245, 140,  64,  28],
       [245, 239, 225,  31, 239, 212, 137,  17, 130, 185, 110,  70,  55],
       [251,  65, 114, 199, 229, 241,  97,  84,  13,  10,   4, 114, 185],
       [217, 252, 205,  94,  93, 202,  99,  91,  65,  34,  86,  84, 233],
       [115,  51, 217, 105, 187,  61, 203,  30, 178, 178, 183, 193, 231],
       [ 75, 195,  21, 143, 180,  32,  38, 224, 188,  85,  80, 250,   4],
       [163, 174,  35,  49, 202, 110, 223, 209,  80,  38, 127,  31, 208],
       [137, 133,  41,  30, 193, 187, 182, 171,  72, 151, 180, 152,  14],
       [145, 108, 112, 254,  92,  87,  45, 173,  45,  28, 189, 248,  48],
       [147, 222,  37,  31, 198,  69,   8, 136,  85, 162, 225, 203,  68]])

注意:我从您的代码中复制了标签范围,其中您以1开始了范围。这意味着标签4的掩码将位于索引3

In [31]: mask[3, :10, :13].astype(int)  # Display bools as ints for compact output                                                                               
Out[31]: 
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, 1, 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, 1],
       [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]])

答案 2 :(得分:0)

array2D==i为您提供了array2D == i的位置,尽管我不理解您要做什么,但是您可以通过以下方式修改代码

import numpy as np
numOfLabels = 80
array2D = np.random.choice(255,(512,512))
mask = np.zeros((512,512,numOfLabels))
for i in range(numOfLabels):
    mask[array2D==i, i] = 1