You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python+Kivy如何无需预初始化相机动态调用独立相机类

问题根源

你现有的KivyCamera实现存在两个核心错误导致无法嵌入其他App或Screen:

  • 继承类选择错误:KivyCamera实际是包含预览画布、启动按钮、拍照按钮的组合容器控件,你错误继承了Image类,应该改为继承MDBoxLayout
  • 初始化逻辑错误:build()是MDApp的专属生命周期方法,普通自定义Widget不会自动触发该方法,需要把UI构建逻辑放到类的__init__初始化方法中
修正后的kivycamera.py代码
from kivy.uix.image import Image
from kivy.graphics.texture import Texture
from kivy.clock import Clock
import cv2
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFillRoundFlatButton
import time

class KivyCamera(MDBoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 配置容器属性
        self.orientation = 'vertical'
        self.spacing = 10
        self.padding = 20

        # 添加预览画布
        self.image = Image()
        self.add_widget(self.image)

        # 添加启动相机按钮
        self.start_camera_button = MDFillRoundFlatButton(
            text="START CAMERA",
            pos_hint={'center_x': 0.5},
            size_hint=(0.4, None),
        )
        self.start_camera_button.bind(on_press=self.start_camera)
        self.add_widget(self.start_camera_button)

        # 添加拍照按钮
        self.save_img_button = MDFillRoundFlatButton(
            text="TAKE PICTURE",
            pos_hint={'center_x': 0.5},
            size_hint=(0.4, None),
        )
        self.save_img_button.bind(on_press=self.take_picture)
        self.add_widget(self.save_img_button)

        # 预定义摄像头实例变量,避免提前初始化
        self.video = None

    def start_camera(self, *args):
        # 避免重复初始化摄像头
        if self.video and self.video.isOpened():
            return
        self.video = cv2.VideoCapture(0)
        Clock.schedule_interval(self.load_video, 1.0 / 30.0)

    def load_video(self, *args):
        check, frame = self.video.read()
        if check:
            x, y, w, h = 200, 200, 250, 250
            p, q, r, s = 220, 220, 210, 210
            frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
            frame = cv2.rectangle(frame, (p, q), (p + r, q + s), (255, 0, 0), 3)
            self.image_frame = frame
            buffer = cv2.flip(frame, 0).tobytes()
            image_texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt="bgr")
            image_texture.blit_buffer(buffer, colorfmt="bgr", bufferfmt="ubyte")
            self.image.texture = image_texture

    def take_picture(self, *args):
        if not hasattr(self, 'image_frame'):
            return
        timestr = time.strftime("%Y%m%d_%H%M%S")
        cv2.imwrite("IMG_{}.png".format(timestr), self.image_frame)
        cv2.imshow("Capture", self.image_frame)

    # 可选:资源释放方法,切换页面/关闭APP时调用避免摄像头占用
    def release_camera(self):
        if self.video and self.video.isOpened():
            self.video.release()
        Clock.unschedule(self.load_video)
引入方式

修正后的KivyCamera是标准的Kivy Widget,你原来的两种引入方案不需要修改业务代码,直接用即可:

方案1:独立MDApp中引入

Python代码和KV文件保持你原来的写法即可,运行后会自动渲染KivyCamera控件,点击START CAMERA才会启动摄像头。

方案2:ScreenManager中引入

UploadScreen的Python代码和KV文件保持你原来的写法即可,进入UploadScreen页面后控件会自动渲染,不会提前启动摄像头。

内容的提问来源于stack exchange,提问作者Jananda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 18:15:02