我在实际工作中需要将一个存在alpha图层的Png图片经过正片叠底后,合成出一个新的渲染后图片,之后图片进行处理导出成jpg图片,这就需要剔除图片中的alpha通道,然而直接粗暴的剔除则会发生图片的正片叠底效果完全无用,变成了一大片图片糊在上面(因为透明内容丢失)

此时我参考了一篇这个文章,因为我核心的处理需求还是(透明底转换成白色底)

https://blog.csdn.net/comeonbabe_/article/details/89266810

#利用Pillow进行处理-opencv同理
from PIL import Image
 
def alphabg2white_PIL(img):
    img=img.convert('RGBA')
    sp=img.size
    width=sp[0]
    height=sp[1]
    print(sp)
    for yh in range(height):
        for xw in range(width):
            dot=(xw,yh)
            color_d=img.getpixel(dot)
            if(color_d[3]==0):
                color_d=(255,255,255,255)
                img.putpixel(dot,color_d)
    img.show()
    return img

使用效果,的确能够把透明内容转换成白色内容,可是:【太】【卡】【了】!

运行效率极其低下

解剖一下代码的原理,无非就是遍历搜索(两层高度和长度的遍历)*(每一层内部的RGBA值得遍历),复杂度高到爆炸。

即时使用numpy进行优化(说明一下原理,numpy会把矩阵处理的内容通过预制的二进制代码的方式进行处理,相比Python解释器慢慢挪动,numpy简直就是火箭),也一样会花费大量的实践。

回头一想

为什么要用遍历呢?【笨蛋!】

一个极其简单的思维,创建一个白色无透明的白色模板,尺寸与相关处理图片尺寸一致,作为底色蒙版,利用PIL的alpha通道混合算法将已经处理后的图片粘贴上去,再将rgb值单独提取出来保存为jpg格式不是更好么?

#渲染代码---需要将两张图片进行合并    
def back_fusion(self):
        savePath = self.savePath + "\\ansBack.png"
        img1 = Image.open("tmp.jpg")
        img1 = img1.convert("RGBA")
        img2 = Image.open(self.FoldDiagram_back_path)
        #创建白色模板
        white = Image.new("RGBA", img2.size, color=(255, 255, 255, 255))
        print("开始正片叠底:", img1.mode, "----", img2.mode)
        ans = IC.multiply(img2, img1)
        # 将白色模板和导出后的图片进行重叠
        ans = Image.alpha_composite(white, ans)
        ans.save(savePath, dpi=(96, 96))
        # 调用去除alpha通道算法,如果不需要去除alpha通道注释掉即可
        self.removeAlpha(savePath)

        if os.path.isfile(savePath):
            os.remove(savePath)
        print("保存褶皱图【后】渲染 成功")


# 移除alpha通道并将png保存为jpg   
 def removeAlpha(self, path):
        img = cv2.imread(path, -1)       # 读取渲染图
        bgr = img[:, :, :3]
        cv2.imwrite(path[:-3]+"jpg", bgr, [
                    int(cv2.IMWRITE_PNG_COMPRESSION), 0])      # 0 ~ 9 (low - high)

和遍历相比较,通过创建一个纯色空间的图片进行重叠处理,比长宽不等消耗内存越来越多速度越来越慢的循环处理方法,可以规避掉O(n^2)的复杂度变为常数级

 

 

分类: PYTHON

2 条评论

路过 · 2020年8月11日 下午3:06

大佬,那个IC是什么模块啊

    Mustenaka · 2020年9月6日 上午12:09

    IC也是属于pillow中的一份子,其提供了一部分基本PS图层操作的内容,比如这个例子正片叠底就用上了

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注