如果想要自动截取一个视频的图片,又不想手动暂停截取,那可以试试用opencv自动截取(比如想要自动截取喜欢电影的经典台词与图片)。

背景说明:一个小意外,录屏视频没有声音,想着把视频里的PPT截取出来,1个小时的视频,自己挨个截取太慢了,灵机一动用opencv试试吧。

问题1:刚开始代码将每帧都进行了截取,发现一共42798帧,太多了,而且截取图片有很多重复的。

解决:隔帧截取保存,隔多少,暂时是默认了80,效果不错(可以根据自己的视频以及效果改动)。(代码如下)

问题2:能不能让代码自己根据图片差异判断保存?只留下变化的图片,

解决:解决见第二个程序。程序最核心的代码  skimage.measure.compare_ssim(X,Y,...)  计算两幅图像之间的平均结构相似性指数,可参考我的另一个博客

注意:

  • 想要尝试代码,配置opencv,pip install -i https://mirrors.aliyun.com/pypi/simple opencv-python==4.1.0.25
    详情见:
  • cap = cv2.VideoCapture('2.mp4')  2.mp4改为你的视频名字
  • 以下代码只尝试了MP4类型文件,别的暂时没有尝试,有需要再来更新改进吧。
# 视频分解图片
# 1 load 2 info 3 parse 4 imshow imwrite
import cv2
import os
# 获取一个视频打开cap 参数1 file name
#cap = cv2.VideoCapture("1.mp4")
#cv2.VideoCapture(0, cv2.CAP_DSHOW) # 摄像头截取
cap = cv2.VideoCapture('2.mp4')
isOpened = cap.isOpened # 判断是否打开‘
print(isOpened)
# 获取信息 宽高
n_frame = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print('总帧数:',n_frame) # 整个视频的总帧数
fps = cap.get(cv2.CAP_PROP_FPS) # 帧率 每秒展示多少张图片
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # w
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # h
print('帧数、宽度、高度分别为:',fps,width,height) # 帧率 宽 高
i = 0 # 记录读取多少帧
frameFrequency = 80 # 每frameFrequency保存一张图片
while(isOpened):
    # 结束标志是否读取到最后一帧
    if i == n_frame:
        break
    else:
        i = i+1
    (flag,frame) = cap.read() # read方法 读取每一张 flag是否读取成功 frame 读取内容
    fileName = 'image'+str(i)+'.jpg' # 名字累加
    # True表示读取成功 进行·写入
    # if 判断需要有冒号
    #if flag == True:
    outPutDirName = './d/' # 设置保存路径
    if not os.path.exists(outPutDirName):
        # 如果文件目录不存在则创建目录
        os.makedirs(outPutDirName)
    if i % frameFrequency == 0:
        print(fileName)
        cv2.imwrite(outPutDirName+fileName,frame,[cv2.IMWRITE_JPEG_QUALITY,100])# 质量控制 100最高
print('end!')

代码运行结果 

opencv 获取视频帧数 0 opencv保存视频每一帧_帧率

opencv 获取视频帧数 0 opencv保存视频每一帧_帧率_02

opencv 获取视频帧数 0 opencv保存视频每一帧_帧率_03

import os
import cv2
from skimage.measure import compare_ssim
'''相邻两个文件比较相似度,相似就把第二个加到新列表(删除列表)里,然后进行新列表去重,统一删除。
  例如:有文件1-10,首先1和2相比较,若相似,则把2加入到新列表里,再接着2和3相比较,若不相似,则继续进行3和4比较...一直比到最后,然后删除新列表里的图片
   只对于连续图片(例一个视频里截下的图片)准确率也较高,其效率高'''
def delete(filename1):
    os.remove(filename1)
if __name__ == '__main__':
    path = r'./E/' # 文件所在路径
    img_path = path
    imgs_n = [] # 新建的删除列表
    i = 0 # 用来统计删了第几张图片
    img_files = [os.path.join(rootdir, file) for rootdir, _, files in os.walk(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
        img = cv2.imread(img_files[currIndex])
        img1 = cv2.imread(img_files[currIndex + 1])
        # https://cloud.tencent.com/developer/section/1414961 开发者手册链接
        # 本程序最核心的代码
        # skimage.measure.compare_ssim(X,Y,...)
        # 计算两幅图像之间的平均结构相似性指数
        ssim = compare_ssim(img, img1, multichannel=True)
        # 相似度大于0.9就加入删除列表
        if ssim > 0.9:
            imgs_n.append(img_files[currIndex + 1]) # 加入新建删除列表
            i = i+1 # 每加入一个就会删除
            print(img_files[currIndex], img_files[currIndex + 1], ssim)
            print('删除次数', i)
        # 否则不删除,给出两图片的相似度
        else:
            print('small_ssim',img_files[currIndex], img_files[currIndex + 1], ssim)
        currIndex += 1
        if currIndex >= len(img_files)-1:
            break
    for image in imgs_n:
        delete(image)
  • 运行结果

opencv 获取视频帧数 0 opencv保存视频每一帧_帧率_04

 可发现共删除294张图片

opencv 获取视频帧数 0 opencv保存视频每一帧_相似度_05

处理前文件夹情况(共403):

opencv 获取视频帧数 0 opencv保存视频每一帧_ide_06

opencv 获取视频帧数 0 opencv保存视频每一帧_opencv 获取视频帧数 0_07

 

opencv 获取视频帧数 0 opencv保存视频每一帧_帧率_08

 

opencv 获取视频帧数 0 opencv保存视频每一帧_ide_09

处理后文件夹情况(剩下109)点开检查发现相似图片基本删除,达到目标:

opencv 获取视频帧数 0 opencv保存视频每一帧_相似度_10