I am currently trying to create an app using Kivy that will turn the video into grayscale when the button is pressed.
At first, I was able to display the camera image on the GUI, but I'm having trouble figuring out how to place buttons and other parts from here.
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()
Also, the application that displays the button works fine.
However, I have no idea how to combine these since build(self)
can only return a button or a single widget for the camera image.
# 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()
thank you in advance.
CodePudding user response:
You can use self.add_widget(..)
to add other widgets inside Widget
, Button
, etc. but it doesn't have function to automatically arange layout.
But build()
can use any widget - it doesn't have to Button
or Widget
.
If you use BoxLayout then you can use self.add_widget(...)
to add widgets in rows or columns.
Other layout
widgets can be useful to organize widgets in different way.
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)
Full working code.
I use BoxLayout
with orientation = 'vertical'
to organize in rows I put Widget
in top row, and Button
in bottom row.
Button
runs function which switch value self.convert_to_grey
- True
/False
- and update()
uses this value to convert image to gray (and back to RGB but with gray color)
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()
More layouts in Kivy doc: Getting Started » Layouts
BTW: you can nested layouts - ie. inside BoxLayout
you can use one row with GridLayout
and other row with different layout or widget.