Opencv GUI python: arrange the created buttons - python

I use python 3.8 and Opencv in Linux.
I have several buttons that have stacked horizontally. How can I arrange them as I like (e.g., in a grid way?)
Is it possible to show some icons for each of the buttons?
Is it possible to make the fonts of the buttons bar larger?
Part of my script: (any suggestion to make my script better is appreciated)
if __name__== "__main__":
Folder_name = "male"
data_path = "path/to/images"
data_path = os.path.join(data_path, Folder_name)
all_imgs_path = glob.glob("{}/*.jpg".format(data_path))
all_imgs_path = sorted(all_imgs_path)
annot = annotation_tool(nof_imgs=len(all_imgs_path))
for index, im_dir in enumerate(all_imgs_path):
annot[index] = im_dir
item_path = "guid.jpg"
img = cv2.imread(item_path)
img_name = item_path.split("/")[-1]
cv2.imshow("{}".format(img_name), img)
cv2.createButton('Next', annot.Next, ["Next Image"])
cv2.createButton('Back', annot.Back, ["Previous Image"])
cv2.createButton('Submit', annot.Submit, ["Submit"])
# there are many of these buttons
UB_Tshirt = cv2.createButton("UB_Tshirt", annot.checkbox, "UB_Tshirt", 1, 0)
UB_Shirt = cv2.createButton("UB_Shirt", annot.checkbox, "UB_Shirt", 1, 0)
UB_Coat = cv2.createButton("UB_Coat", annot.checkbox, "UB_Coat", 1, 0)
cv2.waitKey(0)
print("end")
Edit:
As you see in the image, the buttons bar is very long and goes out of the screen. I would like to create a button pad that is squared.

This isn't a complete answer, but in regards to button arrangement, you have a little control using 'cv2.QT_NEW_BUTTONBAR'.
There's further detail here: https://docs.opencv.org/4.x/dc/d46/group__highgui__qt.html#gad15c7adb377e778dc907c0e318be193e

Related

ipywidgets: button.on_click() has output delay

Introduction
I am trying to make a small tool for classifying images using the ipywidgets in a Jupyter Notebook, but I am having some trouble aligning the classes and the images. Do you have any suggestion how to fix this.
What I did
import ipywidgets as widgets
from IPython.display import display
import glob
# My images
image_paths = glob.glob("./images/*.png")
# Display image
def display_image(path):
file = open(path, "rb")
image = file.read()
return widgets.Image(
value=image,
format='png',
width=700,
height=700,
)
# Dropdown
def create_dropdown():
return widgets.Dropdown(
options=["1","2","3","4","5","6","7","8","9","10"],
value='5',
description='Category:',
disabled=False
)
# Creating widgets
input_dropdown = create_dropdown()
button = widgets.Button(description="Submit")
output_image = widgets.Image()
output_image.value = display_image(image_paths[-1]).value
# Define function to bind value of the input to the output variable
def bind_input_to_output(sender):
image_path = image_paths[-1]
image_score = input_dropdown.value
next_image_path = image_paths.pop()
print(image_score, image_path)
output_image.value = display_image(next_image_path).value
# Tell the text input widget to call bind_input_to_output() on submit
button.on_click(bind_input_to_output)
# Displaying widgets
display(output_image, input_dropdown, button)
Results
With the above code I end up categorising the upcoming picture, but I really don't understand why. It seems the widgets does not update the image the first time I press the button.
def bind_input_to_output(sender):
image_path = image_paths.pop()
image_score = input_dropdown.value
next_image_path = image_paths[-1]
print(image_score, image_path)
output_image.value = display_image(next_image_path).value
pop first and give next filename at last item

Python select ROI OpenCV

Sample Image
Hello,
I created an application in python that select the Region of Interest(ROI) of an image, record and label it. But I has a limit of one ROI per image, anyone know how to have multiple selection of ROI per image? Also on attached image, as you can see I have multiple window, I want it to be in one window with different options, what packages are use on this kind of application.
here's my code in python using opencv2. Thank you in advance for the help
for image in filelist:
img = cv2.imread(image)
fromCenter = False
r = cv2.selectROI(img, fromCenter)
lbl = simpledialog.askstring("Image Label", "Please Enter Label")
result = eTree.SubElement(results, "Image")
path = eTree.SubElement(result, 'Path')
roi = eTree.SubElement(result, 'ROI')
label = eTree.SubElement(result, 'Label')
path.text = str(image)
roi.text = str(r)
label.text = str(lbl)
tree = eTree.ElementTree(results)
i = i + 1
if i == count:
format = [('XML Files', '*.xml'), ('All Files', '*.*')]
save = filedialog.asksaveasfilename(filetype=format, defaultextension='*.xml')
tree.write(save, xml_declaration=True, encoding='utf-8', method="xml")
Well at least for the first part of the question, have you considered to try the cv2.createROIs() instead of cv2.createROI() ? When the image window is opened you then select your first ROI and press enter, then the second and press enter etc. And when you are finished then press the escape key. It returns x,y,w,h of each ROI. Note that you will have to change your code accordingly but it will allow you to select multiple ROI.
Input image:
Example:
import cv2
img = cv2.imread('rois.png')
fromCenter = False
ROIs = cv2.selectROIs('Select ROIs', img, fromCenter)
ROI_1 = img[ROIs[0][1]:ROIs[0][1]+ROIs[0][3], ROIs[0][0]:ROIs[0][0]+ROIs[0][2]]
ROI_2 = img[ROIs[1][1]:ROIs[1][1]+ROIs[1][3], ROIs[1][0]:ROIs[1][0]+ROIs[1][2]]
ROI_3 = img[ROIs[2][1]:ROIs[2][1]+ROIs[2][3], ROIs[2][0]:ROIs[2][0]+ROIs[2][2]]
cv2.imshow('1', ROI_1)
cv2.imshow('2', ROI_2)
cv2.imshow('3', ROI_3)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
For custom ROI you can use EasyROI. It supports rectangle, line, circle and polygon.
For using it:
pip install EasyROI
from EasyROI import EasyROI
roi_helper = EasyROI()
roi = roi_helper.draw_rectangle(frame, quantity=2)

How to change Bitmap1 for ToolBarToolBase Object in wxPython

How does one change the "image" shown on a toolbar button dynamically in wxPython?
frame = wx.Frame( ... )
tb = frame.CreateToolBar()
tool_bmp = wx.Bitmap("/path/to/tool.png", wx.BITMAP_TYPE_PNG)
tb.AddLabelTool(id=wx.ID_ANY, label="Clicky", bitmap=tool_bmp, bmpDisabled=wx.NullBitmap, shortHelp="Clicky")
tbtb = tb.GetToolByPos(0)
Specifically, I want to change the "image" shown on the ToolBarToolBase object tbtb. I have tried things like:
new_bmp = wx.Bitmap("/path/to/new.png", wx.BITMAP_TYPE_PNG)
tbtb.SetBitmap1(new_bmp)
tb.Refresh()
and
tool_bmp = wx.BitMap("/path/to/new.png, sx.BITMAP_TYPE_PNG)
tb.Refresh()
to no avail.
Try using SetNormalBitmap instead
new_bmp = wx.Bitmap("/path/to/new.png", wx.BITMAP_TYPE_PNG)
tbtb.SetNormalBitmap(new_bmp)
tb.Realize()
tb.Refresh()

Generating consecutive bitmaps with wxPython trouble

Well, while I don't consider myself an experienced programmer, especially when it comes to multimedia applications, I had to do this image viewer sort of a program that displays images fullscreen, and the images change when the users press <- or -> arrows.
The general idea was to make a listbox where all the images contained in a certain folder (imgs) are shown, and when someone does double click or hits RETURN a new, fullscreen frame is generated containing, at first, the image selected in the listbox but after the user hits the arrows the images change in conecutive order, just like in a regular image viewer.
At the beginning, when the first 15 - 20 images are generated, everything goes well, after that, although the program still works an intermediary, very unpleasant and highly unwanted, effect appears between image generations, where basically some images that got generated previously are displayed quickly on the screen and after this the right, consecutive image appears. On the first apparitions the effect is barelly noticeble, but after a while it takes longer and longer between generations.
Here's the code that runs when someone does double click on a listbox entry:
def lbclick(self, eve):
frm = wx.Frame(None, -1, '')
frm.ShowFullScreen(True)
self.sel = self.lstb.GetSelection() # getting the selection from the listbox
def pressk(eve):
keys = eve.GetKeyCode()
if keys == wx.WXK_LEFT:
self.sel = self.sel - 1
if self.sel < 0:
self.sel = len(self.chk) - 1
imgs() # invocking the function made for displaying fullscreen images when left arrow key is pressed
elif keys == wx.WXK_RIGHT:
self.sel = self.sel + 1
if self.sel > len(self.chk) - 1:
self.sel = 0
imgs() # doing the same for the right arrow
elif keys == wx.WXK_ESCAPE:
frm.Destroy()
eve.Skip()
frm.Bind(wx.EVT_CHAR_HOOK, pressk)
def imgs(): # building the function
imgsl = self.chk[self.sel]
itm = wx.Image(str('imgs/{0}'.format(imgsl)), wx.BITMAP_TYPE_JPEG).ConvertToBitmap() # obtaining the name of the image stored in the list self.chk
mar = itm.Size # Because not all images are landscaped I had to figure a method to rescale them after height dimension, which is common to all images
frsz = frm.GetSize()
marx = float(mar[0])
mary = float(mar[1])
val = frsz[1] / mary
vsize = int(mary * val)
hsize = int(marx * val)
panl = wx.Panel(frm, -1, size = (hsize, vsize), pos = (frsz[0] / 2 - hsize / 2, 0)) # making a panel container
panl.SetBackgroundColour('#000000')
imag = wx.Image(str('imgs/{0}'.format(imgsl)), wx.BITMAP_TYPE_JPEG).Scale(hsize, vsize, quality = wx.IMAGE_QUALITY_NORMAL).ConvertToBitmap()
def destr(eve): # unprofessionaly trying to destroy the panel container when a new image is generated hopeing the unvanted effect, with previous generated images will disappear. But it doesn't.
keycd = eve.GetKeyCode()
if keycd == wx.WXK_LEFT or keycd == wx.WXK_RIGHT:
try:
panl.Destroy()
except:
pass
eve.Skip()
panl.Bind(wx.EVT_CHAR_HOOK, destr) # the end of my futile tries
if vsize > hsize: # if the image is portrait instead of landscaped I have to put a black image as a container, otherwise in the background the previous image will remain, even if I use Refresh() on the container (the black bitmap named fundal)
intermed = wx.Image('./res/null.jpg', wx.BITMAP_TYPE_JPEG).Scale(frsz[0], frsz[1]).ConvertToBitmap()
fundal = wx.StaticBitmap(frm, 101, intermed)
stimag = wx.StaticBitmap(fundal, -1, imag, size = (hsize, vsize), pos = (frsz[0] / 2 - hsize / 2, 0))
fundal.Refresh()
stimag.SetToolTip(wx.ToolTip('Esc = exits fullscreen\n<- -> arrows = quick navigation'))
def destr(eve): # the same lame attempt to destroy the container in the portarit images situation
keycd = eve.GetKeyCode()
if keycd == wx.WXK_LEFT or keycd == wx.WXK_RIGHT:
try:
fundal.Destroy()
except:
pass
eve.Skip()
frm.Bind(wx.EVT_CHAR_HOOK, destr)
else: # the case when the images are landscape
stimag = wx.StaticBitmap(panl, -1, imag)
stimag.Refresh()
stimag.SetToolTip(wx.ToolTip('Esc = exits fullscreen\n<- -> arrows = quick navigation'))
imgs() # invocking the function imgs for the situation when someone does double click
frm.Center()
frm.Show(True)
Thanks for any advice in advance.
Added later:
The catch is I'm trying to do an autorun presentation for a DVD with lots of images on it. Anyway it's not necessarely to make the above piece of code work properly if there are any other options. I've already tried to use windows image viewer, but strangely enough it doesn't recognizes relative paths and when I do this
path = os.getcwd() # getting the path of the current working directory
sel = listbox.GetSelection() # geting the value of the current selection from the list box
imgname = memlist[sel] # retrieving the name of the images stored in a list, using the listbox selection, that uses as choices the same list
os.popen(str('rundll32.exe C:\WINDOWS\System32\shimgvw.dll,ImageView_Fullscreen {0}/imgsdir/{1}'.format(path, imgname))) # oepning the images up with bloody windows image viewer
it opens the images only when my program is on the hard disk, if it's on a CD / image drive it doesn't do anything.
There's an image viewer included with the wxPython demo package. I also wrote a really simple one here. Either one should help you in your journey. I suspect that you're not reusing your panels/frames and instead you're seeing old ones that were never properly destroyed.

python aboutdialog space between program name/version and logo

please how can i set space between program name/version and logo in this code? I am using pygtk. thanks
about = gtk.AboutDialog()
about.set_program_name("name")
about.set_version("0.0.1")
about.set_logo(gtk.gdk.pixbuf_new_from_file("file.png"))
It's kind of hacky I suppose, but this works:
import gtk
about = gtk.AboutDialog()
about.set_program_name("name")
about.set_version("0.0.1")
about.set_logo(gtk.gdk.pixbuf_new_from_file("file.png"))
about.show()
vbox = about.get_children()[0].get_children()[0] # vbox containing everything but the buttons at the bottom
label = vbox.get_children()[1] # Label containing name and version
alignment = gtk.Alignment(xalign=0.5, yalign=0.5)
alignment.set_padding(100, 0, 0, 0)
alignment.show()
vbox.remove(label)
alignment.add(label)
vbox.add(alignment)
vbox.reorder_child(alignment, 1) # Put it back in the correct order, rather than below the URL and stuff
gtk.main()
Change 100 to the number of pixels you want to add between the logo and the program name.

Categories