【问题标题】:kivy.Image not updating when ran from another thread in a while loopkivy.Image 在while循环中从另一个线程运行时不更新
【发布时间】:2019-10-30 22:04:14
【问题描述】:

我的班级中有两个 Kivy.Image 对象,主图像显示来自网络摄像头的主流,另一个显示从主流中收集的训练样本,该过程可以完成,但我们首先在线程之前运行它它阻止了我的应用程序/导致它冻结,然后我引入了它运行的线程,但它没有更新主流和显示正在收集的训练样本的线程。

我在 python 中尝试了多种多线程方式,但似乎我无法弄清楚

    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.button import Button
    from kivy.app import App
    import threading

    import cv2
    from kivy.uix.image import Image
    from Clock_In import face as f
    class example(App):

        def build(self):

            layout = FloatLayout()
            self.user = Image()
            self.trainingSample = Image(source="C://Users//SELINA//Project Clock-in//data//Images//face_avatar.jpg")

            self.user.allow_stretch = True
            self.user.keep_ratio = True

            self.user.size_hint_x = 0.5
            self.user.size_hint_y = 0.9


            self.user.pos_hint = {"x":0.06, "y":0.2}

            self.trainingSample.allow_stretch =False
            self.trainingSample.keep_ratio = False

            self.trainingSample.size_hint_x = None
            self.trainingSample.size_hint_y = None

            self.trainingSample.width =160
            self.trainingSample.height=160

            self.face_Recognition = f.Recognition()
            self.capture = cv2.VideoCapture(0)
            self.trainingSample.pos_hint = {"x":0.6, "y": 0.68}
    self.btnText = Button(text="Collect Data", font_size=12, size_hint_y=None, size_hint_x=None, width = 150, height = 30, pos_hint= {"x":0.4, "y":0.6})
            self.btnText.bind(on_press=self.cdata)



            layout.add_widget(self.user)
            layout.add_widget(self.trainingSample)
            layout.add_widget(self.btnText)

            return layout
     #I have tried this
        def cdata(self, instance):
            threading.Thread(
              target=self.another, daemon=True
            ).start()

def another(self, dt):
    (self.im_width, self.im_height) = (160, 160)



    self.count = 0
    self.count_max = 10



    while self.count < self.count_max:

        ret = False

        while(not ret):
            (ret, frame) = self.capture.read()
            if(not ret):
                print("Couldn't run trying again")


                height, width, channels = frame.shape

                frame = cv2.flip(frame, 1, 0)
                normal = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                normal = cv2.cvtColor(normal, cv2.COLOR_RGB2BGR)

                if self.face_Recognition.identify(frame) is None:
                    faces = None


                if self.face_Recognition.identify(frame) is not None:
                    faces, points = self.face_Recognition.identify(frame)



                if faces is not None:
                    for face in faces:
                            face_bb = face.bounding_box.astype(int)
                            yourface = normal[max(0, face_bb[1]):min(face_bb[3], normal.shape[0]-1), max(0, face_bb[0]):min(face_bb[2], normal.shape[1]-1)]


                            face_resize = cv2.resize(yourface, (self.im_width, self.im_height))
                            cv2.rectangle(frame, (face_bb[0], face_bb[1]), (face_bb[2], face_bb[3]),(220,20,60), 1)
                            cv2.putText(frame, 'user', (face_bb[0], face_bb[3] + 20),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (220,20,60),1, cv2.LINE_AA)




                            print("Saving training sample " + str(self.count)+"/"+str(self.count_max))


                            cv2.imwrite('example' + str(self.count) + '.png', face_resize)

                            self.trainingSample.source = 'example' + str(self.count) + '.png'

                            self.count += 1

                    buf1 = cv2.flip(frame, 0)

                    buf = buf1.tostring()

                    texture1 = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
                    texture1.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')


                    self.user.texture = texture1





if __name__ == '__main__':
    example().run()

我希望 self.user 更新为它获取用户面部图像,并在 while 循环的另一个线程中显示用户在训练样本图像中拍摄的图像样本,我使用来自 github 的 david sandberg facenet,如果您可以尝试使用 haarcascade 或其他简单的方法,问题不在于识别,而是在收集训练样本时,kivy 小部件会实时更新给用户

【问题讨论】:

  • @eyllanesc 我尝试在上面实现它,我想知道您是否有时间实现 facenet 以进行人脸识别
  • 不要使用Thread.run()。那不是在做多线程。使用Thread.start()。并且在你的coll()方法中,使用Clock.schedule_once()调用一个简单的方法来设置self.user.texture,这需要在主线程上完成。
  • @John Anderson 我按照你说的做了,它完全破坏了 gui

标签: python kivy


【解决方案1】:

您修改后的代码仍然没有真正使用多线程,因为您的新 coll() 方法只是安排 another() 方法在主线程上运行。

要实际使用多线程,请将胆量放回coll() 方法中,以便它实际上在新线程中运行。并将self.user.texture = texture1 替换为Clock.schedule_once() 调用。这是我认为它应该看起来的样子(但我没有测试过这段代码):

def cdata(self, instance):
    threading.Thread(
      target=self.coll, daemon=True).start()    

def coll(self):
    (self.im_width, self.im_height) = (160, 160)    
    self.count = 0
    self.count_max = 10  

    while self.count < self.count_max:    
        ret = False

        while(not ret):
            (ret, frame) = self.capture.read()
            if(not ret):
                print("Couldn't run trying again") 
                height, width, channels = frame.shape
                frame = cv2.flip(frame, 1, 0)
                normal = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                normal = cv2.cvtColor(normal, cv2.COLOR_RGB2BGR)

                if self.face_Recognition.identify(frame) is None:
                    faces = None
                if self.face_Recognition.identify(frame) is not None:
                    faces, points = self.face_Recognition.identify(frame)
                if faces is not None:
                    for face in faces:
                            face_bb = face.bounding_box.astype(int)
                            yourface = normal[max(0, face_bb[1]):min(face_bb[3], normal.shape[0]-1), max(0, face_bb[0]):min(face_bb[2], normal.shape[1]-1)]
                            face_resize = cv2.resize(yourface, (self.im_width, self.im_height))
                            cv2.rectangle(frame, (face_bb[0], face_bb[1]), (face_bb[2], face_bb[3]),(220,20,60), 1)
                            cv2.putText(frame, 'user', (face_bb[0], face_bb[3] + 20),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (220,20,60),1, cv2.LINE_AA)
                            print("Saving training sample " + str(self.count)+"/"+str(self.count_max))
                            cv2.imwrite('example' + str(self.count) + '.png', face_resize)    
                            self.trainingSample.source = 'example' + str(self.count) + '.png'    
                            self.count += 1    
                    buf1 = cv2.flip(frame, 0)    
                    buf = buf1.tostring()    
                    texture1 = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
                    texture1.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')  
                    #self.user.texture = texture1
                    Clock.schedule_once(partial(self.setUserTexture, texture1))

def setUserTexture(self, newTexture, dt)
    self.user.texture = newTexture

这是显示图形用户界面的图片

【讨论】:

  • 好吧,我确实尝试了您对self.user.texture 的建议编辑,它仍然没有在GUI 中更改或更新,它只是变成黑色,但对于self.trainingSample Image 对象,我确实应用了Clock.schedule_once对它来说,它现在随着样本的采集而更新。
猜你喜欢
  • 2021-05-27
  • 2021-02-09
  • 2014-08-03
  • 2018-09-06
  • 2015-01-04
  • 1970-01-01
  • 1970-01-01
  • 2012-10-28
  • 1970-01-01
相关资源
最近更新 更多