[英]Colorize image while preserving transparency with PIL?
Okay, here's the situation:好的,情况是这样的:
I want to use the Python Image Library to "theme" an image like this:我想使用 Python 图像库来“主题化”这样的图像:
Theme color:主题色:
"#33B5E5"
IN:在:
OUT:
出去:
I got the result using this commands with ImageMagick:我通过 ImageMagick 使用此命令得到了结果:
convert image.png -colorspace gray image.png
mogrify -fill "#33b5e5" -tint 100 image.png
Explanation:
The image is first converted to black-and-white, and then it is themed.图像首先转换为黑白,然后是主题。
I want to get the same result with the Python Image Library.我想用 Python 图像库获得相同的结果。 But it seems I'm having some problems using it since:
但似乎我在使用它时遇到了一些问题,因为:
I'm trying to use this script:我正在尝试使用此脚本:
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)
You can see I did not convert it to a grayscale first, because that didn't work with transparency either.您可以看到我没有先将其转换为灰度,因为这也不适用于透明度。
I'm sorry to post so many issues in one question, but I couldn't do anything else :$很抱歉在一个问题中发布了这么多问题,但我无能为力:$
Hope you all understand.希望大家理解。
Note : There's a Python 3/pillow fork of PIL version of this answer here .注:有这个答案的PIL版本一个Python 3 /枕头叉这里。
Update 4 : Guess the previous update to my answer wasn't the last one after all.更新 4 :猜猜对我的答案的上一次更新毕竟不是最后一次。 Although converting it to use
PIL
exclusively was a major improvement, there were a couple of things that seemed like there ought to be better, less awkward, ways to do, if only PIL
had the ability.尽管将其转换为专门使用
PIL
是一项重大改进,但有一些事情似乎应该有更好的、不那么尴尬的方法,只要PIL
有能力。
Well, after reading the documentation closely as well as some of the source code, I realized what I wanted to do was in fact possible.那么,阅读文档紧密以及一些源代码后,我意识到我想做的事,其实是可能的。 The trade-off was that now it has to build the look-up table used manually, so the overall code is slightly longer.
权衡是现在它必须手动构建查找表,因此整体代码稍长。 However the result is that it only needs to make one call to the relatively slow
Image.point()
method, instead of three of them.然而结果是它只需要调用一次相对较慢的
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'
Here's a screenshot showing input images on the left with corresponding outputs on the right.这是一个屏幕截图,左侧显示输入图像,右侧显示相应输出。 The upper row is for one with an alpha layer and the lower is a similar one that doesn't have one.
上面一行是带有 alpha 层的,下面一行是类似的,没有 alpha 层。
You need to convert to grayscale first.您需要先转换为灰度。 What I did:
我做了什么:
Image.split()
Image.split()
获取原始 alpha 层ImageOps.colorize
ImageOps.colorize
着色Resulting code:结果代码:
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.