Miles Jarra Gloekler
Miles Jarra Gloekler

Reputation: 33

Hue cycling effect on webcam footage with Python

I am trying to create a program in Python that retrieves webcam footage and applies a slow and constant change in hue, similar to a hue cycling effect. Additionally, I am wondering if it would be possible to apply the hue cycle only to the color green in the webcam footage, though I am unsure how to detect the color in the frame and apply the cycle only to that color.

I have tried playing around with this code I found, though it gets applied to the whole frame and on the output in certain spots discoloration/weird spots depending on the part of the cycle it is on.

import cv2
import numpy as np

# Initialize video capturer
cap = cv2.VideoCapture(0)

# Set frame width and height
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# Initialize angle for hue rotation
angle = 0

while True:
    # Capture frame
    ret, frame = cap.read()

    # Convert frame to HSV color space
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    # Split channels
    h, s, v = cv2.split(hsv)

    # Increment angle
    angle = (angle + 1) % 360

    # Rotate hue channel
    h = (h + angle) % 180

    # Merge channels back to HSV image
    hsv = cv2.merge((h, s, v))

    # Convert back to BGR color space
    result = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

    # Display frame
    cv2.imshow("Webcam", result)

    # Check for user input
    key = cv2.waitKey(1)
    if key == 27: # Esc key
        break

# Release video capturer
cap.release()

# Close all windows
cv2.destroyAllWindows()

Upvotes: 2

Views: 113

Answers (2)

Rotem
Rotem

Reputation: 32124

There is an issue with the expression h = (h + angle) % 180.

h type is uint8, and the range of uint8 elements is [0, 255].
The valid range of hue in OpenCV is [0, 180].
When angle > 75, the expression h + angle may result numerical overflow.

For preventing the overflow we may cast to uint16, add the angle, and cast back to uint8 after applying the modulo.

Replace h = (h + angle) % 180 with:

h = ((h.astype(np.uint16) + angle) % 180).astype(np.uint8)

For testing I used an image instead of using a Webcam - it makes the solution more reproducible.

Code sample:

import cv2
import numpy as np

frame = cv2.imread('peppers.png')  # Read sample image

cv2.imshow("frame", frame)

# Initialize angle for hue rotation
angle = 0

for i in range(1000):
    # Convert frame to HSV color space
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    # Split channels
    h, s, v = cv2.split(hsv)

    # Increment angle
    angle = (angle + 1) % 360

    # Rotate hue channel
    #h = (h + angle) % 180
    h = ((h.astype(np.uint16) + angle) % 180).astype(np.uint8)

    # Merge channels back to HSV image
    hsv = cv2.merge((h, s, v))

    # Convert back to BGR color space
    result = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

    # Display frame    
    cv2.imshow("Webcam", result)
    cv2.waitKey(40)

cv2.destroyAllWindows()

Animated GIF:
enter image description here

Input image (used for testing):
enter image description here


About applying hue cycle only to the color green, it's not very "well defined".
We may find the green pixels, form a mask, and modify only the non-zero pixels in the mask.

The issue is that there is going to be discontinuity between the pixels that are considered green, and the surrounding pixels that are almost green.

Upvotes: 1

kalzso
kalzso

Reputation: 536

You can detect the color green in the frame using color thresholds and a mask. To detect the color green try the inRange function:

import cv2
import numpy as np

# Initialize video capturer
cap = cv2.VideoCapture(0)

# Set frame width and height
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# Initialize angle for hue rotation
angle = 0

while True:
    # Capture frame
    ret, frame = cap.read()

    # Convert frame to HSV color space
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    # Split channels
    h, s, v = cv2.split(hsv)

    # Define lower and upper bounds for green color
    lower_green = np.array([50, 50, 50])
    upper_green = np.array([70, 255, 255])

    # Create mask for green color
    mask = cv2.inRange(hsv, lower_green, upper_green)

    # Increment angle
    angle = (angle + 1) % 360

    # Rotate hue channel only for green pixels
    h[mask != 0] = (h[mask != 0] + angle) % 180

    # Merge channels back to HSV image
    hsv = cv2.merge((h, s, v))

    # Convert back to BGR color space
    result = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

    # Display frame
    cv2.imshow("Webcam", result)

    # Check for user input
    key = cv2.waitKey(1)
    if key == 27: # Esc key
        break

# Release video capturer
cap.release()

# Close all windows
cv2.destroyAllWindows()

Upvotes: 2

Related Questions