OpenCV实现视频防抖技术

该博客介绍了一个视频处理流程,包括读取视频、计算帧间变换、平滑轨迹以及稳定视频。通过OpenCV库实现特征点检测、光流估计和仿射变换,然后使用移动平均对轨迹进行平滑,最后应用平滑后的变换矩阵来稳定视频帧。此外,还讨论了调整平滑参数以改变视频稳定效果的方法。
摘要由CSDN通过智能技术生成
# Import numpy and OpenCV
import numpy as np
import cv2

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



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)
        #radius=30表示需要平滑的视频半径
        smoothed_trajectory[:, i] = movingAverage(trajectory[:, i], radius=30)

    return smoothed_trajectory



# Read input video
cap = cv2.VideoCapture('3.mp4');

# Get frame count
n_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print(n_frames)



# Get width and height of video stream
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))


# Define the codec for output video
fourcc = cv2.VideoWriter_fourcc(*'mp4v')

fps = 20.0
# Set up output video
out = cv2.VideoWriter('video_out1.mp4', fourcc, fps, (w, h),True)




# Read first frame
_, prev = cap.read()

# Convert frame to grayscale
prev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)



# Pre-define transformation-store array
transforms = np.zeros((n_frames - 1, 3), np.float32)

for i in range(n_frames - 2):
    # Detect feature points in previous frame
    prev_pts = cv2.goodFeaturesToTrack(prev_gray,
                                       maxCorners=200,
                                       qualityLevel=0.01,
                                       minDistance=30,
                                       blockSize=3)

    # Read next frame
    success, curr = cap.read()
    if not success:
        break

        # Convert to grayscale
    curr_gray = cv2.cvtColor(curr, cv2.COLOR_BGR2GRAY)

    # Calculate optical flow (i.e. track feature points)
    curr_pts, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, curr_gray, prev_pts, None)

    # Sanity check
    assert prev_pts.shape == curr_pts.shape

    # Filter only valid points
    idx = np.where(status == 1)[0]
    prev_pts = prev_pts[idx]
    curr_pts = curr_pts[idx]

    # Find transformation matrix
    m,_ = cv2.estimateAffinePartial2D(prev_pts, curr_pts)  # will only work with OpenCV-3 or less

    # Extract traslation
    dx = m[0, 2]
    dy = m[1, 2]

    # Extract rotation angle
    da = np.arctan2(m[1, 0], m[0, 0])

    # Store transformation
    transforms[i] = [dx, dy, da]

    # Move to next frame
    prev_gray = curr_gray

    print("Frame: " + str(i) + "/" + str(n_frames) + " -  Tracked points : " + str(len(prev_pts)))



# Compute trajectory using cumulative sum of transformations
trajectory = np.cumsum(transforms, axis=0)





# Compute trajectory using cumulative sum of transformations
trajectory = np.cumsum(transforms, axis=0)


smoothed_trajectory = smooth(trajectory)
# Calculate difference in smoothed_trajectory and trajectory
difference = smoothed_trajectory - trajectory

# Calculate newer transformation array
transforms_smooth = transforms + difference








# Reset stream to first frame
cap.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 = cap.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, (w, h))

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

        # print('********************')
        # print(frame_out.shape[1] / 2)
        # print(frame_out.shape[0])
        #
        #
        # print(type((frame_out.shape[1])))
        # print((frame_out.shape[1]))

        frame_out = cv2.resize(frame_out, (int(frame_out.shape[1] / 2) , int(frame_out.shape[0])))

    # print('---------------------')
    # print(w)
    # print(h)
    # print(frame_out.shape)


    cv2.imshow("Before and After", frame_out)
    out.write(frame_out)
    cv2.waitKey(10)

 

 

用的时候,需要注意几个地方:

  • 视频保存的时候,输入和输出的尺寸是需要保持一致的,如果最终保存的视频大小为几kb的话,那么就查看一下下面这行代码里面,图像的尺寸

frame_out = cv2.resize(frame_out, (int(frame_out.shape[1] / 2) , int(frame_out.shape[0])))

将其下面注释掉的内容打开即可

  • 修改radius的值即可调整视频调节的幅度

smoothed_trajectory[:, i] = movingAverage(trajectory[:, i], radius=30)

 

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值