见代码改进了对于大视频文件会溢出的问题处理的视频文件下载https://download.csdn.net/download/babytiger/12732306# 视频输入目录input_dirrE:\video\xueshan\1# 图像输出目录output_dirre:/image/# smoothing window sizelen_window int(25)len_window 如果改大到100会使局部运行感知不明显图中的松鼠比较小就不会被感知到程序会认为整体没啥变化就不会生成关键帧上面的要自行设定实测一个小视频900多帧下面程序提取出23多个有效帧# -*- coding: utf-8 -*- import cv2 import operator import numpy as np import matplotlib.pyplot as plt import os from scipy.signal import argrelextrema # Setting fixed threshold criteria USE_THRESH False # fixed threshold value THRESH 0.6 # Setting fixed threshold criteria USE_TOP_ORDER False # Setting local maxima criteria USE_LOCAL_MAXIMA True # Number of top sorted frames NUM_TOP_FRAMES 20 # 视频输入目录 input_dirrE:\video\xueshan\1 # 图像输出目录 output_dirre:/image/ # smoothing window size len_window int(25) def smooth(x, window_len13, windowhanning): smooth the data using a window with requested size. This method is based on the convolution of a scaled window with the signal. The signal is prepared by introducing reflected copies of the signal (with the window size) in both ends so that transient parts are minimized in the begining and end part of the output signal. input: x: the input signal window_len: the dimension of the smoothing window window: the type of window from flat, hanning, hamming, bartlett, blackman flat window will produce a moving average smoothing. output: the smoothed signal example: import numpy as np t np.linspace(-2,2,0.1) x np.sin(t)np.random.randn(len(t))*0.1 y smooth(x) see also: numpy.hanning, numpy.hamming, numpy.bartlett, numpy.blackman, numpy.convolve scipy.signal.lfilter TODO: the window parameter could be the window itself if an array instead of a string print(len(x), window_len) # if x.ndim ! 1: # raise ValueError, smooth only accepts 1 dimension arrays. # # if x.size window_len: # raise ValueError, Input vector needs to be bigger than window size. # # if window_len 3: # return x # # if not window in [flat, hanning, hamming, bartlett, blackman]: # raise ValueError, Window is on of flat, hanning, hamming, bartlett, blackman s np.r_[2 * x[0] - x[window_len:1:-1], x, 2 * x[-1] - x[-1:-window_len:-1]] # print(len(s)) if window flat: # moving average w np.ones(window_len, d) else: w getattr(np, window)(window_len) y np.convolve(w / w.sum(), s, modesame) return y[window_len - 1:-window_len 1] # Class to hold information about each frame class Frame: def __init__(self, id, frame, value): self.id id self.frame frame self.value value def __lt__(self, other): if self.id other.id: return self.id other.id return self.id other.id def __gt__(self, other): return other.__lt__(self) def __eq__(self, other): return self.id other.id and self.id other.id def __ne__(self, other): return not self.__eq__(other) def rel_change(a, b): if(max(a,b)!0): x (b - a) / max(a, b) print(x) else: return 0 return x def write_frames(dir,filename): if USE_TOP_ORDER: # sort the list in descending order frames.sort(keyoperator.attrgetter(value), reverseTrue) for keyframe in frames[:NUM_TOP_FRAMES]: name frame_ str(keyframe.id) .jpg cv2.imwrite(dir / filename_name, keyframe.frame) if USE_THRESH: print(Using Threshold) for i in range(1, len(frames)): if (rel_change(np.float(frames[i - 1].value), np.float(frames[i].value)) THRESH): # print(prev_frame:str(frames[i-1].value) curr_frame:str(frames[i].value)) name frame_ str(frames[i].id) .jpg cv2.imwrite(dir / filename_name, frames[i].frame) if USE_LOCAL_MAXIMA: print(Using Local Maxima) diff_array np.array(frame_diffs) sm_diff_array smooth(diff_array, len_window) frame_indexes np.asarray(argrelextrema(sm_diff_array, np.greater))[0] for i in frame_indexes: name frame_ str(frames[i - 1].id) .jpg print(dirname) cv2.imwrite(dir / filename_ name, frames[i - 1].frame) frame_diffs [] frames [] def all_path(dirname): for maindir, subdir, file_name_list in os.walk(dirname): for fn in file_name_list: file_path os.path.join(maindir, fn) # 合并成一个完整路径 (filepath,tempfilename) os.path.split(file_path) (filename,extension) os.path.splitext(tempfilename) if not os.path.exists(output_dirfilename/): os.mkdir(output_dirfilename/) videopath file_path # Directory to store the processed frames dir output_dirfilename print(Video : videopath) print(Frame Directory: dir) cap cv2.VideoCapture(str(videopath)) curr_frame None prev_frame None ret, frame cap.read() i 1 while (ret): luv cv2.cvtColor(frame, cv2.COLOR_BGR2LUV) curr_frame luv if curr_frame is not None and prev_frame is not None: # logic here diff cv2.absdiff(curr_frame, prev_frame) count np.sum(diff) frame_diffs.append(count) frame Frame(i, frame, count) frames.append(frame) print(filename,i ) #防止载入大视频内存溢出每1000帧清空一次 if(i%10000): write_frames(dir,filename) frame_diffs.clear() frames.clear() prev_frame curr_frame i i 1 ret, frame cap.read() cv2.imshow(frame,luv) if cv2.waitKey(1) 0xFF ord(q): break write_frames(dir,filename) cap.release() all_path(input_dir) cv2.destroyAllWindows()但是这23帧中看到还有不少很相似的于是用下面代码再次去重代码中的用户可以根据自己情况调整大概原理是把图像缩小到46*46计算相似哈希#相似度如果大于max_ssim就进行删除max_ssim0.6又去重了7张效果如下# -*- coding: utf-8 -*- import os import cv2 from skimage.measure import compare_ssim import shutil def yidong(filename1,filename2): shutil.move(filename1,filename2) def delete(filename1): os.remove(filename1) #相似度如果大于max_ssim就进行删除 max_ssim0.5 #利用拉普拉斯算子计算图片的二阶导数反映图片的边缘信息同样事物的图片 # 清晰度高的相对应的经过拉普拉斯算子滤波后的图片的方差也就越大。 def getImageVar(image): img2gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) imageVar cv2.Laplacian(img2gray, cv2.CV_64F).var() return imageVar if __name__ __main__: img_path rE:\image\xuedi del_list [] img_files [os.path.join(rootdir, file) for rootdir, _, files in os.walk(img_path) for file in files if (file.endswith(.jpg))] for currIndex, filename in enumerate(img_files): if not os.path.exists(img_files[currIndex]): print(not exist, img_files[currIndex]) break new_cur 0 for i in range(10000000): currIndex1 new_cur if currIndex1 len(img_files) - currIndex - 1: break else: size os.path.getsize(img_files[currIndex1 currIndex 1]) if size 64: # delete(img_files[currIndex 1]) del_list.append(img_files.pop(currIndex1 currIndex 1)) else: img cv2.imread(img_files[currIndex]) #计算图像清晰度 var_imggetImageVar(img) img cv2.resize(img, (46, 46), interpolationcv2.INTER_CUBIC) img1 cv2.imread(img_files[currIndex1 currIndex 1]) # 计算图像清晰度 var_img1getImageVar(img1) img1 cv2.resize(img1, (46, 46), interpolationcv2.INTER_CUBIC) ssim compare_ssim(img, img1, multichannelTrue) if ssim max_ssim: #当达到了门限比较两个图像的清晰度把不清晰的放入删除列表中 print(var_img,var_img1,img_files[currIndex], img_files[currIndex1 currIndex 1], ssim) if(var_imgvar_img1): del_list.append(img_files.pop(currIndex1 currIndex 1)) else: del_list.append(img_files.pop(currIndex)) new_cur currIndex1 else: new_cur currIndex1 1 if ssim 0.4: print(small_ssim,img_files[currIndex], img_files[currIndex1 currIndex 1], ssim) for image in del_list: #delete(image) print(delete,image)去重过程中会保留更清晰的帧比较两个图像的清晰度把不清晰的放入删除列表中#利用拉普拉斯算子计算图片的二阶导数反映图片的边缘信息同样事物的图片# 清晰度高的相对应的经过拉普拉斯算子滤波后的图片的方差也就越大。def getImageVar(image):img2gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)imageVar cv2.Laplacian(img2gray, cv2.CV_64F).var()return imageVar