What will we cover in this tutorial?
How to make a simple live graph that updates into a live webcam stream by using OpenCV.
The result can be seen in the video below.
Step 1: A basic webcam flow with OpenCV
If you need to install OpenCV for the first time we suggest you read this tutorial.
A normal webcam flow in Python looks like the following code.
import cv2 # Setup webcam camera cap = cv2.VideoCapture(0) # Set a smaller resolution cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: # Capture frame-by-frame _, frame = cap.read() frame = cv2.flip(frame, 1) cv2.imshow("Webcam", frame) if cv2.waitKey(1) == ord('q'): break # When everything done, release the capture cap.release() cv2.destroyAllWindows()
This will make a live webcam stream from your webcam to a window. That is too easy not to enjoy.
Step 2: Create an object to represent the graph
There are many ways to create a graph. Here we will make an object which will have a representation of the graph. Then it will have a function to update the value and update the graph image.
class Graph: def __init__(self, width, height): self.height = height self.width = width self.graph = np.zeros((height, width, 3), np.uint8) def update_frame(self, value): if value < 0: value = 0 elif value >= self.height: value = self.height - 1 new_graph = np.zeros((self.height, self.width, 3), np.uint8) new_graph[:,:-1,:] = self.graph[:,1:,:] new_graph[self.height - value:,-1,:] = 255 self.graph = new_graph def get_graph(self): return self.graph
This object is a simple object that keeps the graph as a OpenCV image (Numpy array).
The update function first verifies that the value of inside the graph size.
Then it creates a a new graph (new_graph) and copies the old values from previous graph, but shifted one position. Then it will update the new value by white color.
Step 3: Putting it all together
The Graph object created in last step needs a value. This value can be anything. Here we make a simple measure of how much movement is in the frame.
This is simply done by comparing the current frame with the previous frame. This could be done straight forward, but to minimize noise we use a gray scaled images, which we use Gaussian blur on. Then the absolute difference from last frame is used, and summing it up.
The value used to scale down is highly dependent on the settings your webcam is in. Also, if you use another resolution, then it will affect it. Hence, if the graph is all low (zero) or high (above height) then adjust this graph.update_frame(int(difference/42111)) to some other integer value in the division.
import cv2 import numpy as np class Graph: def __init__(self, width, height): self.height = height self.width = width self.graph = np.zeros((height, width, 3), np.uint8) def update_frame(self, value): if value < 0: value = 0 elif value >= self.height: value = self.height - 1 new_graph = np.zeros((self.height, self.width, 3), np.uint8) new_graph[:,:-1,:] = self.graph[:,1:,:] new_graph[self.height - value:,-1,:] = 255 self.graph = new_graph def get_graph(self): return self.graph # Setup camera cap = cv2.VideoCapture(0) # Set a smaller resolution cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) graph = Graph(100, 60) prev_frame = np.zeros((480, 640), np.uint8) while True: # Capture frame-by-frame _, frame = cap.read() frame = cv2.flip(frame, 1) frame = cv2.resize(frame, (640, 480)) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (25, 25), None) diff = cv2.absdiff(prev_frame, gray) difference = np.sum(diff) prev_frame = gray graph.update_frame(int(difference/42111)) roi = frame[-70:-10, -110:-10,:] roi[:] = graph.get_graph() cv2.putText(frame, "...wanted a live graph", (20, 430), cv2.FONT_HERSHEY_PLAIN, 1.8, (200, 200, 200), 2) cv2.putText(frame, "...measures motion in frame", (20, 460), cv2.FONT_HERSHEY_PLAIN, 1.8, (200, 200, 200), 2) cv2.imshow("Webcam", frame) if cv2.waitKey(1) == ord('q'): break # When everything done, release the capture cap.release() cv2.destroyAllWindows()