Project 8
This code is written based on learnings in week 8 of CompVision
for concept explanation "Opencv24-python-tutorial" is referred
the code below shi tomasi corner detector and Lucas Kanade optical flow model
- The shi-tomasi corner detector is modified version of Haris corner detector Haris corner detector uses: R = lambda_1*lambda_2 - k(lambda_1+lambda_2)^2 where as shi-tomasi model uses R = min(lamda_1,lamda_2), in case of shi tomasi model if lambda_1 and lamda_2 is greater than lamda_min then it is considered as corner
import cv2
import numpy as np
- finds N strongest corners in the image by Shi-Tomasi method
- the image should be a grayscale image
- specify number of corners we want to find
- specify the quality level, which is a value between 0-1, this denotes the minimum quality of corner below which neuron is rejected.
- Then we provide the minimum euclidean distance between corners detected.
- the function finds corners in the image. All corners below quality level are rejected.
- Then it sorts the remaining corners based on quality in the descending order.
# tracking feature. identifying corner detector through shi-tomasi corner detector method
def find_features(gray_image):
# extract the features information from the gray image using shi tomasi corner detector method
points = cv2.goodFeaturesToTrack(gray_image,mask=None,maxCorners=100,qualityLevel=0.1,minDistance=10,blockSize=5)
return points
-
Optical flow is the pattern of apparent motion of image objects between two consecutive frames caused by the movemement of object or camera.
-
It is 2D vector field where each vector is a displacement vector showing the movement of points from first frame to second
-
Optical flow works on several assumptions: a. The pixel intensities of an object do not change between consecutive frames. b. Neighbouring pixels have similar motion.
-
the Lucas–Kanade method is a widely used differential method for optical flow estimation
-
in python we use cv2.calcOpticalFlowPyrLK(): to this function we pass the previous frame, previous points and next frame. It returns next points along with some status numbers which has a value of 1 if next point is found, else zero. We iteratively pass these next points as previous points in next step
# Lucas Kanade sparse optical flow model
def lk_model(gray_t_1,gray_t,prevpoints):
#win_size = (10,10)
#max_level = 2
#criteria = (cv2.TERM_CRITERIA_EPS|cv2.TERM_CRITERIA_COUNT,10,0.03)
points,status,error = cv2.calcOpticalFlowPyrLK(gray_t_1,gray_t,prevpoints,None,winSize=(10,10),maxLevel=2,criteria=(cv2.TERM_CRITERIA_EPS|cv2.TERM_CRITERIA_COUNT,10,0.03))
return (points,status,error)
myvideo = cv2.VideoCapture('traffic.mp4') # read the video
color = np.random.randint(0,255,(100,3)) # extract the colours to draw the optical flow lines
# extract the status and first frame that will be treated as the previous frame(t-1)th frame
ret_status,prev_frame = myvideo.read()
prev_gray = cv2.cvtColor(prev_frame,cv2.COLOR_BGR2GRAY) # convert the color image to gray image
prev_points = find_features(prev_gray) # find the feature like corners
mask_image = np.zeros_like(prev_frame) # create a mask image with all zeros
## Video writing
# grab the width, height, and fps of the frames in the video stream.
frame_width = int(myvideo.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(myvideo.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(myvideo.get(cv2.CAP_PROP_FPS))
# initialize the FourCC and a video writer object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
output = cv2.VideoWriter('output.mp4', fourcc, fps, (frame_width, frame_height))
# reading further frames
while(1):
ret,frame = myvideo.read() # read the next frame from video
cur_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) # converted the extracted frome from color to gray
# use Lucas Kanade model to find current features and their status
cur_points,status,error = lk_model(prev_gray,cur_gray,prev_points)
if cur_points is not None: # confirm the frame exists
cur_points = cur_points[status==1] # consider all the current feature whose status is 1
old_points = prev_points[status==1]# consider all the current feature whose status is 1
for i, (current,prev) in enumerate(zip(cur_points,old_points)):
a,b = current.ravel() # extract the features in form of 1-D array
c,d = prev.ravel()
mask_image = cv2.line(mask_image,(int(a),int(b)),(int(c),int(d)),color[i].tolist(),2)
frame = cv2.circle(frame,(int(a),int(b)),5,color[i].tolist(),-1)
img = cv2.add(frame,mask_image) # overlay the optical flow over the video
#img = frame
# display image
cv2.imshow('frame',img) # display overlayed video frame by frame
#cv2.imshow('masked image', mask_image)
#cv2.imwrite('myframe.jpg',frame)
k = cv2.waitKey(5)
if k==27:
#cv2.destroyAllWindows()
break
# Set the current frame as (t-1)th frame and update the current point as prev point
prev_gray = cur_gray.copy()
prev_points = cur_points.reshape(-1,1,2)
output.write(img)
cv2.destroyAllWindows()
cap.release()