基于python视频去抖动算法

原理

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()

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
基于灰度投影的视频抖动算法可以通过对视频中每一帧图像进行灰度投影防抖动处理来实现。下面是用Python实现基于灰度投影的视频抖动算法的代码: ```python import cv2 import numpy as np def gray_projection_dithering(image): # 将彩色图像转换成灰度图像 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 计算灰度图像的投影 horizontal = np.sum(gray, axis=1) vertical = np.sum(gray, axis=0) # 将投影值转换成二值化图像 horizontal_image = np.zeros_like(gray) vertical_image = np.zeros_like(gray) for i in range(gray.shape[0]): if horizontal[i] > np.mean(horizontal): horizontal_image[i, :] = 255 for j in range(gray.shape[1]): if vertical[j] > np.mean(vertical): vertical_image[:, j] = 255 # 对二值化图像进行腐蚀操作 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) horizontal_image = cv2.erode(horizontal_image, kernel) vertical_image = cv2.erode(vertical_image, kernel) # 将水平和垂直方向的二值化图像合并 mask = horizontal_image + vertical_image # 对原始图像进行掩模操作 result = cv2.bitwise_and(image, image, mask=mask) return result def video_stabilization(video_path): # 打开视频文件 cap = cv2.VideoCapture(video_path) # 获取视频帧数和帧率 fps = cap.get(cv2.CAP_PROP_FPS) frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 创建输出视频文件 fourcc = cv2.VideoWriter_fourcc(*'XVID') out = cv2.VideoWriter('stabilized_video.avi', fourcc, fps, (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))) # 读取第一帧图像并进行灰度投影防抖动处理 ret, prev_frame = cap.read() prev_frame = gray_projection_dithering(prev_frame) # 循环读取视频中的每一帧图像并进行灰度投影防抖动处理 for i in range(frame_count - 1): ret, curr_frame = cap.read() if not ret: break curr_frame = gray_projection_dithering(curr_frame) # 计算当前帧图像与前一帧图像之间的光流 prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY) curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY) flow = cv2.calcOpticalFlowFarneback(prev_gray, curr_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0) # 根据光流计算位移矩阵 dx = np.median(flow[:, :, 0]) dy = np.median(flow[:, :, 1]) M = np.float32([[1, 0, dx], [0, 1, dy]]) # 通过仿射变换对当前帧图像进行平移 rows, cols, _ = curr_frame.shape curr_frame = cv2.warpAffine(curr_frame, M, (cols, rows)) # 输出平移后的图像到输出视频文件 out.write(curr_frame) # 将当前帧图像设为前一帧图像 prev_frame = curr_frame # 释放视频文件和输出视频文件 cap.release() out.release() video_stabilization('input_video.avi') ``` 上述代码中,使用OpenCV库实现了基于灰度投影的视频抖动算法。通过对每一帧图像进行灰度投影防抖动处理,然后使用光流法计算帧与帧之间的位移矩阵,最后通过仿射变换对当前帧图像进行平移,从而实现视频抖动。最终将平移后的图像输出到输出视频文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值