Skip to content

Instantly share code, notes, and snippets.

@Syncrossus
Last active September 5, 2019 08:40
Show Gist options
  • Select an option

  • Save Syncrossus/38e2886205602443620c871957ddfdd6 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown
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