python脚本-视频抽帧程序

python脚本-视频抽帧程序

前言

    因为前几天刷都用刷到“按住虚线向右滑动”这样的视频,我感觉很有趣,于是就想着我也要不要做几个这样的作品。刚开始是想着使用pr进行视频抽帧,可是要知道做一个这样的作品需要至少60张视频抽帧的图片,而且必须以相同的间隔帧进行抽取,所以用pr制作的话会很累很慢,于是就想着能不能使用python来实现一个这样的功能。

一、准备工作

    因为python有着很多的库所以想要实现这样的功能应该会比较简单,经过网上搜索只需要使用这个库(cv2)就可以很简单的实现视频抽帧的功能。

    简单的学习了一下就可以开始上手了。

二、文件夹创建

    因为直接进行抽帧的话会使图片散的到都是,所以需要先建一个文件夹开始这个工作。

    创建代码:

# 创建一个名为 "images" 的子目录
output_folder = 'images'
if not os.path.exists(output_folder):
    os.makedirs(output_folder)

    这样我们就可以创建一个文件夹用来保存图片啦!

三、抽帧工作

1.获取抽帧视频路径

    刚开始没考虑这么多所以我默认使用同一目录下的视频进行操作,怎么获得同一目录下的视频文件呢?
我们可以通过这个代码来实现:

# 获取当前目录下所有的视频文件
video_files = glob.glob("*.mp4") + glob.glob("*.avi")  # 可以根据需要添加更多视频格式(当前只识别mp4和avi)
print(f'{video_files}')
key = int(input('请选择要抽帧的视频(输入0则为第一个视频):'))
video_file = video_files[key]  # 设置操作的视频

2.抽帧操作

(一)修改图片的创建时间和修改时间

    为什么要修改图片的时间呢?
因为经过我的实践,发现抖音发布页面的图片排列时是按照图片修改时间排列的,所以我需要将每一张图片按照时间发展的顺序进行修改。
部分代码:

# 保存图片并将日期信息保存在属性中,每张图片的日期增加一分钟
cap = cv2.VideoCapture(video_file)
fps = cap.get(cv2.CAP_PROP_FPS)
print(f'当前帧速率为:{fps}')
interval = int(fps * float(frame_seconds))  # 将frame_seconds转换为浮点数再计算
i = 0
frame_count = 0
current_time = datetime.now()  # 获取当前日期
one_day = timedelta(days=1)  # 设置增加一分钟
new_time = current_time - one_day  # 增加一分钟

(二)开始抽帧

    通过死循环将视频的每一帧都进行读取,然后判断是否符合自己需要抽取的帧若符合则保存,不符合则跳过。这段代码同时也包含修改时间代码的片段。
代码:

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    frame_count += 1
    if frame_count % interval == 0 or is_first_frame is True:
        is_first_frame = False
        i = i + 1
        video_name = os.path.splitext(video_file)[0]  # 获取视频文件名(不包含扩展名)
        output_file = os.path.join(output_folder, f"{i}-{video_name}_frame{frame_count}.jpg")
        jpeg_binary = cv2.imencode('.jpg', frame)[1]  # 将抽帧转换为JPEG
        # 将二进制数据保存
        try:
            with open(output_file, 'wb+') as f:
                f.write(jpeg_binary)
            print(f'保存成功:{output_file}')

            one_minute = timedelta(minutes=1)  # 设置增加一分钟
            new_time = new_time + one_minute  # 增加一分钟
            formatted_time = new_time.strftime('%Y:%m:%d %H:%M:%S')  # 将当前时间转换为指定格式
            FixTime.writeTime(output_file, formatted_time)  # 调用修改时间函数
        except Exception  as e:
            print(f'保存失败,异常抛出:{e}')
            a = input('执行已暂停,任意键结束执行')
            sys.exit()
cap.release()
cv2.destroyAllWindows()

2.修改图片的方法

    我尝试过其他方法进行时间修改可是每次修改都不成功。在解决这个问题的过程中我发现了一篇文章讲到怎么修改文件的创建时间和修改时间,于是我点了进去。里面的文章写的很好,而且还提供了代码文件,我拉到本地运行之后发现确实可以解决修改时间的问题。本着效率第一的原则我就直接拿来用了。很感谢这位提供解决方法的同学。
修改时间文章地址:使用Python将图片的创建时间修改为拍摄时间

    修改时间代码:

import os
import piexif
from win32file import CreateFile, SetFileTime, GetFileTime, CloseHandle
from win32file import GENERIC_READ, GENERIC_WRITE, OPEN_EXISTING
from pywintypes import Time # 可以忽视这个 Time 报错(运行程序还是没问题的)
import time

class ModifTime2ShootTime:
    def __init__(self, path):
        self.dir_path = path
        self.current_file_path = ""
        self.current_file_time = ""
        self.custom_file_time = "" # 如果没有获取到时间,则使用默认时间

    def modifDirAllFile(self):
        file_name_list = os.listdir(self.dir_path)
        # 从文件夹中获取文件文件
        for file_name in file_name_list:
            if not file_name.endswith(".JPG"):
                continue
            # 生成具体文件路径
            self.current_file_path = self.dir_path + file_name
            print(self.current_file_path)
            # 提取拍摄时间
            self.readShootTime()
            print(self.current_file_time)
            # 写入到 创建时间 修改时间 访问时间
            writeTime(self.current_file_path, self.custom_file_time)

            # 休息一下,防止太快
            time.sleep(0.01)

    def readShootTime(self):
        exif_dict = piexif.load(self.current_file_path)
        # 尝试获取拍摄时间,如果没有获取到,则使用自定义时间
        try:
            time_str = str(exif_dict["Exif"][36868])
            self.current_file_time = time_str[2:len(time_str) - 1]
        except:
            self.current_file_time = self.custom_file_time


def timeOffsetAndStruct(times, format, offset):
  return time.localtime(time.mktime(time.strptime(times, format)) + offset)

def writeTime(file_path,file_times):
    format = "%Y:%m:%d %H:%M:%S"  # 时间格式
    # 进行时间偏移 1S,避免创建时间,修改时间,访问时间都一样
    cTime_t = timeOffsetAndStruct(file_times, format, 0)
    mTime_t = timeOffsetAndStruct(file_times, format, 1)
    aTime_t = timeOffsetAndStruct(file_times, format, 2)

    fh = CreateFile(file_path, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, 0)

    createTimes, accessTimes, modifyTimes = GetFileTime(fh)
    createTimes = Time(time.mktime(cTime_t))
    accessTimes = Time(time.mktime(aTime_t))
    modifyTimes = Time(time.mktime(mTime_t))
    SetFileTime(fh, createTimes, accessTimes, modifyTimes)
    CloseHandle(fh)


if __name__ == '__main__':


    # 对某个目录下所有JPG后缀的图片进行时间修改,将其拍摄时间设置到创建时间
    # modif = ModifTime2ShootTime("D:\\Downloads\\Compressed\\iCloud\\20160615192000\\")
    # modif.custom_file_time = "2016:06:15 19:20:00"
    # modif.modifDirAllFile()


    # 对任意文件进行时间修改
    writeTime("D:\\Downloads\\Compressed\\iCloud\\day\\IMG_4496.mp4","2017:04:26 18:15:00")

至此,所有的代码就都写完啦!想要完整代码的同学在文章评论后我会将代码发出来的。

消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息