如何在Python中用图像制作电影

问题描述 投票:0回答:9

我目前正在尝试用图像制作电影,但我找不到任何有用的东西。

这是迄今为止我的代码:

import time

from PIL import  ImageGrab

x =0

while True:
    try:
        x+= 1
        ImageGrab().grab().save('img{}.png'.format(str(x))
    except:
        movie = #Idontknow
        for _ in range(x):
            movie.save("img{}.png".format(str(_)))

movie.save()
python image video screenshot
9个回答
158
投票

您可以考虑使用 ffmpeg 等外部工具将图像合并到电影中(参见答案此处),或者您可以尝试使用 OpenCv 将图像合并到电影中,如示例此处

我在下面附加了一段代码片段,我用来将名为“images”的文件夹中的所有 png 文件合并到视频中。

import cv2
import os

image_folder = 'images'
video_name = 'video.avi'

images = [img for img in os.listdir(image_folder) if img.endswith(".png")]
frame = cv2.imread(os.path.join(image_folder, images[0]))
height, width, layers = frame.shape

video = cv2.VideoWriter(video_name, 0, 1, (width,height))

for image in images:
    video.write(cv2.imread(os.path.join(image_folder, image)))

cv2.destroyAllWindows()
video.release()

这个答案中评论最多的部分似乎是VideoWriter的使用。您可以在这个答案(静态)的链接中查找它的文档,或者您可以自己进行一些挖掘。第一个参数是文件名,后跟一个整数(文档中的fourcc,使用的编解码器)、FPS 计数和帧尺寸的元组。如果您真的喜欢挖掘那些蠕虫,这里是 fourcc 视频编解码器列表


60
投票

谢谢,但我找到了使用 ffmpeg 的替代解决方案:

def save():
    os.system("ffmpeg -r 1 -i img%01d.png -vcodec mpeg4 -y movie.mp4")

但是谢谢你的帮助:)


33
投票

这是一个使用 moviepy 的最小示例。对我来说,这是最简单的解决方案。

import os
import moviepy.video.io.ImageSequenceClip
image_folder='folder_with_images'
fps=1

image_files = [os.path.join(image_folder,img)
               for img in os.listdir(image_folder)
               if img.endswith(".png")]
clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(image_files, fps=fps)
clip.write_videofile('my_video.mp4')

19
投票

我使用

ffmpeg-python
绑定。您可以在此处找到更多信息。

import ffmpeg
(
    ffmpeg
    .input('/path/to/jpegs/*.jpg', pattern_type='glob', framerate=25)
    .output('movie.mp4')
    .run()
)

1
投票

使用 moviepy 的

ImageSequenceClip
时,图像按顺序排列非常重要。

虽然文档指出框架可以在引擎盖下按字母数字顺序排序,但我发现事实并非如此。

因此,如果您遇到问题,请务必先手动订购框架。


1
投票

@Wei Shan Lee(和其他人):当然,我的整个代码看起来像这样

import os
import moviepy.video.io.ImageSequenceClip
from PIL import Image, ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

image_files = []

for img_number in range(1,20): 
    image_files.append(path_to_images + 'image_folder/image_' + str(img_number) + '.png') 

fps = 30

clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(image_files, fps=fps)
clip.write_videofile(path_to_videos + 'my_new_video.mp4')

0
投票

我创建了一个函数来执行此操作。与第一个答案(使用 opencv)类似,但想补充一点,对我来说,“.mp4”格式不起作用。这就是我在函数中使用加注的原因。

import cv2
import typing

def write_video(video_path_out:str,
                frames_sequence:typing.Tuple[np.ndarray,...]):
  
  if ".mp4" in video_path_out: raise ValueError("[ERROR] This method does not support .mp4; try .avi instead")
  height, width, _ = frames_sequence[0].shape
  # 0 means no preprocesing
  # 1 means  each image will be played with 1 sec delay (1fps)
  out = cv2.VideoWriter(video_path_out,0, 1,(width,height))
  for frame in frames_sequence:
      out.write(frame)
  out.release()

# you can use as much images as you need, I just use 3 for this example
# put your img1_path,img2_path, img3_path

img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
img3 = cv2.imread(img3_path)
# img1 can be cv2.imread out; which is a np.ndarray; you can also se PIL
# if you'd like to.
frames_sequence = [img1,img2,img3]

write_video(video_path_out = "mypath_outvideo.avi",
frames_sequence = frames_sequence
)

希望有用!


0
投票

有点 hacky,但避免创建文件,只是让您实时观看它。

import glob 
from PIL import Image
import cv2 
import numpy as np 
import time 
####### PARAMS 

imgs_path = "/Users/user/Desktop/lidar_rig/ouster_data_wide_angle_cam_v9/imgs/*"

cur_img_index = 0
ds_st_index = 0
ds_en_index = -1

fps = 35 # tweak this 


###### PARAMS 

def cnvt_pil_to_cv2(pil_img):
    open_cv_image = np.array(pil_img) 
    # Convert RGB to BGR 
    open_cv_image = open_cv_image[:, :, ::-1].copy()     
    return open_cv_image




img_files = sorted(glob.glob(imgs_path), key = lambda x: int(x.split('/')[-1].split('.')[0]))[ds_st_index:ds_en_index][cur_img_index:]
cnt = 0 

for img_pth in img_files:
    if not cnt %50: ## DDD -- avoid mem overflow  
        cv2.destroyAllWindows()
    img = Image.open(img_pth).resize((750,750))
    cv2.imshow(img_pth.split("/")[-1], cnvt_pil_to_cv2(img))
    time.sleep(float(1.0/float(fps)))
    cnt+=1 

0
投票

作为额外贡献,如果有人难以按字母顺序对加载的图像进行排序,这里有一个使用内置排序(os.listdir(image_folder))函数的版本。

import os
import moviepy.video.io.ImageSequenceClip
from PIL import Image, ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

image_folder='frames'
fps=10


image_files = [os.path.join(image_folder,img)
               for img in sorted(os.listdir(image_folder))
               if img.endswith(".png")]
print(image_files)

clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(image_files, fps=fps)
clip.write_videofile('myvideo.mp4')

但是,请注意,它取决于文件系统/文件名,并且会将数字排序错误(1,10,2,3…)。下面是另一个带有

sorted_alphanumeric(data)
函数的解决方案,可以解决这个问题(来自另一个 线程

import os
import moviepy.video.io.ImageSequenceClip
from PIL import Image, ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

image_folder='frames'
fps=10

import re
def sorted_alphanumeric(data):
    convert = lambda text: int(text) if text.isdigit() else text.lower()
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(data, key=alphanum_key)

image_files = [os.path.join(image_folder,img)
               for img in sorted_alphanumeric(os.listdir(image_folder))
               if img.endswith(".png")]
print(image_files)

clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(image_files, fps=fps)
clip.write_videofile('myvideo.mp4')
© www.soinside.com 2019 - 2024. All rights reserved.