【问题标题】:Set white background for a png instead of transparency with OpenCV使用 OpenCV 为 png 设置白色背景而不是透明度
【发布时间】:2019-05-12 22:50:18
【问题描述】:

我也有一个 OpenCv 图像;

opencvImage = cv2.cvtColor(numpy_image, cv2.COLOR_RGBA2BGRA)

然后使用以下代码片段,我想删除透明度并设置白色背景。

source_img = cv2.cvtColor(opencvImage[:, :, :3], cv2.COLOR_BGRA2GRAY)
source_mask = opencvImage[:,:,3]  * (1 / 255.0)

background_mask = 1.0 - source_mask

bg_part = (background_color * (1 / 255.0)) * (background_mask)
source_part = (source_img * (1 / 255.0)) * (source_mask)

result_image = np.uint8(cv2.addWeighted(bg_part, 255.0, source_part, 255.0, 0.0))

实际上,我可以将背景设置为白色,但是实际图像颜色也会发生变化。 我相信 COLOR_BGRA2GRAY 方法会导致此问题。这就是为什么,我尝试使用 IMREAD_UNCHANGED 方法,但我有这个错误:unsupported color conversion code in function 'cvtColor'

顺便说一句,我对任何解决方案持开放态度,我只是分享我的代码 - 可能需要一个小修复。

【问题讨论】:

    标签: python-3.x image numpy opencv


    【解决方案1】:

    这是一个基本脚本,它将用白色替换所有完全透明的像素,然后删除 Alpha 通道。

    import cv2
    #load image with alpha channel.  use IMREAD_UNCHANGED to ensure loading of alpha channel
    image = cv2.imread('your image', cv2.IMREAD_UNCHANGED)    
    
    #make mask of where the transparent bits are
    trans_mask = image[:,:,3] == 0
    
    #replace areas of transparency with white and not transparent
    image[trans_mask] = [255, 255, 255, 255]
    
    #new image without alpha channel...
    new_img = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
    

    【讨论】:

    • 执行此操作并腌制 new_image 我无法打开它,每个程序都说文件(图片)已损坏。尺寸也增加了 x20
    • @AnnaVopureta 你可能想使用 imwrite 函数来保存你的图像而不是腌制它。
    【解决方案2】:

    我不知道这个错误到底是什么,但我刚才正在测试一个可能的解决方案。即使它是 C++,我想你也可以轻松地将它转换为 python。

     /* Setting data info */
    std::string test_image_path = "Galicia.png";
    
    /* General variables */
    cv::namedWindow("Input image", cv::WINDOW_NORMAL);
    cv::namedWindow("Input image R", cv::WINDOW_NORMAL);
    cv::namedWindow("Input image G", cv::WINDOW_NORMAL);
    cv::namedWindow("Input image B", cv::WINDOW_NORMAL);
    cv::namedWindow("Input image A", cv::WINDOW_NORMAL);
    cv::namedWindow("Output image", cv::WINDOW_NORMAL);
    
    /* Process */
    cv::Mat test_image = cv::imread(test_image_path, cv::IMREAD_UNCHANGED);
    std::cout << "Image type: " << test_image.type() << std::endl;
    
    // Split channels of the png files
    std::vector<cv::Mat> pngChannels(4);
    cv::split(test_image, pngChannels);
    
    cv::imshow("Input image", test_image);
    cv::imshow("Input image R", pngChannels[0]);
    cv::imshow("Input image G", pngChannels[1]);
    cv::imshow("Input image B", pngChannels[2]);
    cv::imshow("Input image A", pngChannels[3]);
    
    // Set to 255(white) the RGB channels where the Alpha channel(mask) is 0(transparency)
    pngChannels[0].setTo(cv::Scalar(255), pngChannels[3]==0);
    pngChannels[1].setTo(cv::Scalar(255), pngChannels[3]==0);
    pngChannels[2].setTo(cv::Scalar(255), pngChannels[3]==0);
    
    // Merge again the channels
    cv::Mat test_image_output;
    cv::merge(pngChannels, test_image_output);
    
    // Show the merged channels.
    cv::imshow("Output image", test_image_output);
    
    // For saving with changes, conversion is needed.
    cv::cvtColor(test_image_output, test_image_output, cv::COLOR_RGBA2RGB);
    cv::imwrite("Galicia_mod.png", test_image_output);
    

    我用这个屏幕截图补充了代码,它可以帮助你更好地理解我的解决方案:

    最好的祝愿, 无味的

    【讨论】:

    • 感谢分享。这也是我遵循的逻辑,你描述得很清楚。谢谢。
    【解决方案3】:

    之前的所有答案都使用二值化,但掩码可以是非二值的。在这种情况下,您可以使用白色背景的alpha blending

    def alpha_blend_with_mask(foreground, background, mask): # modified func from link
        # Convert uint8 to float
        foreground = foreground.astype(float)
        background = background.astype(float)
    
        # Normalize the mask mask to keep intensity between 0 and 1
        mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
        mask = mask.astype(float) / 255
    
        # Multiply the foreground with the mask matte
        foreground = cv2.multiply(mask, foreground)
    
        # Multiply the background with ( 1 - mask )
        background = cv2.multiply(1.0 - mask, background)
    
        # Add the masked foreground and background.
        return cv2.add(foreground, background).astype(np.uint8)
    
    img_with_white_background = alpha_blend_with_mask(img[..., :3], np.ones_like(clip_img) * 255, img[..., 3])
    

    【讨论】:

      【解决方案4】:

      这对我有用..

      # import cv2
      # #load image with alpha channel.  use IMREAD_UNCHANGED to ensure loading of alpha channel
      image = cv2.imread('/content/test1.jpg')    
      
      #make mask of where the transparent bits are
      transp_mask = image[:,:,:3] == 0
      transp_mask = image[:,:,:3] == 1 # swap 
      
      #replace areas of transparency with white and not transparent
      image[transp_mask] = [100]
      
      
      #new image without alpha channel...
      new_img = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
      cv2.imwrite('testingnew.jpg',new_img)  converted to binary img
      print(new_img.shape)
      plt.imshow(new_img)
      

      透明图片

      输出

      输出2

      真实图片

      【讨论】:

        【解决方案5】:

        @user1269942 的回答留下了黑色边缘,并在图像周围形成了不必要的轮廓。 我需要为这张图片填充背景 This was the image I needed to convert

        this is the image after following the steps in accepted answer 但是,如果我们根据阈值进行屏蔽,我们可以根据我们选择阈值的程度来减少不必要的轮廓。在我的情况下,我选择了 75。
        所以而不是trans_mask = image[:,:,3] == 0 如果我们这样做

        img2gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)    
        ret, trans_mask = cv2.threshold(img2gray, 75, 255, cv2.THRESH_BINARY)    
        trans_mask = trans_mask == 0    
        
        def fillColor(imageFile, color):    
          image = cv2.imread(imageFile, cv2.IMREAD_UNCHANGED)    
          #trans_mask = image[:,:,3] == 0
          img2gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)    
          ret, trans_mask = cv2.threshold(img2gray, 75, 255, cv2.THRESH_BINARY)
          trans_mask = trans_mask == 0
          image[trans_mask] = color    
          new_img = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)    
          return new_img
        

        The Output Image

        【讨论】:

          猜你喜欢
          • 2015-06-22
          • 2012-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-15
          • 2012-12-13
          • 1970-01-01
          相关资源
          最近更新 更多