Kivy相机在多个屏幕上 [英] Kivy Camera on multiple screen

查看:121
本文介绍了Kivy相机在多个屏幕上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试用kivy创建一个具有两个屏幕的简单应用程序,我需要在每个屏幕中同时加载一个自定义相机,而不需要同时进行操作.

I'm trying to create a simples app in kivy that have two screen and i need it load the a custom camera in each screen dont need do in same time.

我尝试在gui.kv显微镜小部件和主小部件中的凸轮中加载,但我误认为是错误

I tryed load in gui.kv the cam in microscope widget and main widget, but's retorn me a erro

self._buffer = frame.reshape(-1)
AttributeError: 'NoneType' object has no attribute 'reshape'

当我移除其中一台摄像机时,它可以工作,但是我需要两个屏幕中的摄像机

When i remove one of the cameras it work, but's i need the camera in both screen

按照我的代码

main.py

import kivy
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder

from camera import CameraCv

#--load cv camera
class Cam(CameraCv):
    pass


class Microscope(Screen):

    def salve(self):
        print('salved')


#-- main widget 
class Main(Screen):


     #-- take a pic       
    def capture(self):
       self.ids.cam.capture()
#--scene manager
class ScreenManager(ScreenManager):
    pass

#--load my.kv gui
GUI = Builder.load_file('gui.kv')

#--main app
class MyApp(App):

    def build(self):

        return GUI

if __name__ == "__main__":

    MyApp().run()

gui.kv

#:kivy 1.11.1
GridLayout:
    cols: 1
    ScreenManager:
        id: screen_manager

        Main:
            name: "main"
            id: main

        Microscope:
            name: "microscope"
            id: microscope

<Main>:
    BoxLayout:

        orientation:'vertical'


        Label:
            text: 'BLA BLA BLA BLA '
            bold: True
            color: [1,1,1,1]
            size_hint: (1, None)
            height: 100

        GridLayout:
            cols:2
            size: root.width, root.height
            padding: 10

            BoxLayout:
                orientation: 'vertical'
                Label:
                    text: 'CAMERA'
                    bold: True
                    color: [1,1,0,1]
                    # size_hint: (1, None)
                    # height: 160
                ToggleButton:
                    id: Cam
                    text:'Play/Pause'
                    on_press: cam.play = not cam.play
                    size_hint: (1, None)
                    height: 60


            Cam:
                id: cam
                play: True
                size_hint: (1, None)
                height: 350     



        BoxLayout:
            orientation:'horizontal'      

            Button:
                text:"MICROSCOPIO"            
                on_press:
                    cam.play = False
                    app.root.ids['screen_manager'].current = 'microscope'



                size_hint: (1, None)
                height: 70

<Microscope>:
    BoxLayout:
        orientation:'horizontal'
        # if i remove this cam it work in main screen
        Cam:
            id:cam
            resolution: (640, 480)
            play: False

        Button:
            text:'SALVAR IMAGEM'
            #on_press: root.save()
            size_hint:(1,None)
            height: 70


<Cam>:
    resolution: (640,480)
    play: False
    keep_ratio: True
    allow_stretch: True

    canvas.before:
        PushMatrix
        Rotate:
            angle: root.angle
            axis: 0, 0, 1
            origin: root.center
    canvas.after:
        PopMatrix   

camera.py

from kivy.uix.camera import Camera
from kivy.properties import BooleanProperty, NumericProperty
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
import kivy
import time
import numpy as np
import cv2
#import controle

class CameraCv(Camera):
    # - determine angle of camera
    angle = NumericProperty(0)

    def __init__(self, **kwargs):
        super(CameraCv, self).__init__(**kwargs)

        self.isAndroid = kivy.platform == "android"
        if self.isAndroid:
            self.angle = -90

    def change_index(self, *args):
        new_index = 1 if self.index == 0 else 0
        self._camera._set_index(new_index)
        self.index = new_index
        self.angle = -90 if self.index == 0 else 90

    #-- convert cv in kv texture
    def on_tex(self, *l):

        image = np.frombuffer(self.texture.pixels, dtype='uint8')
        image = image.reshape(self.texture.height, self.texture.width, -1)
        #image = controle.cropCircle(image,50,210)


        numpy_data = image.tostring()

        self.texture.blit_buffer(numpy_data, bufferfmt="ubyte", colorfmt='rgba')

        super(CameraCv, self).on_tex(self.texture)

    def get_cameras_count(self):
        cameras = 1

        if self.isAndroid:
            cameras = self._camera.get_camera_count()
        return cameras

    def capture(self,*args):

        #timestr = time.strftime("%Y%m%d_%H%M%S")
        #self.export_to_png("temp/IMG_{}.png".format(timestr))
        self.export_to_png('temp/temp.png')

首先,我感谢 Furas 的回答和示例,它非常有效,因此我只需要适应他的代码.

first, i thank Mr Furas for the answer and the example, it worked perfectly so I just had to adapt the his code.

所以现在的代码是:

camera.py

import numpy as np
import cv2
#import controle #--custom opncv methods

from kivy.uix.image import Image
from kivy.core.camera import Camera as CoreCamera
from kivy.properties import NumericProperty, ListProperty, BooleanProperty

# access to camera
core_camera = CoreCamera(index=0, resolution=(640, 480), stopped=True)

# Widget to display camera
class CameraCv(Image):
    '''Camera class. See module documentation for more information.
    '''

    play = BooleanProperty(True)
    '''Boolean indicating whether the camera is playing or not.
    You can start/stop the camera by setting this property::
        # start the camera playing at creation (default)
        cam = Camera(play=True)
        # create the camera, and start later
        cam = Camera(play=False)
        # and later
        cam.play = True
    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults to
    True.
    '''

    index = NumericProperty(-1)
    '''Index of the used camera, starting from 0.
    :attr:`index` is a :class:`~kivy.properties.NumericProperty` and defaults
    to -1 to allow auto selection.
    '''

    resolution = ListProperty([-1, -1])
    '''Preferred resolution to use when invoking the camera. If you are using
    [-1, -1], the resolution will be the default one::
        # create a camera object with the best image available
        cam = Camera()
        # create a camera object with an image of 320x240 if possible
        cam = Camera(resolution=(320, 240))
    .. warning::
        Depending on the implementation, the camera may not respect this
        property.
    :attr:`resolution` is a :class:`~kivy.properties.ListProperty` and defaults
    to [-1, -1].
    '''

    def __init__(self, **kwargs):
        self._camera = None
        super(CameraCv, self).__init__(**kwargs)  # `CameraCv` instead of `Camera`
        if self.index == -1:
            self.index = 0
        on_index = self._on_index
        fbind = self.fbind
        fbind('index', on_index)
        fbind('resolution', on_index)
        on_index()

    def on_tex(self, *l):

        image = np.frombuffer(self.texture.pixels, dtype='uint8')
        image = image.reshape(self.texture.height, self.texture.width, -1)
        #image = controle.cropCircle(image,50,210) #custom opencv method
        numpy_data = image.tostring()

        self.texture.blit_buffer(numpy_data, bufferfmt="ubyte", colorfmt='rgba')
        self.canvas.ask_update()

    def _on_index(self, *largs):
        self._camera = None
        if self.index < 0:
            return
        if self.resolution[0] < 0 or self.resolution[1] < 0:
            return

        self._camera = core_camera # `core_camera` instead of `CoreCamera(index=self.index, resolution=self.resolution, stopped=True)`

        self._camera.bind(on_load=self._camera_loaded)
        if self.play:
            self._camera.start()
            self._camera.bind(on_texture=self.on_tex)

    def _camera_loaded(self, *largs):
        self.texture = self._camera.texture
        self.texture_size = list(self.texture.size)

    def on_play(self, instance, value):
        if self._camera:
            return
        if not value:
            self._camera.start()
        else:
            self._camera.stop()

gui.kv

#:kivy 1.11.1
GridLayout:
    cols: 1
    ScreenManager:
        id: screen_manager

        Main:
            name: "main"
            id: main

        Microscope:
            name: "microscope"
            id: microscope

<Main>:
    BoxLayout:

        orientation:'vertical'


        Label:
            text: 'BLA BLA BLA BLA '
            bold: True
            color: [1,1,1,1]
            size_hint: (1, None)
            height: 100

        GridLayout:
            cols:2
            size: root.width, root.height
            padding: 10
            id:box1
            BoxLayout:

                orientation: 'vertical'
                Label:
                    text: 'CAMERA'
                    bold: True
                    color: [1,1,0,1]
                    # size_hint: (1, None)
                    # height: 160
                ToggleButton:

                    text:'Play/Pause'
                    on_press: camera1.play = not camera1.play
                    size_hint: (1, None)
                    height: 60


            CameraCv:
                id: camera1
                resolution: (640,480)
                size_hint: (1, None)
                height: 350

        BoxLayout:
            orientation:'horizontal'          
            Button:
                text:"MICROSCOPIO"            
                on_press:        
                    app.root.ids['screen_manager'].current = 'microscope'                         
                size_hint: (1, None)
                height: 70

<Microscope>:
    BoxLayout:
        id: box2
        orientation:'vertical'
        # if i remove this cam it work in main screen
        CameraCv:
            id: camera2
            resolution: (640,480)
            size_hint: (1, None)
            height: 350
            keep_ratio: True
            allow_stretch: True

        Button:
            text:'image salve'
            on_press: app.root.ids['screen_manager'].current = 'main'
            size_hint:(1,None)
            height: 70


<CameraCv>:

    keep_ratio: True
    allow_stretch: True

    canvas.before:
        PushMatrix
        Rotate:
            axis: 0, 0, 1
            origin: root.center
    canvas.after:
        PopMatrix 

main.py

import kivy
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder

from camera import CameraCv

class Microscope(Screen):

    pass

#-- main widget 
class Main(Screen):
    pass

#--scene manager
class ScreenManager(ScreenManager):
    pass

#--load my.kv gui
GUI = Builder.load_file('gui.kv')

#--main app
class MyApp(App):

    def build(self):

        return GUI

if __name__ == "__main__":

    MyApp().run()

现在可以完美地工作了

推荐答案

我获取了类Camera

https://github.com/kivy/kivy /blob/master/kivy/uix/camera.py

并创建自己的类MyCamera

我在类MyCamera之外创建了CoreCamera的实例,并且MyCamera的所有实例都使用CoreCamera的相同一个实例

I create instance of CoreCamera outside class MyCamera and all instances of MyCamera use the same one instance of CoreCamera

core_camera = CoreCamera(index=0, resolution=(640, 480), stopped=True)

class MyCamera(Image):

    def _on_index(self, *largs):
        # ... 

        self._camera = core_camera

代替

class MyCamera(Image):

    def _on_index(self, *largs):
        # ... 

        self._camera = CoreCamera(index=self.index, resolution=self.resolution, stopped=True)

仍然存在一些问题

    CoreCamera中的
  • 被设置为分辨率,并且所有MyClass都使用相同的分辨率-但它们仍然需要gui.kv中的resolution: (640, 480)(但是他们不使用该值)
  • play为所有MyClass启动/停止动画,因为CoreCamera控制了它.
  • in CoreCamera is set resolution and all MyClass use the same resolution - but they still need resolution: (640, 480) in gui.kv (but they don't use this value)
  • play starts/stops animation for all MyClass because CoreCamera control it.

我使用了

https://kivy.org/doc/stable/examples/gen__camera__main__py.html

使用两个显示同一摄像机的小部件创建示例

to create example with two widgets displaying the same camera

# https://kivy.org/doc/stable/examples/gen__camera__main__py.html
# https://github.com/kivy/kivy/blob/master/kivy/uix/camera.py

from kivy.uix.image import Image
from kivy.core.camera import Camera as CoreCamera
from kivy.properties import NumericProperty, ListProperty, BooleanProperty

# access to camera
core_camera = CoreCamera(index=0, resolution=(640, 480), stopped=True)

# Widget to display camera
class MyCamera(Image):
    '''Camera class. See module documentation for more information.
    '''

    play = BooleanProperty(True)
    '''Boolean indicating whether the camera is playing or not.
    You can start/stop the camera by setting this property::
        # start the camera playing at creation (default)
        cam = Camera(play=True)
        # create the camera, and start later
        cam = Camera(play=False)
        # and later
        cam.play = True
    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults to
    True.
    '''

    index = NumericProperty(-1)
    '''Index of the used camera, starting from 0.
    :attr:`index` is a :class:`~kivy.properties.NumericProperty` and defaults
    to -1 to allow auto selection.
    '''

    resolution = ListProperty([-1, -1])
    '''Preferred resolution to use when invoking the camera. If you are using
    [-1, -1], the resolution will be the default one::
        # create a camera object with the best image available
        cam = Camera()
        # create a camera object with an image of 320x240 if possible
        cam = Camera(resolution=(320, 240))
    .. warning::
        Depending on the implementation, the camera may not respect this
        property.
    :attr:`resolution` is a :class:`~kivy.properties.ListProperty` and defaults
    to [-1, -1].
    '''

    def __init__(self, **kwargs):
        self._camera = None
        super(MyCamera, self).__init__(**kwargs)  # `MyCamera` instead of `Camera`
        if self.index == -1:
            self.index = 0
        on_index = self._on_index
        fbind = self.fbind
        fbind('index', on_index)
        fbind('resolution', on_index)
        on_index()

    def on_tex(self, *l):
        self.canvas.ask_update()

    def _on_index(self, *largs):
        self._camera = None
        if self.index < 0:
            return
        if self.resolution[0] < 0 or self.resolution[1] < 0:
            return

        self._camera = core_camera # `core_camera` instead of `CoreCamera(index=self.index, resolution=self.resolution, stopped=True)`

        self._camera.bind(on_load=self._camera_loaded)
        if self.play:
            self._camera.start()
            self._camera.bind(on_texture=self.on_tex)

    def _camera_loaded(self, *largs):
        self.texture = self._camera.texture
        self.texture_size = list(self.texture.size)

    def on_play(self, instance, value):
        if not self._camera:
            return
        if value:
            self._camera.start()
        else:
            self._camera.stop()


from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
import time

Builder.load_string('''
<CameraClick>:
    orientation: 'vertical'
    MyCamera:
        id: camera1
        resolution: (640, 480)
    MyCamera:
        id: camera2
        resolution: (640, 480)
    ToggleButton:
        text: 'Play'
        on_press: camera1.play = not camera1.play
        size_hint_y: None
        height: '48dp'
    Button:
        text: 'Capture'
        size_hint_y: None
        height: '48dp'
        on_press: root.capture()
''')


class CameraClick(BoxLayout):
    def capture(self):
        '''
        Function to capture the images and give them the names
        according to their captured time and date.
        '''
        camera = self.ids['camera1']
        timestr = time.strftime("%Y%m%d_%H%M%S")
        camera.export_to_png("IMG_{}.png".format(timestr))
        print("Captured")

class TestCamera(App):

    def build(self):
        return CameraClick()

TestCamera().run()

这篇关于Kivy相机在多个屏幕上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆