通过python、numpy理解png贴图的透明原理 作者:马育民 • 2020-04-30 17:01 • 阅读:11057 需要掌握:[通过python、numpy理解png alpha通道(透明)原理](https://www.malaoshi.top/show_1EF5RBxcyfIV.html "通过python、numpy理解png alpha通道(透明)原理") # 介绍 本文通过python的PIL库、numpy理解png贴图的透明原理 最终效果,猪头png图片 粘贴 到背景图片,透明部分不覆盖,如下: [![](https://www.malaoshi.top/upload/0/0/1EF5RBw6cd7U.png)](https://www.malaoshi.top/upload/0/0/1EF5RBw6cd7U.png) # 准备图片 jpg图片 [![](https://www.malaoshi.top/upload/0/0/1EF5RBWxrTqr.jpg)](https://www.malaoshi.top/upload/0/0/1EF5RBWxrTqr.jpg) # 代码 ### 读取jpg图片,并显示 ``` bg=Image.open("/Users/mym/Desktop/可删除/QQ20200428-151456.jpg") bg ``` 转成矩阵 ``` bg_arr=np.array(bg) bg_arr.shape ``` 执行结果: ``` (717, 822, 3) ``` 由于是jpg图片,是 rgb 3个通道,所以 矩阵最后一个维度是 3 ### 直接替换矩阵的值 由于 png图片 是 rgba 4个通道,所以png矩阵是`(650, 650, 4)` 而背景图是 rgb 3个通道,所以 背景图 矩阵是 `(717, 822, 3)` 通过numpy,不能 直接替换,是将png矩阵的 rgb 3个通道 替换 背景图矩阵: ``` bg_arr[0:png.size[0],0:png.size[1]]=png_rgb Image.fromarray(bg_arr) ``` 显示结果如下: [![](https://www.malaoshi.top/upload/0/0/1EF5RC4tcOKe.png)](https://www.malaoshi.top/upload/0/0/1EF5RC4tcOKe.png) 因为 3个通道的 png图片,不具备透明的 alpha 通道,所以不能实现透明,需要额外处理 # 透明贴图 ### 掩膜(mask) 掩膜是二维矩阵数组,通过对图像进行遮挡,来控制图像处理的区域 举个例子:掩膜相当于下图中 镂空喷漆的遮挡版 [![](https://www.malaoshi.top/upload/0/0/1EF5REiVabjz.png)](https://www.malaoshi.top/upload/0/0/1EF5REiVabjz.png) 图像矩阵,原图 与 mask 进行乘法运算,或者 与运算(x & 1 = x;x & 0 = 0): [![](https://www.malaoshi.top/upload/0/0/1EF5REkuXTL3.png)](https://www.malaoshi.top/upload/0/0/1EF5REkuXTL3.png) 具体作用(摘自百度百科): 1. 提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。 2. 屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。 3. 结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。 4. 特殊形状图像的制作。 ### 将png alpha通道转成掩膜 将3个 png alpha 通道,合并成矩阵,再除以255(这样像素值在 0-1之间,但有过渡值。也有二值化处理,只有0和1)做掩膜用 ``` png_a3=np.dstack((png_a,png_a,png_a)) png_a3=png_a3/255 from collections import Counter Counter(png_a3.flatten()) ``` 透明部分是0,不透明的部分是1,中间有过渡值 ### png rgb3 通道 与 掩膜相乘 将png rgb 3 通道 与 掩膜相乘,相乘后,透明的部分就是0,不透明的部分就是png rgb 的原值 ``` fg=np.multiply(png_rgb,png_a3) Image.fromarray(fg.astype("uint8")) ``` 结果: [![](https://www.malaoshi.top/upload/0/0/1EF5RCcNKS4M.png)](https://www.malaoshi.top/upload/0/0/1EF5RCcNKS4M.png) 透明部分是黑色,像素值是0,不透明部分是png rgb的原值 ### 从背景图中截取 png图片的大小区域 从背景图中截取 png图片的大小区域 ``` bg_arr_cut=bg_arr[0:png.size[0],0:png.size[1]] Image.fromarray(bg_arr_cut) ``` [![](https://www.malaoshi.top/upload/0/0/1EF5RCUIBGbB.png)](https://www.malaoshi.top/upload/0/0/1EF5RCUIBGbB.png) ### 将背景图截取部分 与 反掩膜 相乘 反掩膜:`1-png_a3`, ``` bg_arr_cut2=np.multiply(bg_arr_cut,1-png_a3) Image.fromarray(bg_arr_cut2.astype("uint8")) ``` [![](https://www.malaoshi.top/upload/0/0/1EF5RCefYowQ.png)](https://www.malaoshi.top/upload/0/0/1EF5RCefYowQ.png) png透明部分,在背景图中显示原像素值,png不透明的部分,背景图中像素值是0 ### 将两个图矩阵相加 ``` res=(bg_arr_cut2+fg).astype("uint8") Image.fromarray(res) ``` [![](https://www.malaoshi.top/upload/0/0/1EF5RCjkYp0Z.png)](https://www.malaoshi.top/upload/0/0/1EF5RCjkYp0Z.png) ### 回填背景图中 ``` bg_arr[0:png.size[0],0:png.size[1]]=res Image.fromarray(bg_arr) ``` 最终结果: [![](https://www.malaoshi.top/upload/0/0/1EF5RBw6cd7U.png)](https://www.malaoshi.top/upload/0/0/1EF5RBw6cd7U.png) 原文出处:http://malaoshi.top/show_1EF5RClROWCa.html