• 视频转高清gif动态图片(Python代码实现)


    如何使用Python编写代码来将视频转换为高清动态图片,从而无需依赖费用高昂的第三方工具或忍受低质量的输出呢?

    具体的实现可以参考本篇博文,这个技术对于制作演示文稿、社交媒体内容或博客文章都非常有用,因为它可以让你轻松地将视频片段转换为清晰的GIF动画。

    背景

    最近,我需要为一次PPT答辩准备一些动态图片,而这些图片需要从一个视频中提取。我尝试了一些在线工具和付费软件,但发现要么转换结果模糊不清,要么带有水印,要么需要付费。于是,我决定自己动手写代码来实现这个任务。

    技术栈

    在开始之前,让我们先了解一下我们将使用的技术栈:

    - Python:作为编程语言的选择,Python是一种功能强大且易于使用的语言,适合处理图像和视频。
    - OpenCV:这是一个广泛用于计算机视觉任务的库,我们将使用它来处理视频帧。
    - imageio:这个库将帮助我们读取视频文件并将帧保存为GIF。

    步骤

    下面是将视频转换为高清动态图片的主要步骤:

    1. 安装所需库:

       使用pip或conda安装所需的Python库:

       pip install opencv-python imageio

    整个过程我分为三个板块进行实现:

    第一步:视频转化为图片 借助opencv

    通过VideoCapture读取视频,然后imwrite保存图片。代码如下:

    1. def video_to_image(videoPath, imgPath, save_format=".jpg", imgNumber=0, nameLength=4):
    2. """
    3. params:
    4. videoPath : 视频路径 例如 u'E:\Test/123.mp4'
    5. imgPath : 图片路径 例如 r'F:\Test/tu/' #保存图片路径,路径最后加/斜杠
    6. save_format : 保存的图片格式,默认为jpg可以改为'.png'
    7. imgNumber : 图片保存的名字数量默认为0开始
    8. """
    9. print("视频转图片的方法")
    10. if imgPath[-1] != "/":
    11. imgPath + "/"
    12. capture = cv2.VideoCapture(videoPath)
    13. frame_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
    14. suc = capture.isOpened() # 是否成功打开
    15. frame_count = imgNumber # 图片张数从多少开始
    16. while suc:
    17. try:
    18. frame_count += 1
    19. suc, frame = capture.read()
    20. cv2.imwrite(imgPath + str(frame_count).zfill(4) + save_format, frame)
    21. # zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0
    22. #:str.zfill(width) 参数width
    23. if frame_num == frame_count:
    24. suc = False
    25. except:
    26. break
    27. capture.release()
    28. print("视频转图片结束! ")
    第二步视频导出的图片集转化为gif图片

    用到的imageio.get_writer作为gif文件流写入图片,

    imageio.get_writer(uri = gifname,mode = "I",fps = 25)

    其中这三个参数分别表示:

    uri:合成后的gif动图的名字,可以随意更改。
    mode:操作模式,I表示多图,不用更改。
    fps:帧率,也就是画面每秒传输帧数,值越大,gif动图的播放速度越大。

    代码如下:

    1. def image_to_gif(st_imagename=1, end_imagename=1, gifname="demo.gif"):
    2. import imageio
    3. """
    4. uri:合成后的gif动图的名字,可以随意更改。
    5. mode:操作模式,I表示多图,不用更改。
    6. fps:帧率,也就是画面每秒传输帧数,值越大,gif动图的播放速度越大。
    7. gifname:保存的gif名字
    8. """
    9. os.chdir(os.getcwd())
    10. if not os.path.exists("images"):
    11. os.makedirs("images")
    12. with imageio.get_writer(uri=gifname, mode="I", fps=25) as writer:
    13. for i in range(st_imagename, end_imagename + 1): # 选择多少张
    14. print(f"正在处理第{i}张")
    15. filename = str(i).zfill(4)
    16. file_path = os.path.join(os.getcwd(), "images", filename)
    17. writer.append_data(imageio.imread(file_path + ".jpg"))
    最后就是将上述2步进行整合,实现视频转化为gif图片

    以下是第三步的代码

    1. def video_to_gif(videoPath, resultName, fps=25):
    2. """
    3. :param videoPath: 视频路径 绝对路径。且路径不要含中文
    4. :param resultName: 输出的gif文件名
    5. :param fps: 保存的gif帧率,fps默认为25
    6. """
    7. sample = [chr(i) for i in range(97, 97 + 26)] + [str(i) for i in range(10)]
    8. random_name = "_" + "".join(random.sample(sample, 10)) # 用于临时存储数据图片
    9. # shutil.rmtree(file_path) #删除
    10. if not os.path.exists(random_name):
    11. os.makedirs(random_name)
    12. tmp_path = os.path.join(os.getcwd(), random_name) + "/"
    13. print("step 1 loading:video_to_image start")
    14. video_to_image(videoPath, tmp_path) # 视频转化完毕
    15. print("step 1 finished:video_to_image end")
    16. image_nums = len(os.listdir(tmp_path))
    17. image_nums = (
    18. 375 if image_nums > 375 else image_nums
    19. ) # TODO 默认上限为15s 即:25 * 15 = 375张照片
    20. print("step 2 loading:image_to_gif start")
    21. image_to_gif(st_imagename=1, end_imagename=image_nums, gifname=resultName)
    22. print("step 2 finished:image_to_gif end")
    23. shutil.rmtree(random_name)
    24. print("All Finished")

    整个项目的代码已上传至:askxiaozhang/Python_tools: To provide some like practical tools that png turn to gif or mp4 turn to gif by Python. (github.com)

    有需要的兄弟姐们可以前往Fork、star一下,,欢迎大家加入本项目一起为开源做贡献!~

    下面是整个项目代码:

    1. import string
    2. import imageio
    3. import os
    4. import cv2
    5. import shutil
    6. import base64
    7. import random
    8. def video_to_image(videoPath, imgPath, save_format=".jpg", imgNumber=0, nameLength=4):
    9. """
    10. params:
    11. videoPath : 视频路径 例如 u'E:\Test/123.mp4'
    12. imgPath : 图片路径 例如 r'F:\Test/tu/' #保存图片路径,路径最后加/斜杠
    13. save_format : 保存的图片格式,默认为jpg可以改为'.png'
    14. imgNumber : 图片保存的名字数量默认为0开始
    15. """
    16. print("视频转图片的方法")
    17. if imgPath[-1] != "/":
    18. imgPath + "/"
    19. capture = cv2.VideoCapture(videoPath)
    20. frame_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
    21. suc = capture.isOpened() # 是否成功打开
    22. frame_count = imgNumber # 图片张数从多少开始
    23. while suc:
    24. try:
    25. frame_count += 1
    26. suc, frame = capture.read()
    27. cv2.imwrite(imgPath + str(frame_count).zfill(4) + save_format, frame)
    28. # zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0
    29. #:str.zfill(width) 参数width
    30. if frame_num == frame_count:
    31. suc = False
    32. except:
    33. break
    34. capture.release()
    35. print("视频转图片结束! ")
    36. def image_to_gif(file_path, st_imagename=1, end_imagename=1, gifname="demo.gif"):
    37. import imageio
    38. """
    39. uri:合成后的gif动图的名字,可以随意更改。
    40. mode:操作模式,I表示多图,不用更改。
    41. fps:帧率,也就是画面每秒传输帧数,值越大,gif动图的播放速度越大。
    42. gifname:保存的gif名字
    43. """
    44. # os.chdir(os.getcwd())
    45. # if not os.path.exists("images"):
    46. # os.makedirs("images")
    47. with imageio.get_writer(uri=gifname, mode="I", fps=25) as writer:
    48. for i in range(st_imagename, end_imagename + 1): # 选择多少张
    49. print(f"正在处理第{i}张")
    50. filename = str(i).zfill(4)
    51. # file_path = os.path.join(os.getcwd(),'images',filename)
    52. file_path2 = file_path + filename + ".jpg"
    53. writer.append_data(imageio.imread(file_path2))
    54. def video_to_gif(videoPath, resultName, fps=25):
    55. """
    56. :param videoPath: 视频路径 绝对路径。且路径不要含中文
    57. :param resultName: 输出的gif文件名
    58. :param fps: 保存的gif帧率,fps默认为25
    59. """
    60. sample = [chr(i) for i in range(97, 97 + 26)] + [str(i) for i in range(10)]
    61. random_name = "_" + "".join(random.sample(sample, 10)) # 用于临时存储数据图片
    62. # shutil.rmtree(file_path) #删除
    63. if not os.path.exists(random_name):
    64. os.makedirs(random_name)
    65. tmp_path = os.path.join(os.getcwd(), random_name) + "/"
    66. print("step 1 loading:video_to_image start")
    67. video_to_image(videoPath, tmp_path) # 视频转化完毕
    68. print("step 1 finished:video_to_image end")
    69. image_nums = len(os.listdir(tmp_path))
    70. image_nums = (
    71. 375 if image_nums > 375 else image_nums
    72. ) # TODO 默认上限为15s 即:25 * 15 = 375张照片
    73. print("step 2 loading:image_to_gif start")
    74. image_to_gif(tmp_path, st_imagename=1, end_imagename=image_nums, gifname=resultName)
    75. print("step 2 finished:image_to_gif end")
    76. shutil.rmtree(random_name)
    77. print("All Finished")
    78. if __name__ == "__main__":
    79. video_to_gif(r"E:\Python_tools\Python_tools\video\test.mp4", "test1.gif")

  • 相关阅读:
    安防监控用品经营商城小程序搭建
    Spring cloud gateway+apollo=bug?
    JVM虚拟机浅谈(三)
    ArcGIS10.8 连接 PostgreSQL 及遇到的两个问题
    通过S2B2C供应链电商平台网站解决方案,实现大宗商品万亿产业数字化转型
    拍视频麦克风什么牌子好?户外无线麦克风哪个牌子好,看本期文章
    通过v_COURSE和V_grade查看期末平均成绩在60分以上的课程名称
    解决ElementUI导航栏重复点菜单报错问题
    二、变量、常量的声明与定义
    【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装播放流程 )
  • 原文地址:https://blog.csdn.net/qq_57329395/article/details/133364468