Home > Enterprise >  Hue cycling effect on webcam footage with Python
Hue cycling effect on webcam footage with Python

Time:01-10

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()

CodePudding user response:

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()

CodePudding user response:

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.

  • Related