Skip to content

Commit 1a39970

Browse files
algobytewisegithub-actions
and
github-actions
authored
Add rgb_hsv_conversion.py (#4334)
* Add rgb_hsv_conversion.py * updating DIRECTORY.md * snake-case Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
1 parent ba97481 commit 1a39970

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

Diff for: DIRECTORY.md

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
* [Molecular Chemistry](https://github.com/TheAlgorithms/Python/blob/master/conversions/molecular_chemistry.py)
113113
* [Octal To Decimal](https://github.com/TheAlgorithms/Python/blob/master/conversions/octal_to_decimal.py)
114114
* [Prefix Conversions](https://github.com/TheAlgorithms/Python/blob/master/conversions/prefix_conversions.py)
115+
* [Rgb Hsv Conversion](https://github.com/TheAlgorithms/Python/blob/master/conversions/rgb_hsv_conversion.py)
115116
* [Roman Numerals](https://github.com/TheAlgorithms/Python/blob/master/conversions/roman_numerals.py)
116117
* [Temperature Conversions](https://github.com/TheAlgorithms/Python/blob/master/conversions/temperature_conversions.py)
117118
* [Weight Conversion](https://github.com/TheAlgorithms/Python/blob/master/conversions/weight_conversion.py)

Diff for: conversions/rgb_hsv_conversion.py

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
"""
2+
The RGB color model is an additive color model in which red, green, and blue light
3+
are added together in various ways to reproduce a broad array of colors. The name
4+
of the model comes from the initials of the three additive primary colors, red,
5+
green, and blue. Meanwhile, the HSV representation models how colors appear under
6+
light. In it, colors are represented using three components: hue, saturation and
7+
(brightness-)value. This file provides functions for converting colors from one
8+
representation to the other.
9+
10+
(description adapted from https://en.wikipedia.org/wiki/RGB_color_model and
11+
https://en.wikipedia.org/wiki/HSL_and_HSV).
12+
"""
13+
14+
15+
def hsv_to_rgb(hue: float, saturation: float, value: float) -> list[int]:
16+
"""
17+
Conversion from the HSV-representation to the RGB-representation.
18+
Expected RGB-values taken from
19+
https://www.rapidtables.com/convert/color/hsv-to-rgb.html
20+
21+
>>> hsv_to_rgb(0, 0, 0)
22+
[0, 0, 0]
23+
>>> hsv_to_rgb(0, 0, 1)
24+
[255, 255, 255]
25+
>>> hsv_to_rgb(0, 1, 1)
26+
[255, 0, 0]
27+
>>> hsv_to_rgb(60, 1, 1)
28+
[255, 255, 0]
29+
>>> hsv_to_rgb(120, 1, 1)
30+
[0, 255, 0]
31+
>>> hsv_to_rgb(240, 1, 1)
32+
[0, 0, 255]
33+
>>> hsv_to_rgb(300, 1, 1)
34+
[255, 0, 255]
35+
>>> hsv_to_rgb(180, 0.5, 0.5)
36+
[64, 128, 128]
37+
>>> hsv_to_rgb(234, 0.14, 0.88)
38+
[193, 196, 224]
39+
>>> hsv_to_rgb(330, 0.75, 0.5)
40+
[128, 32, 80]
41+
"""
42+
if hue < 0 or hue > 360:
43+
raise Exception("hue should be between 0 and 360")
44+
45+
if saturation < 0 or saturation > 1:
46+
raise Exception("saturation should be between 0 and 1")
47+
48+
if value < 0 or value > 1:
49+
raise Exception("value should be between 0 and 1")
50+
51+
chroma = value * saturation
52+
hue_section = hue / 60
53+
second_largest_component = chroma * (1 - abs(hue_section % 2 - 1))
54+
match_value = value - chroma
55+
56+
if hue_section >= 0 and hue_section <= 1:
57+
red = round(255 * (chroma + match_value))
58+
green = round(255 * (second_largest_component + match_value))
59+
blue = round(255 * (match_value))
60+
elif hue_section > 1 and hue_section <= 2:
61+
red = round(255 * (second_largest_component + match_value))
62+
green = round(255 * (chroma + match_value))
63+
blue = round(255 * (match_value))
64+
elif hue_section > 2 and hue_section <= 3:
65+
red = round(255 * (match_value))
66+
green = round(255 * (chroma + match_value))
67+
blue = round(255 * (second_largest_component + match_value))
68+
elif hue_section > 3 and hue_section <= 4:
69+
red = round(255 * (match_value))
70+
green = round(255 * (second_largest_component + match_value))
71+
blue = round(255 * (chroma + match_value))
72+
elif hue_section > 4 and hue_section <= 5:
73+
red = round(255 * (second_largest_component + match_value))
74+
green = round(255 * (match_value))
75+
blue = round(255 * (chroma + match_value))
76+
else:
77+
red = round(255 * (chroma + match_value))
78+
green = round(255 * (match_value))
79+
blue = round(255 * (second_largest_component + match_value))
80+
81+
return [red, green, blue]
82+
83+
84+
def rgb_to_hsv(red: int, green: int, blue: int) -> list[float]:
85+
"""
86+
Conversion from the RGB-representation to the HSV-representation.
87+
The tested values are the reverse values from the hsv_to_rgb-doctests.
88+
Function "approximately_equal_hsv" is needed because of small deviations due to
89+
rounding for the RGB-values.
90+
91+
>>> approximately_equal_hsv(rgb_to_hsv(0, 0, 0), [0, 0, 0])
92+
True
93+
>>> approximately_equal_hsv(rgb_to_hsv(255, 255, 255), [0, 0, 1])
94+
True
95+
>>> approximately_equal_hsv(rgb_to_hsv(255, 0, 0), [0, 1, 1])
96+
True
97+
>>> approximately_equal_hsv(rgb_to_hsv(255, 255, 0), [60, 1, 1])
98+
True
99+
>>> approximately_equal_hsv(rgb_to_hsv(0, 255, 0), [120, 1, 1])
100+
True
101+
>>> approximately_equal_hsv(rgb_to_hsv(0, 0, 255), [240, 1, 1])
102+
True
103+
>>> approximately_equal_hsv(rgb_to_hsv(255, 0, 255), [300, 1, 1])
104+
True
105+
>>> approximately_equal_hsv(rgb_to_hsv(64, 128, 128), [180, 0.5, 0.5])
106+
True
107+
>>> approximately_equal_hsv(rgb_to_hsv(193, 196, 224), [234, 0.14, 0.88])
108+
True
109+
>>> approximately_equal_hsv(rgb_to_hsv(128, 32, 80), [330, 0.75, 0.5])
110+
True
111+
"""
112+
if red < 0 or red > 255:
113+
raise Exception("red should be between 0 and 255")
114+
115+
if green < 0 or green > 255:
116+
raise Exception("green should be between 0 and 255")
117+
118+
if blue < 0 or blue > 255:
119+
raise Exception("blue should be between 0 and 255")
120+
121+
float_red = red / 255
122+
float_green = green / 255
123+
float_blue = blue / 255
124+
value = max(max(float_red, float_green), float_blue)
125+
chroma = value - min(min(float_red, float_green), float_blue)
126+
saturation = 0 if value == 0 else chroma / value
127+
128+
if chroma == 0:
129+
hue = 0.0
130+
elif value == float_red:
131+
hue = 60 * (0 + (float_green - float_blue) / chroma)
132+
elif value == float_green:
133+
hue = 60 * (2 + (float_blue - float_red) / chroma)
134+
else:
135+
hue = 60 * (4 + (float_red - float_green) / chroma)
136+
137+
hue = (hue + 360) % 360
138+
139+
return [hue, saturation, value]
140+
141+
142+
def approximately_equal_hsv(hsv_1: list[float], hsv_2: list[float]) -> bool:
143+
"""
144+
Utility-function to check that two hsv-colors are approximately equal
145+
146+
>>> approximately_equal_hsv([0, 0, 0], [0, 0, 0])
147+
True
148+
>>> approximately_equal_hsv([180, 0.5, 0.3], [179.9999, 0.500001, 0.30001])
149+
True
150+
>>> approximately_equal_hsv([0, 0, 0], [1, 0, 0])
151+
False
152+
>>> approximately_equal_hsv([180, 0.5, 0.3], [179.9999, 0.6, 0.30001])
153+
False
154+
"""
155+
check_hue = abs(hsv_1[0] - hsv_2[0]) < 0.2
156+
check_saturation = abs(hsv_1[1] - hsv_2[1]) < 0.002
157+
check_value = abs(hsv_1[2] - hsv_2[2]) < 0.002
158+
159+
return check_hue and check_saturation and check_value

0 commit comments

Comments
 (0)