如何在 Kivy 中将相机小部件添加到屏幕?

How to add a Camera widget to a Screen in Kivy?

提问人:Kacper Masny 提问时间:11/17/2023 最后编辑:Christoph RackwitzKacper Masny 更新时间:11/19/2023 访问量:26

问:

我想构建一个具有人脸识别验证功能的密码管理器应用程序。我使用 Kivy 作为 GUI。 我想创建一个带有摄像头的屏幕,我可以在其中捕获某人的脸部以保存它,并创建另一个用于验证。我希望能够从其他屏幕呼叫他们。

class CameraWindow(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        layout = BoxLayout(orientation='vertical')
        self.camera = Camera(play=False)
        layout.add_widget(self.camera)
        layout.add_widget(ToggleButton(text='Play', on_press=self.play))
        layout.add_widget(Button(text='Capture', on_release=self.capture))
        self.add_widget(layout)

每次运行程序时,我都会收到错误。

[ WARN:[email protected]] global cap_v4l.cpp:982 open VIDEOIO(V4L2:/dev/video0): can't open camera by index
[ERROR:[email protected]] global obsensor_uvc_stream_channel.cpp:156 getStreamChannelGroup Camera index out of range
 Traceback (most recent call last):
   File "/home/kacper/Documents/password_manager/password_manager/main.py", line 114, in <module>
     PasswordApp().run()
   File "/home/kacper/Documents/password_manager/.venv/lib/python3.10/site-packages/kivy/app.py", line 955, in run
     self._run_prepare()
   File "/home/kacper/Documents/password_manager/.venv/lib/python3.10/site-packages/kivy/app.py", line 925, in _run_prepare
     root = self.build()
   File "/home/kacper/Documents/password_manager/password_manager/main.py", line 105, in build
     sm.add_widget(CameraWindow(name='camerawindow'))
   File "/home/kacper/Documents/password_manager/password_manager/main.py", line 60, in __init__
     self.camera = Camera(play=False)
   File "/home/kacper/Documents/password_manager/.venv/lib/python3.10/site-packages/kivy/uix/camera.py", line 91, in __init__
     on_index()
   File "/home/kacper/Documents/password_manager/.venv/lib/python3.10/site-packages/kivy/uix/camera.py", line 103, in _on_index
     self._camera = CoreCamera(index=self.index, stopped=True)
   File "/home/kacper/Documents/password_manager/.venv/lib/python3.10/site-packages/kivy/core/camera/camera_opencv.py", line 70, in __init__
     super(CameraOpenCV, self).__init__(**kwargs)
   File "/home/kacper/Documents/password_manager/.venv/lib/python3.10/site-packages/kivy/core/camera/__init__.py", line 70, in __init__
     self.init_camera()
   File "/home/kacper/Documents/password_manager/.venv/lib/python3.10/site-packages/kivy/core/camera/camera_opencv.py", line 120, in init_camera
     self._resolution = (int(frame.shape[1]), int(frame.shape[0]))
 AttributeError: 'NoneType' object has no attribute 'shape'

不知道我是否应该发布错误消息的中间,对不起,如果它是错误的,我会在需要时发布它。

我的整个代码:

main.py

import time
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.camera import Camera
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput

# kv = Builder.load_file('my.kv')

class LogInWindow(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        layout = BoxLayout(orientation='vertical')
        self.username_input = TextInput(text='Username')
        self.password_input = TextInput(text='Password', password=True)
        layout.add_widget(self.username_input)
        layout.add_widget(self.password_input)
        layout.add_widget(Button(text='Login', on_release=self.login))
        layout.add_widget(Button(text='Register', on_release=self.go_to_register))
        layout.add_widget(Button(text='Exit', on_release=App.get_running_app().stop))
        self.add_widget(layout)

    def login(self, instance):
        username = self.username_input.text
        password = self.password_input.text

        if username == 'admin' and password == 'admin':
            self.go_to_camera(instance)

    def go_to_camera(self, instance):
        self.manager.current = 'camerawindow'

    def go_to_register(self, instance):
        self.manager.current = 'register'

class RegisterWindow(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        layout = BoxLayout(orientation='vertical')
        layout.add_widget(Button(text='Scan your face', on_release=self.go_to_camera))
        layout.add_widget(Button(text='Back', on_release=self.go_to_login))
        self.add_widget(layout)

    def go_to_camera(self, instance):
        self.manager.current = 'camerawindow'

    def go_to_login(self, instance):
        self.manager.current = 'login'
        

class CameraWindow(Screen):
    pass
    # def __init__(self, **kwargs):
    #     super().__init__(**kwargs)
    #     layout = BoxLayout(orientation='vertical')
    #     self.camera = Camera(play=False)
    #     layout.add_widget(self.camera)
    #     layout.add_widget(ToggleButton(text='Play', on_press=self.play))
    #     layout.add_widget(Button(text='Capture', on_release=self.capture))
    #     layout.add_widget(Button(text='Recognize Face', on_release=self.recognize_face))
    #     self.add_widget(layout)

    

class PasswordListWindow(Screen):
    pass

class PasswordEntryWindow(Screen):
    pass

class WindowManager(ScreenManager):
    pass


class PasswordApp(App):
    def build(self):
        sm = ScreenManager()
        sm.add_widget(LogInWindow(name='login'))
        sm.add_widget(RegisterWindow(name='register'))
        sm.add_widget(CameraWindow(name='camerawindow'))
        sm.add_widget(PasswordListWindow(name='list'))
        sm.add_widget(PasswordEntryWindow(name='entry'))
        
        return sm



if __name__ == '__main__':
    PasswordApp().run()

密码.kv

WindowManager:
    LogInWindow:
    RegisterWindow:
    CameraWindow:
    PasswordListWindow:
    PasswordEntryWindow:

<LogInWindow>:
    name: 'login'
    BoxLayout:
        orientation: 'vertical'
        size: root.width, root.height
        Label:
            text: 'Login'
            font_site: 32
        Button:
            text: 'Login'
            on_press: root.manager.current = 'list'    
        Button:
            text: 'Register'
            on_press: root.manager.current = 'register'
        Button:
            text: 'Quit'

<RegisterWindow>:
    name: 'register'
    BoxLayout:
        Button:
            text: 'Goto settings'
            on_press: root.manager.current = 'settings'
        Button:
            text: 'Quit'

<<CameraWindow>:
    name: 'camerawindow'
    BoxLayout:
        orientation: 'vertical'
        Camera:
            id: camera
        Button:
            text: 'Back'
            on_release: root.manager.current = 'login'

<PasswordListWindow>:
    name: 'list'
    BoxLayout:
        Button:
            text: 'Goto settings'
            on_press: root.manager.current = 'login'
        Button:
            text: 'Quit'

<PasswordEntryWindow>:
    name: 'entry'
    BoxLayout:
        Button:
            text: 'Goto settings'
            on_press: root.manager.current = 'list'
        Button:
            text: 'Quit'

我尝试了来自 opencv 的简单相机调用,它按预期工作。我看到我的相机弹出。

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()

    cv2.imshow('frame', frame)

    if cv2.waitKey(1) == ord('q'):
        break
cap.release()
cv2.destroyAllWindows

我尝试了文档 https://kivy.org/doc/stable/examples/gen__camera__main__py.html 中的相机示例,它工作得很好,但它是由应用程序直接调用的类,这不是我想要的。我尝试将其重新加工成屏幕,但它停止工作:

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

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

class WindowManager(ScreenManager):
    pass

Builder.load_string('''
ScreenManager:
    Screen1:
                    
<Screen1>:
    name: 'screen1'
    BoxLayout:
        orientation: 'vertical'
        Camera:
            id: camera
            resolution: (640, 480)
            play: False
        ToggleButton:
            text: 'Play'
            on_press: camera.play = not camera.play
            size_hint_y: None
            height: '48dp'
        Button:
            text: 'Capture'
            size_hint_y: None
            height: '48dp'
            on_press: root.capture()
''')

class TestCamera(App):

    def build(self):
        sm=ScreenManager()
        sm.add_widget(Screen1(name='screen1'))
        return sm
    
if __name__ == '__main__':
    TestCamera().run()

在上面的示例中,我尝试在创建 Screen1 之前和之后调用它,但根本没有调用它。在 Screen1 之后使用 builder,我收到与上面相同的错误,在 Screen1 之前使用 builder,我收到“未知类错误”,没有构建器,我得到黑屏。Builder

我尝试过的其他事情。 我试着在课外打电话,程序运行了,但我显然没有在屏幕上看到摄像头。cam = Camera()

我尝试了一个空白的 CameraWindow 类和

<<CameraWindow>:
    name: 'camerawindow'
    BoxLayout:
        orientation: 'vertical'
        Camera:
            id: camera
        Button:
            text: 'Back'
            on_release: root.manager.current = 'login'

在 .kv 文件中,如上面文档中的示例所示。程序启动,但当我导航到 CameraWindow 时,出现黑屏。

我尝试在我的 .kv 中只留下名称:指定。- AttributeError:“NoneType”对象没有属性“shape”<CameraWindow>

我试过两者兼而有之。- AttributeError:“NoneType”对象没有属性“shape”

python 相机 kivy 属性错误

评论

0赞 Community 11/17/2023
请修剪您的代码,以便更轻松地找到您的问题。请遵循这些准则,以创建最小的可重现示例

答: 暂无答案