4

I am using Kivy with a webcam. I have followed this example by @Arnav of using opencv to form and display the camera as a widget. I have "extended" the layout within python it to add two buttons as a test, in preparation for a more complicated layout.

class CamApp(App):
    def build(self):
        self.capture = cv2.VideoCapture(0)
        self.my_camera = KivyCamera(capture=self.capture, fps=30,resolution=(1920,1080))
        root = BoxLayout(orientation = 'vertical')
        root.add_widget(self.my_camera,1)
        box2 = BoxLayout(orientation = 'vertical')
        btn1 = Button(text='Hello world 1')
        btn2 = Button(text='Hello world 2')
        box2.add_widget(btn1)
        box2.add_widget(btn2)
        root.add_widget(box2, 0)
        return root
        #return Builder.load_string(kv)

While this works I would prefer to move the UI components out of python and into a kv language file. The problem is knowing how to "describe" the self.my_camera in the kv file?

I am not sure whether to inherit the KivyCamera class as a widget within the kv file i.e.

kv = '''
<Cam1@KivyCamera>:
    texture: self.my_camera
    resolution: (1920, 1080)
    pos: self.pos
    size: self.size

Or whether to use the canvas widget

<MyWidget>:
    canvas:
        Rectangle:
            source: self.my_camera
            pos: self.pos
            size: self.size

I have tried other "hacked" implementations, but in all cases the problem is linking through the self.my_camera into the kv file.

Any suggestions?

Community
  • 1
  • 1
tomdertech
  • 497
  • 1
  • 9
  • 27

1 Answers1

4

Perhaps this example may help you.

# Import 'kivy.core.text' must be called in entry point script
# before import of cv2 to initialize Kivy's text provider.
# This fixes crash on app exit.

import kivy.core.text
import cv2
from kivy.app import App
from kivy.base import EventLoop
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.graphics.texture import Texture
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window


class KivyCamera(Image):

    def __init__(self, **kwargs):
        super(KivyCamera, self).__init__(**kwargs)
        self.capture = None

    def start(self, capture, fps=30):
        self.capture = capture
        Clock.schedule_interval(self.update, 1.0 / fps)

    def stop(self):
        Clock.unschedule_interval(self.update)
        self.capture = None

    def update(self, dt):
        return_value, frame = self.capture.read()
        if return_value:
            texture = self.texture
            w, h = frame.shape[1], frame.shape[0]
            if not texture or texture.width != w or texture.height != h:
                self.texture = texture = Texture.create(size=(w, h))
                texture.flip_vertical()
            texture.blit_buffer(frame.tobytes(), colorfmt='bgr')
            self.canvas.ask_update()


capture = None


class QrtestHome(BoxLayout):

    def init_qrtest(self):
        pass

    def dostart(self, *largs):
        global capture
        capture = cv2.VideoCapture(0)
        self.ids.qrcam.start(capture)

    def doexit(self):
        global capture
        if capture != None:
            capture.release()
            capture = None
        EventLoop.close()


class qrtestApp(App):

    def build(self):
        Window.clearcolor = (.4,.4,.4,1)
        Window.size = (400, 300)
        homeWin = QrtestHome()
        homeWin.init_qrtest()
        return homeWin

    def on_stop(self):
        global capture
        if capture:
            capture.release()
            capture = None

qrtestApp().run()

and the kv file:

<QrtestHome>:

    BoxLayout:
        orientation: "vertical"

        Label:
            height: 20
            size_hint_y: None
            text: 'Testing the camera'

        KivyCamera:
            id: qrcam

        BoxLayout:
            orientation: "horizontal"
            height: 20
            size_hint_y: None

            Button:
                id: butt_start
                size_hint: 0.5,1
                text: "start"
                on_press: root.dostart()

            Button:
                id: butt_exit
                text: "quit"
                size_hint: 0.5,1
                on_press: root.doexit()
Bill Bridge
  • 821
  • 1
  • 9
  • 30
  • Just tried your suggestion, however, it just produces a light grey screen with nothing else. Assuming this is from `Window.clearcolor = (.4,.4,.4,1)` – tomdertech Nov 29 '16 at 14:30
  • This is probably caused by the filenames of your. py and .kv files. Just name these qrtest.py and qrtest.kv. And try again. – Bill Bridge Nov 29 '16 at 16:42
  • That works! Although after sometime I am getting a memory exception. `[WARNING] [GL ] BGRA texture support is not available Exception Exception: Exception('Unable to allocate memory for texture (size is 921600)',) in 'kivy.graphics.texture.Texture.allocate' ignored` should I raise another question? – tomdertech Nov 29 '16 at 16:57
  • I have had it running for 30 mins without any issues. So can't reproduce your problem. – Bill Bridge Nov 29 '16 at 17:59
  • Please could you tick the answer if it was the answer you were looking for? – Bill Bridge Nov 30 '16 at 18:04