python - 如何使用 kivy 在 python 中动态访问单独的相机类(无需预初始化相机)
问题描述
我已经使用 python+kivy (kivycamera.py) 编写了一个相机访问类,它正在工作。 kivycamera.py
# from kivymd.app import MDApp
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(MDApp):
class KivyCamera(Image):
def build(self):
layout = MDBoxLayout(orientation='vertical', spacing=10)
self.image = Image()
layout.add_widget(self.image)
self.start_camera_button = MDFillRoundFlatButton(
text="START CAMERA",
pos_hint={'center_x': 0.5, 'center_y': 0.5},
size_hint=(0.4, None),
# size=("100dp", "100dp")
)
self.start_camera_button.bind(on_press=self.start_camera)
layout.add_widget(self.start_camera_button)
self.save_img_button = MDFillRoundFlatButton(
text="TAKE PICTURE",
pos_hint={'center_x': 0.5, 'center_y': 0.5},
size_hint=(0.4, None),
# size=("100dp", "100dp")
)
self.save_img_button.bind(on_press=self.take_picture)
layout.add_widget(self.save_img_button)
# self.video = cv2.VideoCapture(0)
# Clock.schedule_interval(self.load_video, 1.0 / 30.0)
# return layout
# return self.image
def start_camera(self, *args):
self.video = cv2.VideoCapture(0)
Clock.schedule_interval(self.load_video, 1.0 / 30.0)
pass
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):
timestr = time.strftime("%Y%m%d_%H%M%S")
cv2.imwrite("IMG_{}.png".format(timestr), self.image_frame)
cv2.imshow("Hi", self.image_frame)
# KivyCamera().run()
如何仅在需要时将此类添加到另一个 MDApp 或屏幕。我尝试了以下方法,但没有成功。不要预先初始化相机。仅使用按钮操作激活相机。
在单独的 MDApp 中
from kivymd.app import MDApp
from kivycamera import KivyCamera
class DemoApp(MDApp):
pass
# def build(self):
# self.camera = KivyCamera()
# self.camera.build()
# print(self.camera)
# return self.camera
if __name__ == '__main__':
DemoApp().run()
基维文件
BoxLayout:
orientation: 'vertical'
MDLabel:
text: 'Hello'
KivyCamera:
或使用屏幕管理器在单独的屏幕内
class UploadScreen(Screen):
pass
# def build(self):
# self.my_camera = KivyCamera()
# self.my_camera.build()
# self.ids.my_camera = self.my_camera
# return self.my_camera
基维文件
<UploadScreen>:
name: 'upload'
KivyCamera:
解决方案
您的KivyCamera
extends Image
,但您将KivyCamera
用作小部件容器。此外,在您的build()
方法中,您正在创建一个layout
,但没有对它做任何事情。我建议修改KivyCamera
定义以将其基类更改为某些Layout
(我选择RelativeLayout
)并将其添加layout
为子类。这是执行此操作的代码的修改版本:
from kivymd.app import MDApp
from kivycamera import KivyCamera
class DemoApp(MDApp):
def build(self):
self.camera = KivyCamera()
self.camera.build()
print(self.camera)
return self.camera
if __name__ == '__main__':
DemoApp().run()
和 kivycamera.py:
# from kivymd.app import MDApp
from kivy.uix.image import Image
from kivy.graphics.texture import Texture
from kivy.clock import Clock
import cv2
from kivy.uix.relativelayout import RelativeLayout
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFillRoundFlatButton
import time
# class KivyCamera(MDApp):
class KivyCamera(RelativeLayout): # make this a container
def build(self):
layout = MDBoxLayout(orientation='vertical', spacing=10)
self.image = Image()
layout.add_widget(self.image)
self.start_camera_button = MDFillRoundFlatButton(
text="START CAMERA",
pos_hint={'center_x': 0.5, 'center_y': 0.5},
size_hint=(0.4, None),
# size=("100dp", "100dp")
)
self.start_camera_button.bind(on_press=self.start_camera)
layout.add_widget(self.start_camera_button)
self.save_img_button = MDFillRoundFlatButton(
text="TAKE PICTURE",
pos_hint={'center_x': 0.5, 'center_y': 0.5},
size_hint=(0.4, None),
# size=("100dp", "100dp")
)
self.save_img_button.bind(on_press=self.take_picture)
layout.add_widget(self.save_img_button)
self.add_widget(layout) # add the layout to the GUI
# self.video = cv2.VideoCapture(0)
# Clock.schedule_interval(self.load_video, 1.0 / 30.0)
# return layout
# return self.image
def start_camera(self, *args):
self.video = cv2.VideoCapture(0)
Clock.schedule_interval(self.load_video, 1.0 / 30.0)
pass
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):
timestr = time.strftime("%Y%m%d_%H%M%S")
cv2.imwrite("IMG_{}.png".format(timestr), self.image_frame)
cv2.imshow("Hi", self.image_frame)
# KivyCamera().run()
您还可以进行其他几种简化。例如,您可以通过将build()
方法更改为方法来消除该__init__()
方法(必须添加super(KivyCamera, self).__init__()
调用),并layout
通过KivyCamera
扩展来消除变量MDBoxLayout
。
推荐阅读
- python - 如何从 API 内容字节对象中提取/隔离整数?
- reactjs - 访问其他用户的属性 (Cognito)
- c++ - CreateService 失败 0x6f7 存根收到错误数据
- python - 级别名称 b 不是索引的名称
- firebase - 使用firebase登录的谷歌停止工作
- r - R 包“comparedf”的安装失败
- java - 如何获取在另一个类中以编程方式创建的视图 ID?
- sql-server - SQL Server 查询 xml 获取节点
- python - Tensorflow 2.x:使用 tf.while_loop 在 tf.function 中处理具有不同形状张量的列表
- java - Appium 脚本为 Android 应用程序抛出“线程“主”java.lang.NoClassDefFoundError:org/objectweb/asm/Type 中的异常”