I have used https://kivymd.readthedocs.io/en/latest/components/selection/ and used https://github.com/stefanpetrescu997/imageGalleryImageThresholdingKivy.
from kivy import app from kivy.uix.screenmanager import Screen from kivymd.app import MDApp from kivy.metrics import dp from kivy.lang.builder import Builder import os from PIL import Image as pillow import cv2 import numpy as np from kivy.uix.textinput import TextInput from kivy.uix.button import Button from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.boxlayout import BoxLayout from kivy.uix.image import Image from kivy.uix.dropdown import DropDown from kivy.core.window import Window
KV = """
<ImgCard@ButtonBehavior+BoxLayout>
path: ""
orientation: "vertical"
size_hint_y: None
on_release: app.root.viewimg(self)
on_release: app.on_selected(*args)
on_release: app.on_unselected(*args)
on_release: app.set_selection_mode(*args)
Image:
source: root.path
size_hint_y: .9
<GalleryApp>
orientation: 'vertical'
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
RecycleView:
id: img_base
viewclass: "ImgCard"
canvas.before:
#$#Color:
#$rgba: (.4, .4, .4, .7)
Rectangle:
size: self.size
pos: self.pos
RecycleGridLayout:
spacing: 10
cols: 3
default_size: None, dp(48)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
overlay_color: app.overlay_color[:-1] + [.2]
icon_bg_color: app.overlay_color
"""
class ImageManager(Screen):
pass
class GalleryApp(BoxLayout):
overlay_color = get_color_from_hex("#6042e4")
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.manager_list = []
self.dir = os.getcwd()
self.available_image_format = ['.png', '.jpg', '.jpeg', '.bmp'] # etc
def build(self):
return Builder.load_string(KV)
def on_start(self):
self.load_images()
def load_images(self):
if not self.manager_list:
for image in os.listdir(self.dir):
target_filename, target_file_extension = os.path.splitext(image)
if target_file_extension in self.available_image_format:
path_to_image = os.path.join(self.dir, image)
self.manager_list.append(
{
"ImgCard": "ImageManager",
"path": path_to_image,
"height": dp(200),
}
)
self.root.ids.img_base.data = self.manager_list
self.images=[self.dir]
def next_image(self):
images = self.images
cur_idx = None
last_idx = len(images) -1
view_children = self.dir
cur_img = None
image_container = None
for child in view_children:
if str(child).find('BoxLayout') > -1:
image_container = child.children[0]
cur_img = image_container.source
for i, img in enumerate(images):
if img == cur_img:
cur_idx = i
if cur_idx != last_idx:
nxt_img = images[cur_idx+1]
else:
nxt_img = images[0]
image_container.source = nxt_img
def prev_image(self):
images = self.images
cur_idx = None
last_idx = len(images) -1
view_children = self.dir
cur_img = None
image_container = None
for child in view_children:
if str(child).find('BoxLayout') > -1:
image_container = child.children[0]
cur_img = image_container.source
for i, img in enumerate(images):
if img == cur_img:
cur_idx = i
if cur_idx != 0:
prev_img = images[cur_idx-1]
else:
prev_img = images[last_idx]
image_container.source = prev_img
def new_img_name(self):
view_children = self.dir
self.dir = view_children
new_name = TextInput(hint_text='New Image Name', multiline=False)
new_name.bind(on_text_validate=self.rename_img)
new_name_modal = ImageManager(size_hint=(None, None), size=(400, 50))
new_name_modal.add_widget(new_name)
new_name_modal.open()
def rename_img(self):
self.dir.dismiss()
new_name = self.dir.text
view_children = self.dir
cur_img = None
image_container = None
for child in view_children:
if str(child).find('BoxLayout') > -1:
image_container = child.children[0]
cur_img = image_container.source
ext = cur_img[cur_img.rfind('.'):]
def callback1(self, inst):
self.text1=self.txt_1.text
return self.text1
def callback2(self, inst):
self.text2=self.txt_2.text
return self.text2
def viewimg(self):
im = Image(source=app.path)
view_size = self.img_resize(im)
effects_drop = DropDown()
btn_prev = Button(text='Prev', size_hint_y=None, height = 50)
btn_prev.bind(on_release=self.prev_image)
btn_rename = Button(text='Rename', size_hint_y=None, height = 50)
btn_rename.bind(on_release=self.new_img_name)
btn_effects = Button(text='Effects', size_hint_y=None, height = 50)
btn_effects.bind(on_release=effects_drop.open)
btn_next = Button(text='Next', size_hint_y=None, height = 50)
btn_next.bind(on_release=self.next_image)
btn_black = Button(text='Grayscale', size_hint_y=None, height = 50)
btn_black.bind(on_release=self.black_image)
btn_bin = Button(text='Binarization', size_hint_y=None, height = 50)
btn_bin.bind(on_release=self.bin_image)
self.txt_1 = TextInput(hint_text='min', size_hint_y=None, height = 50, multiline = False)
#btn_1.bind(on_release=self.callback)
self.txt_1.bind(on_text_validate=self.callback1)
self.txt_2 = TextInput(hint_text='max', size_hint_y=None, height = 50, multiline = False)
#btn_bin.bind(on_release=self.bin_image)
self.txt_2.bind(on_text_validate=self.callback2)
effects_drop.add_widget(btn_black)
effects_drop.add_widget(btn_bin)
effects_drop.add_widget(self.txt_1)
effects_drop.add_widget(self.txt_2)
image_ops = BoxLayout(size_hint=(None, None), size=(400, 30), spacing=4)
image_ops.add_widget(btn_prev)
image_ops.add_widget(btn_rename)
image_ops.add_widget(btn_effects)
image_ops.add_widget(btn_next)
anchor = AnchorLayout(anchor_x='center', anchor_y='bottom')
anchor.add_widget(image_ops)
image_container = BoxLayout()
view = ImageManager(size_hint=(None,None),size=view_size)
image_container.add_widget(im)
view.add_widget(image_container)
view.add_widget(anchor)
view.open()
self.dir = view.children
def bin_image(self):
if self.txt_1.text == '' and self.txt_2.text=='':
minimum_minimorum = 0
maximum_maximorum = 255
elif self.txt_1.text == '' and self.txt_2.text!='':
minimum_minimorum = 0
maximum_maximorum = int(self.txt_2.text)
elif self.txt_1.text != '' and self.txt_2.text=='':
minimum_minimorum = int(self.txt_1.text)
maximum_maximorum = 255
else:
minimum_minimorum = int(self.txt_1.text)
maximum_maximorum = int(self.txt_2.text)
# print(self.txt_1.text)
# print(self.txt_2.text)
view_children = self.dir
cur_img = None
image_container = None
for child in view_children:
if str(child).find('BoxLayout') > -1:
image_container = child.children[0]
cur_img = image_container.source
im = pillow.open(cur_img)
open_cv_image = np.array(im)
retval, threshold = cv2.threshold(open_cv_image, minimum_minimorum, maximum_maximorum, cv2.THRESH_BINARY)
print(minimum_minimorum, maximum_maximorum)
new_im = pillow.fromarray(threshold)
name = im.filename[:-4] + '_bin' + im.filename[-4:]
im_cap = im.filename[im.filename.rfind('/')+1:]
new_im.save(name)
self.ids.img_base.data.insert(0, {'im_source':name, 'im_caption':im_cap})
self.ids.img_base.refresh_from_data()
image_container.source = name
def img_resize(self, img):
im_size_x, im_size_y = img.texture_size
ratio = im_size_x/im_size_y
aspect = self.aspect_ratio(ratio, 50)
while im_size_x >= Window.width or im_size_y >= Window.height:
if im_size_x > im_size_y:
im_size_x -= aspect[0]
im_size_y -= aspect[1]
else:
im_size_y -= aspect[1]
return [im_size_x, im_size_y]
def aspect_ratio(self, val, lim):
lower = [0, 1]
upper = [1, 0]
while True:
mediant = [lower[0] + upper[0], lower[1] + upper[1]]
if (val * mediant[1] > mediant[0]) :
if (lim < mediant[1]) :
return upper
lower = mediant
elif (val * mediant[1] == mediant[0]) :
if (lim >= mediant[1]) :
return mediant
if (lower[1] < upper[1]) :
return lower
return upper
else :
if (lim < mediant[1]) :
return lower
upper = mediant
class Gallery(MDApp):
def build(self):
return GalleryApp()
if __name__=='__main__':
Gallery().run()
Here's gallery But why is an empty in the gallery ? but also add selection in that. Can anyone help me?
You are never loading your kv
string. The build()
method in your GalleryApp
class is not used and can be removed. Then add the call to Builder
into your build()
method of the actual App
class:
class Gallery(MDApp):
def build(self):
Builder.load_string(KV)
return GalleryApp()
The basic problem with your code is confusion between the App
class and other classes. Your GalleryApp
class is not an App
class, but you have App
methods in it (like build()
and on_start()
). The actual App
class in your code is the Gallery
class. Perhaps a poor choice of class names.
As noted earlier, you can remove the build()
method from the GalleryApp
class. Now you need to move the on_start()
method into the App
class (Gallery
) with slight modification:
class Gallery(MDApp):
overlay_color = get_color_from_hex("#6042e4")
def build(self):
Builder.load_string(KV)
return GalleryApp()
def on_start(self):
self.root.load_images()
Note that the overlay_color
that is referenced in the KV
must also be moved into the correct class.