How to show a frame of a video file (image)

2019-09-11 19:36发布

问题:

I am trying to show video frames (not from a stream) with tkinter. The next step are buttons which allow the user to get a frame backward or forward in the video. I have to say that I am quite new in programming with python. So first I read the following articles:

Python snippets: Converting video to images http://srand.fr/blog/python%20import%20video.html

The Tkinter PhotoImage Class: http://effbot.org/tkinterbook/photoimage.htm

The problem is that I can’t use the image converted with imageio or VideoFileClip to show it with tkinter photoimage. I get the following error:

_tkinter.TclError: image "[[  …(some numbers)…   ]]" doesn't exist

Here is my simple code. I hope you can help me :)

from moviepy.editor import VideoFileClip
from tkinter import *
import pylab

vid =VideoFileClip("example.mp4")

window = Tk()
window.title("Choose Frame")
window.geometry ("900x600")

count =20

photo = vid.get_frame(count)
label =Label(window, image = photo)
label.pack()

Other Code, same problem:

import imageio
from tkinter import *
import pylab

filename = './example.mp4'
vid = imageio.get_reader(filename,  'ffmpeg')

window = Tk()
window.title("Choose Frame")
window.geometry ("900x600")

count =20

photo = vid.get_data(count)
label =Label(window, image = photo)
label.pack()

回答1:

This is a bit late but better late than never.

Here is a working example I found and modify a little, this works with '.mp4', videos but not with '.flv', don't know why.

Note:

python 2.7 import Tkinter

python 3 import tkinter

import Tkinter as tk
import threading
import imageio
from PIL import Image, ImageTk

video_name = "test_video.mp4" #This is your video file path
video = imageio.get_reader(video_name)

def stream(label):

    frame = 0
    for image in video.iter_data():
        frame += 1                                    #counter to save new frame number
        image_frame = Image.fromarray(image)          
        image_frame.save('FRAMES/frame_%d.png' % frame)      #if you need the frame you can save each frame to hd
        frame_image = ImageTk.PhotoImage(image_frame)
        label.config(image=frame_image)
        label.image = frame_image
        if frame == 40: break                         #after 40 frames stop, or remove this line for the entire video

if __name__ == "__main__":

    root = tk.Tk()
    my_label = tk.Label(root)
    my_label.pack()
    thread = threading.Thread(target=stream, args=(my_label,))
    thread.daemon = 1
    thread.start()
    root.mainloop()


回答2:

And here is another nice working example of a player that I was trying to make with Tkinter and some sample code with Opencv module. This is a just an example idea, not finish code by any means.

import cv2
from Tkinter import *
from PIL import Image, ImageTk
import io
import threading
import os, sys

def resize(image):
    im = image
    new_siz = siz
    im.thumbnail(new_siz, Image.ANTIALIAS)
    return im

def size(event):
    global siz
    if siz == screenWH:
        siz = (200, 200)
    else:
        siz = screenWH
        win.state('zoomed')
    print 'size is: ', siz

def view_frame_video():
    vc = cv2.VideoCapture('test_video.flv')
    if vc.isOpened():
        rval , frame = vc.read()
    else:
        rval = False

    while rval:
        rval, frame = vc.read()
        img =Image.fromarray(frame)
        img = resize(img)
        imgtk = ImageTk.PhotoImage(img)
        lbl.config(image=imgtk)
        lbl.img = imgtk
        if stop == True: 
            vc.release()
            break      #stop the loop thus stops updating the label and reading imagge frames
        cv2.waitKey(1)
    vc.release()

def stop_():
    global stop
    stop = True

def play():
    stop = False
    t = threading.Thread(target=view_frame_video)
    t.start()



win = Tk()

stop = None
screenWH = (win.winfo_screenwidth(), win.winfo_screenheight())
siz = (200, 200)

Label(text='Press Play Button').pack()
frm_ = Frame(bg='black')
frm_.pack()
lbl = Label(frm_, bg='black')
lbl.pack(expand=True)
lbl.bind('<Double-Button-1>', size)

frm = Frame()
frm.pack()
Button(text='Play', command = play).pack(side=LEFT)
Button(text='Stop', command = stop_).pack(side=LEFT)

win.mainloop()