• 视频提取关键帧工具类KeyFramesExtractUtils.py,动态支持三种取帧方式,关键参数可配置,代码经过优化处理,效果和性能更好。


    同步上一期视频关键帧提取方法:

    视频提取关键帧的三种方式【已调通】_君临天下tjm的博客-CSDN博客_视频关键帧提取关键代码如下:# -*- coding: utf-8 -*-"""this key frame extract algorithm is based on interframe difference.The principle is very simpleFirst, we load the video and compute the interframe difference between each framesThen, we can choose one of t...https://blog.csdn.net/shanxiderenheni/article/details/124499862

    项目中可以直接导入该工具类KeyFramesExtractUtils.py,三种取帧方式通过参数选择,method可以取"use_top_order"、"use_thresh"、"use_local_maxima"中的任何一种,第三种方式效果最佳,默认也是"use_local_maxima"。

    优化点:

    key_frame = 10  # 所隔帧数
    cap.set(cv2.CAP_PROP_POS_FRAMES, j)  # 这里的cv2.CAP_PROP_POS_FRAMES参数是说:取第j帧之后的那一帧
    j += key_frame
    ......
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
    视频提取关键帧工具类KeyFramesExtractUtils.py完整代码如下:
    1. # -*- coding: utf-8 -*-
    2. """
    3. this key frame extract algorithm is based on interframe difference.
    4. The principle is very simple
    5. First, we load the video and compute the interframe difference between each frames
    6. Then, we can choose one of these three methods to extract keyframes, which are
    7. all based on the difference method:
    8. 1. use the difference order
    9. The first few frames with the largest average interframe difference
    10. are considered to be key frames.
    11. 2. use the difference threshold
    12. The frames which the average interframe difference are large than the
    13. threshold are considered to be key frames.
    14. 3. use local maximum
    15. The frames which the average interframe difference are local maximum are
    16. considered to be key frames.
    17. It should be noted that smoothing the average difference value before
    18. calculating the local maximum can effectively remove noise to avoid
    19. repeated extraction of frames of similar scenes.
    20. After a few experiment, the third method has a better key frame extraction effect.
    21. """
    22. import cv2
    23. import operator
    24. import numpy as np
    25. import matplotlib.pyplot as plt
    26. import sys
    27. import time
    28. from scipy.signal import argrelextrema
    29. # USE_LOCAL_MAXIMA=True,效果还行,时间有点长,54张图,包括一张差异趋势图
    30. # 使用cv2.CAP_PROP_POS_FRAMES间隔取帧,主要消耗CPU,效率比内存高,效果更好
    31. # 视频提取关键帧工具类
    32. class KeyFramesExtractUtils:
    33. # 初始化
    34. def __init__(self, video_path=None, save_path=None):
    35. self.video_path = video_path
    36. self.save_path = save_path
    37. # 提取关键帧
    38. def extract_keyframe(self, method="use_local_maxima"):
    39. print(sys.executable)
    40. print("method===>", method)
    41. # fixed threshold value
    42. thresh = 0.6
    43. # Number of top sorted frames
    44. num_top_frames = 50
    45. # smoothing window size
    46. len_window = int(50)
    47. print("target video: " + self.video_path)
    48. print("frame save directory: " + self.save_path)
    49. # load video and compute diff between frames
    50. cap = cv2.VideoCapture(str(self.video_path))
    51. curr_frame = None
    52. prev_frame = None
    53. frame_diffs = []
    54. frames = []
    55. video_frames = []
    56. key_frame = 10 # 所隔帧数
    57. t0_start = time.time()
    58. k = 0
    59. j = 0
    60. while True:
    61. if key_frame >= 1:
    62. t1_start = time.time()
    63. print("j======>", j)
    64. cap.set(cv2.CAP_PROP_POS_FRAMES, j) # 这里的cv2.CAP_PROP_POS_FRAMES参数是说:取第j帧之后的那一帧
    65. j += key_frame
    66. success, frame = cap.read()
    67. if not success:
    68. print("第一次视频帧读取完毕!")
    69. break
    70. gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    71. curr_frame = gray
    72. if curr_frame is not None and prev_frame is not None:
    73. # logic here
    74. diff = cv2.absdiff(curr_frame, prev_frame)
    75. diff_sum = np.sum(diff)
    76. diff_sum_mean = diff_sum / (diff.shape[0] * diff.shape[1])
    77. frame_diffs.append(diff_sum_mean)
    78. temp_frame = Frame(k, diff_sum_mean)
    79. frames.append(temp_frame)
    80. video_frames.append(frame)
    81. k = k + 1
    82. prev_frame = curr_frame
    83. t1_end = time.time()
    84. print("计算一次差分耗时:", (t1_end - t1_start), "s")
    85. cap.release()
    86. t0_end = time.time()
    87. print("计算共耗时:", (t0_end - t0_start), "s")
    88. t_start = time.time()
    89. # compute keyframe
    90. keyframe_id_set = set()
    91. if method == "use_top_order":
    92. print("---------------Using use_top_order---------------")
    93. # sort the list in descending order
    94. frames.sort(key=operator.attrgetter("diff"), reverse=True)
    95. for keyframe in frames[:num_top_frames]:
    96. keyframe_id_set.add(keyframe.id)
    97. elif method == "use_thresh":
    98. print("---------------Using Threshold---------------")
    99. for i in range(1, len(frames)):
    100. if rel_change(np.float(frames[i - 1].diff), np.float(frames[i].diff)) >= thresh:
    101. keyframe_id_set.add(frames[i].id)
    102. else:
    103. print("---------------Using Local Maxima---------------")
    104. diff_array = np.array(frame_diffs)
    105. sm_diff_array = smooth(diff_array, len_window)
    106. frame_indexes = np.asarray(argrelextrema(sm_diff_array, np.greater))[0]
    107. for i in frame_indexes:
    108. keyframe_id_set.add(frames[i - 1].id)
    109. plt.figure(figsize=(40, 20))
    110. plt.locator_params(numticks=100)
    111. plt.stem(sm_diff_array)
    112. plt.savefig(self.save_path + 'plot.png')
    113. for idx in keyframe_id_set:
    114. name = "keyframe_" + str(idx) + ".jpg"
    115. cv2.imwrite(self.save_path + name, video_frames[idx])
    116. t_end = time.time()
    117. print("取帧共耗时:", (t_end - t_start), "s")
    118. class Frame:
    119. """class to hold information about each frame
    120. """
    121. def __init__(self, id, diff):
    122. self.id = id
    123. self.diff = diff
    124. def __lt__(self, other):
    125. if self.id == other.id:
    126. return self.id < other.id
    127. return self.id < other.id
    128. def __gt__(self, other):
    129. return other.__lt__(self)
    130. def __eq__(self, other):
    131. return self.id == other.id and self.id == other.id
    132. def __ne__(self, other):
    133. return not self.__eq__(other)
    134. def rel_change(a, b):
    135. x = (b - a) / max(a, b)
    136. print(x)
    137. return x
    138. def smooth(x, window_len=13, window='hanning'):
    139. """smooth the data using a window with requested size.
    140. """
    141. print(len(x), window_len)
    142. s = np.r_[2 * x[0] - x[window_len:1:-1],
    143. x, 2 * x[-1] - x[-1:-window_len:-1]]
    144. # print(len(s))
    145. if window == 'flat': # moving average
    146. w = np.ones(window_len, 'd')
    147. else:
    148. w = getattr(np, window)(window_len)
    149. y = np.convolve(w / w.sum(), s, mode='same')
    150. return y[window_len - 1:-window_len + 1]
    151. if __name__ == "__main__":
    152. keyFrame = KeyFramesExtractUtils(video_path="e956ed44fffe4bfb97cf23474fb48ef3.avi", save_path="./extract_result/")
    153. keyFrame.extract_keyframe(method="use_local_maxima")
    154. # 计算共耗时: 307.6547501087189 s
    155. # 取帧共耗时: 22.484756231307983 s

     

     

     

     

     提取的关键帧如下:

     检测结果总结:视频帧的提取率约为1.66‰,21m15s的视频,耗时约330s(即5分30秒)。

     

  • 相关阅读:
    Part2_扩展MATSIM_Subpart2_Mobsim_第11章 QSim
    ELK体系部署文档(elk+filebeat+redis)
    MQTT平台实体硬件VS PlantSimulation实战
    卷积神经网络基础
    8.1 建军 环境配置
    kettle基础使用教程
    Ubuntu下载工具ip addr、ifconfig、ping、make
    负载均衡应用场景
    【Android】在使用约束布局(ConstraintLayout)中,当某个子View发生隐藏后,某个View无法正确显示了
    第五章:最新版零基础学习 PYTHON 教程—Python 字符串操作指南(第七节 - Python 中使用 % 进行字符串格式化)
  • 原文地址:https://blog.csdn.net/shanxiderenheni/article/details/125891527