Python以RGB平均

时间:2016-03-26 21:07:14

标签: 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 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    

2 个答案:

答案 0 :(得分:2)

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

因此,人们可以取代它 -

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,这可能会进一步提升效果,就像这样 -

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 加速了!

答案 1 :(得分:1)

您可以使用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)]