public
Created

Colour-match two sets of images pairwise, adjust colour bqlance in the first set of images.

  • Download Gist
match-colours.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
#!/usr/bin/env python2
 
# requires PIL (python-imaging)
 
import Image
import ImageStat
 
from sys import argv, exit
from os.path import basename, splitext
 
MODIFIED_SUFFIX = "_mod.jpg"
 
def match_colours(source_image, target_image):
"""
Calculate per-channel amplification to match colours of the target_file.
 
Return (x_red, x_green, x_blue).
"""
s = ImageStat.Stat(source_image)
t = ImageStat.Stat(target_image)
k_chans = [ (tc/sc if sc else 1.0) for sc, tc in zip(s.mean, t.mean) ]
return tuple(k_chans)
 
def amplify_channels(image, factors):
"""
Apply per-channel amplification to the image.
image PIL image
factors a tuple of amplification coefficients, one per channel
 
Return a new PIL image.
"""
chans = image.split()
chans2 = [ Image.eval(c, lambda x: x*f) for c,f in zip(chans, factors)]
image2 = Image.merge(image.mode, chans2)
return image2
 
def main(source_images, target_images):
# calculate average transform coefficients using all image pairs
avg_multipliers = []
n = len(zip(source_images, target_images)) # number of pairs
for s, t in zip(source_images, target_images):
simg = Image.open(s)
simg.load() # workaround for http://bugs.debian.org/561965
timg = Image.open(t)
multipliers = match_colours(simg, timg)
ms = [ float(m)/n for m in multipliers ]
if not avg_multipliers:
avg_multipliers = [ float(m)/n for m in multipliers ]
else:
avg_multipliers = [ old_avg+float(m)/n
for old_avg, m
in zip(avg_multipliers, multipliers)]
# transform and save every source image
for s in source_images:
simg = Image.open(s)
simg.load() # workaround for http://bugs.debian.org/561965
modified = amplify_channels(simg, avg_multipliers)
out_filename = splitext(s)[0] + MODIFIED_SUFFIX
modified.save(out_filename)
 
def usage():
help = \
"""%s bad_image_1 bad_image_2 ... good_image_1 good_image_2 ...
 
Compare bad and good images pairwise, calculate per-channel
amplification coefficients to match colours in average, adjust bad
images and save them to new files appending "%s" to the filename.
"""
print help % (basename(argv[0]), MODIFIED_SUFFIX)
 
if __name__ == "__main__":
args = argv[1:]
if not args or "-h" in args or "--help" in args:
usage()
exit(0)
else:
n = len(args)
bad_imgs = args[0:n//2]
good_imgs = args[n//2:]
main(bad_imgs, good_imgs)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.