ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【小工具系列】Python + OpenCV 图片序列转换成视频

2020-05-20 20:02:05  阅读:415  来源: 互联网

标签:转换成 target Python args cv2 OpenCV fps path resize


图片序列转换成视频

最近一直在找一个工具,能够将一堆图片转化成视频。网上找了一些小软件,还有 win10 的照片自带的视频制作功能,都不是很满意。
又不想下载那些专业的视频剪辑软件大材小用。

然后找到了ffmpeg这个非常出名非常常用的多媒体编解码库,看了下文档试着用了下,它确实可以完成上述功能,但是命令行对输入图片的命名有规定(文件名必须开头相同、且包含连续编号),并且windows下的编译版不支持Pattern type 'glob'
先尝试了用python写了批量重命名然后调用ffmpeg的命令,然后发现还需要相同的分辨率才行。。。

最后决定参照网上的其他使用OpenCV(OpenCV在视频处理功能底层也是用的ffmpeg)的博客自己写一个。

这里先把完整代码和使用说明贴出来:

import os, sys
import cv2
import numpy as np
import argparse

imgs_path = 'C:\\'

target_size = (1280, 720)
target_fps = 1.0
# 输出文件名
target_video = 'out.mp4'
# 是否保存 resize 的中间图像
saveResizeFlag = False
img_types = ('.bmp', '.dib', '.png', '.jpg', '.jpeg', '.pbm', '.pgm', '.ppm', '.tif', '.tiff')

# 不存在则创建目录
def mkdir(path):
    if not os.path.exists(path):
        os.mkdir(path)

# 将图片等比例缩放,不足则填充黑边
def resizeAndPadding(img):
    size = img.shape
    h, w = size[0], size[1]
    target_h, target_w = target_size[1], target_size[0]

    # 确定缩放的尺寸
    scale_h, scale_w= float(h / target_h), float(w / target_w)
    scale = max(scale_h, scale_w)
    new_w, new_h = int(w / scale), int(h / scale)

    # 缩放后其中一条边和目标尺寸一致
    resize_img = cv2.resize(img, (new_w, new_h))

    # 图像上、下、左、右边界分别需要扩充的像素数目
    top = int((target_h - new_h) / 2)
    bottom = target_h - new_h - top
    left = int((target_w - new_w) / 2)
    right = target_w - new_w - left
    # 填充至 target_w * target_h
    pad_img = cv2.copyMakeBorder(resize_img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=[0,0,0]) 

    return pad_img
 
 
def imgs2video():
    output_path = imgs_path + 'out\\'
    mkdir(output_path)
    target = output_path + target_video
    fourcc = cv2.VideoWriter_fourcc(*"mp4v")
    vw = cv2.VideoWriter(target, fourcc, target_fps, target_size)

    images = os.listdir(imgs_path)
    count = 0
    for image in images:
        if not (image.lower().endswith(img_types)):
            continue
        try:
            print(image)
            # cv2.waitKey(100)
            # frame = cv2.imread(imgs_path + image)
            # imread 不能读中文路径,unicode也不行
            frame = cv2.imdecode(np.fromfile(imgs_path + image, dtype=np.uint8), cv2.IMREAD_COLOR) #, cv2.IMREAD_UNCHANGED
            
            pad_frame = resizeAndPadding(frame)
            # print(pad_frame.shape)

            if saveResizeFlag:
                # 保存缩放填充后的图片
                resize_path = imgs_path + 'resize\\'
                mkdir(resize_path)
                resize_name = resize_path + 'resize_' + image
                # cv2.imwrite(resize_name, pad_frame)
                # imwrite 不能读中文路径,unicode也不行
                cv2.imencode(os.path.splitext(image)[-1], pad_frame)[1].tofile(resize_name)
            
            # 写入视频
            vw.write(pad_frame)
            count += 1
        except Exception as exc:
            print(image, exc)
    vw.release()
    print('\r\nConvert Success! Total ' + str(count) + ' images be combined into the video at: ' + target + '\r\n')

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Function: convert images to video")
    parser.add_argument('--input', '-i', required = True)
    parser.add_argument('--output', '-o', default='out.mp4')
    parser.add_argument('--fps', '-f', type=float, default = 1.0)
    parser.add_argument('--resolution', '-r', type=int, nargs = 2, default = [1280, 720])
    parser.add_argument('--save', '-s', action='store_true')
    args = parser.parse_args()
    if args.input:
        if not os.path.isdir(args.input):
            print("input is not a directory")
            sys.exit(0)
        imgs_path = args.input
        if not imgs_path.endswith(('\\', '/')):
            imgs_path += os.path.sep
        print('input path: ' + imgs_path)
    if args.output:
        target_video = args.output
        print('output file: ' + target_video)
    if args.fps:
        if not args.fps > 0:
            print('fps should be greater than zero')
            sys.exit(0)
        target_fps = args.fps
        print('output file fps: ' + str(target_fps))
    if args.resolution:
        if not args.resolution[0] > 0 and args.resolution[1] > 0:
            print('resolution should be greater than zero')
            sys.exit(0)
        target_size = (args.resolution[0], args.resolution[1])
        print('output file resolution: ' + str(target_size))
    if args.save:
        saveResizeFlag = True
    imgs2video()

使用方法:

  1. 依赖numpycv2:(当然首先得有 Python 环境)
pip install numpy
pip install opencv-python
  1. 下载本代码到本地;
  2. 在命令行运行本代码,并指定参数:
python imgs2video.py -i D:\images\
python imgs2video.py -i D:\images\ -o test.mp4 -f 0.5 -r 1920 1080 -s
  • 参数介绍:
--input, -i: 输入图片的路径,必须参数;
--output, -o: 输出视频的名字,默认 out.mp4;
--fps, -f: 指定的帧率,类型浮点数,默认 1.0;
--resolution, -r: 指定视频的分辨率,类型两个整数,默认 1280 720;
--save, -s: 是否保存图片转化分辨率之后的中间结果,默认不保存。

说明

代码看起来有点长,其实核心功能在函数imgs2video中:创建一个cv2.VideoWriter用于写视频文件,cv2.imdecode读图片,然后缩放,然后写入视频。可选项:cv2.imencode将缩放后的图片保存下来。之所以不用cv2.imreadcv2.imwrite是因为这俩没办法处理中文路径

标签:转换成,target,Python,args,cv2,OpenCV,fps,path,resize
来源: https://www.cnblogs.com/caophoenix/p/12925767.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有