原理
1.视频图像中每帧特征提取及相邻帧特征点的偏移
2.特征点的偏移形成光流
3.平滑光流
4.图像变换并存储
详细请参阅https://blog.51cto.com/u_15457455/4806516
# -*- coding: utf-8 -*-
# author:
# date:
import cv2
import numpy as np
import cvxpy as cp
import pickle
sift = cv2.xfeatures2d.SIFT_create(200)
def getAffMat(I1, I2):
'''
提取特征并构造变换相邻帧之间对应关系
:param I1:
:param I2:
:return:
'''
I1 = cv2.cvtColor(I1, cv2.COLOR_BGR2GRAY)
I2 = cv2.cvtColor(I2, cv2.COLOR_BGR2GRAY)
kp1, desc1 = sift.detectAndCompute(I1, None)
kp2, desc2 = sift.detectAndCompute(I2, None)
bf = cv2.BFMatcher()
matches = bf.knnMatch(desc1, desc2, k=2)
good = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good.append(m)
pts_src = []
pts_dst = []
for i in range(len(good)):
pts_src.append([kp1[good[i].queryIdx].pt[0], kp1[good[i].queryIdx].pt[1]])
pts_dst.append([kp2[good[i].trainIdx].pt[0], kp2[good[i].trainIdx].pt[1]])
pts_src = np.array(pts_src).astype(np.float32)
pts_dst = np.array(pts_dst).astype(np.float32)
return cv2.estimateAffinePartial2D(pts_src, pts_dst)[0]
def pointMatching(video_path):
'''
对整条视频进行特征匹配
:param video_path:
:return:
'''
transforms = [[], [], [], []]
V = cv2.VideoCapture(video_path)
_, prev = V.read()
while V.isOpened():
res, frame = V.read()
if not res:
break
transMat = getAffMat(prev, frame)
try:
transforms[0].append(transMat[0][2])
transforms[1].append(transMat[1][2])
transforms[2].append(np.arctan2(transMat[1][0], transMat[0][0]))
transforms[3].append(np.sqrt(transMat[1][0] ** 2 + transMat[0][0] ** 2))
except:
transforms[0].append(0)
transforms[1].append(0)
transforms[2].append(0)
transforms[3].append(1)
prev = frame
pass
V.release()
return transforms
def record_stabilize(trajectory):
'''
各个方向光流偏移计算
:param trajectory:
:return:
'''
fx = cp.Variable(len(trajectory[0]))
fy = cp.Variable(len(trajectory[1]))
fth = cp.Variable(len(trajectory[2]))
fs = cp.Variable(len(trajectory[3]))
lbd1 = 10000
lbd2 = 1000
lbd3 = 100000
DispThresh = int(200)
constraints = [cp.abs(fx - trajectory[0]) <= DispThresh,
cp.abs(fy - trajectory[1]) <= DispThresh,
cp.abs(fth - trajectory[2]) <= 0.05,
cp.abs(fs - trajectory[3]) <= 0.01]
# Defining the minimization objective function
obj = 0
for i in range(len(trajectory[0])):
obj += ((trajectory[0][i] - fx[i]) ** 2 + (trajectory[1][i] - fy[i]) ** 2 + (trajectory[2][i] - fth[i]) ** 2 + (
trajectory[3][i] - fs[i]) ** 2)
# DP1
for i in range(len(trajectory[0]) - 1):
obj += lbd1 * (cp.abs(fx[i + 1] - fx[i]) + cp.abs(fy[i + 1] - fy[i]) + cp.abs(fth[i + 1] - fth[i]) + cp.abs(
fs[i + 1] - fs[i]))
# DP2
for i in range(len(trajectory[0]) - 2):
obj += lbd2 * (cp.abs(fx[i + 2] - 2 * fx[i + 1] + fx[i]) + cp.abs(fy[i + 2] - 2 * fy[i + 1] + fy[i]) + cp.abs(
fth[i + 2] - 2 * fth[i + 1] + fth[i]) + cp.abs(fs[i + 2] - 2 * fs[i + 1] + fs[i]))
# DP3
for i in range(len(trajectory[0]) - 3):
obj += lbd3 * (cp.abs(fx[i + 3] - 3 * fx[i + 2] + 3 * fx[i + 1] - fx[i]) + cp.abs(
fy[i + 3] - 3 * fy[i + 2] + 3 * fy[i + 1] - fy[i]) + cp.abs(
fth[i + 3] - 3 * fth[i + 2] + 3 * fth[i + 1] - fth[i]) + cp.abs(
fs[i + 3] - 3 * fs[i + 2] + 3 * fs[i + 1] - fs[i]))
prob = cp.Problem(cp.Minimize(obj), constraints)
prob.solve(solver=cp.ECOS)
smoothTrajectory = np.array([fx.value, fy.value, fth.value, fs.value])
return smoothTrajectory
if __name__ == '__main__':
PATH = r'.\20220525.mp4'
pointTransform = pointMatching(PATH)
trajectory = np.cumsum(pointTransform, axis=1)
smoothTrajectory = record_stabilize(trajectory)
diff = trajectory - smoothTrajectory
smoothTransforms = pointTransform - diff
v = cv2.VideoCapture(PATH)
W = int(v.get(cv2.CAP_PROP_FRAME_WIDTH))
H = int(v.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(v.get(cv2.CAP_PROP_FPS))
n_frames = int(v.get(cv2.CAP_PROP_FRAME_COUNT))
DispThresh = int(200)
DispThresh += 10
out = cv2.VideoWriter('video_out.avi', cv2.VideoWriter_fourcc(*'XVID'), fps,
(W - 2 * DispThresh, H - 2 * DispThresh))
m = np.zeros([2, 3])
for i in range(n_frames - 1):
_, frame = v.read()
# 平滑变换
m[0][0] = (smoothTransforms[3][i]) * np.cos(smoothTransforms[2][i])
m[0][1] = (smoothTransforms[3][i]) * np.sin(smoothTransforms[2][i])
m[1][0] = (smoothTransforms[3][i]) * np.sin(smoothTransforms[2][i])
m[1][1] = (smoothTransforms[3][i]) * np.cos(smoothTransforms[2][i])
m[0][2] = smoothTransforms[0][i]
m[1][2] = smoothTransforms[1][i]
# 写入视频
stable = cv2.warpAffine(frame, m, (W, H))
boxPart = stable[DispThresh:H - DispThresh, DispThresh:W - DispThresh, :]
out.write(boxPart)
pass
v.release()
out.release()