-
Notifications
You must be signed in to change notification settings - Fork 13
/
video_stabilization.py
159 lines (115 loc) · 4.05 KB
/
video_stabilization.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# source learnopencv.com
import numpy as np
import cv2
SMOOTHING_RADIUS=50
def movingAverage(curve, radius):
window_size = 2 * radius + 1
# Define the filter
f = np.ones(window_size)/window_size
# Add padding to the boundaries
curve_pad = np.lib.pad(curve, (radius, radius), 'edge')
# Apply convolution
curve_smoothed = np.convolve(curve_pad, f, mode='same')
# Remove padding
curve_smoothed = curve_smoothed[radius:-radius]
# return smoothed curve
return curve_smoothed
def smooth(trajectory):
smoothed_trajectory = np.copy(trajectory)
# Filter the x, y and angle curves
for i in range(3):
smoothed_trajectory[:,i] = movingAverage(trajectory[:,i], radius=SMOOTHING_RADIUS)
return smoothed_trajectory
def fixBorder(frame):
s = frame.shape
# Scale the image 4% without moving the center
T = cv2.getRotationMatrix2D((s[1]/2, s[0]/2), 0, 1.04)
frame = cv2.warpAffine(frame, T, (s[1], s[0]))
return frame
# Read input video
cp = cv2.VideoCapture('path to video file.mp4')
# To get number of frames
n_frames = int(cp.get(cv2.CAP_PROP_FRAME_COUNT))
# To check the number of frames in the video
print(n_frames)
width = int(cp.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cp.get(cv2.CAP_PROP_FRAME_HEIGHT))
print("height", width)
print("height", height)
# get the number of frames per second
fps = cp.get(cv2.CAP_PROP_FPS)
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
print(fourcc)
# Try doing 2*width
out = cv2.VideoWriter('video_out.mp4',0x7634706d, fps, (width, height))
# read the first frame
_, prev = cp.read()
prev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)
transforms = np.zeros((n_frames-1, 3), np.float32)
for i in range(n_frames-2):
prev_pts = cv2.goodFeaturesToTrack(prev_gray, maxCorners=200, qualityLevel=0.01, minDistance=30, blockSize=3)
succ, curr = cp.read()
if not succ:
break
curr_gray = cv2.cvtColor(curr, cv2.COLOR_BGR2GRAY)
# Track feature points
# status = 1. if flow points are found
# err if flow was not find the error is not defined
# curr_pts = calculated new positions of input features in the second image
curr_pts, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, curr_gray, prev_pts, None)
idx = np.where(status==1)[0]
prev_pts = prev_pts[idx]
curr_pts = curr_pts[idx]
assert prev_pts.shape == curr_pts.shape
# fullAffine= FAlse will set the degree of freedom to only 5 i.e translation, rotation and scaling
# try fullAffine = True
m = cv2.estimateRigidTransform(prev_pts, curr_pts, fullAffine=False)
dx = m[0,2]
dy = m[1,2]
# Extract rotation angle
da = np.arctan2(m[1,0], m[0,0])
transforms[i] = [dx,dy,da]
prev_gray = curr_gray
#print("Frame: " + str(i) + "/" + str(n_frames) + " - Tracked points : " + str(len(prev_pts)))
# Find the cumulative sum of tranform matrix for each dx,dy and da
trajectory = np.cumsum(transforms, axis=0)
smoothed_trajectory = smooth(trajectory)
difference = smoothed_trajectory - trajectory
transforms_smooth = transforms + difference
# Reset stream to first frame
cp.set(cv2.CAP_PROP_POS_FRAMES, 0)
# Write n_frames-1 transformed frames
for i in range(n_frames-2):
# Read next frame
success, frame = cp.read()
if not success:
break
# Extract transformations from the new transformation array
dx = transforms_smooth[i,0]
dy = transforms_smooth[i,1]
da = transforms_smooth[i,2]
# Reconstruct transformation matrix accordingly to new values
m = np.zeros((2,3), np.float32)
m[0,0] = np.cos(da)
m[0,1] = -np.sin(da)
m[1,0] = np.sin(da)
m[1,1] = np.cos(da)
m[0,2] = dx
m[1,2] = dy
# Apply affine wrapping to the given frame
frame_stabilized = cv2.warpAffine(frame, m, (width,height))
# Fix border artifacts
frame_stabilized = fixBorder(frame_stabilized)
# Write the frame to the file
frame_out = cv2.hconcat([frame, frame_stabilized])
# If the image is too big, resize it.
if(frame_out.shape[1] > 1920):
frame_out = cv2.resize(frame_out, (frame_out.shape[1]/2, frame_out.shape[0]/2));
cv2.imshow("Before and After", frame_out)
cv2.waitKey(10)
out.write(frame_out)
# Release video
cp.release()
out.release()
# Close windows
cv2.destroyAllWindows()