Python嵌套用于RGB平均值中的循环



我在一些想要优化的代码中遇到了一个相当慢的问题。在蒙版图像中,我计算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 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    

您可以用矢量化方法替换最里面的两个嵌套循环。

因此,可以取代

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))

一个人可以进行一点冒险,并在最后一步使用np.einsum,这可能会进一步提高性能,比如so-

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.而不是嵌套for循环

示例:

>>> 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)]

最新更新