[英]Colorize image while preserving transparency with PIL?
好的,情况是这样的:
我想使用 Python 图像库来“主题化”这样的图像:
主题色:
"#33B5E5"
在: 出去:
我通过 ImageMagick 使用此命令得到了结果:
convert image.png -colorspace gray image.png
mogrify -fill "#33b5e5" -tint 100 image.png
解释:
图像首先转换为黑白,然后是主题。
我想用 Python 图像库获得相同的结果。 但似乎我在使用它时遇到了一些问题,因为:
我正在尝试使用此脚本:
import Image import ImageEnhance def image_overlay(src, color="#FFFFFF", alpha=0.5): overlay = Image.new(src.mode, src.size, color) bw_src = ImageEnhance.Color(src).enhance(0.0) return Image.blend(bw_src, overlay, alpha) img = Image.open("image.png") image_overlay(img, "#33b5e5", 0.5)
您可以看到我没有先将其转换为灰度,因为这也不适用于透明度。
很抱歉在一个问题中发布了这么多问题,但我无能为力:$
希望大家理解。
注:有这个答案的PIL版本一个Python 3 /枕头叉这里。
更新 4 :猜猜对我的答案的上一次更新毕竟不是最后一次。 尽管将其转换为专门使用PIL
是一项重大改进,但有一些事情似乎应该有更好的、不那么尴尬的方法,只要PIL
有能力。
那么,阅读文档紧密以及一些源代码后,我意识到我想做的事,其实是可能的。 权衡是现在它必须手动构建查找表,因此整体代码稍长。 然而结果是它只需要调用一次相对较慢的Image.point()
方法,而不是三个。
from PIL import Image
from PIL.ImageColor import getcolor, getrgb
from PIL.ImageOps import grayscale
def image_tint(src, tint='#ffffff'):
if Image.isStringType(src): # file path?
src = Image.open(src)
if src.mode not in ['RGB', 'RGBA']:
raise TypeError('Unsupported source image mode: {}'.format(src.mode))
src.load()
tr, tg, tb = getrgb(tint)
tl = getcolor(tint, "L") # tint color's overall luminosity
if not tl: tl = 1 # avoid division by zero
tl = float(tl) # compute luminosity preserving tint factors
sr, sg, sb = map(lambda tv: tv/tl, (tr, tg, tb)) # per component adjustments
# create look-up tables to map luminosity to adjusted tint
# (using floating-point math only to compute table)
luts = (map(lambda lr: int(lr*sr + 0.5), range(256)) +
map(lambda lg: int(lg*sg + 0.5), range(256)) +
map(lambda lb: int(lb*sb + 0.5), range(256)))
l = grayscale(src) # 8-bit luminosity version of whole image
if Image.getmodebands(src.mode) < 4:
merge_args = (src.mode, (l, l, l)) # for RGB verion of grayscale
else: # include copy of src image's alpha layer
a = Image.new("L", src.size)
a.putdata(src.getdata(3))
merge_args = (src.mode, (l, l, l, a)) # for RGBA verion of grayscale
luts += range(256) # for 1:1 mapping of copied alpha values
return Image.merge(*merge_args).point(luts)
if __name__ == '__main__':
import os
input_image_path = 'image1.png'
print 'tinting "{}"'.format(input_image_path)
root, ext = os.path.splitext(input_image_path)
result_image_path = root+'_result'+ext
print 'creating "{}"'.format(result_image_path)
result = image_tint(input_image_path, '#33b5e5')
if os.path.exists(result_image_path): # delete any previous result file
os.remove(result_image_path)
result.save(result_image_path) # file name's extension determines format
print 'done'
这是一个屏幕截图,左侧显示输入图像,右侧显示相应输出。 上面一行是带有 alpha 层的,下面一行是类似的,没有 alpha 层。
您需要先转换为灰度。 我做了什么:
Image.split()
获取原始 alpha 层ImageOps.colorize
着色结果代码:
import Image
import ImageOps
def tint_image(src, color="#FFFFFF"):
src.load()
r, g, b, alpha = src.split()
gray = ImageOps.grayscale(src)
result = ImageOps.colorize(gray, (0, 0, 0, 0), color)
result.putalpha(alpha)
return result
img = Image.open("image.png")
tinted = tint_image(img, "#33b5e5")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.