【问题标题】:OpenCV - Splitting and merging alpha channels slowOpenCV - 拆分和合并阿尔法通道很慢
【发布时间】:2019-07-15 09:46:12
【问题描述】:

我正在使用 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 秒

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

【问题讨论】:

    标签: python opencv


    【解决方案1】:

    对于你正在做的事情,使用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 毫秒

    【讨论】:

      【解决方案2】:

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

      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)
      

      【讨论】:

        【解决方案3】:

        最快的解决方案

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

        • 可以通过调整大小来执行更快、更合理的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 分钟内处理。

        之后

        在调整图像大小后,它在调整大小的图像上缩小为0.001 ms

        标准图片

        调整大小的图像

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-04-09
          • 1970-01-01
          • 2011-08-13
          • 2013-07-09
          • 1970-01-01
          • 2021-12-25
          • 1970-01-01
          相关资源
          最近更新 更多