File size: 3,203 Bytes
41dda1b
56a9526
41dda1b
 
 
56a9526
 
 
 
 
 
 
 
 
 
41dda1b
56a9526
 
 
 
41dda1b
56a9526
 
41dda1b
56a9526
 
41dda1b
56a9526
 
 
41dda1b
56a9526
 
 
41dda1b
56a9526
 
 
41dda1b
56a9526
 
 
41dda1b
56a9526
 
41dda1b
56a9526
 
41dda1b
56a9526
 
41dda1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import numpy as np
import warnings


def rgb_to_hsv(rgb):
    with warnings.catch_warnings():
        # Suppress the specific RuntimeWarning
        warnings.filterwarnings(
            "ignore", category=RuntimeWarning, message="invalid value encountered in divide")

        # Ensure the input is a float numpy array and in the range [0, 1]
        rgb = np.asarray(rgb)

        # Separate the R, G, B channels
        r, g, b = rgb[..., 0], rgb[..., 1], rgb[..., 2]

        # Max and min of RGB values
        max_rgb = np.max(rgb, axis=-1)
        min_rgb = np.min(rgb, axis=-1)
        delta = max_rgb - min_rgb

        # Hue calculation
        hue = np.zeros_like(max_rgb)

        # Avoid division by zero: Only calculate where delta is non-zero
        mask = delta != 0

        # Red is max
        idx = (max_rgb == r) & mask
        hue[idx] = (60 * ((g - b) / delta % 6))[idx]

        # Green is max
        idx = (max_rgb == g) & mask
        hue[idx] = (60 * ((b - r) / delta + 2))[idx]

        # Blue is max
        idx = (max_rgb == b) & mask
        hue[idx] = (60 * ((r - g) / delta + 4))[idx]

        # Saturation calculation
        saturation = np.zeros_like(max_rgb)
        saturation[mask] = delta[mask] / max_rgb[mask]

        # Handle the edge case where max_rgb is 0 (black pixels)
        saturation[max_rgb == 0] = 0

        # Value calculation
        value = max_rgb

        # Stack the HSV components together
        hsv = np.stack((hue, saturation, value), axis=-1)
    return hsv


def hsv_to_rgb(hsv):
    # Ensure the input is a float numpy array and in the range [0, 1]
    hsv = np.asarray(hsv)

    # Separate the H, S, V channels
    h, s, v = hsv[..., 0], hsv[..., 1], hsv[..., 2]

    # Chromaticity component
    c = v * s
    x = c * (1 - np.abs((h / 60) % 2 - 1))
    m = v - c

    # Initialize RGB
    r, g, b = np.zeros_like(h), np.zeros_like(h), np.zeros_like(h)

    # Compute the RGB components based on the hue range
    h0_60 = (h >= 0) & (h < 60)
    r[h0_60], g[h0_60], b[h0_60] = c[h0_60], x[h0_60], 0

    h60_120 = (h >= 60) & (h < 120)
    r[h60_120], g[h60_120], b[h60_120] = x[h60_120], c[h60_120], 0

    h120_180 = (h >= 120) & (h < 180)
    r[h120_180], g[h120_180], b[h120_180] = 0, c[h120_180], x[h120_180]

    h180_240 = (h >= 180) & (h < 240)
    r[h180_240], g[h180_240], b[h180_240] = 0, x[h180_240], c[h180_240]

    h240_300 = (h >= 240) & (h < 300)
    r[h240_300], g[h240_300], b[h240_300] = x[h240_300], 0, c[h240_300]

    h300_360 = (h >= 300) & (h < 360)
    r[h300_360], g[h300_360], b[h300_360] = c[h300_360], 0, x[h300_360]

    # Add m to each component and stack them together
    rgb = np.stack((r + m, g + m, b + m), axis=-1)

    return rgb


def test_conversion():
    # RGB array example (range [0, 1])
    rgb = np.array([[[0.5, 0.4, 0.7], [0.1, 0.2, 0.3]],
                    [[0.8, 0.7, 0.6], [0.9, 0.1, 0.2]]])
    # rgb = np.random.rand(1000, 100, 3)
    # Convert RGB to HSV
    hsv = rgb_to_hsv(rgb)
    print(hsv.shape)

    # Convert HSV back to RGB
    rgb_back = hsv_to_rgb(hsv)
    assert np.allclose(rgb, rgb_back), "Conversion failed!"


if __name__ == "__main__":
    test_conversion()