Challenge

Project 8

Optical Flow is a method to estimate the apparent flow of scene points from a sequence of images taken in quick succession.

Lucas Kanade Optical Flow method assumes flow is locally smooth and Neighboring pixels have same displacement. Optical flow is estimated by solving optical flow equations for all the pixels in the neighborhood using Least Squares method.


Procedure:

1) A video capture object is created using cv2.VideoCapture()

2) The first frame is then read using capture.read() 

Lucas Kanade is a sparse optical flow method which estimates the flow for the selected set of interest points. The interest points is selected using Shi-Thomasi feature detector. cv2.goodFeaturesToTrack() is used to find the feature points using Shi-Thomasi feature detector.

3) The feature points for the first frame is detected using the Shi-Thomasi detector. find_features() detects the keypoints using cv2.goodFeaturesToTrack().

4) While loop is initiated to read and perform operations on successive frames of the video

5) From the previous frame image, current frame image and detected keypoints the Lucas Kanade optical flow is computed for the first sequence in the video

6) Similarly for each further sequences the optical flow is computed

7) For each optical flow computed a line is drawn using cv2.line() and detected points in each frame are marked using cv2.circle()

8) The line and circle drawn are then added to the original frames

9) The output is displayed using cv.imshow()

10) Also the output is appended to a list to covert it to a video

10) After iterating through all the frames the while loop is terminated

11) Finally the output frames are written into a video using cv2.VideoWriter() and writing by appending through each output frame

Code:

# Import the required libraries
import cv2
import numpy as np

# cv2.goodFeaturesToTrack is used find the features using Shi-Tomasi corner detector algorithm 
def find_features(gray_image):
    # gray_image - Input image in which features has to be detected
    # maxCorners - If there are more than 100 corners detected, then only strongest 100 is returned
    # qualityLevel - To determine the minimum accepted quality of a corner
    # minDistance - Minimum distance between two corners
    # points - Returns the feature points using Shi-Thomasi corner detection algorithm
    points = cv2.goodFeaturesToTrack(gray_image,mask = None, maxCorners = 100,qualityLevel = 0.2,minDistance = 10,blockSize = 7)
    return points

# Preforms Lukas Kanade Optical flow
def LK_model(gray_t_1,gray_t,prev_points):
    # gray_t_1 - Previous frame image in gray scale
    # gray_t - Current frame image in gray scale
    # winSize - Size of search window
    # maxLevel - Maximum pyramid level. Since set to 2, three levels of pyramid are used
    # criteria - Termination criteria for algorithm when max number of iterations is reached or search window moves less than criteria
    # The function returns the next points, status whether correspondance is found and the error
    points,status,error = cv2.calcOpticalFlowPyrLK(gray_t_1,gray_t,prev_points,None,winSize = (20,20),maxLevel=2,criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.04))
    return (points,status,error)

capture = cv2.VideoCapture("traffic.mp4")       # Creating a video capture object
color = np.random.randint(0,255,(100,3))       # Creating a list of 100 BGR value to draw lines for each feature 
ret,prev_frame = capture.read()                # Reads the video 
# ret - Boolean value; True if frame is detected and read
# prev_frame - frame read in BGR format
prev_gray= cv2.cvtColor(prev_frame,cv2.COLOR_BGR2GRAY)        # Initialize the first frame to prev_gray in gray scale
prev_points = find_features(prev_gray)         # Find the features (keypoints) in the frame         
mask_image = np.zeros_like(prev_frame)         # Intialize a mask image with zeroes of size prev_frame
output_frames = []

while(True):
    ret,frame = capture.read()   # Reads the video 
    # ret - Boolean value; True if frame is detected and read
    # frame - frame read in BGR format              

    if not ret:
        break         # If no frame is detected the while loop is terminated
    
    current_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)         # Converting the current frame to gray scale
    current_points,status,error = LK_model(prev_gray,current_gray,prev_points)    # Previous frame, current frame and previous detected points are passed
    # LK_model returns the current points,status whether corresponding feature is found and error
    
    if current_points is not None: 
        current_points = current_points[status ==1]                 # Storing only the points with status as 1 (points for which corresponding feature is found)
        old_points = prev_points[status==1]
        
    for i, (current,prev) in enumerate(zip(current_points,old_points)):    # Iterating through each point
        a,b = current.ravel()
        c,d = prev.ravel()
        mask_image = cv2.line(mask_image,(int(a),int(b)),(int(c),int(d)),color[i].tolist(),2)   # Draws a line between previous point and current point each in different color
        frame = cv2.circle(frame,(int(a),int(b)),5,color[i].tolist(),-1)  # Draw a circle for each current point
    
    img = cv2.add(frame,mask_image)       # Adding the frame and mask_image to dispay the lines on the video itself
    
    cv2.imshow('frame',img)              # Displaying each output frame
    output_frames.append(img)        # Storing all the output frames in a array
    # To close the video if esc is pressed
    k = cv2.waitKey(5)
    if k ==27:             
        break
    
    prev_gray = current_gray.copy()       # Current frame is copied to prev_gray
    prev_points = current_points.reshape(-1,1,2)        # Current points is stored in prev_points
    
capture.release()                 #Release the capture object

cv2.destroyAllWindows()           # Close all the windows

height,width,_ = img.shape         # Get the height and width of image
size = (width,height)              # Store the width, height as tuple

# Creating object for Writing the video
output = cv2.VideoWriter('Output_Opticalflow.mp4',cv2.VideoWriter_fourcc('F','M','P','4'), 30, size)

# Writing the video by iterating through each frame
for image in output_frames:
    output.write(image)

Output:

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.