【问题标题】:Kivy segmentation fault on blitting opencv picture在 blitting opencv 图片上出现 Kivy 分割错误
【发布时间】:2020-06-02 08:45:56
【问题描述】:

我正在尝试将通过 aliexpress EasyCap 捕获的外部摄像头中的视频投射到我的 kivy 应用程序中。我遇到的一个问题是在尝试进行分段错误时崩溃

texture = Texture.create(size=(frame.shape[0], frame.shape[1]))

我发现问题出在kivy's side。它有时无法创建 NPOT 纹理。因此,我将其更改为 POT 形状并将可能的内容复制到另一个 numpy 数组中。

flipped = cv2.flip(frame, 0)
buf = np.zeros((512, 512, 3), dtype=np.uint8)
for i in range(min(frame.shape[0], 512)):
   for j in range(min(frame.shape[1], 512)):
      buf[i, j] = flipped[i, j]
buf = buf.tostring()
texture = Texture.create(size=(512, 512))
texture.blit_buffer(buf, colorfmt="bgr", bufferfmt="ubyte")
self.texture = texture

但它仍然会因以下行中的旧分段错误而崩溃:

texture.blit_buffer(buf, colorfmt="bgr", bufferfmt="ubyte")

如果相关,则在 buf.tostring() 之前的 cv2.imshow("image", buf) 正确显示图像。

这是原始代码:

from kivy.app import App
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.graphics.texture import Texture
import cv2
import threading
from time import sleep
import numpy as np

class KivyCamera(Image):
   def __init__(self, **kwargs):
      super(KivyCamera, self).__init__(**kwargs)
      self.fps = 30
      self.capture = cv2.VideoCature(0)
      threading.Thread(target=self.update).start()

   def update(self):
      while True:
         ret, frame = self.capture.read()
         if ret:
            buf = cv2.flip(frame, 0).tostring()
            texture = Texture.create(size=(frame.shape[0], frame.shape[1])
            texture.blit_buffer(buf, colorfmt="bgr", bufferfmt="ubyte")
            self.texture = texture
         sleep(1.0 / self.fps)


class CamApp(App):
   def build(self):
         return KivyCamera()

if __name__ == "__main__":
   CamApp().run()

【问题讨论】:

    标签: python kivy opencv-python


    【解决方案1】:

    您的代码存在一些问题:

    1. GUI 更新应始终在主线程中完成,如John Anderson 所示。因此,应该通过Clock 调度调用update() 函数,而不是单独的线程。
    2. Texture.create 语句中的size 元组应颠倒过来,应添加colorfmt="bgr"。应该是:texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt="bgr")
    3. 没有定义布局。 BoxLayout 等布局应添加为 Image 小部件的占位符。

    以下是修改后的代码工作版本:

    from kivy.app import App
    from kivy.uix.image import Image
    from kivy.uix.boxlayout import BoxLayout
    from kivy.clock import Clock
    from kivy.graphics.texture import Texture
    import cv2
    
    class KivyCamera(BoxLayout):
       def __init__(self, **kwargs):
          super(KivyCamera, self).__init__(**kwargs)
          self.img1=Image()
          self.add_widget(self.img1)
          self.capture = cv2.VideoCapture(0)
          Clock.schedule_interval(self.update, 1.0/33.0)
    
       def update(self, *args):
         ret, frame = self.capture.read()
         if ret:
            buf = cv2.flip(frame, 0).tostring()
            texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt="bgr")
            texture.blit_buffer(buf, colorfmt="bgr", bufferfmt="ubyte")
            self.img1.texture = texture
    
    class CamApp(App):
       def build(self):
             return KivyCamera()
    
    if __name__ == "__main__":
       CamApp().run()
    

    while 循环被移除,Clock.schedule_interval1 / 33. 步骤一起使用。

    希望这会有所帮助。

    【讨论】:

    • 谢谢,确实很有帮助!现在,我使用@mainthread 在单独的函数中创建了一个 512x512 纹理,并使用单独创建的 numpy 数组对其进行了更新,该数组由原始图像填充。它奏效了!然而,你能解释一下为什么纹理大小是相反的吗?
    • OpenCV 返回图像的 numpy 数组。形状按高度、宽度和通道的顺序返回元组。但是在 Kivy Texture 中,大小需要按顺序宽度和高度的元组。因此 shape[0] 对应于图像的高度,而 shape[1] 对应于图像的宽度。
    【解决方案2】:

    没有很好的记录,但我相信Texture 操作(特别是blit_buffer())必须在主线程上完成。您的update() 方法正在另一个线程中运行,因此请使用Clock.schedule_once() 调用在主线程中执行Texture 操作(和self.texture = texture)的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-22
      • 1970-01-01
      • 2014-04-06
      • 1970-01-01
      • 1970-01-01
      • 2019-04-22
      相关资源
      最近更新 更多