Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shifting HSV pixel values in python using Numpy

I'm trying to convert (shift) the values of every pixel in an HSV image (taken from a frame of a video).

The idea is to invert yellow and red colours into blue colour (to avoid using three threshold later in the program, when I can use just one) by inverting the red and yellow values into blue values using following equation.

(Hue + 90) % 180 (in OpenCV 3 Hue is in range [0,180])

Here's what I came up with:

hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV);
H = hsv[:,:,0]
mask= [H<75 and H>128]
print("orig",hsv[mask])
hsv[mask] = ((hsv[mask]+90) % 180)

Unfortunately It doesn't work as by this approach Im selecting the whole hue channel not its pixel values

like image 722
GodIsAnAstronaut Avatar asked Jun 21 '26 08:06

GodIsAnAstronaut


2 Answers

There's two different possibilities here, and I'm not sure which you want, but they're both trivial to implement. You can invert (reverse may be a better word) the hue rainbow, which you can just do by using 180 - hue. Or you can shift the color by 180 degrees by using (hue + 90) % 180 like you mention.

Reversing the colors:

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
rev_h = 180 - h
rev_hsv = cv2.merge([rev_h, s, v])
rev_img = cv2.cvtColor(rev_hsv, cv2.COLOR_HSV2BGR)

Shifting the colors:

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
shift_h = (h + 90) % 180
shift_hsv = cv2.merge([shift_h, s, v])
shift_img = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2BGR)

Those are the idiomatic ways to do it in OpenCV.

Now you want to do the same thing as above but only for some masked subset of pixels that meet a condition. This is not too hard to do; if you want to shift some masked pixels:

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
h_mask = (h < 75) | (h > 128)
h[h_mask] = (h[h_mask] + 90) % 180
shift_hsv = cv2.merge([h, s, v])
shift_img = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2BGR)
like image 93
alkasm Avatar answered Jun 24 '26 08:06

alkasm


Hue channel is uint8 type, value range is [0, 179]. Therefore, when add with a large number or a negative number, Python returns a garbage number. Here is my solution base on @alkasm color shifting code:

img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
shift_h = random.randint(-50, 50)
h = ((h.astype('int16') + shift_h) % 180).astype('uint8')
shift_hsv = cv2.merge([h, s, v])

For random hue, saturation, and value shifting. Shift channel base on @bill-grates:

def shift_channel(c, amount):
   if amount > 0:
        lim = 255 - amount
        c[c >= lim] = 255
        c[c < lim] += amount
    elif amount < 0:
        amount = -amount
        lim = amount
        c[c <= lim] = 0
        c[c > lim] -= amount
    return c

rand_h, rand_s, rand_v = 50, 50, 50
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
# Random shift hue
shift_h = random.randint(-rand_h, rand_h)
h = ((h.astype('int16') + shift_h) % 180).astype('uint8')
# Random shift saturation
shift_s = random.randint(-rand_s, rand_s)
s = shift_channel(s, shift_s)
# Random shift value
shift_v = random.randint(-rand_v, rand_v)
v = shift_channel(v, shift_v)
shift_hsv = cv2.merge([h, s, v])
print(shift_h, shift_s, shift_v)
img_rgb = cv2.cvtColor(shift_hsv, cv2.COLOR_HSV2RGB)
like image 29
Phan Van Hoai Duc Avatar answered Jun 24 '26 08:06

Phan Van Hoai Duc



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!