Balzer82
Balzer82

Reputation: 1009

Overlay a graph over a Video

Is there a solution to open a mp4 and overlay a graph (Matplotlib) or something like this?

Something like this

Upvotes: 7

Views: 13834

Answers (2)

abggcv
abggcv

Reputation: 461

I find the python script in this blog as a good alternate way of drawing graph using OpenCV without using matplotlib which would be slow as mentioned by tylerjw in the comments for the answer by Ed Smith

I have made modifications from my side in the Graph class defined in the script provided in the blog by aligning x-axis with frame-count and using cv2.line() instead of filling numpy array with white color:

class Graph:
    def __init__(self, width, height):
        self.height = height
        self.width = width
        self.graph = np.zeros((height, width, 3), np.uint8)
        self.x = 0
        self.y = 0
    def update_frame(self, value, frame_count):
        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:,:]

        # cv2.line(self.graph, (self.y, self.x), (value, frame_count//1000), (0, 0, 255))
    cv2.line(new_graph, (self.x, self.y), (frame_count//10, value), (0, 0, 255))

    self.x = frame_count // 10
    self.y = value

    # new_graph[self.height - value:self.height - value + 5,-1,:2] = 0
    # new_graph[self.height - value:self.height - value + 5,-1,2] = 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)
frame_count = 0
while True:
    # Capture frame-by-frame
    ret, frame = cap.read()
    if not ret:
        break
    frame_count += 1
    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), frame_count)
    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, (0, 200, 200), 2)
    cv2.putText(frame, "...measures motion in frame", (20, 460), cv2.FONT_HERSHEY_PLAIN, 1.8, (0, 200, 200), 2)
    cv2.imshow("Webcam", frame)
    if cv2.waitKey(1) == ord('q'):
        break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

Upvotes: 0

Ed Smith
Ed Smith

Reputation: 13206

You can obtain the frames from the video using openCV, as in this example, and plot a graph over the top with matplotlib, e.g.

import cv2
import matplotlib.pyplot as plt
import numpy as np

filename = './SampleVideo.mp4'
cap = cv2.VideoCapture(filename)

try:
    frames = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))
    width  = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT))
except AttributeError:
    frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    width  = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

fig, ax = plt.subplots(1,1)
plt.ion()
plt.show()

#Setup a dummy path
x = np.linspace(0,width,frames)
y = x/2. + 100*np.sin(2.*np.pi*x/1200)

for i in range(frames):
    fig.clf()
    flag, frame = cap.read()

    plt.imshow(frame)
    plt.plot(x,y,'k-', lw=2)
    plt.plot(x[i],y[i],'or')
    plt.pause(0.01)

    if cv2.waitKey(1) == 27:
        break
    

I got the video from here.

Upvotes: 4

Related Questions