Displaying multiple images side by side with tkinter - python

I wrote a program for facial recognition and now I have to make a GUI for it. What I need to do is to display 5 images of recognized person. But I can only display one of them. The others are shown empty. Here is the code:
root = Tk()
root.title("Test state")
def train_button():
os.system('python3 extract_embeddings.py --dataset dataset --embeddings output/embeddings.pickle --detector face_detection_model --embedding-model openface_nn4.small2.v1.t7')
os.system('python3 train_model.py --embeddings output/embeddings.pickle --recognizer output/recognizer.pickle --le output/le.pickle')
messagebox.showinfo("INFO","Training completed")
def select_photo():
global my_image
root.filename = filedialog.askopenfilename(initialdir="test",title ="Select a photo",filetypes=(("all files","*.*"),("png files","*.png"),("jpeg files","*.jpeg")))
output = subprocess.check_output("python3 recognize.py --detector face_detection_model --embedding-model openface_nn4.small2.v1.t7 --recognizer output/recognizer.pickle --le output/le.pickle --image "+root.filename, shell=True)
output = output.decode('utf-8')
pic_name = output.split('\n')[0]
my_image = ImageTk.PhotoImage(Image.open("images/"+pic_name+"/"+pic_name+"1.jpeg"))
my_image_label = Label(image = my_image).grid(row = 1 ,column = 0)
name_label = Label(text = pic_name).grid(row=2,column=0)
my_image1 = ImageTk.PhotoImage(Image.open("images/"+pic_name+"/"+pic_name+"2.jpeg"))
my_image_label1 = Label(image = my_image1).grid(row =1 ,column=1)
my_image2 = ImageTk.PhotoImage(Image.open("images/"+pic_name+"/"+pic_name+"3.jpeg"))
my_image_label2 = Label(image = my_image2).grid(row = 1,column = 2)
button1 = Button(root,text = "Train" , command = train_button).grid(row=0 ,column=0)
button2 = Button(root,text = "Recognise from image", command = select_photo).grid(row = 0 ,column=1)
root.mainloop()
This is how the program shows images
Resulting program
Thank you for your time

It is bug in PhotoImage which removes image when it is assigned to local variable in function.
You have to assing it to global variable (it can be list if you have many images) or assign to widgets which you use to display it - label.photo = image
I can test it but here is version which uses label.photo = image to resolve this problem
It also uses for-loop to create labels and keep them on list.
But when you use label.photo = image then list is not necessary. List is only useful to access labels to remove old labels before you create new labels.
import tkinter as tk # PEP8: `import *` is not preferred
from tkinter import filedialog
# --- functions ---
def train_button():
os.system('python3 extract_embeddings.py --dataset dataset --embeddings output/embeddings.pickle --detector face_detection_model --embedding-model openface_nn4.small2.v1.t7')
os.system('python3 train_model.py --embeddings output/embeddings.pickle --recognizer output/recognizer.pickle --le output/le.pickle')
messagebox.showinfo("INFO","Training completed")
def select_photo():
#global all_labels
root.filename = filedialog.askopenfilename(initialdir="test", title ="Select a photo", filetypes=(("all files","*.*"),("png files","*.png"),("jpeg files","*.jpeg")))
output = subprocess.check_output("python3 recognize.py --detector face_detection_model --embedding-model openface_nn4.small2.v1.t7 --recognizer output/recognizer.pickle --le output/le.pickle --image "+root.filename, shell=True)
output = output.decode('utf-8')
pic_name = output.split('\n')[0]
# remove previous labels
for label in all_labels:
label.destroy()
for number in range(3):
#filename = f"images/{pic_name}/{pic_name}{number+1}.jpeg" # f-string (Python 3.6+)
filename = "images/{}/{}{}.jpeg".format(pic_name, pic_name, number+1) # (Python 2.7, 3.0+)
image = ImageTk.PhotoImage(Image.open(filename))
label = tk.Label(image=image)
label.photo = image # assign to class variable to resolve problem with bug in `PhotoImage`
label.grid(row=1, column=number)
all_labels.append(label)
# --- main ---
all_labels = []
root = tk.Tk()
button1 = tk.Button(root, text="Train", command=train_button)
button1.grid(row=0, column=0)
button2 = tk.Button(root, text="Recognise from image", command=select_photo)
button2.grid(row=0, column=1)
root.mainloop()

Related

Tkinter opening two windows instead of one

I'm working on a checkers game GUI, and i can't seem to figure out why it keeps opening two windows instead of the one i initialize.
Here's my code: https://pastebin.com/s7XWLdfY
And here's a screenshot:link
Any help would be really appreciated, i'm fairly new to tkinter.
def init():
global root
global extraref #creates a reference to the pieces images
#so they don't get garbage collected
extraref = np.array([tk.Label() for item in range(64)]).reshape(8, 8)
def switch(board, val):
switcher = {
Board.E: "imgs/E.gif",
Board.W: "imgs/W.gif",
Board.B: "imgs/B.gif",
Board.DW: "imgs/DW.gif",
Board.DB: "imgs/DB.gif",
}
return switcher.get(val)
def refresh(board): #refreshes the board after a turn
mat = board.getMat()
#print(mat)
for i in range(8):
for j in range(8):
path = switch(board, mat[i][j])
#path = "imgs/B.gif"
tmp_img = Image.open(path)
img = itk.PhotoImage(tmp_img, master=root)
extraref[i][j] = tk.Label(root)
extraref[i][j].img = img
extraref[i][j].config(image = extraref[i][j].img)
butts[i*8+j].config(image = extraref[i][j].img)
extraref[i][j].pack()
init()
root = tk.Tk()
frame = tk.Frame(root, width=800, height=800, background="white")
frame.pack_propagate(0)
frame.pack()
lab = tk.Label(frame)
lab.pack()
butts = list()
for i in range (8):
for j in range (8):
lab.grid(row=i, column=j)
butt = tk.Button(lab, bg=("black" if i%2 != j%2 else "white"))
#butt.config(height=5, width=8)
#butt.bind("<Enter>", on_enter)
#butt.bind("<Leave>", on_leave)
butts.append(butt)
butt.grid(row=i, column=j) #creating button grid
board = Board()
refresh(board) #places pieces on the grid
root.mainloop()
P.S: for the complete code please check pastebin, i had to cut some functions to be able to post it
You are calling tk.Label() inside init() function which will create the first window. Then root = tk.Tk() will create the second window.
You should call init() after root = tk.Tk():
root = tk.Tk()
init()
frame = ...

how to hide labels in python until a button is pressed

I'm building a flashcard app and want a label to pop up when the user gets the answer correct. I was wondering how to make it so that both labels are hidden until one of the buttons is pressed and then only one would show up(and preferably disappear when the next button is pressed). My code so far is below.
from tkinter import *
from PIL import ImageTk, Image
from random import randint
import random
root = Tk()
root.title('Chemistry Flashcards')
root.geometry("500x500")
def balancing():
hide_all_frames()
balancing_frame.pack(fill="both", expand=1)
global show_balancing
show_balancing = Label(balancing_frame)
show_balancing.pack(pady=15)
global balancing_list
balancing_list = ['balanced1', 'balanced2', 'balanced3', 'balanced4', 'balanced5', 'unbalanced1', 'unbalanced2', 'unbalanced3', 'unbalanced4', 'unbalanced5']
global balanced_list
balanced_list = balancing_list[:5]
global unbalanced_list
unbalanced_list = balancing_list[5:10]
global rando_image
rando_image = random.choice(balancing_list)
global balancing_image
balancing1 = "C:/Users/Kisitu/Desktop/project/balancing/" + rando_image + ".png"
balancing_image = ImageTk.PhotoImage(Image.open(balancing1))
show_balancing.config(image=balancing_image)
global balanced_button
balanced_button = Button(balancing_frame, text = 'balanced', command = balancing_answer).pack()
global unbalanced_button
unbalanced_button = Button(balancing_frame, text = 'unbalanced', command = balancing_answer).pack()
global balanced_label
balanced_label = Label(balancing_frame, text='It was balanced', font=("Helvetica",18), bg='#B3FDFF')
balanced_label.pack(pady=15)
global unbalanced_label
unbalanced_label = Label(balancing_frame, text='It was unbalanced', font=("Helvetica",18), bg='#B3FDFF')
unbalanced_label.pack(pady=15)
balancing()
def hide_all_frames():
for widget in balancing_frame.winfo_children():
widget.destroy()
balancing_frame.pack_forget()
balancing_frame = Frame(root, width=500, height=500, )
my_menu = Menu(root)
root.config(menu=my_menu, bg='#B7F7BB')
#menu options(elements and compound)
lesson_menu = Menu(my_menu)
my_menu.add_cascade(label="Lesson", menu=lesson_menu)
lesson_menu.add_command(label="balancing", command=balancing)
lesson_menu.add_separator()
lesson_menu.add_command(label="Exit", command=root.quit)
'''
end
'''
root.mainloop()
add functions to both buttons
def balancing_answer(): #this will make the label to show and hide
balanced_label.pack(pady=15)
unbalanced_label.pack_forget()
def unbalancing_answer(): #this will make the label to show and hide
balanced_label.pack_forget()
unbalanced_label.pack(pady=15)
global balanced_button
balanced_button = Button(balancing_frame, text = 'balanced', command = balancing_answer).pack()
global unbalanced_button
unbalanced_button = Button(balancing_frame, text = 'unbalanced', command = unbalancing_answer).pack() # change the command to unbalancing_answer
global balanced_label
balanced_label = Label(balancing_frame, text='It was balanced', font=("Helvetica",18), bg='#B3FDFF')
global unbalanced_label
unbalanced_label = Label(balancing_frame, text='It was unbalanced', font=("Helvetica",18), bg='#B3FDFF')
# balancing() # no need for this
If I get your question correctly; this will make the labels to pop up and disappear.
from tkinter import *
from PIL import ImageTk, Image
from random import randint
import random
root = Tk()
root.title('Chemistry Flashcards')
root.geometry("500x500")
def balancing_answer():
balancing_frame.pack()
balanced_label.pack(pady=15)
unbalanced_label.pack_forget()
show_balancing.config(image=balancing_image)
def unbalancing_answer():
balancing_frame.pack_forget()
balanced_label.pack_forget()
unbalanced_label.pack(pady=15)
show_balancing.config(image=balancing_image)
#two frames-unbalancing frame and balancing frame
balancing_frame = Frame(root)
unbalancing_frame=Frame(root)
#this is the show balancing frame
show_balancing = Label(balancing_frame)
show_balancing.pack()
#only one image is specified. there can be no random images.but the image will flash up at a click and disappear at another click
img = Image.open('p.jpg').convert("RGBA")
w, h = img.size
left = w/5
right = 3*w/5
upper = h/5
lower = 3*h/5
img2 = img.crop([ left, upper, right, lower]) #this part is used to crop the image. you can choose to ignore
balancing_image= ImageTk.PhotoImage(img2)
#two buttons to click
balanced_button = Button(unbalancing_frame, text = 'balanced', command = balancing_answer).pack()
unbalanced_button = Button(unbalancing_frame, text = 'unbalanced', command = unbalancing_answer).pack()
#the two labels balanced and unbalanced
balanced_label = Label(balancing_frame, text="it was balanced", font=("Helvetica",9), bg='#B3FDFF')
unbalanced_label = Label(unbalancing_frame, text='It was unbalanced', font=("Helvetica",9), bg='#B3FDFF')
#when the user click balancing.. a new frame appear
def balancing():
unbalancing_frame.pack()
#========the menu=========
my_menu = Menu(root)
root.config(menu=my_menu, bg='#B7F7BB')
#menu options(elements and compound)
lesson_menu = Menu(my_menu)
my_menu.add_cascade(label="Lesson", menu=lesson_menu)
lesson_menu.add_command(label="balancing", command=balancing)
lesson_menu.add_separator()
lesson_menu.add_command(label="Exit", command=root.quit)
root.mainloop()

How to give the location of "Input" and "Output" for a python code using User Interface and run the code from UI itself?

I have a python code :
import gdal
import numpy
from skimage.filters import threshold_otsu
ds = gdal.Open('A:\\algo\\f2.tif')
In this code, line 4 gives the location/path of "input file" and line 10 gives the location of "output file".
I want to create a user interface to give this location in the user interface itself and run the code from user interface itself.
I have tried making a user interface using "tkinter" module :
from tkinter import *
from tkinter import filedialog
def input():
file1 = filedialog.askopenfile()
label = Label(text=file1).pack()
def input2():
file2 = filedialog.asksaveasfile(mode="w", defaultextension=".tif")
label = Label(text=file2).pack()
w = Tk()
w.geometry("500x500")
w.title("FLOOD_MAPPER")
h = Label(text = "S1A FLOOD MAPPER", bg = "yellow", fg = "black", height = "3", width = "500")
h.pack()
i1 = Label(text = "Input*")
i1.place(x=10, y=70)
i1b = Button(w, text = "Select File", command =input)
i1b.place(x=250, y=70)
i2 = Label(text = "Intermediate Product*")
i2.place(x=10, y=140)
i2b = Button(w, text = "Save as", command =input2)
i2b.place(x=250, y=140)
button = Button(w, text="Generate Map", bg = "red", fg = "black", height = "2", width="30")
button.place(x=150, y=400)
w.mainloop()
But I didn't understand how to link these two codes.
The moment I click on button "generate map" in the user interface I want the location/path of Input and output given in the user interface box to move to their respective places in the 1st code and then run the same code aumoatically.
Kindly, help me to achieve my requirement.
It can look like this. I removed keep only important elements in tkinter.
I put code in your_code and it can get filenames as paramaters. So this code looks similar as before.
I create function gen_map which get run your_code with filenames which are assigned to global variables input_filename, `output_filename.
I assing gen_map to button Button( command=gen_map) so it will run it when you press button.
Other buttons open dialog to get file names and assign to global variables input_filename, output_filename.
from tkinter import *
from tkinter import filedialog
import gdal
import numpy
from skimage.filters import threshold_otsu
def your_code(input_file, output_file):
#ds = gdal.Open('A:\\algo\\f2.tif')
ds = gdal.Open(input_file)
band = ds.GetRasterBand(1)
arr = band.ReadAsArray()
thresh = threshold_otsu(arr,16)
binary = arr > thresh
driver = gdal.GetDriverByName("GTiff")
#outdata = driver.Create("A:\\algo\\test11.tif", 14823, 9985, 1, gdal.GDT_UInt16)
outdata = driver.Create(output_file, 14823, 9985, 1, gdal.GDT_UInt16)
outdata.SetGeoTransform(ds.GetGeoTransform())
outdata.SetProjection(ds.GetProjection())
outdata.GetRasterBand(1).WriteArray(binary)
outdata.GetRasterBand(1).SetNoDataValue(10000)
outdata.FlushCache() ##saves to disk!!
#outdata = None
#band = None
#ds = None
def get_input_filename():
global input_filename
# `askopenfilename` instead of `askopenfile` to get filename instead of object file
input_filename = filedialog.askopenfilename()
input_label['text'] = input_filename
def get_output_filename():
global output_filename
# `asksaveasfilename` instead of `asksaveasfile` to get filename instead of object file
output_filename = filedialog.asksaveasfilename(defaultextension=".tif")
output_label['text'] = output_filename
def gen_map():
#global input_filename
#global output_filename
print('input:', input_filename)
print('output:', output_filename)
your_code(input_filename, output_filename)
#---------------------------------------------
# global variables with default values at start
input_filename = 'A:\\algo\\f2.tif'
output_filename = "A:\\algo\\test11.tif"
root = Tk()
#input_label = Label(root, text=input_filename)
input_label = Label(root, text="Input*")
input_label.pack()
input_button = Button(root, text="Select File", command=get_input_filename)
input_button.pack()
#output_label = Label(root, text=output_filename)
output_label = Label(root, text="Intermediate Product*")
output_label.pack()
output_button = Button(root, text="Save as", command=get_output_filename)
output_button.pack()
gen_map_button = Button(root, text="Generate Map", command=gen_map)
gen_map_button.pack()
root.mainloop()

Tkinter images crashing

So I made a script in python with Tkinter and the thing is that the first Tkinter window pops up without problems but when the code goes to the second window it says :
_tkinter.TclError: image "pyimage1" doesn't exist
and I didn't find anything that helped me, could someone help me please ?
Here is the code :
from Tkinter import *
from PIL import ImageTk, Image
def choose():
global name, chosen
name = name1.get()
chosen = chosen1.get()
print name
print chosen
root0.quit()
root0 = Tk()
name1 = Entry(root0)
name1.pack()
chosen1 = Entry(root0)
chosen1.pack()
Button(root0, text="ENTER", command=choose).pack()
root0.mainloop()
root = Tk()
img = ImageTk.PhotoImage(Image.open('person1.png'))
panel1 = Label(root, image = img)
panel1.pack(side="left")
img2 = ImageTk.PhotoImage(Image.open('person2.png'))
panel2 = Label(root, image = img2)
panel2.pack(side="right")
root.mainloop()
by the way, the python version is 2.7
This is a side effect of using 2 roots (Tk() instances). The images default to associate with the first root window. The quick fix is to provide the image with the correct root:
img2 = ImageTk.PhotoImage(Image.open('person2.png'), master=root)
The proper fix is to never use more than one Tk(). Put all your code into Frame instances, and then destroy one and load the other when the time is right:
import Tkinter as tk
def choose():
global name, chosen
name = name1.get()
chosen = chosen1.get()
print name
print chosen
frame0.destroy() # kill this frame
frame1.pack() # open new frame
root = tk.Tk()
frame0 = tk.Frame(root)
name1 = tk.Entry(frame0)
name1.pack()
chosen1 = tk.Entry(frame0)
chosen1.pack()
tk.Button(frame0, text="ENTER", command=choose).pack()
frame1 = tk.Frame(root)
img = ImageTk.PhotoImage(Image.open('person1.png'))
panel1 = tk.Label(frame1, image = img)
panel1.pack(side="left")
img2 = ImageTk.PhotoImage(Image.open('person2.png'))
panel2 = tk.Label(frame1, image = img2)
panel2.pack(side="right")
#start the program
frame0.pack() # load frame0
root.mainloop()
Note I also moved you away from the evil wildcard imports (from module import *).

Making a function run code

I am making a app with python and Tkinter. Say I added two buttons one for MAIN and one for NEWS when I press MAIN make the function mainthumsfun run and set the variables and after that run gui function with the new variables. How would I make that work?
import StringIO
import Scraper
import Tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
root.title('RazeTheWorld')
maintumbs = Scraper.maintumbs()
newstumbs = Scraper.newstumbs()
def mainthumsfun():
url0 = mainthumbs[0]
url1 = mainthumbs[1]
url2 = mainthumbs[2]
url3 = mainthumbs[3]
def newsthumbsfun():
url0 = newsthumbs[0]
url1 = newsthumbs[1]
url2 = newsthumbs[2]
url3 = newsthumbs[3]
def gui():
imgf1 = urllib.urlopen(url0)
imgwr1 = StringIO.StringIO(imgf1.read())
image1 = ImageTk.PhotoImage(Image.open(imgwr1))
panel1 = tk.Label(root, image=image1)
panel1.grid(row=0,column=0)
imgf2 = urllib.urlopen(url1)
imgwr2 = StringIO.StringIO(imgf2.read())
image2 = ImageTk.PhotoImage(Image.open(imgwr2))
panel2 = tk.Label(root, image=image2)
panel2.grid(row=1,column=0)
imgf3 = urllib.urlopen(url2)
imgwr3 = StringIO.StringIO(imgf3.read())
image3 = ImageTk.PhotoImage(Image.open(imgwr3))
panel3 = tk.Label(root, image=image3)
panel3.grid(row=2,column=0)
imgf4 = urllib.urlopen(url4)
imgwr4 = StringIO.StringIO(imgf4.read())
image4 = ImageTk.PhotoImage(Image.open(imgwr4))
panel4 = tk.Label(root, image=image4)
panel4.grid(row=3,column=0)
root.mainloop()
You just want buttons that run code when clicked?
What you do is draw a widget within your root Frame, such as a button or a menu field.
Check out this example text editor
It's a text editor with a menu and a couple of buttons calling a method when you click 'it. No more. Easy to grok :)

Categories

Resources