Эффективно (в режиме реального времени) отображать изображение PIL в tkinter?

В настоящее время я пишу программу, которая должна позволить пользователю рисовать простые линии, а также рисовать прямоугольники для выбора области. Раньше я использовал холст tkinter, но у него была производительность с некоторыми операциями, а также утечка памяти, поэтому вместо этого я пытаюсь использовать подушку для рисования.

Вот мой код для рисования прямоугольника:


  def drawRect(self, start, end):

        x1 = end[0]
        y1 = end[1]

        x0 = start[0]
        y0 = start[1]

        t0 = time()
        t = time()
        
        #size of image is roughly between 1000x1000 to 1080p
        rectLayer = Image.new("RGBA", self.backgroundImage.size)
        rectDraw = ImageDraw.Draw(rectLayer)
        rectDraw.rectangle([start, end], fill="#00000080")
        rectDraw.line((x0, y0, x1, y0, x1, y1, x0, y1, x0, y0), fill="#ffffff", width=1)
        print("drawing: ", time() - t)
        t = time()

        displayImage = Image.alpha_composite(self.backgroundImage, self.linesLayer)
        displayImage.alpha_composite(rectLayer, (0, 0), (0, 0))
        print("image blend: ", time() - t)
        t = time()

        self.photoImage = ImageTk.PhotoImage(displayImage)
        print("photoImage convert: ", time() - t)
        t = time()

        self.imageContainer.configure(image=self.photoImage)  # imageContainer is a Label
        print("label config: ", time() - t)
        print("total: ", time() - t0)

'''
Output for drawing a single rect:

    drawing:  0.001994609832763672
    image blend:  0.009583711624145508
    photoImage convert:  0.0139617919921875
    label config:  0.02194380760192871
    total:  0.049475669860839844
'''

Проблема, с которой я столкнулся, заключается в том, что, хотя PIL работает быстро, отображение этого изображения - нет. Со времени моего профилирования рисование прямоугольника занимало очень мало времени, а вот преобразование изображения в фотоизображение, затем установка его как изображения этикетки заняло много времени. Я надеялся, что эти функции могут выполняться не менее 60 раз или около того в секунду, чтобы программа работала более плавно. Есть ли способ, которым я могу отображать изображения быстрее?


person goldenotaste    schedule 10.05.2021    source источник
comment
Если вам нужна производительность, то нужно взять tkinter и выкинуть в ближайшую мусорку. Tkinter ВСЕГДА был хаком. Вы можете не знать, что tkinter — это библиотека, написанная на языке под названием tcl. Python должен запускать свой собственный интерпретатор tcl внутри интерпретатора Python. Все, что вы делаете в tkinter, заканчивается запуском команды в интерпретаторе tcl. Выбросьте это и используйте настоящую библиотеку пользовательского интерфейса, такую ​​как wxPython или Qt. Если все, что вам нужно, это изображения, даже OpenCV может это сделать.   -  person Tim Roberts    schedule 10.05.2021
comment
У холста нет утечки памяти. Что вы имеете в виду под раньше я использовал холст tkinter, но у него была производительность при некоторых операциях, а также утечка памяти?   -  person Bryan Oakley    schedule 10.05.2021
comment
@BryanOakley Возможно, мое понимание утечки памяти неверно: p Насколько я понимаю, когда нарисованный объект удаляется с холста, холст не освобождает память, которую раньше удерживал объект. Кроме того, еще одна проблема, с которой я столкнулся с холстом, заключается в том, что после рисования многих линий изменение существующих линий занимает много времени (например, масштабирование всего холста).   -  person goldenotaste    schedule 10.05.2021
comment
Ok. Объекты освобождаются, но идентификаторы не используются повторно, поэтому да, если вы продолжаете создавать и удалять объекты вместо повторного использования идентификаторов, у вас в конечном итоге закончатся идентификаторы.   -  person Bryan Oakley    schedule 10.05.2021
comment
@TimRoberts: tkinter более чем достаточно для очень большого количества задач. Хотя он не подходит для создания новой версии фотошопа или дума, он очень хорошо работает для того, что нужно большинству людей. Tkinter — это действительно настоящая библиотека пользовательского интерфейса, разработанная с самого начала для встраивания в другие продукты.   -  person Bryan Oakley    schedule 10.05.2021
comment
Вы можете использовать self.photoImage.paste(displayImage) для замены self.photoImage = ImageTk.PhotoImage(...) и self.imageContainer.configure(...).   -  person acw1668    schedule 10.05.2021
comment
@BryanOakley Я не согласен. Тк 30 лет, и это свидетельствует о древнем наследии. Поскольку он построен на столь же древнем tcl, он не может двигаться вперед. Это поощряет плохие методы программирования. Это только на Python, потому что в то время не было альтернатив. Теперь есть альтернативы.   -  person Tim Roberts    schedule 10.05.2021
comment
@acw1668 acw1668 .paste(displayImage) был немного лучше (0,025 с), так как требуется на 1 вызов tcl меньше   -  person goldenotaste    schedule 10.05.2021
comment
@BryanOakley, что бы вы порекомендовали для моего варианта использования? Для холста tkinter повторное использование идентификатора кажется подходящим для рисования квадратов, но когда мне нужно изменить все линии, например, при изменении размера холста или нужно переключить видимость линии. Для холста с разумным количеством каракулей на нем изменение линий начинает занимать много времени (~ полсекунды). Теперь, когда я перешел к рендерингу линий с помощью PIL, я столкнулся с фотоизображением и установкой изображения для метки. Возможно, простая программа рисования в tkinter нежизнеспособна?   -  person goldenotaste    schedule 10.05.2021
comment
Не уверен, что именно вы пытаетесь сделать, но, возможно, вы могли бы использовать OpenCV с обратными вызовами для рисования, как я сделал здесь — я знаю, что это C, но в Python есть прямой эквивалент, если концепция работает stackoverflow.com/a/42297587/2836621   -  person Mark Setchell    schedule 14.05.2021
comment
@TimRoberts Привет, Тим. Не могли бы вы назвать некоторые из лучших альтернатив, на которые вы намекаете? Спасибо.   -  person Mark Setchell    schedule 14.05.2021
comment
@MarkSetchell Я так и сделал в своем первоначальном комментарии.   -  person Tim Roberts    schedule 14.05.2021
comment
@TimRoberts А, хорошо, теперь я понимаю, что ты сказал. Спасибо.   -  person Mark Setchell    schedule 14.05.2021