0

我正在使用屏幕管理器,并希望在访问 ScreenThree 时显示相机图像。我希望使用 cv2 相机代码。单击按钮后,我希望捕获一张图片,然后使用该图像执行代码。到目前为止,我在互联网上找到了一个线程版本,可以很好地显示相机输入。通过单击按钮捕获图片正在挫败我的努力。

Screen3 包含一个放置视频的地方和一个执行代码拍照的按钮。

<ScreenThree>:
    name: "screenthree"
    FloatLayout:
        Image:
            id: vid    #Vido image
            pos_hint: {'x':0.0, 'y':0.2}
            size_hint: 1.0, 0.8
        Image:
            source: "clue.png" # Decorative image
            size_hint:(0.20,0.20)
            pos_hint: {"x":0.05,"y":0.75}
        Button:
            text: "Click to scan"
            background_color : 0, 0, 1, 1
            size_hint: 0.2,0.05
            pos_hint: {"x":0.25,"y":0.85}
            on_press: root.takepic()
        Button:
            text: "Go to next screen"      # Screen4
            background_color : 1, 0, 1, 1
            size_hint: 0.2,0.05
            pos_hint: {"x":0.45,"y":0.85}
            on_press:
                root.manager.transition.direction = 'left'
                root.manager.transition.duration = 1
                root.manager.current = 'screen_four'

线程代码是(我不知道隐藏窗口是关于什么的);

class ScreenApp(App):
    def build(self):
        threading.Thread(target=self.doit, daemon=True).start()
        self.new_screen = ScreenThree()
        return screen_manager

    def doit(self):
        self.do_vid = True
        cv2.namedWindow('Hidden', cv2.WINDOW_NORMAL | cv2.WINDOW_FREERATIO)
        cv2.resizeWindow('Hidden', 0, 0)
        cam=cv2.VideoCapture('/dev/video0', cv2.CAP_V4L)

        while (self.do_vid):
            ret, frame = cam.read()
            Clock.schedule_once(partial(self.display_frame, frame))
            cv2.imshow('Hidden', frame)
            cv2.waitKey(1)
        cam.release()
        cv2.destroyAllWindows()

    def display_frame(self, frame, dt):
        texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
        texture.blit_buffer(frame.tobytes(order=None), colorfmt='bgr', bufferfmt='ubyte')
        texture.flip_vertical()

        self.root.get_screen('screen_three').ids.vid.texture = texture

我将捕获图像的代码放在 ScreenThree 类中。单击按钮会转移到 takepic() 方法,但无法读取图像,尝试写入空图像时会崩溃。/dev/video0 上的摄像头仍由线程代码持有。如何访问相机以捕捉照片,或者如何提示线程例程为我拍照。

class ScreenThree(Screen):
    def takepic(self):
        cap = cv2.VideoCapture('/dev/video0', cv2.CAP_V4L)

        # set dimensions
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

        # take frame
        ret, frame = cap.read()
        # write frame to file
        cv2.imwrite('image.jpg', frame)
        # release camera
        cap.release()
4

2 回答 2

0

由于您的线程已经从相机捕获帧,您可以只使用已捕获的当前帧,如下所示:

def doit(self):
    self.do_vid = True
    self.frame = None  # add reference to the current frame
    cv2.namedWindow('Hidden', cv2.WINDOW_NORMAL | cv2.WINDOW_FREERATIO)
    cv2.resizeWindow('Hidden', 0, 0)
    cam=cv2.VideoCapture('/dev/video0', cv2.CAP_V4L)

    while (self.do_vid):
        ret, self.frame = cam.read()  # save the current frame
        Clock.schedule_once(partial(self.display_frame, self.frame))
        cv2.imshow('Hidden', self.frame)
        cv2.waitKey(1)
    cam.release()
    cv2.destroyAllWindows()

在方法中使用当前帧takepic()

class ScreenThree(Screen):
    def takepic(self):
        # get current frame
        frame = App.get_running_app().frame
        # write frame to file
        cv2.imwrite('image.jpg', frame)
于 2021-08-10T17:24:30.457 回答
0

感谢 John Anderson 先生的帮助,这个通用代码可以正常工作,并且可能对其他人有用。

"""
 Sets up multiple screens with transitions between screens.
 From Screen three the camera imaging appears.
 There may be a delay before appearing
 A button labeled Click to take" captures and stores the camera image
"""
import threading
from functools import partial
import kivy
import gi
gi.require_version('Gst', '1.0')
from kivy.app import App
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.graphics.texture import Texture
from PIL import Image as Pimage
from kivy.config import Config
import numpy
import cv2
# Builder is used when .kv file is in .py file
from kivy.lang import Builder

# The screen manager is a widget
# dedicated to managing multiple screens for your application.
from kivy.uix.screenmanager import ScreenManager, Screen

from kivy.uix.camera import Camera
Config.set('graphics', 'resizable', True)

# You can create your kv code in the Python file
Builder.load_string("""
<ScreenOne>:
    BoxLayout:
        Button:
            text: "This is screen one"
            font_size: 48
            background_color : 0, 0, 1, 1
            on_press:
                # Define the duration of the change and the direction of the slide
                root.manager.transition.direction = 'left'
                root.manager.transition.duration = 1
                root.manager.current = 'screen_two'
<ScreenTwo>:
    BoxLayout:
        orientation: 'vertical'
        background_color: 1,1,1,1
#        Image:
#            source: "somepic.png"
#            size_hint:(0.7,0.35)
#            pos_hint:{"center_x":0.5,"center_y":0.5}
#            allow_stretch: True
#            keep_ratio: False

        Button:
            text: "Screen Two press to change screen"
            font_size: 34
            font_name: 'AbyssinicaSIL-R'
            background_color : 1, 1, 0, 1
            on_press:
                root.manager.transition.direction = 'left'
                root.manager.transition.duration = 1
                root.manager.current = 'screen_three'
<ScreenThree>:
    name: "screenthree"
    FloatLayout:
        Image:
            id: vid
            pos_hint: {'x':0.0, 'y':0.2}
            size_hint: 1.0, 0.8
#        Image:
#            source: "Somepic2.png"
#            size_hint:(0.20,0.20)
#            pos_hint: {"x":0.05,"y":0.75}
        Button:
            text: "Click to scan"
            background_color : 0, 0, 1, 1
            size_hint: 0.2,0.05
            pos_hint: {"x":0.25,"y":0.85}
            on_press: root.takepic()
        Button:
            text: "Go to next screen"      #Goes to Screen4
            background_color : 1, 0, 1, 1
            size_hint: 0.2,0.05
            pos_hint: {"x":0.45,"y":0.85}
            on_press:
                root.manager.transition.direction = 'left'
                root.manager.transition.duration = 1
                root.manager.current = 'screen_four'
        Label:
            id:notif
            text:"Wait for camera image."
            font_size: 20
            pos_hint: {"x":0.2,"y":0.1}
<ScreenFour>:
    BoxLayout:
        Button:
            text: "Go to Screen 5"
            background_color : 0, 1, 1, 1
            on_press:
                root.manager.transition.direction = 'left'
                root.manager.transition.duration = 1
                root.manager.current = 'screen_one'
""")
# Create a class for all screens in which you can include
# helpful methods specific to that screen
class ScreenOne(Screen):
    pass

class ScreenTwo(Screen):
    pass

class ScreenThree(Screen):
    def takepic(self):
        kk = App.get_running_app()
        frame = App.get_running_app().frame
        pdb.set_trace()
        cv2.imwrite('image.jpg', frame)

class ScreenFour(Screen):
    pass

# The ScreenManager controls moving between screens
screen_manager = ScreenManager()

# Add the screens to the manager and then supply a name
# that is used to switch screens
screen_manager.add_widget(ScreenOne(name ="screen_one"))
screen_manager.add_widget(ScreenTwo(name ="screen_two"))
screen_manager.add_widget(ScreenThree(name ="screen_three"))
screen_manager.add_widget(ScreenFour(name ="screen_four"))
# Create the App class
class ScreenApp(App):
    def build(self):
        threading.Thread(target=self.doit, daemon=True).start()
        self.new_screen = ScreenThree()
        return screen_manager

    def doit(self):
        self.do_vid = True
        self.frame=None
        cv2.namedWindow('Hidden', cv2.WINDOW_NORMAL | cv2.WINDOW_FREERATIO)
        cv2.resizeWindow('Hidden', 0, 0)
        cam=cv2.VideoCapture('/dev/video0', cv2.CAP_V4L)

        while (self.do_vid):
            ret, self.frame = cam.read()
            Clock.schedule_once(partial(self.display_frame, self.frame))
            cv2.imshow('Hidden', self.frame)
            cv2.waitKey(1)
        cam.release()
        cv2.destroyAllWindows()

    def display_frame(self, frame, dt):
        texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
        texture.blit_buffer(frame.tobytes(order=None), colorfmt='bgr', bufferfmt='ubyte')
        texture.flip_vertical()
        self.root.get_screen('screen_three').ids.vid.texture = texture

# run the app
sample_app = ScreenApp()
sample_app.run()
于 2021-08-15T22:54:16.783 回答