简体   繁体   English

Kivy 更新图像纹理时的奇怪行为

[英]Kivy strange behavior when it updates Image Texture

I am trying to update the Kivy Image.texture with the OpenCV image, and I am using a new thread to do it.我正在尝试使用 OpenCV 图像更新 Kivy Image.texture,并且我正在使用一个新线程来执行此操作。 I found some discussion that "the graphics operation should be in the main thread".我发现了一些关于“图形操作应该在主线程中”的讨论。 But still, I want to figure out why the code below works.但是,我仍然想弄清楚为什么下面的代码有效。

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.graphics.texture import Texture
import cv2
from threading import Thread
class MainApp(App):
    def __init__(self):
        super().__init__()
        self.layout = FloatLayout()
        self.image = Image()
        self.layout.add_widget(self.image)
        Thread(target=self.calculate).start()
    def build(self):
        return self.layout
    def calculate(self):
        img = cv2.imread("test.png")
        w, h = img.shape[1], img.shape[0]
        img = cv2.flip(img, flipCode=0)
        buf = img.tostring()
        texture = Texture(0, 0, 0).create(size=(w, h), colorfmt="bgr")
        texture.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')
        self.image.texture = texture
def main():
    Image(source='test.png')  # remove this line will froze the app
    MainApp().run()
if __name__ == "__main__":
    main()

If I remove this line:如果我删除这一行:

Image(source='test.png')

the app is frozen.该应用程序被冻结。 Can someone help me to understand why decalring an Image object outside the main loop will affect the MainApp running.有人可以帮助我理解为什么在主循环外贴上 Image 对象会影响 MainApp 的运行。

The "test.png" image can be any simple image, like below. “test.png”图像可以是任何简单的图像,如下所示。 You need to put the image in the same directory as this script.您需要将图像放在与此脚本相同的目录中。 在此处输入图片说明

Not sure exactly why that line affects your code, but the main problem is that not only is the GUI manipulation required to be done on the main thread, but also any blit_buffer() must also be done on the main thread.不确定为什么该行会影响您的代码,但主要问题是不仅需要在主线程上完成 GUI 操作,而且任何blit_buffer()也必须在主线程上完成。 So, a working version of your code (with the Image() removed) looks like this:因此,您的代码的工作版本Image()删除了Image() )如下所示:

from functools import partial

from kivy.app import App
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.graphics.texture import Texture
import cv2
from threading import Thread


class MainApp(App):
    def __init__(self):
        super().__init__()
        self.layout = FloatLayout()
        self.image = Image()
        self.layout.add_widget(self.image)
        Thread(target=self.calculate).start()

    def build(self):
        return self.layout

    def calculate(self):
        img = cv2.imread("test.png")
        w, h = img.shape[1], img.shape[0]
        img = cv2.flip(img, flipCode=0)
        buf = img.tostring()
        Clock.schedule_once(partial(self.do_blit, buf, w, h))

    def do_blit(self, buf, w, h, dt):
        texture = Texture(0, 0, 0).create(size=(w, h), colorfmt="bgr")
        texture.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')
        self.image.texture = texture

def main():
    # Image(source='test.png')  # remove this line will froze the app
    MainApp().run()

if __name__ == "__main__":
    main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM