I have tried to find a good formula in Python 3 to calculate the complementary colour of a rgb code eg. complementary of a = b. Is there any way to do this?
Here's how to calculate the complement of an RGB colour directly. It gives the same results as the algorithm using colorsys
as shown in Iva Klass's answer, but in my tests it's about 50% faster. Note that it works for any RGB scheme, it doesn't matter whether the RGB components are integers or floats (as long as each component uses the same range!).
The function hilo
implements a simple sorting network to sort the RGB components.
# Sum of the min & max of (a, b, c)
def hilo(a, b, c):
if c < b: b, c = c, b
if b < a: a, b = b, a
if c < b: b, c = c, b
return a + c
def complement(r, g, b):
k = hilo(r, g, b)
return tuple(k - u for u in (r, g, b))
Here's a short demo, using PIL / Pillow.
#!/usr/bin/env python3
''' Complement the colours in a RGB image
Written by PM 2Ring 2016.10.08
'''
import sys
from PIL import Image
# Sum of the min & max of (a, b, c)
def hilo(a, b, c):
if c < b: b, c = c, b
if b < a: a, b = b, a
if c < b: b, c = c, b
return a + c
def complement(r, g, b):
k = hilo(r, g, b)
return tuple(k - u for u in (r, g, b))
def complement_image(iname, oname):
print('Loading', iname)
img = Image.open(iname)
#img.show()
size = img.size
mode = img.mode
in_data = img.getdata()
print('Complementing...')
out_img = Image.new(mode, size)
out_img.putdata([complement(*rgb) for rgb in in_data])
out_img.show()
out_img.save(oname)
print('Saved to', oname)
def main():
if len(sys.argv) == 3:
complement_image(*sys.argv[1:])
else:
fmt = 'Complement colours.\nUsage: {} input_image output_image'
print(fmt.format(sys.argv[0]))
if __name__ == '__main__':
main()
Here's a Numpy version of complement_image
. On my machine it processes the "Glasses" image about 3.7 times faster than the previous version.
import numpy as np
def complement_image(iname, oname):
print('Loading', iname)
img = Image.open(iname)
#img.show()
in_data = np.asarray(img)
#print(in_data.shape)
print('Complementing...')
lo = np.amin(in_data, axis=2, keepdims=True)
hi = np.amax(in_data, axis=2, keepdims=True)
out_data = (lo + hi) - in_data
out_img = Image.fromarray(out_data)
#out_img.show()
out_img.save(oname)
print('Saved to', oname)
I don't think there is ready solution for this, but there is a colorsys module in standard library, it can help.
I think you first need to convert RGB into HSV or HSL, then "rotate" hue, and convert back to RGB, if you need. For example (I'm not sure about proper rotating):
from colorsys import rgb_to_hsv, hsv_to_rgb
def complementary(r, g, b):
"""returns RGB components of complementary color"""
hsv = rgb_to_hsv(r, g, b)
return hsv_to_rgb((hsv[0] + 0.5) % 1, hsv[1], hsv[2])
r,g,b = [25,25,25]
def get_complementary(color):
color = color[1:]
color = int(color, 16)
comp_color = 0xFFFFFF ^ color
comp_color = "#%06X" % comp_color
return comp_color
hex_val = "#%02x%02x%02x" % (r,g,b)
h = get_complementary(hex_val)
print("Complementary color",h)
h = h.lstrip('#')
print('RGB =', tuple(int(h[i:i+2], 16) for i in (0, 2, 4)))
output:
Complementary color #E6E6E6
RGB = (230, 230, 230)