OpenCV is a popular and powerful computer vision library for Python. It allows the user to efficiently computation intensive task on images and videos, including live webcam feed. By default, OpenCV displays images in its own independent window. However, it is often more practical to visualize results directly in the notebook. Here, I'll demonstrate how to display the webcam feed in the notebook and how to setup Ipywidgets to interact with the feed.

Setup

Let's start by importing the necessary libraries

import matplotlib.pyplot as plt
import cv2
import numpy as np
from IPython.display import display, Image
import ipywidgets as widgets
import threading

Display the webcam in OpenCV's own window

To start, here's the standard way of display the webcam feed with OpenCV.

cap = cv2.VideoCapture(0)
cap.set(3,640) # adjust width
cap.set(4,480) # adjust height

while True:
    success, img = cap.read()
    cv2.imshow("Webcam", img) # This will open an independent window
    if cv2.waitKey(1) & 0xFF==ord('q'): # quit when 'q' is pressed
        cap.release()
        break
        
cv2.destroyAllWindows() 
cv2.waitKey(1) # normally unnecessary, but it fixes a bug on MacOS where the window doesn't close

Display the webcam inside the notebook

Here I combine the display code proposed here with an Ipywidget button. Since the feed is updated inside a loop, the button is not updated by default, which renders it inactive. To fix that I use the asynchronous widget update described here. Now, when clicked the button will stop the feed and remove the output. Note that the code reference your own webcam so it won't work on Google Colab.

# ================
stopButton = widgets.ToggleButton(
    value=False,
    description='Stop',
    disabled=False,
    button_style='danger', # 'success', 'info', 'warning', 'danger' or ''
    tooltip='Description',
    icon='square' # (FontAwesome names without the `fa-` prefix)
)


# Display function
# ================
def view(button):
    cap = cv2.VideoCapture(0)
    display_handle=display(None, display_id=True)
    i = 0
    while True:
        _, frame = cap.read()
        frame = cv2.flip(frame, 1) # if your camera reverses your image
        _, frame = cv2.imencode('.jpeg', frame)
        display_handle.update(Image(data=frame.tobytes()))
        if stopButton.value==True:
            cap.release()
            display_handle.update(None)

            
# Run
# ================
display(stopButton)
thread = threading.Thread(target=view, args=(stopButton,))
thread.start()

Et voilà! The output looks like this

webcam capture
hmmmm.... What an insightful blogpost