繁体   English   中英

OpenCV - 拆分和合并阿尔法通道很慢

[英]OpenCV - Splitting and merging alpha channels slow

我正在使用 Python OpenCV 来分割通道并像这样删除黑色背景......

    b_channel, g_channel, r_channel = cv2.split(image_1)
    alpha_channel = np.zeros_like(gray)

    for p in range(alpha_channel.shape[0]):
        for q in range(alpha_channel.shape[1]):
            if b_channel[p][q]!=0 or g_channel[p][q]!=0 or r_channel[p][q]!=0:
                alpha_channel[p][q] = 255

    merged = cv2.merge((b_channel, g_channel, r_channel, alpha_channel))

这是可行的,但在仅 200kb 的图像上完成大约需要 10 秒

有没有更有效的方法来做到这一点,或者我可以使用我拥有的代码获得一些速度提升?

使用for循环遍历像素实际上非常缓慢且效率低下。 另外,根据此处的文档,

cv2.split()是一项昂贵的操作(就时间而言)。 因此,仅在需要时才这样做。 否则请进行Numpy索引。

您可以尝试使用numpy进行矢量化和索引编制,如下所示:

# create the image with alpha channel
img_rgba = cv2.cvtColor(img, cv2.COLOR_RGB2RGBA)

# mask: elements are True any of the pixel value is 0         
mask = (img[:, :, 0:3] != [0,0,0]).any(2) 
#assign the mask to the last channel of the image
img_rgba[:,:,3]  = (mask*255).astype(np.uint8)

对于您正在做的事情,使用cv2.bitwise_or似乎是最快的方法:

image_1 = img
# your method
start_time = time.time()
b_channel, g_channel, r_channel = cv2.split(image_1)
alpha_channel = np.zeros_like(gray)
for p in range(alpha_channel.shape[0]):
    for q in range(alpha_channel.shape[1]):
        if b_channel[p][q]!=0 or g_channel[p][q]!=0 or r_channel[p][q]!=0:
            alpha_channel[p][q] = 255
elapsed_time = time.time() - start_time
print('for cycles:  ' + str(elapsed_time*1000.0) + ' milliseconds')

# my method
start_time = time.time()
b_channel, g_channel, r_channel = cv2.split(image_1)
alpha_channel2 = cv2.bitwise_or(g_channel,r_channel)
alpha_channel2 =  cv2.bitwise_or(alpha_channel2, b_channel)
_,alpha_channel2 = cv2.threshold(alpha_channel2,0,255,cv2.THRESH_BINARY)
elapsed_time2 = time.time() - start_time
print('bitwise + threshold:  '+ str(elapsed_time2*1000.0) + ' milliseconds')

# annubhav's method
start_time = time.time()
img_rgba = cv2.cvtColor(image_1, cv2.COLOR_RGB2RGBA)
# mask: elements are True any of the pixel value is 0         
mask = (img[:, :, 0:3] != [0,0,0]).any(2) 
#assign the mask to the last channel of the image
img_rgba[:,:,3]  = (mask*255).astype(np.uint8)
elapsed_time3 = time.time() - start_time
print('anubhav:  ' + str(elapsed_time3*1000.0) + ' milliseconds')

周期:2146.300792694092毫秒

按位+阈值:4.959583282470703毫秒

anubhav:27.924776077270508毫秒

最快的解决方案

让我们考虑一个使用cv2.split的函数,我们知道它的效率非常低,我们可以继续调整或裁剪图像的某个部分,然后对其进行计算。 在我必须使用cv2.split计算图像的色彩度的情况下,我继续调整大小并裁剪图像以使cv2.split工作。

  • 可以通过Resizing进行更快更合理cv2.split计算

代码

def image_colorfulness(self,image):
        # split the image into its respective RGB components
        (B, G, R) = cv2.split(image.astype("float"))
        print(f'Split Image to B G R {(B, G, R)}')
        # compute rg = R - G
        rg = np.absolute(R - G)
        print(f'Computed RG to {rg}')
        # compute yb = 0.5 * (R + G) - B
        yb = np.absolute(0.5 * (R + G) - B)
        # compute the mean and standard deviation of both `rg` and `yb`
        print('Performing Absolute')
        (rbMean, rbStd) = (np.mean(rg), np.std(rg))
        (ybMean, ybStd) = (np.mean(yb), np.std(yb))
        # combine the mean and standard deviations
        print('Performing Standard Deviation')
        stdRoot = np.sqrt((rbStd ** 2) + (ybStd ** 2))
        meanRoot = np.sqrt((rbMean ** 2) + (ybMean ** 2))
        # derive the "colorfulness" metric and return it
        return stdRoot + (0.3 * meanRoot)


def crop_square(self, img, size, interpolation=cv2.INTER_AREA):
        h, w = img.shape[:2]
        min_size = np.amin([h,w])

        # Centralize and crop
        crop_img = img[int(h/2-min_size/2):int(h/2+min_size/2), int(w/2-min_size/2):int(w/2+min_size/2)]
        resized = cv2.resize(crop_img, (size, size), interpolation=interpolation)

        return resized


img = cv2.imread(image_path)
resize_img = self.crop_square(img, 300)
## perform your calculation on the resized_img and continue with the original img then 
colorness =  self.image_colorfulness(resize_img)

仅调整大小

如果您不想裁剪而只调整图像大小,可以通过查看square_crop函数中的这行代码来实现。

resized = cv2.resize(crop_img, (size, size), interpolation=interpolation)

测试结果

  • 我测试了一个5.0 MB *.PNG图像,然后在cv2.split中使用标准图像输入,它在8 Minutes中处理。

在图像调整大小之后,调整大小的图像上的时间减少到0.001 ms

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM