Search code examples
pythoncamerakivy

Two differents screens with camera for each one


In my app, I can't creat 2 differents screens with camera for each one. However, I can creat only one screen with camera

my Python code

from kivymd.app import MDApp
from kivy.uix.camera import Camera
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition

class ZTest(MDApp):
    def build(self):
        manager = ScreenManager()
        manager.add_widget(FirstLayout(name='First'))
        manager.add_widget(SecondLayout(name='Second'))
        manager.add_widget(ThirdLayout(name='Third'))
        return manager


class FirstLayout(Screen):
    def btn1(self):
        self.manager.transition = SlideTransition(direction="left")
        self.manager.current = 'Second'

    def btn2(self):
        self.manager.transition = SlideTransition(direction="left")
        self.manager.current = 'Third'


class SecondLayout(Screen):
    cam = Camera()

    def on_enter(self, *largs):
        self.manager.get_screen('Second').ids.cam1.clear_widgets()
        self.cam.play = True
        self.manager.get_screen('Second').ids.cam1.add_widget(self.cam)

    def press(self):
        self.cam.play = False
        self.manager.transition = SlideTransition(direction="right")
        self.manager.current = 'First'


class ThirdLayout(Screen):
    cam = Camera()

    def on_enter(self, *largs):
        self.manager.get_screen('Third').ids.cam2.clear_widgets()
        self.cam.play = True
        self.manager.get_screen('Third').ids.cam2.add_widget(self.cam)

    def press(self):
        self.cam.play = False
        self.manager.transition = SlideTransition(direction="right")
        self.manager.current = 'First'


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

My Kivy code 'Ztest.kv'

<FirstLayout>:
    MDBoxLayout:
        orientation: 'vertical'
        spacing: 10
        size_hint_y: 0.5

        MDBoxLayout:
            size_hint_y: 0.5

            MDRaisedButton:
                id: B1
                text:"Second"
                md_bg_color: (0, 0, 1, 1)
                font_size: 40
                size_hint: (0.8, None)
                pos_hint: {'center_x':0.5}
                on_press: root.btn1()

        MDBoxLayout:
            size_hint_y: 0.5

            MDRaisedButton:
                id: B2
                text:"Third"
                md_bg_color: (1, 0, 0, 1)
                font_size: 40
                size_hint: (0.8, None)
                pos_hint: {'center_x':0.5}
                on_press: root.btn2()


<SecondLayout>:
    BoxLayout:
        orientation: 'vertical'

        MDToolbar:
            id: bar2
            title: "Second Layout"
            md_bg_color: (0, 0, 1, 1)
            right_action_items:[["arrow-left", lambda x: root.press()]]

        BoxLayout:
            id: cam1

        BoxLayout:
            orientation: 'vertical'

            MDFloatingActionButton:
                icon: "camera"
                md_bg_color: (0, 0, 1, 1)
                pos_hint: {'center_x':0.5}


<ThirdLayout>:
    BoxLayout:
        orientation: 'vertical'

        MDToolbar:
            id: bar2
            title: "Third Layout"
            md_bg_color: (1, 0, 0, 1)
            right_action_items:[["arrow-left", lambda x: root.press()]]

        BoxLayout:
            id: cam2

        BoxLayout:
            orientation: 'vertical'

            MDFloatingActionButton:
                icon: "camera"
                md_bg_color: (1, 0, 0, 1)
                pos_hint: {'center_x':0.5}

I obtain this error message

[ERROR  ] [OpenCV      ] Couldn't get image from Camera
Traceback (most recent call last):
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python36\lib\site-packages\kivy\core\camera\camera_opencv.py", line 144, in _update
    self._buffer = frame.imageData
AttributeError: 'NoneType' object has no attribute 'imageData'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python36\lib\site-packages\kivy\core\camera\camera_opencv.py", line 148, in _update
    self._buffer = frame.reshape(-1)
AttributeError: 'NoneType' object has no attribute 'reshape'

But when I delete the ThirdLayout class, the code and the camera operate properly. So, I don't understand if the problem is related to the methode of creating another screen, or the problem is related to method of calling the Camera.


Solution

  • This is due to the fact that you create 2 cameras, I would advise you to create 1 instance of the Camera class and then use it wherever you want, without forgetting to remove the camera from the previous launch location (layout).

    from kivymd.app import MDApp
    from kivy.uix.camera import Camera
    from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
    from kivy.lang.builder import Builder
    
    Builder.load_string("""
    <FirstLayout>:
        MDBoxLayout:
            orientation: 'vertical'
            spacing: 10
            size_hint_y: 0.5
    
            MDBoxLayout:
                size_hint_y: 0.5
    
                MDRaisedButton:
                    id: B1
                    text:"Second"
                    md_bg_color: (0, 0, 1, 1)
                    font_size: 40
                    size_hint: (0.8, None)
                    pos_hint: {'center_x':0.5}
                    on_press: root.btn1()
    
            MDBoxLayout:
                size_hint_y: 0.5
    
                MDRaisedButton:
                    id: B2
                    text:"Third"
                    md_bg_color: (1, 0, 0, 1)
                    font_size: 40
                    size_hint: (0.8, None)
                    pos_hint: {'center_x':0.5}
                    on_press: root.btn2()
    
    
    <SecondLayout>:
        BoxLayout:
            orientation: 'vertical'
    
            MDToolbar:
                id: bar2
                title: "Second Layout"
                md_bg_color: (0, 0, 1, 1)
                right_action_items:[["arrow-left", lambda x: root.press()]]
    
            BoxLayout:
                id: cam1
    
            BoxLayout:
                orientation: 'vertical'
    
                MDFloatingActionButton:
                    icon: "camera"
                    md_bg_color: (0, 0, 1, 1)
                    pos_hint: {'center_x':0.5}
    
    
    <ThirdLayout>:
        BoxLayout:
            orientation: 'vertical'
    
            MDToolbar:
                id: bar2
                title: "Third Layout"
                md_bg_color: (1, 0, 0, 1)
                right_action_items:[["arrow-left", lambda x: root.press()]]
    
            BoxLayout:
                id: cam2
    
            BoxLayout:
                orientation: 'vertical'
    
                MDFloatingActionButton:
                    icon: "camera"
                    md_bg_color: (1, 0, 0, 1)
                    pos_hint: {'center_x':0.5}
    """)
    
    camera = None
    
    
    class ZTest(MDApp):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            global camera
            camera = Camera()
    
        def build(self):
            manager = ScreenManager()
            manager.add_widget(FirstLayout(name='First'))
            manager.add_widget(SecondLayout(name='Second'))
            manager.add_widget(ThirdLayout(name='Third'))
            return manager
    
    
    class FirstLayout(Screen):
        def btn1(self):
            self.manager.transition = SlideTransition(direction="left")
            self.manager.current = 'Second'
    
        def btn2(self):
            self.manager.transition = SlideTransition(direction="left")
            self.manager.current = 'Third'
    
    
    class SecondLayout(Screen):
        def __init__(self, **kw):
            super().__init__(**kw)
            global camera
            self.cam = camera
    
        def on_enter(self, *largs):
            self.manager.get_screen('Second').ids.cam1.clear_widgets()
            self.manager.get_screen('Third').ids.cam2.clear_widgets()
            
            self.cam.play = True
            self.manager.get_screen('Second').ids.cam1.add_widget(self.cam)
    
        def press(self):
            self.cam.play = False
            self.manager.transition = SlideTransition(direction="right")
            self.manager.current = 'First'
    
    
    class ThirdLayout(Screen):
        def __init__(self, **kw):
            super().__init__(**kw)
            global camera
            self.cam = camera
    
        def on_enter(self, *largs):
            self.manager.get_screen('Second').ids.cam1.clear_widgets()
            self.manager.get_screen('Third').ids.cam2.clear_widgets()
            
            self.cam.play = True
            self.manager.get_screen('Third').ids.cam2.add_widget(self.cam)
    
        def press(self):
            self.cam.play = False
            self.manager.transition = SlideTransition(direction="right")
            self.manager.current = 'First'
    
    
    if __name__ == "__main__":
        ZTest().run()