Skip to content

Instantly share code, notes, and snippets.

@Syncrossus
Last active September 5, 2019 08:40
Show Gist options
  • Save Syncrossus/38e2886205602443620c871957ddfdd6 to your computer and use it in GitHub Desktop.
Save Syncrossus/38e2886205602443620c871957ddfdd6 to your computer and use it in GitHub Desktop.
Functions to convert RGB values to HSV and vice versa, and a code sample to get them working on an image.
def hsv_to_rgb(pixel):
""" converts a pixel expressed in RGB to an HSV expression
see https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
Args:
pixel<(h, s, v)>:
h <float[0-360]>: hue
s <float[0-1]>: saturation
v <float[0-1]>: "value" (brightness)
Return:
r <int[0-255]>: red value
g <int[0-255]>: green value
b <int[0-255]>: blue value
"""
h, s, v = pixel
chroma = v * s
h /= 60
x = chroma * (1 - abs((h % 2) - 1))
if 0 <= h <= 1:
r1, g1, b1 = chroma, x, 0
elif 1 < h <= 2:
r1, g1, b1 = x, chroma, 0
elif 2 < h <= 3:
r1, g1, b1 = 0, chroma, x
elif 3 < h <= 4:
r1, g1, b1 = 0, x, chroma
elif 4 < h <= 5:
r1, g1, b1 = x, 0, chroma
elif 5 < h < 6:
r1, g1, b1 = chroma, 0, x
else:
r1, g1, b1 = 0, 0, 0
m = v - chroma
r = int(round((r1 + m) * 255))
g = int(round((g1 + m) * 255))
b = int(round((b1 + m) * 255))
return r, g, b
from rgb_to_hsv import rgb_to_hsv
from hsv_to_rgb import hsv_to_rgb
import png # example in __main__ uses pypng
import sys
from itertools import chain
def read_img(f):
""" Reads the image. This returns a tuple of the form
(height, width, raw_image_data, other_metadata_dict)
"""
img = png.Reader(file=f).read()
raw_img = img[2]
step = 4 if img[3]['alpha'] else 3
processed_img = []
for row in raw_img:
new_row = []
for i in range(0, len(row), step):
r, g, b = row[i], row[i + 1], row[i + 2]
new_row.append((r, g, b))
processed_img.append(new_row)
return processed_img
def convert_image(img, fun, args=()):
""" Applies a pixel-wise function to an entire image.
Args:
img <list<list<tuple>>>: an image represented as a list of rows
with each row a list of pixels with each pixel a tuple
fun <func>: the function to apply
args <tuple>: arguments to pass on to the pixel-wise function
Return:
new_img: a new image (same representation as argument) after
the pixel-wise function has been applied
"""
new_img = []
for row in img:
new_row = []
for px in row:
new_row.append(fun(px, *args))
new_img.append(new_row)
return new_img
if __name__ == '__main__':
# getting filename
fname = sys.argv[1]
with open(fname, 'rb') as f:
img = read_img(f)
# converting image from RGB to HSV
img = convert_image(img, rgb_to_hsv)
# do stuff with your HSV image
# converting modified image back to RGB from HSV
img = convert_image(img, hsv_to_rgb)
# overwriting image file
w = png.Writer(len(img[0]), len(img), greyscale=False)
img = [chain(*row) for row in img] # only necessary wih pypng 0.0.20+
with open(fname, 'wb') as f:
w.write(f, img)
def rgb_to_hsv(pixel):
""" converts a pixel expressed in RGB to an HSV expression
see https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB
Args:
pixel<(r, g, b)>:
r <int[0-255]>: red value
g <int[0-255]>: green value
b <int[0-255]>: blue value
Return:
h <float[0-360]>: hue
s <float[0-1]>: saturation
v <float[0-1]>: "value" (brightness)
"""
r, g, b = pixel
r /= 255
g /= 255
b /= 255
MAX = max(r, g, b)
MIN = min(r, g, b)
if MAX == MIN:
h = 0
elif MAX == r:
h = 60 * (((g - b) / (MAX - MIN)) + 0)
elif MAX == g:
h = 60 * (((b - r) / (MAX - MIN)) + 2)
else:
h = 60 * (((r - g) / (MAX - MIN)) + 4)
if h < 0:
h += 360
if MAX == 0:
s = 0
else:
s = (MAX - MIN) / MAX
v = MAX
return h, s, v
@Syncrossus
Copy link
Author

This code is released under the WTFPL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment