Last time, I introduced various buttons. It is also related to buttons. Previously, I tried to attach an image to a button and it didn't work, so I did a little research. I think it will be a memorandum. By the way, I would like to show an example of how to use it (although the content of the title is not the main one ...)
I was simply trying to use Image
with add_widget
for the `` `Button``` widget. I think it will look like this. The button appears firmly behind the image, which makes it look awkward. (Maybe if you write a lot, it may look good) Also, if you shift the position of the button, the image will not follow, so I do not understand why. Therefore, I gave up the implementation before.
What to do It looks like this.
To create an image button, use a module called kivy.uix.behaviors
. By using `` `behaviors.ButtonBehavior```, you can add button functions to labels and images. There seems to be many other things you can do!
https://kivy.org/doc/stable/api-kivy.uix.behaviors.html
The source code is as follows. Create a new class that inherits `` `behaviors.ButtonBehaviorand what you want to be a button, here
Image```. And if you change the image of Image and specify the image when you press the button and the image when you talk, it works well.
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
class MyButton(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
#Appropriate image
self.source = 'data/val2017/000000000285.jpg'
def on_press(self):
#Image when pressed
self.source = 'data/val2017/000000000776.jpg'
def on_release(self):
#Revert to original image
self.source = 'data/val2017/000000000285.jpg'
class SampleApp(App):
def build(self):
return MyButton()
SampleApp().run()
If you want to use toggle buttons, inherit `` `ToggleButtonBehavior```.
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.behaviors import ToggleButtonBehavior
class MyButton(ToggleButtonBehavior, Image):
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
self.source = 'data/val2017/000000000285.jpg'
def on_state(self, widget, value):
if value == 'down':
self.source = 'data/val2017/000000000776.jpg'
else:
self.source = 'data/val2017/000000000285.jpg'
class SampleApp(App):
def build(self):
return MyButton()
SampleApp().run()
While investigating how to make an image button, an image viewer was created before I knew it. The image looks like this.
It's like displaying all the images in any image folder in the scroll view and displaying the image of the clicked image button in the image above.
The result is as below.
import os
import cv2
import numpy as np
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.behaviors import ToggleButtonBehavior
from kivy.clock import Clock
from kivy.graphics.texture import Texture
#Image button class
class MyButton(ToggleButtonBehavior, Image):
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
#Stores the image name of the image button
self.source = kwargs["source"]
#Treat the image as a texture so you can edit it
self.texture = self.button_texture(self.source)
#The image changes depending on the state of the toggle button and the state.
def on_state(self, widget, value):
if value == 'down':
self.texture = self.button_texture(self.source, off=True)
else:
self.texture = self.button_texture(self.source)
#Change the image, rectangular when pressed+Darken the color
def button_texture(self, data, off=False):
im = cv2.imread(data)
im = self.square_image(im)
if off:
im = self.adjust(im, alpha=0.6, beta=0.0)
im = cv2.rectangle(im, (2, 2), (im.shape[1]-2, im.shape[0]-2), (255, 255, 0), 10)
#flip upside down
buf = cv2.flip(im, 0)
image_texture = Texture.create(size=(im.shape[1], im.shape[0]), colorfmt='bgr')
image_texture.blit_buffer(buf.tostring(), colorfmt='bgr', bufferfmt='ubyte')
return image_texture
#Make the image square
def square_image(self, img):
h, w = img.shape[:2]
if h > w:
x = int((h-w)/2)
img = img[x:x + w, :, :]
elif h < w:
x = int((w - h) / 2)
img = img[:, x:x + h, :]
return img
#Darken the color of the image
def adjust(self, img, alpha=1.0, beta=0.0):
#Performs a product-sum operation.
dst = alpha * img + beta
# [0, 255]Clip with to make uint8 type.
return np.clip(dst, 0, 255).astype(np.uint8)
class Test(BoxLayout):
def __init__(self, **kwargs):
super(Test, self).__init__(**kwargs)
#Directory to read
image_dir = "data/val2017"
#Vertical arrangement
self.orientation = 'vertical'
#Manage image file names
self.image_name = ""
#Preparing a widget to display an image
self.image = Image(size_hint=(1, 0.5))
self.add_widget(self.image)
#Definition of scroll view to place image buttons
sc_view = ScrollView(size_hint=(1, None), size=(self.width, self.height*4))
#Because only one widget can be placed in the scroll view
box = GridLayout(cols=5, spacing=10, size_hint_y=None)
box.bind(minimum_height=box.setter('height'))
#Batch definition of image buttons, arranged in grid layout
box = self.image_load(image_dir, box)
sc_view.add_widget(box)
self.add_widget(sc_view)
#Load image button
def image_load(self, im_dir, grid):
images = sorted(os.listdir(im_dir))
for image in images:
button = MyButton(size_hint_y=None,
height=300,
source=os.path.join(im_dir, image),
group="g1")
button.bind(on_press=self.set_image)
grid.add_widget(button)
return grid
#When you press the image button, the image is displayed in the image widget
def set_image(self, btn):
if btn.state=="down":
self.image_name = btn.source
#Update screen
Clock.schedule_once(self.update)
#Screen update
def update(self, t):
self.image.source = self.image_name
class SampleApp(App):
def build(self):
return Test()
SampleApp().run()
In the above explanation, I think that it was not clear whether the button was pressed, just by switching the image of the button. Therefore, we added a process so that when you press the image, a frame is attached and the image becomes a little dark and you can tell that you pressed it. In addition, in order to arrange them neatly in the grid layout, we have also added a process of trimming at the center of the image.
In the image button class, there is a variable `` `source``` that stores the file name of the image to be the button, and this function is used to process the image with opencv from the image name. Also, in order to use the processed image, it is necessary to use texture, so texture is specified as the return value.
#Change the image, rectangular when pressed+Darken the color
def button_texture(self, data, off=False):
im = cv2.imread(data)
im = self.square_image(im)
if off:
im = self.adjust(im, alpha=0.6, beta=0.0)
im = cv2.rectangle(im, (2, 2), (im.shape[1]-2, im.shape[0]-2), (255, 255, 0), 10)
#flip upside down
buf = cv2.flip(im, 0)
image_texture = Texture.create(size=(im.shape[1], im.shape[0]), colorfmt='bgr')
image_texture.blit_buffer(buf.tostring(), colorfmt='bgr', bufferfmt='ubyte')
return image_texture
It is a process when the button on the application side is pressed, but when the button is pressed, the image does not change just by changing the `source``` of the ```Image``` at the top of the screen. You need to refresh the screen to change the image. Therefore, when you press the image,
`Clock``` is moved once to update the screen.
#When you press the image button, the image is displayed in the image widget
def set_image(self, btn):
if btn.state=="down":
self.image_name = btn.source
#Update screen
Clock.schedule_once(self.update)
#Screen update
def update(self, t):
self.image.source = self.image_name
-OpenCV-Change image brightness and contrast, gamma correction, etc.-Pynote I referred to the source of the process of darkening the image.
・ COCO Dataset This is the link of the image used this time.
Recommended Posts