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()
Ответы
Ответ 1
Это очень похоже на такой интерференционный паттерн, когда смешиваются образцы 60 и 50 Гц:
![Interference Pattern of competing 60 Hz and 50 Hz samples]()
(Оригинальный Wolfram | Альфа-сюжет)
Вероятно, это связано с наличием двух вещей при разных (но близких) частотах обновления. Это тот же самый тип вещей, который случается, когда вы пытаетесь снять телевизионный экран, и похоже, что черная полоса продолжает двигаться вниз по изображению или когда колесики автомобилей поворачиваются назад вокруг своих осей в автомобильных рекламных роликах. Это по существу расширение Moiré Effect.
Я не знаю, вызвано ли это драйверами видео и/или аппаратными средствами, но это почти наверняка вызвано вмешательством циклических шаблонов. Это очень похоже на то, что цикл GC мешает вашему циклу for
(отсюда внезапное падение пилообразной волны, когда память освобождается и может быть выделена)