blitting opencv图片上的Kivy分割错误

Kivy segmentation fault on blitting opencv picture

我正在尝试将通过某些 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")

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

原代码如下:

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()

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

您的代码有几个问题:

  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. 个步骤一起使用。

希望对您有所帮助。