Last active
September 5, 2019 08:40
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code is released under the .