使用 Kivy 在 GUI 应用程序中同时放置相机图像和按钮

Simultaneous placement of camera images and buttons in GUI applications using Kivy

我目前正在尝试使用 Kivy 创建一个应用程序,它会在按下按钮时将视频转换为灰度。

起初,我能够在 GUI 上显示相机图像,但我在弄清楚如何从这里放置按钮和其他部件时遇到了问题。

import sys
import numpy as np
import cv2

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.graphics.texture import Texture

from kivy.clock import Clock
from kivy.core.window import Window

import datetime
import random

WINDOW_WIDTH = 1500
WINDOW_HEIGHT = 1008

### Setting of the window
Window.size = (WINDOW_WIDTH, WINDOW_HEIGHT)

class MyApp(App, Widget):
        title = "opencv on kivy"

        def __init__(self, **kwargs):
            super(MyApp, self).__init__(**kwargs)
            Clock.schedule_interval(self.update, 1.0 / 30)
            self.widget = Widget()
            # self.cap = cv2.VideoCapture(0)
            self.cap = cv2.VideoCapture(1)

        # The method by the intarval
        def update(self, dt):
            ret, img = self.cap.read()
            ### The color sequence in openCV is BGR, so fix it to RGB.
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            ### The origin of Kivy's coordinates is the lower left, so flip it upside down.
            img = cv2.flip(img, 0)
            # if img is not None:
            texture = Texture.create(size=(img.shape[1], img.shape[0]))
            texture.blit_buffer(img.tostring())
            with self.widget.canvas:
                Rectangle(texture=texture ,pos=(0 + int(WINDOW_WIDTH/2) - int(img.shape[1]/2), WINDOW_HEIGHT - img.shape[0]), size=(img.shape[1], img.shape[0]))
                
            return self.widget

        def build(self):
            return self.widget
            # return MyApp()

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

此外,显示该按钮的应用程序工作正常。 但是,我不知道如何组合这些,因为 build(self) 只能 return 相机图像的按钮或单个小部件。

# import kivy module
import kivy
 
# this restrict the kivy version i.e
# below this kivy version you cannot
# use the app or software
kivy.require("1.9.1")
 
# base Class of your App inherits from the App class.
# app:always refers to the instance of your application
from kivy.app import App
 
# creates the button in kivy
# if not imported shows the error
from kivy.uix.button import Button
 
# class in which we are creating the button
class ButtonApp(App):
     
    def build(self):
         
        btn = Button(text ="Push Me !")
        return btn
 
# creating the object root for ButtonApp() class
root = ButtonApp()
 
# run function runs the whole program
# i.e run() method which calls the
# target function passed to the constructor.
root.run()

提前致谢。

您可以使用self.add_widget(..)WidgetButton等中添加其他小部件,但它没有自动排列布局的功能。

但是 build() 可以使用任何小部件 - 它不必 ButtonWidget

如果您使用 BoxLayout,那么您可以使用 self.add_widget(...) 在行或列中添加小部件。

其他 layout 小部件可用于以不同方式组织小部件。

class MyApp(App, BoxLayout): # class MyApp(App, Widget)

      def __init__(self, **kwargs):
     
            # ... code ...

            self.orientation = 'vertical'  # BoxLayout
     
            self.widget = Widget()
            self.add_widget(self.widget)

            self.button = Button(text='Gray', on_press=self.change_color)
            self.add_widget(self.button)

完整的工作代码。

我使用 BoxLayoutorientation = 'vertical' 来组织行 我把 Widget 放在顶行,Button 在底行。

Button 运行切换值 self.convert_to_grey - True/False - 并且 update() 使用此值将图像转换为灰色(并返回)的函数为 RGB,但为灰色)

import sys
import numpy as np
import cv2

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.graphics.texture import Texture

from kivy.clock import Clock
from kivy.core.window import Window

import datetime
import random

WINDOW_WIDTH = 1500
WINDOW_HEIGHT = 1008

### Setting of the window
Window.size = (WINDOW_WIDTH, WINDOW_HEIGHT)

class MyApp(App, BoxLayout):
        title = "opencv on kivy"

        def __init__(self, **kwargs):
            super(MyApp, self).__init__(**kwargs)

            self.orientation = 'vertical'  # BoxLayout
            
            self.convert_to_grey = False   # 
            
            self.cap = cv2.VideoCapture(0)
            #self.cap = cv2.VideoCapture(1)

            self.widget = Widget()
            self.add_widget(self.widget)

            self.button = Button(text='Gray', on_press=self.change_color)
            self.add_widget(self.button)
            
            Clock.schedule_interval(self.update, 1.0 / 30)
            
        def change_color(self, *args):
            print('args:', args)
            self.convert_to_grey = not self.convert_to_grey

        def update(self, dt):
            ret, img = self.cap.read()
            
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            img = cv2.flip(img, 0)
            
            if self.convert_to_grey:
                img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
                img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)

            texture = Texture.create(size=(img.shape[1], img.shape[0]))
            texture.blit_buffer(img.tostring())
            with self.widget.canvas:
                Rectangle(texture=texture, pos=(0 + int(WINDOW_WIDTH/2) - int(img.shape[1]/2), WINDOW_HEIGHT - img.shape[0]), size=(img.shape[1], img.shape[0]))
                
            return self.widget

        def build(self):
            return self

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

Kivy 文档中的更多布局: Getting Started » Layouts

顺便说一句:您可以嵌套布局 - 即。在 BoxLayout 中,您可以将一行与 GridLayout 一起使用,另一行与不同的布局或小部件一起使用。