Python嵌套用于RGB平均值中的循环
我想优化的一些代码有一个相当慢的点。在蒙版图像中,我计算R、G和B通道的平均值。我想摆脱嵌套for循环,但不确定如何实现。有什么想法吗Python嵌套用于RGB平均值中的循环,python,performance,numpy,vectorization,Python,Performance,Numpy,Vectorization,我想优化的一些代码有一个相当慢的点。在蒙版图像中,我计算R、G和B通道的平均值。我想摆脱嵌套for循环,但不确定如何实现。有什么想法吗 maskimage = cv2.imread(filename) hsv = cv2.cvtColor(maskimage, cv2.COLOR_BGR2HSV) boundaries = [([25, 146, 190], [62, 174, 250])] for (lower, upper) in boundaries: # create N
maskimage = cv2.imread(filename)
hsv = cv2.cvtColor(maskimage, cv2.COLOR_BGR2HSV)
boundaries = [([25, 146, 190], [62, 174, 250])]
for (lower, upper) in boundaries:
# create NumPy arrays from the boundaries
lower = np.array(lower, dtype = "uint8")
upper = np.array(upper, dtype = "uint8")
# find the colors within the specified boundaries and apply
# the mask
mask = cv2.inRange(hsv, lower, upper)
masked_img = cv2.bitwise_and(bgimage, bgimage, mask = mask)
meanblue = 0
meangreen = 0
meanred = 0
count = 0
H, W, b = masked_img.shape
for i in range(0,H,1):
for j in range(0,W,1):
if masked_img[i,j,0] > 1 or masked_img[i,j,1] > 1 or masked_img[i,j,2] > 1:
meanblue = meanblue + masked_img[i,j,0]
meangreen = meangreen + masked_img[i,j,1]
meanred = meanred + masked_img[i,j,2]
count = count+1
if count !=0:
omeanb = meanblue/count
omeang = meangreen/count
omeanr = meanred/count
if count ==0:
omeanb = 255
omeang = 255
omeanr = 255
您可以使用 例如:
>>> from itertools import product
>>> [(i,j) for i, j in product((1,2,3), (4, 5, 6))]
[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
可以使用矢量化方法替换最里面的两个嵌套循环 因此,有人可以取代这一点-
H, W, b = masked_img.shape
for i in range(0,H,1):
for j in range(0,W,1):
if masked_img[i,j,0] > 1 or masked_img[i,j,1] > 1 or masked_img[i,j,2] > 1:
meanblue = meanblue + masked_img[i,j,0]
meangreen = meangreen + masked_img[i,j,1]
meanred = meanred + masked_img[i,j,2]
count = count+1
因此—
mask = (masked_img > 1).any(2)
count = mask.sum()
mean_bgr = (masked_img*(mask[...,None])).sum(axis=(0,1))
一个人可以冒险一点,在最后一步使用,这可能会进一步提高性能,就像这样-
mean_bgr = np.einsum('ijk,ij->k',masked_img.astype(int),mask)
运行时测试
函数定义-
def original_app(masked_img):
meanblue = 0
meangreen = 0
meanred = 0
count = 0
H, W, b = masked_img.shape
for i in range(0,H,1):
for j in range(0,W,1):
if masked_img[i,j,0] > 1 or masked_img[i,j,1] > 1 or masked_img[i,j,2] > 1:
meanblue = meanblue + masked_img[i,j,0]
meangreen = meangreen + masked_img[i,j,1]
meanred = meanred + masked_img[i,j,2]
count = count+1
return [meanblue, meangreen, meanred], count
def vectorized_app1(masked_img):
mask = (masked_img > 1).any(2)
count = mask.sum()
mean_bgr = (masked_img*(mask[...,None])).sum(axis=(0,1))
return mean_bgr, count
def vectorized_app2(masked_img):
mask = (masked_img > 1).any(2)
count = mask.sum()
mean_bgr = np.einsum('ijk,ij->k',masked_img.astype(int),mask)
return mean_bgr, count
时间安排-
In [235]: # Random image input array
...: masked_img = np.random.randint(0,255,(512,512,3)).astype('uint8')
In [236]: original_app(masked_img)
Out[236]: ([33273503, 33274596, 33323215], 262144)
In [237]: vectorized_app1(masked_img)
Out[237]: (array([33273503, 33274596, 33323215], dtype=uint32), 262144)
In [238]: vectorized_app2(masked_img)
Out[238]: (array([ 33273503, 33274596, 33323215]), 262144)
In [239]: %timeit original_app(masked_img)
1 loops, best of 3: 2.08 s per loop
In [240]: %timeit vectorized_app1(masked_img)
100 loops, best of 3: 17.9 ms per loop
In [241]: %timeit vectorized_app2(masked_img)
10 loops, best of 3: 16.5 ms per loop
这是一个
100+x
加速 看看itertools.product:试试np.average(masked\u img,axis=-1)
,再加上一些修改以满足您的其他需求。np.average似乎很有希望,尽管我有点困惑。打印出来的结果是:[[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.]这仍然需要通过所有(i,j)对并用python进行计算。这并没有多大的改进,因为没有嵌套for循环来做N(i,j)对,而是有一个for循环来做N(i,j)对。是的,我希望通过去掉这些循环来提高性能,而itertools似乎没有这样做。的确,它只是稍微优雅一点,但如果Numpy有一种使您的生活更轻松、代码更可读的特定方式,请按照lija的建议使用它。mean_bgr=(masked_img*(mask[…,None])。sum(axis=(0.1))似乎有一个错误,因为我得到的值高于255。然而,np.einsum似乎完成了这个任务,比以前快得多。你能解释一下ijk的情况吗,ij->k?@MarkBrown是的,你需要缩小到255
。正如在文章中所述,我们只是删除嵌套循环。所以,所有其他的事情都必须完成,包括接下来的两个IF条件语句。希望这是有道理的。另外,einsum
的解释有点复杂。我建议您遵循官方文件。@MarkBrown请查看编辑内容。很抱歉,我的意思是按计数的比例缩小
仍然保留,之后的值将在[0255]
范围内。所以要快得多。我已经等了好几个小时了,现在只剩几分钟了。@MarkBrown,太好了!