在做网站logo的时候，我遇到了一个棘手难以解释的问题：logo图片需要与背景融合在一起，虽然我使用了PNG格式对图片进行编辑，但仍有部分区域呈现白色。于是我又使用了Ps对图片进行二值化处理，但此番操作下来图片却有了许多锯齿，十分难看。最终我结合一些图像处理的知识，使用Pillow实现了理想的效果，并做了一些扩展研究。思路PNGPNG图像采用RGBA存储图像色彩信息，其中RGB分别指红绿蓝三色光的亮度，A指的是Alpha通道，存储透明度信息，因此PNG图像可以实现半透明效果。 PNG图片上的每一个点都有RGBA这四个数值。灰度对于上文的辣种图片是纯黑白的图，所以也可以用灰度来存储它的信息。总结由此可以先把上文的图片转成灰度图，获取到每个像素点的灰度值，将其作为Alpha通道的值，RGB色值为纯黑(0, 0, 0)即可实现。实现# 导入Pillow from PIL import Image, ImageDraw def imGreyAlpha(im): grey = im.convert('L') # 转成灰度 px = grey.load() # 获取灰度数组 im2 = Image.new(mode="RGBA", size=(w, h), color=(255,255,255,0)) # 新建图片 draw = ImageDraw.Draw(im2) # 获取绘制句柄 w,h = im.size # 获取图片大小 # 遍历像素点 for i in range(w): for j in range(h): alpha = px[i, j] # 获取灰度作为alpha值 draw.point((i, j), fill=(0, 0, 0, 255 - alpha)) # 填充像素点 return im2 # 返回图像 # 函数使用示例 demoInput = Image.open('xxx.png') # 打开图像 demoOutput = imGreyAlpha(demoInput) # 丢进函数输出图像 demoOutput.save('ouput.png') # 保存图像拓展彩色图如果仅仅是需要简单的彩色输出，那么只需修改以上代码即可：# 导入Pillow from PIL import Image, ImageDraw def imGreyAlpha(im): ################ color = im.convert('RGB') # 获取原图RGB模式 pxColor = color.load() # 获取色彩数组 ################ grey = im.convert('L') # 转成灰度 px = grey.load() # 获取灰度数组 im2 = Image.new(mode="RGBA", size=(w, h), color=(255,255,255,0)) # 新建图片 draw = ImageDraw.Draw(im2) # 获取绘制句柄 w, h = im.size # 获取图片大小 # 遍历像素点 for i in range(w): for j in range(h): alpha = px[i, j] # 获取灰度作为alpha值 ######## r, g, b = pxColor[i, j] # 获取原图颜色 draw.point((i, j), fill=(r, g, b, 255 - alpha)) # 填充像素点 ######## return im2 # 返回图像 # 函数使用示例 demoInput = Image.open('xxx.png') # 打开图像 demoOutput = imGreyAlpha(demoInput) # 丢进函数输出图像 demoOutput.save('ouput.png') # 保存图像抠图滤色 如图所示，可以将背景色值周围的色值设置Alpha值，这个周围的范围和PS里的魔棒工具的容差概念相似据此可写出如下代码：# bgColor为背景颜色，是一个包含三个数的Tuple # intv为容差 def imColorAlpha(im, bgColor, intv): imConverted = im.convert('RGB') w, h = imConverted.size rb = bgColor[0] gb = bgColor[1] bb = bgColor[2] im2 = Image.new(mode="RGBA", size=(w, h), color=(255,255,255,0)) draw = ImageDraw.Draw(im2) tempPx = imConverted.load() for i in range(w): for j in range(h): r, g, b = tempPx[i, j] ar = (255/intv*(r-rb+intv)) if r<rb else (-255/intv*(r-rb-intv)) ag = (255/intv*(g-gb+intv)) if g<gb else (-255/intv*(g-gb-intv)) ab = (255/intv*(b-bb+intv)) if b<bb else (-255/intv*(b-bb-intv)) if ar<=0 or ag<=0 or ab<=0: ar, ag, ab = (0, 0, 0) a = 255 - int((ar + ag + ab)/3) #r1 = int((r - rb)*a/255 + rb) #g1 = int((g - gb)*a/255 + gb) #b1 = int((b - bb)*a/255 + bb) draw.point((i, j), fill=(r, g, b, a)) return im2滤色 如上图所示，此处的“滤色”是指计算所有像素点颜色相对于背景色的差距，以其作为Alpha通道的值实现代码如下：def imColorAlpha(im, bgColor): imConverted = im.convert('RGB') w, h = imConverted.size rb = bgColor[0] gb = bgColor[1] bb = bgColor[2] im2 = Image.new(mode="RGBA", size=(w, h), color=(255,255,255,0)) draw = ImageDraw.Draw(im2) tempPx = imConverted.load() for i in range(w): for j in range(h): r, g, b = tempPx[i, j] ar = (255/rb*r) if r<rb else (255/(rb-255)*(r-255)) ag = (255/gb*g) if g<gb else (255/(gb-255)*(g-255)) ab = (255/bb*b) if b<bb else (255/(bb-255)*(b-255)) a = 255 - int((ar + ag + ab)/3) #r1 = int((r - rb)*a/255 + rb) #g1 = int((g - gb)*a/255 + gb) #b1 = int((b - bb)*a/255 + bb) draw.point((i, j), fill=(r, g, b, a)) return im2