是否有一种矢量化以下数组计算的方法(即不使用for循环):
for i in range(numCells):
z[i] = ((i_mask == i)*s_image).sum()/pixel_counts[i]
s_image是存储为二维ndarray的图像(为简单起见,我在此处删除了颜色维度)。 i_mask也是一个与s_image大小相同的二维数组,但它包含整数,这些整数是长度为numCells的“单元”列表的索引。结果z是长度为numCell的一维数组。计算的目的是对掩码包含相同索引的所有像素值求和,并将结果放在z向量中。 (pixel_counts也是长度为numCell的一维数组)。
答案 0 :(得分:1)
作为一种矢量化方法,您可以利用broadcasting
和matrix-multiplication
,就像这样 -
# Generate a binary array of matches for all elements in i_mask against
# an array of indices going from 0 to numCells
matches = i_mask.ravel() == np.arange(numCells)[:,None]
# Do elementwise multiplication against s_image and sum those up for
# each such index going from 0 to numCells. This is essentially doing
# matix multiplicatio. Finally elementwise divide by pixel_counts
out = matches.dot(s_image.ravel())/pixel_counts
或者,作为另一种向量化方法,您也可以使用np.einsum
进行乘法和求和,这可能会提升性能,就像这样 -
out = np.einsum('ij,j->i',matches,s_image.ravel())/pixel_counts
运行时测试 -
功能定义:
def vectorized_app1(s_image,i_mask,pixel_counts):
matches = i_mask.ravel() == np.arange(numCells)[:,None]
return matches.dot(s_image.ravel())/pixel_counts
def vectorized_app2(s_image,i_mask,pixel_counts):
matches = i_mask.ravel() == np.arange(numCells)[:,None]
return np.einsum('ij,j->i',matches,s_image.ravel())/pixel_counts
def org_app(s_image,i_mask,pixel_counts):
z = np.zeros(numCells)
for i in range(numCells):
z[i] = ((i_mask == i)*s_image).sum()/pixel_counts[i]
return z
时序:
In [7]: # Inputs
...: numCells = 100
...: m,n = 100,100
...: pixel_counts = np.random.rand(numCells)
...: s_image = np.random.rand(m,n)
...: i_mask = np.random.randint(0,numCells,(m,n))
...:
In [8]: %timeit org_app(s_image,i_mask,pixel_counts)
100 loops, best of 3: 8.13 ms per loop
In [9]: %timeit vectorized_app1(s_image,i_mask,pixel_counts)
100 loops, best of 3: 7.76 ms per loop
In [10]: %timeit vectorized_app2(s_image,i_mask,pixel_counts)
100 loops, best of 3: 4.08 ms per loop
答案 1 :(得分:0)
这是我的解决方案(处理了所有三种颜色)。不确定这是多么有效。有人有更好的解决方案吗?
import numpy as np
import pandas as pd
# Unravel the mask matrix into a 1-d array
i = np.ravel(i_mask)
# Unravel the image into 1-d arrays for
# each colour (RGB)
r = np.ravel(s_image[:,:,0])
g = np.ravel(s_image[:,:,1])
b = np.ravel(s_image[:,:,2])
# prepare a dictionary to create the dataframe
data = {'i' : i, 'r' : r, 'g' : g, 'b' : b}
# create a dataframe
df = pd.DataFrame(data)
# Use pandas pivot table to average the colour
# intensities for each cell index value
pixAvgs = pd.pivot_table(df, values=['r', 'g', 'b'], index='i')
pixAvgs.head()
输出:
b g r
i
-1 26.719482 68.041868 101.603297
0 75.432432 170.135135 202.486486
1 92.162162 184.189189 208.270270
2 71.179487 171.897436 201.846154
3 76.026316 178.078947 211.605263
答案 2 :(得分:0)
最后,我以不同的方式解决了这个问题,并大大提高了速度。不是使用如上所述的i_mask,而是在输出强度的1-d阵列中的二维索引数组z,我创建了一个不同的数组mask1593,其尺寸为(numCells×45)。每行是平展的256x256像素图像(0到65536)中大约35到45个索引的列表。
In [10]: mask1593[0]
Out[10]:
array([14853, 14854, 15107, 15108, 15109, 15110, 15111, 15112, 15363,
15364, 15365, 15366, 15367, 15368, 15619, 15620, 15621, 15622,
15623, 15624, 15875, 15876, 15877, 15878, 15879, 15880, 16131,
16132, 16133, 16134, 16135, 16136, 16388, 16389, 16390, 16391,
16392, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32)
然后,我可以使用numpy的高级索引实现与以下相同的转换:
def convert_image(self, image_array):
"""Convert 256 x 256 RGB image array to 1593 RGB led intensities."""
global mask1593
shape = image_array.shape
img_data = image_array.reshape(shape[0]*shape[1], shape[2])
return np.mean(img_data[mask1593], axis=1)
这是结果!一个256x256像素的彩色图像转换成1593种颜色的阵列,用于在这个不规则的LED显示屏上显示: