توليد الفيديو أو الرسوم المتحركة برمجيا في بيثون؟

StackOverflow https://stackoverflow.com/questions/753190

سؤال

لدي سلسلة من الصور التي أريد إنشاء فيديو من. من الناحية المثالية، يمكنني تحديد مدة إطار لكل إطار ولكن معدل الإطار الثابت سيكون على ما يرام أيضا. أقوم بذلك في Wxpython، لذلك يمكنني تقديم WXDC أو يمكنني حفظ الصور على الملفات، مثل PNG. هل هناك مكتبة بيثون تسمح لي بإنشاء فيديو (AVI، MPG، إلخ) أو GIF متحرك من هذه الإطارات؟

تحرير: لقد حاولت بالفعل PIS ولا يبدو أنها تعمل. هل يمكن لشخص تصحيحني بهذا الاستنتاج أو اقتراح مجموعة أدوات أخرى؟ يبدو أن هذا الرابط احتياطيا استنتاجي فيما يتعلق بيل: http://www.somethethinkodd.com/oddthinking/2005/12/06/Python-Imaging-library-pil-and-animated-gifs/

هل كانت مفيدة؟

المحلول 3

حسنا، الآن أنا أستخدم ImageMagick. أحفظ إطاراتي كملفات PNG ثم استدعاء Convert.exe ImageMagick من Python لإنشاء GIF متحرك. الشيء الجميل في هذا النهج هو يمكنني تحديد مدة إطار لكل إطار بشكل فردي. لسوء الحظ، هذا يعتمد على ImageMagick يجري تثبيته على الجهاز. لديهم غلاف بيثون ولكن يبدو كربي رائع وغير مدعوم. لا تزال مفتوحة على اقتراحات أخرى.

نصائح أخرى

أوصي بعدم استخدام Images2GIF من Visvis لأنه يحتوي على مشاكل مع PIL / وسادة ولا يتم الحفاظ عليها بنشاط (يجب أن أعرف، لأنني مؤلف).

بدلا من ذلك، يرجى استخدام imageio., ، الذي تم تطويره لحل هذه المشكلة وأكثر من ذلك، ويهدف إلى البقاء.

حل سريع وقذرة:

import imageio
images = []
for filename in filenames:
    images.append(imageio.imread(filename))
imageio.mimsave('/path/to/movie.gif', images)

لأفلام أطول، استخدم نهج البث:

import imageio
with imageio.get_writer('/path/to/movie.gif', mode='I') as writer:
    for filename in filenames:
        image = imageio.imread(filename)
        writer.append_data(image)

اعتبارا من يونيو 2009، تتمتع وظيفة بلوق المذكورة في الأصل بطريقة لإنشاء صور متحركة في التعليقات. وبعد قم بتنزيل البرنامج النصي images2gif.py. (سابقا images2gif.py., ، تحديث مجاملة egraphika).

ثم، لعكس الإطارات في GIF، على سبيل المثال:

#!/usr/bin/env python

from PIL import Image, ImageSequence
import sys, os
filename = sys.argv[1]
im = Image.open(filename)
original_duration = im.info['duration']
frames = [frame.copy() for frame in ImageSequence.Iterator(im)]    
frames.reverse()

from images2gif import writeGif
writeGif("reverse_" + os.path.basename(filename), frames, duration=original_duration/1000.0, dither=0)

انا إستعملت images2gif.py. التي كانت سهلة الاستخدام. يبدو أن ضعف حجم الملف على الرغم من ..

26 110kb ملفات PNG، كنت أتوقع 26 * 110kb = 2860kb، ولكن كان my_gif.gif 5.7 ميغابايت

أيضا لأن GIF كان 8bit، أصبحت PNG لطيفة غامضة قليلا في GIF

هنا هو الرمز الذي استخدمته:

__author__ = 'Robert'
from images2gif import writeGif
from PIL import Image
import os

file_names = sorted((fn for fn in os.listdir('.') if fn.endswith('.png')))
#['animationframa.png', 'animationframb.png', 'animationframc.png', ...] "

images = [Image.open(fn) for fn in file_names]

print writeGif.__doc__
# writeGif(filename, images, duration=0.1, loops=0, dither=1)
#    Write an animated gif from the specified images.
#    images should be a list of numpy arrays of PIL images.
#    Numpy images of type float should have pixels between 0 and 1.
#    Numpy images of other types are expected to have values between 0 and 255.


#images.extend(reversed(images)) #infinit loop will go backwards and forwards.

filename = "my_gif.GIF"
writeGif(filename, images, duration=0.2)
#54 frames written
#
#Process finished with exit code 0

هنا 3 من 26 إطارات:

Here are 3 of the 26 frames

تقلص الصور خفض الحجم:

size = (150,150)
for im in images:
    im.thumbnail(size, Image.ANTIALIAS)

smaller gif

لإنشاء فيديو، يمكنك استخدام opencv.,

#load your frames
frames = ...
#create a video writer
writer = cvCreateVideoWriter(filename, -1, fps, frame_size, is_color=1)
#and write your frames in a loop if you want
cvWriteFrame(writer, frames[i])

جئت عبر هذا المنصب وأي من الحلول التي عملت، لذلك هنا الحل الذي يعمل

مشاكل الحلول الأخرى حتى الآن:
1) لا يوجد حل صريح حول كيفية تعديل المدة
2) لا يوجد حل لتكرار دليل الطلب، وهو أمر ضروري ل GIF
3) لا شرح حول كيفية تثبيت ImageIO ل Python 3

تثبيت ImageIo مثل هذا: python3 -m pip تثبيت imageio

ملحوظة: سترغب في التأكد من أن إطاراتك تحتوي على نوع من الفهرس في اسم الملف حتى يتم فرزها، وإلا فلن يكون لديك طريقة لمعرفة أين يبدأ أو ينتهي GIF

import imageio
import os

path = '/Users/myusername/Desktop/Pics/' # on Mac: right click on a folder, hold down option, and click "copy as pathname"

image_folder = os.fsencode(path)

filenames = []

for file in os.listdir(image_folder):
    filename = os.fsdecode(file)
    if filename.endswith( ('.jpeg', '.png', '.gif') ):
        filenames.append(filename)

filenames.sort() # this iteration technique has no built in order, so sort the frames

images = list(map(lambda filename: imageio.imread(filename), filenames))

imageio.mimsave(os.path.join('movie.gif'), images, duration = 0.04) # modify duration as needed

إنها ليست مكتبة بيثون، لكن مينسودر يمكن أن تفعل ذلك: ترميز من ملفات صورة الإدخال المتعددة. وبعد يمكنك تنفيذ Mencoder من Python مثل هذا:

import os

os.system("mencoder ...")

مثل وارن قال العام الماضي, هذا سؤال قديم. نظرا لأن الناس ما زالوا يشاهدون الصفحة، أود إعادة توجيههم إلى حل أكثر حداثة. مثل blakev قال هنا, ، هناك مثال وسادة على جيثب.

 import ImageSequence
 import Image
 import gifmaker
 sequence = []

 im = Image.open(....)

 # im is your original image
 frames = [frame.copy() for frame in ImageSequence.Iterator(im)]

 # write GIF animation
 fp = open("out.gif", "wb")
 gifmaker.makedelta(fp, frames)
 fp.close()

ملاحظة: هذا المثال قديم (gifmaker ليست وحدة استغلالية، فقط سيناريو). وسادة لديها أ gifimageplugin. (الذي المصدر على جيثب)، لكن الوثيقة على imagesequence يبدو أنه يشير إلى دعم محدود (قراءة فقط)

أقوم بنشر إجابة أخرى كما هو أبسط من كل شيء نشرت حتى الآن:

from PIL import Image

width = 300
height = 300
im1 = Image.new("RGBA", (width, height), (255, 0, 0))
im2 = Image.new("RGBA", (width, height), (255, 255, 0))
im3 = Image.new("RGBA", (width, height), (255, 255, 255))
im1.save("out.gif", save_all=True, append_images=[im2, im3], duration=100, loop=0)

باستخدام الصور الموجودة:

from PIL import Image

im1 = Image.open('a.png')
im2 = Image.open('b.png')
im3 = Image.open('c.png')
im1.save("out.gif", save_all=True, append_images=[im2, im3], duration=100, loop=0)

ومع ذلك، نظرا لأن إصدارات وسادة منخفضة جدا، فستكون الفشل بصمت هنا هي إصدار مكافأة مع فحص إصدار المكتبة:

from packaging import version
from PIL import Image

im1 = Image.open('a.png')
im2 = Image.open('b.png')
im3 = Image.open('c.png')
if version.parse(Image.PILLOW_VERSION) < version.parse("3.4"):
    print("Pillow in version not supporting making animated gifs")
    print("you need to upgrade library version")
    print("see release notes in")
    print("https://pillow.readthedocs.io/en/latest/releasenotes/3.4.0.html#append-images-to-gif")
else:
    im1.save("out.gif", save_all=True, append_images=[
             im2, im3], duration=100, loop=0)

هل حاولت Pymedia.ب أنا لست متأكدا 100٪ ولكن يبدو هذا البرنامج التعليمي يستهدف مشكلتك.

مع Windows7، Python2.7، OpenCV 3.0، يعمل ما يلي بالنسبة لي:

import cv2
import os

vvw           =   cv2.VideoWriter('mymovie.avi',cv2.VideoWriter_fourcc('X','V','I','D'),24,(640,480))
frameslist    =   os.listdir('.\\frames')
howmanyframes =   len(frameslist)
print('Frames count: '+str(howmanyframes)) #just for debugging

for i in range(0,howmanyframes):
    print(i)
    theframe = cv2.imread('.\\frames\\'+frameslist[i])
    vvw.write(theframe)

السؤال القديم، الكثير من الإجابات الجيدة، ولكن قد لا يزال هناك اهتمام بديل آخر ...

ال numpngw الوحدة التي وضعت مؤخرا على جيثب (https://github.com/warrenweckesser/numpngw.) يمكن كتابة ملفات PNG الرسوم المتحركة من صفائف Numpy. فيتحديث: numpngw هو الآن على pypi: https://pypi.python.org/pypi/numpngw..)

على سبيل المثال، هذا البرنامج النصي:

import numpy as np
import numpngw


img0 = np.zeros((64, 64, 3), dtype=np.uint8)
img0[:32, :32, :] = 255
img1 = np.zeros((64, 64, 3), dtype=np.uint8)
img1[32:, :32, 0] = 255
img2 = np.zeros((64, 64, 3), dtype=np.uint8)
img2[32:, 32:, 1] = 255
img3 = np.zeros((64, 64, 3), dtype=np.uint8)
img3[:32, 32:, 2] = 255
seq = [img0, img1, img2, img3]
for img in seq:
    img[16:-16, 16:-16] = 127
    img[0, :] = 127
    img[-1, :] = 127
    img[:, 0] = 127
    img[:, -1] = 127

numpngw.write_apng('foo.png', seq, delay=250, use_palette=True)

يخلق:

animated png

ستحتاج إلى متصفح يدعم PNG الرسوم المتحركة (إما مباشرة أو مع البرنامج المساعد) لرؤية الرسوم المتحركة.

كعضو واحد المذكورة أعلاه، تعد ImageO طريقة رائعة للقيام بذلك. يسمح لك Imageio أيضا بضبط معدل الإطار، وكتبت فعلا وظيفة في Python التي تتيح لك تعيين الإيقاف النهائي. يمكنني استخدام هذه الوظيفة للرسوم المتحركة العلمية حيث يكون الحلقات مفيدا ولكن إعادة التشغيل الفوري ليس كذلك. هنا هو الرابط والوظيفة:

كيفية جعل GIF باستخدام بيثون

import matplotlib.pyplot as plt
import os
import imageio

def gif_maker(gif_name,png_dir,gif_indx,num_gifs,dpi=90):
    # make png path if it doesn't exist already
    if not os.path.exists(png_dir):
        os.makedirs(png_dir)

    # save each .png for GIF
    # lower dpi gives a smaller, grainier GIF; higher dpi gives larger, clearer GIF
    plt.savefig(png_dir+'frame_'+str(gif_indx)+'_.png',dpi=dpi)
    plt.close('all') # comment this out if you're just updating the x,y data

    if gif_indx==num_gifs-1:
        # sort the .png files based on index used above
        images,image_file_names = [],[]
        for file_name in os.listdir(png_dir):
            if file_name.endswith('.png'):
                image_file_names.append(file_name)       
        sorted_files = sorted(image_file_names, key=lambda y: int(y.split('_')[1]))

        # define some GIF parameters

        frame_length = 0.5 # seconds between frames
        end_pause = 4 # seconds to stay on last frame
        # loop through files, join them to image array, and write to GIF called 'wind_turbine_dist.gif'
        for ii in range(0,len(sorted_files)):       
            file_path = os.path.join(png_dir, sorted_files[ii])
            if ii==len(sorted_files)-1:
                for jj in range(0,int(end_pause/frame_length)):
                    images.append(imageio.imread(file_path))
            else:
                images.append(imageio.imread(file_path))
        # the duration is the time spent on each image (1/duration is frame rate)
        imageio.mimsave(gif_name, images,'GIF',duration=frame_length)

Example GIF using this method

أسهل شيء يجعله يعمل بالنسبة لي هو استدعاء أمر Shell في Python.

إذا تم تخزين صورك مثل Dummy_Image_1.png، Dummy_Image_2.png ... Dummy_Image_n.png، ثم يمكنك استخدام الوظيفة:

import subprocess
def grid2gif(image_str, output_gif):
    str1 = 'convert -delay 100 -loop 1 ' + image_str  + ' ' + output_gif
    subprocess.call(str1, shell=True)

مجرد تنفيذ:

grid2gif("dummy_image*.png", "my_output.gif")

سيبني هذا ملف GIF الخاص بك my_output.gif.

يمكن إكمال المهمة عن طريق تشغيل البرنامج النصي من Python الخطين من نفس المجلد باعتباره تسلسل ملفات الصور. ل PNG تنسيق الملفات النصي هو -

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')

كنت أبحث عن رمز خط واحد ووجد ما يلي للعمل في طلبي. هنا هو ما فعلته:

الخطوة الأولى: تثبيت ImageMagick من الرابط أدناه

https://www.imagemagick.org/script/download.php.

enter image description here

الخطوة الثانية: أشر إلى خط CMD إلى المجلد حيث يتم وضع الصور (بتنسيق الحالة .png)

enter image description here

خطوة ثالثة: اكتب الأمر التالي

magick -quality 100 *.png outvideo.mpeg

enter image description here

شكرا foglebird للفكرة!

جربت فقط ما يلي وكان مفيدا للغاية:

أولا قم بتنزيل المكتبات Figtodat و images2gif إلى الدليل المحلي الخاص بك.

ثانيا جمع الأرقام في صفيف وتحويلها إلى GIF المتحركة:

import sys
sys.path.insert(0,"/path/to/your/local/directory")
import Figtodat
from images2gif import writeGif
import matplotlib.pyplot as plt
import numpy

figure = plt.figure()
plot   = figure.add_subplot (111)

plot.hold(False)
    # draw a cardinal sine plot
images=[]
y = numpy.random.randn(100,5)
for i in range(y.shape[1]):
    plot.plot (numpy.sin(y[:,i]))  
    plot.set_ylim(-3.0,3)
    plot.text(90,-2.5,str(i))
    im = Figtodat.fig2img(figure)
    images.append(im)

writeGif("images.gif",images,duration=0.3,dither=0)

جئت على بيل imagesequence. الوحدة النمطية، والتي توفر لعوامة أفضل (وأكثر قياسية) GIF. أنا أيضا استخدام TK بعد() طريقة هذه المرة، وهو أفضل من وقت النوم().

from Tkinter import * 
from PIL import Image, ImageTk, ImageSequence

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = im.info['duration'] # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True;
while play:
  for frame in ImageSequence.Iterator(im):
    if not play: break 
    root.after(delay);
    img = ImageTk.PhotoImage(frame)
    lbl.config(image=img); root.update() # Show the new frame/image

root.mainloop()

وظيفة بسيطة تجعل gifs:

import imageio
import pathlib
from datetime import datetime


def make_gif(image_directory: pathlib.Path, frames_per_second: float, **kwargs):
    """
    Makes a .gif which shows many images at a given frame rate.
    All images should be in order (don't know how this works) in the image directory

    Only tested with .png images but may work with others.

    :param image_directory:
    :type image_directory: pathlib.Path
    :param frames_per_second:
    :type frames_per_second: float
    :param kwargs: image_type='png' or other
    :return: nothing
    """
    assert isinstance(image_directory, pathlib.Path), "input must be a pathlib object"
    image_type = kwargs.get('type', 'png')

    timestampStr = datetime.now().strftime("%y%m%d_%H%M%S")
    gif_dir = image_directory.joinpath(timestampStr + "_GIF.gif")

    print('Started making GIF')
    print('Please wait... ')

    images = []
    for file_name in image_directory.glob('*.' + image_type):
        images.append(imageio.imread(image_directory.joinpath(file_name)))
    imageio.mimsave(gif_dir.as_posix(), images, fps=frames_per_second)

    print('Finished making GIF!')
    print('GIF can be found at: ' + gif_dir.as_posix())


def main():
    fps = 2
    png_dir = pathlib.Path('C:/temp/my_images')
    make_gif(png_dir, fps)

if __name__ == "__main__":
    main()

إليك كيفية القيام بذلك باستخدام سلي فقط (تثبيت مع: pip install Pillow):

import glob
from PIL import Image

# filepaths
fp_in = "/path/to/image_*.png"
fp_out = "/path/to/image.gif"

# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
img, *imgs = [Image.open(f) for f in sorted(glob.glob(fp_in))]
img.save(fp=fp_out, format='GIF', append_images=imgs,
         save_all=True, duration=200, loop=0)

إنه أمر لا يصدق حقا ... يقترح الجميع بعض الحزمة الخاصة للعب GIF متحركة، في الوقت الحالي يمكن القيام به مع Tkinter ووحدة PIL الكلاسيكية!

فيما يلي طريقة الرسوم المتحركة الخاصة بي الخاصة (خلقت منذ فترة). بسيط جدا:

from Tkinter import * 
from PIL import Image, ImageTk
from time import sleep

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}    
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = float(im.info['duration'])/1000; # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True; frame = 0
while play:
  sleep(delay);
  frame += 1
  try:
    im.seek(frame); img = ImageTk.PhotoImage(im)
    lbl.config(image=img); root.update() # Show the new frame/image
  except EOFError:
    frame = 0 # Restart

root.mainloop()

يمكنك تعيين وسائل خاصة بك لإيقاف الرسوم المتحركة. اسمحوا لي أن أعرف إذا كنت ترغب في الحصول على النسخة الكاملة مع أزرار اللعب / الإيقاف المؤقت / الإيقاف.

ملاحظة: لست متأكدا من قراءة الإطارات المتتالية من الذاكرة أو من الملف (القرص). في الحالة الثانية، سيكون الأمر أكثر كفاءة إذا قرأوا مرة واحدة وحفظها في صفيف (قائمة). (أنا غير مهتم جدا لمعرفة ذلك! :)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top