【问题标题】:opencv: how to convert all black pixels to transparent and save it to png fileopencv:如何将所有黑色像素转换为透明并将其保存为png文件
【发布时间】:2022-01-10 09:12:16
【问题描述】:

图片如下,我希望所有黑色像素都是透明的并保存到png文件中。

【问题讨论】:

    标签: python opencv


    【解决方案1】:

    根据documentation

    使用此功能可以保存带有 alpha 通道的 PNG 图像。到 这样做,创建 8 位(或 16 位)4 通道图像 BGRA,其中 阿尔法通道最后。完全透明的像素应该有 alpha 设置为 0,完全不透明的像素应将 alpha 设置为 255/65535(请参阅 下面的代码示例)。

    透明图像带有一个额外的通道,我们称之为 alpha 通道,在 opencv 中用BGRA 表示。您需要做的就是创建一个格式为BGRA 的蒙版图像。然后检测图像中的所有黑色像素,并为这些黑色像素分配蒙版图像的 alpha 通道为 0。

    注意: 使用 opencv imshow 或其他您将无法看到透明图像,因为 opencv 无法显示 alpha 通道。所以你需要用imwrite写成png格式

    注意:使任何像素透明意味着将其 Alpha 通道分配为 0。

    这是我的意思的输出:

    由于我不熟悉 python,所以我用 C++ 编写了这些步骤。很抱歉。

    #include <iostream>
    #include <opencv2/highgui.hpp>
    #include <opencv2/imgproc.hpp>
    
    
    int main()
    {
    
    
        cv::Mat img = cv::imread("/ur/input/img.png",cv::IMREAD_COLOR);
    
        cv::Mat mask = cv::Mat::zeros(cv::Size(img.cols,img.rows),CV_8UC4);
    
        cv::namedWindow("Input",0);
        cv::namedWindow("Output",0);
    
    
        for(int i=0; i<mask.cols; i++)
        {
            for(int j=0; j<mask.rows; j++)
            {
    
                if(img.at<cv::Vec3b>(cv::Point(i,j))[0] == 0 &&
                        img.at<cv::Vec3b>(cv::Point(i,j))[1] == 0 &&
                        img.at<cv::Vec3b>(cv::Point(i,j))[2] == 0)
                {
                    mask.at<cv::Vec4b>(cv::Point(i,j))[0] = img.at<cv::Vec3b>(cv::Point(i,j))[0];
                    mask.at<cv::Vec4b>(cv::Point(i,j))[1] = img.at<cv::Vec3b>(cv::Point(i,j))[1];
                    mask.at<cv::Vec4b>(cv::Point(i,j))[2] = img.at<cv::Vec3b>(cv::Point(i,j))[2];
                    mask.at<cv::Vec4b>(cv::Point(i,j))[3] = 0;
                }
                else {
                    mask.at<cv::Vec4b>(cv::Point(i,j))[0] = img.at<cv::Vec3b>(cv::Point(i,j))[0];
                    mask.at<cv::Vec4b>(cv::Point(i,j))[1] = img.at<cv::Vec3b>(cv::Point(i,j))[1];
                    mask.at<cv::Vec4b>(cv::Point(i,j))[2] = img.at<cv::Vec3b>(cv::Point(i,j))[2];
                    mask.at<cv::Vec4b>(cv::Point(i,j))[3] = 255;
                }
    
            }
        }
    
    
    
    
        cv::imshow("Input",img);
        cv::imshow("Output",mask);
    
    
        cv::imwrite("/ur/writing/dir/transparent.png",mask);
        cv::waitKey(0);
    
    
    
        return 0;
    }
    

    【讨论】:

      【解决方案2】:

      您可以像这样快速并矢量化:

      import cv2
      import numpy as np
      
      # Load image as Numpy array in BGR order
      na = cv2.imread('I5jKW.png')
      
      # Make a True/False mask of pixels whose BGR values sum to more than zero
      alpha = np.sum(na, axis=-1) > 0
      
      # Convert True/False to 0/255 and change type to "uint8" to match "na"
      alpha = np.uint8(alpha * 255)
      
      # Stack new alpha layer with existing image to go from BGR to BGRA, i.e. 3 channels to 4 channels
      res = np.dstack((na, alpha))
      
      # Save result
      cv2.imwrite('result.png', res)
      

      注意事项:

      1 您同样可以使用cv2.merge() 代替np.dstack(),它可能更快。

      2 您同样可以使用 PIL/Pillow 代替 OpenCV 函数来读取/保存图像。

      【讨论】:

        【解决方案3】:

        这是在 Python/OpenCV/Numpy 中执行此操作的另一种方法。

        import cv2
        import numpy as np
        
        # load image
        img = cv2.imread('girl_on_black.png')
        
        # threshold on black to make a mask
        color = (0,0,0)
        mask = np.where((img==color).all(axis=2), 0, 255).astype(np.uint8)
        
        # put mask into alpha channel
        result = img.copy()
        result = cv2.cvtColor(result, cv2.COLOR_BGR2BGRA)
        result[:, :, 3] = mask
        
        # save resulting masked image
        cv2.imwrite('girl_on_black_transparent.png', result)
        
        # display result, though it won't show transparency
        cv2.imshow("MASK", mask)
        cv2.imshow("RESULT", result)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        

        【讨论】:

        • 很好的解决方案!
        • @Bin Chen 如果我的回答对您有帮助,请给它投票。
        猜你喜欢
        • 2011-03-26
        • 2014-08-09
        • 1970-01-01
        • 2012-07-30
        • 2021-04-11
        • 1970-01-01
        • 2013-04-29
        • 1970-01-01
        • 2020-07-17
        相关资源
        最近更新 更多