Класс KivyMD — KivyCamera инициализируется без вызова

#python #opencv #kivy #initialization #kivymd

#питон #opencv #киви #инициализация #кивимд

Вопрос:

Это мой первый раз, когда я задаю здесь вопрос, так что, пожалуйста, потерпите меня. Я пытаюсь создать приложение для камеры, используя opencv и kivy. Мне удалось это сделать, но моя проблема в том, что камера вызывается сразу, даже если ее нет на нужном экране. Я подозреваю, что это из-за моего класса init в КивиКамере, но я не знаю никаких других методов для этого. Я хочу, чтобы камера инициализировалась только после нажатия кнопки.

вот мое главное приложение

 from kivy.lang import Builder  from kivymd.app import MDApp from kivymd.uix.list import OneLineIconListItem, IconLeftWidget from kivymd.uix.list import OneLineListItem, MDList from kivy.uix.screenmanager import ScreenManager, Screen from kivy.uix.scrollview import ScrollView from kivy.uix.image import Image from kivy.clock import Clock from kivy.graphics.texture import Texture import cv2  import random import string  class OneLine(OneLineListItem):  pass  class Scr(ScrollView):  pass  class list(MDList):  pass  class MenuScreen(Screen):  pass  class CamScreen(Screen):  # def show_cam(self):  # self.capture = cv2.VideoCapture(0)   def on_stop(self):  self.capture.release()  class SecondScreen(Screen):  # def mama(self):  # for i in range(20):  # self.parent.parent.ids.container.add_widget(  # OneLineListItem(text=f"Single-line item {i}")  # )  def on_released(self):  # items=   # self.add_widget()   for i in range(20):  list = OneLine(text=f"dsafsd {i}", on_release= lambda list: print(list.text))  list.text = f"dsafsd {i}"  # list.bind(on_release=lambda btn: self.dropdown.select(list.text))  self.ids['container'].add_widget(list)   # pass class KivyCamera(Image):  def __init__(self, capture = cv2.VideoCapture(0), fps=30, **kwargs):  super(KivyCamera, self).__init__(**kwargs)  self.capture = capture  Clock.schedule_interval(self.update, 1.0/fps)   def update(self, dt):  ret, frame = self.capture.read()  if ret:  buf1 = cv2.flip(frame, 0)  buf = buf1.tostring()  image_texture =Texture.create(  size = (frame.shape[1], frame.shape[0]), colorfmt='bgr'  )  image_texture.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')   self.texture = image_texture     sm = ScreenManager() sm.add_widget(MenuScreen(name='menu')) sm.add_widget(SecondScreen(name='second')) sm.add_widget(CamScreen(name='cam'))   class Test(MDApp):   def on_start(self):  size= 0.5,0.5  # self.help.get_screen('cam').ids['cam'].add_widget(KivyCamera(size_hint = size, pos_hint = {"x":0.1,"top":1}))  for i in range(20):  self.help.get_screen('second').ids['container'].add_widget(  OneLineListItem(text=f"Single-line item {i}")  )   letters = string.ascii_lowercase  random = random.choice(letters)     def build(self):  screen = Screen()  self.help = Builder.load_file('tes.kv')  screen.add_widget(self.help)  return screen  Test().run()  

а вот файл kv

 ScreenManager:  MenuScreen:  SecondScreen:  CamScreen:  lt;MenuScreengt;:  name: 'menu'  MDRectangleFlatButton:  text: 'to second'  pos_hint: {'center_x':0.1,'center_y':0.2}  on_press:   root.manager.current = 'second'   MDRectangleFlatButton:  text: 'to cam'  pos_hint: {'center_x':0.1,'center_y':0.9}  on_press:   root.manager.current = 'cam'   MDLabel:  id:our_label  text: " "  pos_hint: {'center_x':0.5,'center_y':0.2}  # on_parent:  # app.samie()  lt;SecondScreengt;:  name: 'second'   MDBoxLayout:  orientaion: 'vertical'  MDRectangleFlatButton:  text: 'to menu'  pos_hint: {'center_x':0.1,'center_y':0.95}  on_press:  root.manager.current = 'menu'   # on_press:  # app.please()  # ScrollView:  # root.on_released()  # list.text = list.text   "bobo"  # root.manager.current = 'menu'  # for i in range(4): print(f"bobo {i}")    ScrollView:  MDList:  id:container  # on_parent:  # app.please()   lt;CamScreengt;:  name: 'cam'  BoxLayout:  orientation: 'vertical'   KivyCamera:  id: cam  size_hint: 0.5,0.5  pos_hint: {"x":0.1,"top":1}     MDRectangleFlatButton:  text: 'show camera'  pos_hint: {'center_x':0.1,'center_y':0.9}  # on_parent:  # app.show_cam()   

Спасибо! Я действительно думаю, что мне просто нужно избавиться от init, но я не знаю другого способа

Ответ №1:

Вы можете запустить обновление камеры, используя on_enter() метод Screen . Попробуйте изменить __init__() метод KivyCamera на:

 class KivyCamera(Image):  def __init__(self, capture=cv2.VideoCapture(0), fps=30, **kwargs):  super(KivyCamera, self).__init__(**kwargs)  self.capture = capture  self.fps = fps  # Clock.schedule_interval(self.update, 1.0 / fps)  

И добавить on_enter() и on_leave() методы к CamScreen :

 class CamScreen(Screen):  # def show_cam(self):  # self.capture = cv2.VideoCapture(0)   def on_stop(self):  self.capture.release()   def on_enter(self, *args):  cam = self.ids.cam  self.clock_event = Clock.schedule_interval(cam.update, 1.0 / cam.fps)   def on_leave(self, *args):  self.clock_event.cancel()  

На несвязанной ноте строки:

 sm = ScreenManager() sm.add_widget(MenuScreen(name='menu')) sm.add_widget(SecondScreen(name='second')) sm.add_widget(CamScreen(name='cam'))  

строим свой корень App , но он никогда не используется. Эти линии могут быть устранены.

Линия:

 self.help = Builder.load_file('tes.kv')  

также создается один и тот же корень, и если нет какой-либо причины для создания другого Screen , содержащего этот корень, вы можете упростить свой build() метод до:

 def build(self):  self.help = Builder.load_file('tes.kv')  return self.help  

Комментарии:

1. Привет @john, спасибо, что мне удалось как-то заставить его работать с небольшими изменениями, cam.fps возникает ошибка AttributeError: 'KivyCamera' object has no attribute 'fps' , поэтому я просто жестко закодировал его до 30. Теперь я столкнулся с другой проблемой, когда я пытаюсь изменить экран, он все еще использует мою веб-камеру. Я попробовал использовать cam.capture.release() вместо self.clock_event.cancel() внутреннего def on_leave . Веб-камера сейчас закрывается, но когда вы возвращаетесь на экран камеры, на нем отображается только статическое изображение, может быть, обновление может помочь?

2. обновление, я не заметил self.fps = fps строки, вот почему у меня возникла ошибка хе-хе 😀

3. этот ответ не решает проблему, а именно, что видеокартинка инициализируется до создания KivyCamera объекта… потому что видеокартинка инициализируется во время определения этого класса, потому что она задана в качестве аргумента по умолчанию. эти выражения вычисляются во время определения. Я добавил ответ, который касается этого.

Ответ №2:

 def __init__(self, capture = cv2.VideoCapture(0), fps=30, **kwargs):  

Эта строка вызывает проблему.

Объект видеозаписи создается во время определения класса и его метода.

Ты, наверное, этого не хочешь.

Используйте capture=None в списке параметров, а в теле __init__ вы должны проверить if capture is None: capture = cv2.VideoCapture...