OpenCV + Python + Webcam: Create a Ghost Effect

What will we cover in this tutorial?

A ghost effect is when multiple images are combined into one image. In this tutorial we will see how this effect can be made effectively and easy. We will make it with a trackbar, so the effect can be adjusted.

Step 1: Understand how to create the ghost effect

We will start simple with only two images. Consider the following two images, which has the same background.

They can be combined using the OpenCV library, as the following code shows.

import cv2


img1 = cv2.imread("image1.png")
img2 = cv2.imread("image2.png")

img3 = cv2.addWeighted(src1=img1, alpha=0.5, src2=img2, beta=0.5, gamma=0.0)

cv2.imwrite("image3.png", img3)

The cv2.imread(…) reads the images into the variables img1 and img2, where the above two images are named image1.png and image2.png, respectively.

Then the cv2.addWeighted(…) is where the magic happens. The src1 and src2 parameters take each an image, while the alpha and beta determines how much weight each image should have. Here we have chose 50% (0.5) each. It is a good rule to let it add up to 100% (1.0).

Hence, the resulting image will be a 50% weighted and composed of the two input images. The result can be seen here.

The function cv2.addWeighted(…) can be used to create a ghost effect in a live stream from a webcam.

Step 2: Understanding the webcam stream

To understand how a processing flow from webcam works it is easiest to illustrate it by some simple code. If you are new to OpenCV and need it installed, please read this tutorial.

import cv2


# Capture the webcam
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# Pre-preprocessing should be done here 

while True:
    # Capture the frame from the webcam
    _, frame = cap.read()

    # Processing should be done here

    # Show the frame to a window
    cv2.imshow("Webcam", frame)

    # Check if q is pressed, terminate if so
    if cv2.waitKey(1) == ord('q'):
        break

# Release the webcam and destroy windows
cap.release()
cv2.destroyAllWindows()

The above code shows how a simple flow of capturing a frame from the webcam and showing it in a windows works. It is important to notice, that each image (or frame) from the webcam is handled individually.

This is handy, if we want to process it.

Step 3: Adding a ghost effect in the processing pipeline

We know from Step 1 how to make simple ghost effect with two images. If we use that simple way, we can actually do it frame-by-frame by saving the old frame. This also makes the effect to last more than one frame back.

import cv2


# Capture the webcam
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# Pre-preprocessing should be done here
_, last_frame = cap.read()
while True:
    # Capture the frame from the webcam
    _, frame = cap.read()

    # Processing
    if frame.shape == last_frame.shape:
        frame = cv2.addWeighted(src1=frame, alpha=0.5, src2=last_frame, beta=0.5, gamma=0.0)

    # Show the frame to a window
    cv2.imshow("Webcam", frame)

    # Update last_frame
    last_frame = frame

    # Check if q is pressed, terminate if so
    if cv2.waitKey(1) == ord('q'):
        break

# Release the webcam and destroy windows
cap.release()
cv2.destroyAllWindows()

That creates a simple ghost effect. While it is not very strong, you can change the values of alpha and beta.

But we can actually add a trackbar in order to change the value.

Step 4: Adding a trackbar to the window

This is just an add on to the above that will enable you to change the shadow effect while you stream your webcam. To add a trackbar we need a few things. First we need a variable that will be accessed anywhere in the code to keep the state of the ghost effect (ghost_effect). Also, we need a named window (cv2.namedWindow(…)) to access the same window to setup the trackbar in the window we stream in from the webcam.

Then we have the callback function on_ghost_trackbar(val) to update the value, both int he named window and the global variable ghost_effect. Then the call to cv2.createTrackbar(…) will set the callback function to on_ghost_trackbar. This will ensure that on any update (every time you move the trackbar) the function on_ghost_trackbar is called with the new value, where you update the ghost_effect variable, which is used to update the ghost effect in the cv2.addWeighted(…) call.

import cv2

# A global variable with the ghost effect
ghost_effect = 0.0
# Setup a window that can be referenced
window = "Webcam"
cv2.namedWindow(window)


# Used by the trackbar to change the ghost effect
def on_ghost_trackbar(val):
    global ghost_effect
    global window

    ghost_effect = val / 100.0
    cv2.setTrackbarPos("Shadow", window, val)


# Capture the webcam
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# Create a trackbar
cv2.createTrackbar("Ghost effect", window, 0, 100, on_ghost_trackbar)


# Get the first frame
_, last_frame = cap.read()
while True:
    # Get the next frame
    _, frame = cap.read()

    # Add the ghost effect
    if frame.shape == last_frame.shape:
        frame = cv2.addWeighted(src1=frame, alpha=1 - ghost_effect, src2=last_frame, beta=ghost_effect, gamma=0.0)

    # Update the frame in the window
    cv2.imshow(window, frame)
    
    # Update last_frame
    last_frame = frame

    # Check if q is pressed, terminate if so
    if cv2.waitKey(1) == ord('q'):
        break

# Release the webcam and destroy windows
cap.release()
cv2.destroyAllWindows()

While the code becomes a bit more complex to add the trackbar to the window in the GUI, it has the same functionality.

Step 5: Test the ghost effect

Now we just need to test it to see if we got the desired effect.

Have fun and play with that.

Leave a Reply