如何以矢量化方式在 3D NumPy 矩阵中有效地进行像素投票以创建新的 2D 矩阵?
How do I efficiently pixel vote, in a vectorized manner, in a 3D NumPy matrix to create a new 2D matrix?
我有一个形状为 (n, height, width)
的 NumPy 矩阵,其中包含 uint8
范围内的灰度图像。每层(总共 n 层)包含来自神经网络的预测。我想比较所有 n layers
并为每个像素获得第二个最常见的值,并使用这个新值创建一个形状为 (height, width)
的新矩阵。换句话说,我使用逐像素投票从分层矩阵中的所有矩阵创建一个新的二维矩阵。我更喜欢第二个最常见的值,因为最常见的值是 3,出于不同的原因,我想忽略它;这就是为什么我用 mode(vote[vote != 3], axis=None)[0][0]
搜索第二个最常见的值。以下是一个可行的解决方案。但是,它不是很快,因为我必须慢慢迭代。我想使用矢量化解决方案来节省时间。
import numpy
from scipy.stats import mode
n = 84
height = 1872
width = 3128
layered_image = numpy.ndarray(shape=(n, height , width), dtype=numpy.uint8)
image = numpy.ndarray(shape=(height , width), dtype=numpy.uint8)
for i in range(0, height):
for j in range(0, width):
vote = []
for k in range(len(layered_image)):
vote.append(layered_image[k][i][j])
vote = numpy.asarray(vote, dtype=numpy.uint8)
image[i][j] = mode(vote[vote != 3], axis=None)[0][0]
感谢您的任何建议。
一种方法是使用外部广播平等 -
np.equal.outer(layered_image,np.arange(3)).sum(0).argmax(-1)
另一个带掩码处理的-
# a is the input layered_image
c0,c1,c2 = (a==0).sum(0), (a==1).sum(0), (a==2).sum(0)
out = np.where(np.maximum(c0,c1)>c2, np.where(c0>c1,0,1), 2)
另一个 2D bincount
-
# @Divakar
def bincount2D_vectorized(a):
N = a.max()+1
a_offs = a + np.arange(a.shape[0])[:,None]*N
return np.bincount(a_offs.ravel(), minlength=a.shape[0]*N).reshape(-1,N)
# a is the input layered_image
b = bincount2D_vectorized(a.reshape(a.shape[0],-1).T)
out = b[:,:-1].argmax(1).reshape(a.shape[1:])
感谢 Divakar,bincounting
方法对我的目的非常有用。为了防止在处理大量层时使用过多的 RAM,我在此方法中添加了切片。这有点慢,但它允许在内存较少的机器上进行处理;鉴于 slice_coordinates
是一个列表,其中包含 (y, x)
、prediction_overlay
3D 分层图像和 prediction_mask
新 2D 图像的元组中所有图像块的左上角坐标,切片工作方式如下:
for i in range(len(slice_coordinates)):
to_process = prediction_overlay [:, slice_coordinates[i][0] : slice_coordinates[i][0] + tile_height, slice_coordinates[i][1] : slice_coordinates[i][1] + tile_width]
b = bincount2D_vectorized(to_process.reshape(to_process.shape[0],-1).T)
processed = b[:,:-1].argmax(1).reshape(to_process.shape[1:])
prediction_mask [slice_coordinates[i][0] : slice_coordinates[i][0] + tile_height, slice_coordinates[i][1] : slice_coordinates[i][1] + tile_width] = processed
我有一个形状为 (n, height, width)
的 NumPy 矩阵,其中包含 uint8
范围内的灰度图像。每层(总共 n 层)包含来自神经网络的预测。我想比较所有 n layers
并为每个像素获得第二个最常见的值,并使用这个新值创建一个形状为 (height, width)
的新矩阵。换句话说,我使用逐像素投票从分层矩阵中的所有矩阵创建一个新的二维矩阵。我更喜欢第二个最常见的值,因为最常见的值是 3,出于不同的原因,我想忽略它;这就是为什么我用 mode(vote[vote != 3], axis=None)[0][0]
搜索第二个最常见的值。以下是一个可行的解决方案。但是,它不是很快,因为我必须慢慢迭代。我想使用矢量化解决方案来节省时间。
import numpy
from scipy.stats import mode
n = 84
height = 1872
width = 3128
layered_image = numpy.ndarray(shape=(n, height , width), dtype=numpy.uint8)
image = numpy.ndarray(shape=(height , width), dtype=numpy.uint8)
for i in range(0, height):
for j in range(0, width):
vote = []
for k in range(len(layered_image)):
vote.append(layered_image[k][i][j])
vote = numpy.asarray(vote, dtype=numpy.uint8)
image[i][j] = mode(vote[vote != 3], axis=None)[0][0]
感谢您的任何建议。
一种方法是使用外部广播平等 -
np.equal.outer(layered_image,np.arange(3)).sum(0).argmax(-1)
另一个带掩码处理的-
# a is the input layered_image
c0,c1,c2 = (a==0).sum(0), (a==1).sum(0), (a==2).sum(0)
out = np.where(np.maximum(c0,c1)>c2, np.where(c0>c1,0,1), 2)
另一个 2D bincount
-
# @Divakar
def bincount2D_vectorized(a):
N = a.max()+1
a_offs = a + np.arange(a.shape[0])[:,None]*N
return np.bincount(a_offs.ravel(), minlength=a.shape[0]*N).reshape(-1,N)
# a is the input layered_image
b = bincount2D_vectorized(a.reshape(a.shape[0],-1).T)
out = b[:,:-1].argmax(1).reshape(a.shape[1:])
感谢 Divakar,bincounting
方法对我的目的非常有用。为了防止在处理大量层时使用过多的 RAM,我在此方法中添加了切片。这有点慢,但它允许在内存较少的机器上进行处理;鉴于 slice_coordinates
是一个列表,其中包含 (y, x)
、prediction_overlay
3D 分层图像和 prediction_mask
新 2D 图像的元组中所有图像块的左上角坐标,切片工作方式如下:
for i in range(len(slice_coordinates)):
to_process = prediction_overlay [:, slice_coordinates[i][0] : slice_coordinates[i][0] + tile_height, slice_coordinates[i][1] : slice_coordinates[i][1] + tile_width]
b = bincount2D_vectorized(to_process.reshape(to_process.shape[0],-1).T)
processed = b[:,:-1].argmax(1).reshape(to_process.shape[1:])
prediction_mask [slice_coordinates[i][0] : slice_coordinates[i][0] + tile_height, slice_coordinates[i][1] : slice_coordinates[i][1] + tile_width] = processed