问题
What is the easiest way to change the colour of the whole image with a RGB value? I have tried wand
, however the documentation didn't make much sense to me, and I can only find changing the intensity of the colours in the Pillow
documentation.
I tried multiple solutions online, however either they didn't do what I wanted, or were out of date and didn't work.
I want it so that the whole image gets tinted and I can control the tint by changing the RGB colour, bit like this:
http://cdn.makeuseof.com/wp-content/uploads/2012/11/Folder-Colorizer-Color-Manager.jpg?69fac7
I can implement the wheel myself, however the actual changing colour part is confusing me. Hopefully it will be an easy solution. :)
回答1:
Here's a Python 3 version of the code in my other answer. It's almost identical except for the imports which had to be changed in order to use the pillow fork of the PIL
(because only it supports Python 3). The other changes I made were changing print
statements into function calls and where the map()
function is used to create the luts
look-up table variable.
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 = (tuple(map(lambda lr: int(lr*sr + 0.5), range(256))) +
tuple(map(lambda lg: int(lg*sg + 0.5), range(256))) +
tuple(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 += tuple(range(256)) # for 1:1 mapping of copied alpha values
return Image.merge(*merge_args).point(luts)
if __name__ == '__main__':
import os
import sys
input_image_path = 'Dn3CeZB.png'
print('tinting "{}"'.format(input_image_path))
root, ext = os.path.splitext(input_image_path)
suffix = '_result_py{}'.format(sys.version_info[0])
result_image_path = root+suffix+ext
print('creating "{}"'.format(result_image_path))
result = image_tint(input_image_path, '#383D2D')
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 before and after images. The test image and tint color are the same as what you said you were using when you encountered the problem. The results look very similar to the Py2 version, to yours, and OK to me...am I missing something?
回答2:
import Image
import numpy as nump
img = Image.open('snapshot.jpg')
# In this case, it's a 3-band (red, green, blue) image
# so we'll unpack the bands into 3 separate 2D arrays.
r, g, b = nump.array(img).T
# Let's make an alpha (transparency) band based on where blue is < 100
a = nump.zeros_like(b)
a[b < 100] = 255
# Random math... This isn't meant to look good...
# Keep in mind that these are unsigned 8-bit integers, and will overflow.
# You may want to convert to floats for some calculations.
r = (b + g) * 5
# Put things back together and save the result...
img = Image.fromarray(nump.dstack([item.T for item in (r,g,b,a)]))
img.save('out.png')
Like this., you can use numpy.
OR
you can use Pillow. [lnk] (https://pillow.readthedocs.org/)
来源:https://stackoverflow.com/questions/29332424/changing-colour-of-an-image