当前位置:   article > 正文

opencv-python 视频流光去抖、实时去抖_python opencv 防抖

python opencv 防抖
import numpy as np
import cv2


def movingAverage(curve, radius):
    window_size = 2 * radius + 1
    # 定义过滤器
    f = np.ones(window_size) / window_size
    # 为边界添加填充
    curve_pad = np.lib.pad(curve, (radius, radius), 'edge')
    # 应用卷积
    curve_smoothed = np.convolve(curve_pad, f, mode='same')
    # 删除填充
    curve_smoothed = curve_smoothed[radius:-radius]
    # 返回平滑曲线
    return curve_smoothed


def smooth(trajectory):
    smoothed_trajectory = np.copy(trajectory)
    # 过滤x, y和角度曲线
    for i in range(3):
        smoothed_trajectory[:, i] = movingAverage(
            trajectory[:, i], radius=SMOOTHING_RADIUS)

    return smoothed_trajectory


def fixBorder(frame):
    s = frame.shape
    # 在不移动中心的情况下,将图像缩放4%
    T = cv2.getRotationMatrix2D((s[1] / 2, s[0] / 2), 0, 1.04)
    frame = cv2.warpAffine(frame, T, (s[1], s[0]))
    return frame


# 尺寸越大,视频越稳定,但对突然平移的反应越小
SMOOTHING_RADIUS = 50

# 读取输入视频
cap = cv2.VideoCapture('v1.mp4')

# 得到帧数
n_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print(n_frames)
# exit()
# #我们的测试视频可能读错了1300帧之后的帧
# n_frames = 1300

# 获取视频流的宽度和高度
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# 获取每秒帧数(fps)
fps = cap.get(cv2.CAP_PROP_FPS)

# 定义输出视频的编解码器
fourcc = cv2.VideoWriter_fourcc(*'MJPG')

# 设置输出视频
out = cv2.VideoWriter('video_out.avi', fourcc, fps, (2 * w, h))

# 读第一帧
_, prev = cap.read()

# 将帧转换为灰度
prev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)

# 预定义转换numpy矩阵
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)

    # 读下一帧
    success, curr = cap.read()
    if not success:
        break

    # 转换为灰度图
    curr_gray = cv2.cvtColor(curr, cv2.COLOR_BGR2GRAY)

    # 计算光流(即轨迹特征点)
    curr_pts, status, err = cv2.calcOpticalFlowPyrLK(
        prev_gray, curr_gray, prev_pts, None)

    # 检查完整性
    assert prev_pts.shape == curr_pts.shape

    # 只过滤有效点
    idx = np.where(status == 1)[0]
    prev_pts = prev_pts[idx]
    curr_pts = curr_pts[idx]

    # 找到变换矩阵
    # 只适用于OpenCV-3或更少的版本吗
    # m = cv2.estimateRigidTransform(prev_pts, curr_pts, fullAffine=False)
    m, inlier = cv2.estimateAffine2D(prev_pts, curr_pts, )

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

    # 提取旋转角
    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)))

# 使用累积变换和计算轨迹
trajectory = np.cumsum(transforms, axis=0)

# 创建变量来存储平滑的轨迹
smoothed_trajectory = smooth(trajectory)

# 计算smoothed_trajectory与trajectory的差值
difference = smoothed_trajectory - trajectory

# 计算更新的转换数组
transforms_smooth = transforms + difference

# 将视频流重置为第一帧
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

# 写入n_frames-1转换后的帧
for i in range(n_frames - 2):
    # 读下一帧
    success, frame = cap.read()
    if not success:
        break

    # 从新的转换数组中提取转换
    dx = transforms_smooth[i, 0]
    dy = transforms_smooth[i, 1]
    da = transforms_smooth[i, 2]

    # 根据新的值重构变换矩阵
    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

    # 应用仿射包装到给定的框架
    frame_stabilized = cv2.warpAffine(frame, m, (w, h))

    # Fix border artifacts
    frame_stabilized = fixBorder(frame_stabilized)

    # 将框架写入文件
    frame_out = cv2.hconcat([frame, frame_stabilized])

    # 如果图像太大,调整它的大小。
    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)

# 发布视频
cap.release()
out.release()
# 关闭窗口
cv2.destroyAllWindows()

  • 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
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180

实时防抖

import numpy as np
import cv2


def movingAverage(curve, radius):
    window_size = 2 * radius + 1
    # 定义过滤器
    f = np.ones(window_size) / window_size
    # 为边界添加填充
    curve_pad = np.lib.pad(curve, (radius, radius), 'edge')
    # 应用卷积
    curve_smoothed = np.convolve(curve_pad, f, mode='same')
    # 删除填充
    curve_smoothed = curve_smoothed[radius:-radius]
    # 返回平滑曲线
    return curve_smoothed


def smooth(trajectory):
    smoothed_trajectory = np.copy(trajectory)
    # 过滤x, y和角度曲线
    for i in range(3):
        smoothed_trajectory[:, i] = movingAverage(
            trajectory[:, i], radius=SMOOTHING_RADIUS)

    return smoothed_trajectory


def fixBorder(frame):
    s = frame.shape
    # 在不移动中心的情况下,将图像缩放4%
    T = cv2.getRotationMatrix2D((s[1] / 2, s[0] / 2), 0, 1.04)
    frame = cv2.warpAffine(frame, T, (s[1], s[0]))
    return frame


# 尺寸越大,视频越稳定,但对突然平移的反应越小
SMOOTHING_RADIUS = 50

# 读取输入视频
# cap = cv2.VideoCapture('v1.mp4')
cap = cv2.VideoCapture(0)

# # 得到帧数
# n_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))


# 获取视频流的宽度和高度
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# 获取每秒帧数(fps)
fps = cap.get(cv2.CAP_PROP_FPS)

# 预定义转换numpy矩阵
# transforms = np.zeros((n_frames - 1, 3), np.float32)

prev_gray = []

k = 0

# 准备存储
transforms = np.zeros((30, 3), np.float32)

while cap.isOpened():
    # 避免内存泄露,清空列表,重新计算
    if len(prev_gray) >= 29:
        prev_gray = []
        k = 0

    print(k)

    # 读取一帧
    success, curr = cap.read()
    
    # 是否还有下一帧,关闭
    if not success:
        break
 
    # 转换为灰度图
    curr_gray = cv2.cvtColor(curr, cv2.COLOR_BGR2GRAY)

    # 为了计算帧差,要把前几帧放入列表中
    prev_gray.append(curr_gray)

    if len(prev_gray) >= 2:
        # 检测前一帧的特征点
        prev_pts = cv2.goodFeaturesToTrack(prev_gray[k - 1],
                                           maxCorners=200,
                                           qualityLevel=0.01,
                                           minDistance=30,
                                           blockSize=3)
        # 计算光流(即轨迹特征点) 前一张 当前张 前一张特征
        curr_pts, status, err = cv2.calcOpticalFlowPyrLK(prev_gray[k - 1], curr_gray, prev_pts, None)

        # 检查完整性
        assert prev_pts.shape == curr_pts.shape

        # 只过滤有效点
        idx = np.where(status == 1)[0]
        prev_pts = prev_pts[idx]
        curr_pts = curr_pts[idx]

        # 找到变换矩阵
        m, inlier = cv2.estimateAffine2D(prev_pts, curr_pts)

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

        # 提取旋转角
        da = np.arctan2(m[1, 0], m[0, 0])

        # 存储转换
        transforms[k] = [dx, dy, da]

        # cv2.imshow("B", curr_gray)
        # cv2.waitKey(1)
    k += 1

    if len(prev_gray) >= 3:
        # 使用累积变换和计算轨迹
        trajectory = np.cumsum(transforms, axis=0)

        # 创建变量来存储平滑的轨迹
        smoothed_trajectory = smooth(trajectory)

        # 计算smoothed_trajectory与trajectory的差值
        difference = smoothed_trajectory - trajectory

        # 计算更新的转换数组
        transforms_smooth = transforms + difference

        # 从新的转换数组中提取转换
        dx = transforms_smooth[k, 0]
        dy = transforms_smooth[k, 1]
        da = transforms_smooth[k, 2]

        # 根据新的值重构变换矩阵
        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

        # 应用仿射包装到给定的框架
        frame_stabilized = cv2.warpAffine(curr, m, (w, h))

        # Fix border artifacts
        frame_stabilized = fixBorder(frame_stabilized)
        cv2.imshow("B", frame_stabilized)
        cv2.waitKey(1)
  • 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
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/732541
推荐阅读
相关标签
  

闽ICP备14008679号