Подтвердить что ты не робот

Sawtooth tkinter mainloop длительность кадра?

Попытка анимации последовательности изображений PIL с использованием tkinter. График длительности кадров (мс) выглядит следующим образом: sawtooth frame duration

Кто-нибудь может подумать, что может вызвать этот колючий пильный рисунок?

Здесь a script для воспроизведения:

from PIL import Image, ImageTk
import Tkinter

import time
import sys

def generate_frames(n):
    """
    keep n under 101 * 101
    """
    out = []
    last_pil = None
    for i in range(n):
        if last_pil:
            pil_image = last_pil.copy()
        else:
            pil_image = Image.new('L', (101, 101), 255)   
        x = i / 101
        y = i % 101
        pil_image.load()[x, y] = 0
        out.append(ImageTk.PhotoImage(pil_image))
        last_pil = pil_image

    return out

def draw():
    FRAME_COUNT =5000

    master = Tkinter.Tk()

    w = Tkinter.Canvas(master, width=302, height=302)
    w.create_rectangle(49, 49, 252, 252)
    w.pack()

    frames = generate_frames(FRAME_COUNT)

    def draw_frame(f, canvas_image):
        print repr(time.time())
        frame = frames[f]
        if canvas_image is None:
            canvas_image = w.create_image((151, 151), image=frame, anchor='center')
        else:
            w.itemconfigure(canvas_image, image=frame)

        w.current_frame = frame  # save a reference
        next_frame = f + 1
        if next_frame < FRAME_COUNT:
            master.after(1, draw_frame, next_frame, canvas_image)
        else:
            sys.exit(0)

    master.after(10, draw_frame, 0, None)
    master.mainloop()


draw()

Чтобы увидеть график, вывод трубы через

import sys

last = None
for line in sys.stdin:
    value = float(line.strip()) * 1000
    if last is None:
        pass
    else:
        print (value - last)
    last = value

то через

from matplotlib import pyplot
import sys

X = []
Y = []

for index, line in enumerate(sys.stdin):
    line = line.strip()
    X.append(index)
    Y.append(float(line))

pyplot.plot(X, Y, '-')
pyplot.show()

Сделать его многопоточным не помогает:

enter image description here

class AnimationThread(threading.Thread):

    FRAME_COUNT = 5000

    def __init__(self, canvas):
        threading.Thread.__init__(self)
        self.canvas = canvas
        self.frames = generate_frames(self.FRAME_COUNT)

    def run(self):
        w = self.canvas
        frames = self.frames
        canvas_image = None
        for i in range(self.FRAME_COUNT):
            print repr(time.time())
            frame = frames[i]
            if canvas_image is None:
                canvas_image = w.create_image((151, 151), image=frame, anchor='center')
            else:
                w.itemconfigure(canvas_image, image=frame)
            w.current_frame = frame
            time.sleep(1 * .001)

def draw_threaded():
    FRAME_COUNT = 5000
    master = Tkinter.Tk()

    w = Tkinter.Canvas(master, width=302, height=302)
    w.create_rectangle(49, 49, 252, 252)
    w.pack()

    animation_thread = AnimationThread(w)
    animation_thread.start()

    master.mainloop()

    animation_thread.join()

draw_threaded()
4b9b3361

Ответ 1

Это очень похоже на такой интерференционный паттерн, когда смешиваются образцы 60 и 50 Гц:

Interference Pattern of competing 60 Hz and 50 Hz samples

(Оригинальный Wolfram | Альфа-сюжет)

Вероятно, это связано с наличием двух вещей при разных (но близких) частотах обновления. Это тот же самый тип вещей, который случается, когда вы пытаетесь снять телевизионный экран, и похоже, что черная полоса продолжает двигаться вниз по изображению или когда колесики автомобилей поворачиваются назад вокруг своих осей в автомобильных рекламных роликах. Это по существу расширение Moiré Effect.

Я не знаю, вызвано ли это драйверами видео и/или аппаратными средствами, но это почти наверняка вызвано вмешательством циклических шаблонов. Это очень похоже на то, что цикл GC мешает вашему циклу for (отсюда внезапное падение пилообразной волны, когда память освобождается и может быть выделена)