-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathcap_key_frames.py
83 lines (67 loc) · 3.21 KB
/
cap_key_frames.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"""Select and extract key frames in a video file.
Key frames are defined as a set of frames where each has an appropriate number
of matching points with its adjacent key frame.
RANSAC is applied to reduce the number of mismatched points and outliers.
"""
import cv2
import numpy as np
import argparse
def main(videofile):
# Construct VideoCapture object to get frame-by-frame stream
vid_cap = cv2.VideoCapture(videofile)
# SIFT descriptors are utilized to describe the overlapping between the
# current frame and its neighbor
sift = cv2.xfeatures2d.SIFT_create()
# The first key frame (frame0.jpg) is selected by default
success, last = vid_cap.read()
cv2.imwrite('key_frames/frame0.jpg', last)
print("Captured frame0.jpg")
count = 1
frame_num = 1
w = int(last.shape[1] * 2 / 3) # the region to detect matching points
stride = 40 # stride for accelerating capturing
min_match_num = 100 # minimum number of matches required (to stitch well)
max_match_num = 600 # maximum number of matches (to avoid redundant frames)
while success:
if count % stride == 0:
# Detect and compute key points and descriptors
kp1, des1 = sift.detectAndCompute(last[:, -w:], None)
kp2, des2 = sift.detectAndCompute(image[:, :w], None)
# Use the Brute-Force matcher to obtain matches
bf = cv2.BFMatcher(normType=cv2.NORM_L2) # Using Euclidean distance
matches = bf.knnMatch(des1, des2, k=2)
# Define Valid Match: whose distance is less than match_ratio times
# the distance of the second best nearest neighbor.
match_ratio = 0.6
# Pick up valid matches
valid_matches = []
for m1, m2 in matches:
if m1.distance < match_ratio * m2.distance:
valid_matches.append(m1)
# At least 4 points are needed to compute Homography
if len(valid_matches) > 4:
img1_pts = []
img2_pts = []
for match in valid_matches:
img1_pts.append(kp1[match.queryIdx].pt)
img2_pts.append(kp2[match.trainIdx].pt)
# Formalize as matrices (for the sake of computing Homography)
img1_pts = np.float32(img1_pts).reshape(-1, 1, 2)
img2_pts = np.float32(img2_pts).reshape(-1, 1, 2)
# Compute the Homography matrix
_, mask = cv2.findHomography(img1_pts, img2_pts,
cv2.RANSAC, 5.0)
if min_match_num < np.count_nonzero(mask) < max_match_num:
# Save key frame as JPG file
last = image
print("Captured frame{}.jpg".format(frame_num))
cv2.imwrite('key_frames/frame%d.jpg' % frame_num, last)
frame_num += 1
success, image = vid_cap.read()
count += 1
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?', default='360video.mp4',
help="path of the video file (default: 360video.mp4)")
args = parser.parse_args()
main(args.file)