I have set up a Rasbperry Pi 3 and using Python 3. I can take images but need to refresh them on screen. VERY new to tkinker. I have some code but would like to know how to place a nice sized image on the canvas and to refresh it when one of my buttons is pressed.
#!/usr/bin/python
import tkinter
import RPi.GPIO as GPIO
import picamera
import time
from PIL import Image, ImageTk
def startup():
def callback(a):
if a==4:
thiscolour="yellow"
camera.capture('/home/pi/Desktop/image.jpg')
if a==2:
thiscolour="red"
lbl.configure(text=thiscolour+" has been pressed")
path = "/home/pi/Desktop/image.jpg"
img = Image.open(path)
new_width = 400
new_height = 600
#img = img.resize((new_width, new_height), Image.ANTIALIAS)
img.save('thisimage.jpg')
path="thisimage.jpg"
path="thisimage.jpg"
image = Image.open(path)
photo = ImageTk.PhotoImage(image)
img = ImageTk.PhotoImage(Image.open(path))
panel.configure(image=photo)
panel.pack()
camera = picamera.PiCamera()
path = "/home/pi/Desktop/image.jpg"
img = Image.open(path)
new_width = 400
new_height = 600
img = img.resize((new_width, new_height), Image.ANTIALIAS)
img.save('thisimage.jpg')
path="thisimage.jpg"
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
buttonyellow = 4
buttonred = 2
t=0
GPIO.setup(buttonyellow, GPIO.IN, GPIO.PUD_UP)
GPIO.setup(buttonred, GPIO.IN, GPIO.PUD_UP)
window=tkinter.Tk()
window.title("Photobooth")
window.geometry("1000x800")
lbl=tkinter.Label(window,text="Instructions")
ent=tkinter.Entry(window)
btn=tkinter.Button(window,text="Press here", bg='red')
btn=tkinter.Button(window,text="Click me",bg='red',command=callback)
btn.pack()
lbl.pack()
ent.pack()
btn.pack()
GPIO.add_event_detect(buttonyellow, GPIO.FALLING, callback=callback, bouncetime=100)
GPIO.add_event_detect(buttonred, GPIO.FALLING, callback=callback, bouncetime=100)
path="thisimage.jpg"
image = Image.open(path)
photo = ImageTk.PhotoImage(image)
img = ImageTk.PhotoImage(Image.open(path))
panel = tkinter.Label(window, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
window.mainloop()
startup()
The image is displayed in a label. The update button triggers a command that first take the new picture (or whatever you want, I haven't written this part of the code), then loads the new image and finally updates the image inside the label using configure(image=...).
import tkinter as tk
from PIL import Image, ImageTk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self) # create window
# load initial image
self.img = ImageTk.PhotoImage(Image.open("path/to/image"))
# display it in a label
self.label = tk.Label(self, image=self.img)
self.label.pack(fill='both', expand=True)
tk.Button(self, text="Update", command=self.update_image).pack()
self.mainloop()
def update_image(self):
# code to capture new image here
# ...
# load new image
self.img = ImageTk.PhotoImage(Image.open("path/to/image"))
# update label image
self.label.configure(image=self.img)
if __name__ == '__main__':
App()
Related
I found on the internet this python code for counting people with the Open CV library. I would need to open the window that opens with CV2, inside a Tkinter window in order to then add the commands for the settings.
This is the code from GitHub: https://github.com/Gupu25/PeopleCounter
How can I make the two OpenCv windows open inside a Tkinter window?
Here is a minimal example of opening a video in a tkinter window with OpenCV's VideoCapture object:
from tkinter import NW, Tk, Canvas, PhotoImage
import cv2
def photo_image(img):
h, w = img.shape[:2]
data = f'P6 {w} {h} 255 '.encode() + img[..., ::-1].tobytes()
return PhotoImage(width=w, height=h, data=data, format='PPM')
def update():
ret, img = cap.read()
if ret:
photo = photo_image(img)
canvas.create_image(0, 0, image=photo, anchor=NW)
canvas.image = photo
root.after(15, update)
root = Tk()
root.title("Video")
cap = cv2.VideoCapture("video.mp4")
canvas = Canvas(root, width=1200, height=700)
canvas.pack()
update()
root.mainloop()
cap.release()
To display 2 OpenCV videos, simply make a few adjustments, and use the np.hstack() method or the np.vstack() method, depending on whether you want your videos to be displayed side by side horizontally or vertically:
from tkinter import NW, Tk, Canvas, PhotoImage
import cv2
import numpy as np
def photo_image(img):
h, w = img.shape[:2]
data = f'P6 {w} {h} 255 '.encode() + img[..., ::-1].tobytes()
return PhotoImage(width=w, height=h, data=data, format='PPM')
def update():
ret1, img1 = cap1.read()
ret2, img2 = cap2.read()
if ret1:
photo = photo_image(np.hstack((img1, img2)))
canvas.create_image(0, 0, image=photo, anchor=NW)
canvas.image = photo
root.after(15, update)
root = Tk()
root.title("Video")
cap1 = cv2.VideoCapture("video1.mp4")
cap2 = cv2.VideoCapture("video2.mp4")
canvas = Canvas(root, width=1200, height=700)
canvas.pack()
update()
root.mainloop()
cap.release()
So currently, I have to design some Menu bars with many options when clicked. But I have Menu bars part settled, what I'm lost about is I want to have 2 images. For instance if I click 'View', it'll drop down 'Original Image' & 'Scaled image' and if I clicked either one, it will show me respective images with the correct images.
import cv2
import numpy as np
img = cv2.imread('image.jpg')
scaled_img = cv2.resize(img, (400, 500))
cv2.imshow('Original image', img)
From my original code; and I'm not sure where to insert above codes(if correct), to below.
def showImg(self):
load = Image.open('image.jpg')
render = ImageTk.PhotoImage(load)
img = Label(self, image=render)
img.image = render
img.place(x=0,y=0)
You can use Pillow module to resize image instead of OpenCV. Below is an example:
from tkinter import *
from PIL import Image, ImageTk
class Window(Tk):
def __init__(self):
Tk.__init__(self)
self.geometry('500x600')
# initialize the images
img = Image.open('image.jpg')
self.original_img = ImageTk.PhotoImage(image=img)
img = img.resize((400, 500))
self.scaled_img = ImageTk.PhotoImage(image=img)
# create the menu bar
menubar = Menu(self)
self.config(menu=menubar)
file = Menu(menubar, tearoff=0)
file.add_command(label='New')
file.add_command(label='Open')
file.add_command(label='Save')
file.add_command(label='Save As')
file.add_separator()
file.add_command(label='Exit', command=self.client_exit)
menubar.add_cascade(label='File', menu=file)
view = Menu(menubar, tearoff=0)
view.add_command(label='Original Image', command=lambda:self.showImg(self.original_img))
view.add_command(label='Scaled Image', command=lambda:self.showImg(self.scaled_img))
menubar.add_cascade(label='View', menu=view)
# create a label to show the image
self.imgbox = Label(self)
self.imgbox.place(x=0, y=0)
def showImg(self, img):
self.imgbox.config(image=img)
def client_exit(self):
self.destroy()
Window().mainloop()
from tkinter import *
import tkinter as tk
from PIL import Image, ImageTk
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
# Creation of init_window
def init_window(self):
img = Image.open("001.png")
img = img.resize((250, 250)) ## The (250, 250) is (height, width)
photo = ImageTk.PhotoImage(img)
quitBtn2 = Label(root, image=photo)
quitBtn2.image = photo
quitBtn2.pack()
Image Module
The Image module provides a class with the same name which is used to
represent a PIL image. The module also provides a number of factory
functions, including functions to load images from files, and to
create new images.
https://pillow.readthedocs.io/en/stable/reference/Image.html
I'm trying to display a thumbnail image in tkinter by saving the image in memory using io.BytesIO(). I'm getting _tkinter.TclError: format error in bitmap data. The BitmapImage supports X11 bitmap image. So my question is how to convert my images to xbm before pass it to BitmapImage method?
from PIL import Image, ImageTk
import tkinter.scrolledtext as tkst
import tkinter as tk
import os, os.path
import io
class Example(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
img = Image.open("1.jpg")
image_size = 256, 256
img.thumbnail(image_size,Image.ANTIALIAS)
b = io.BytesIO()
img.save(b, 'gif')
p = b.getvalue()
photo = tk.BitmapImage(data=p)
self.photo = photo
self.imageview = tk.Label(self, image = self.photo, background="black")
self.imageview.grid(row=0, column=0, rowspan=2, sticky="nsew")
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.geometry("800x400")
root.mainloop()
Last time, I solved the problem using this code but sometimes the height of the image will get cut off.
image = Image.open("1.jpg")
basewidth = 900
wpercent = (basewidth/float(image.size[0]))
hsize = int((float(image.size[1])*float(wpercent)))
image = image.resize((basewidth,hsize),Image.ANTIALIAS)
self.photo = ImageTk.PhotoImage(image)
self.imageview.configure(image=self.photo)
I'm trying to make a python script that shows a image that is acessed on a listbox. This code that I got on the internet works:
import Tkinter as tk
from PIL import ImageTk, Image
window = tk.Tk()
path = 'img\\2015722_univ_sqs_sm.jpg'
img = ImageTk.PhotoImage(Image.open(path))
panel = tk.Label(window, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
window.mainloop()
But when I tried to adapt it do the listbox it stopped working.
from Tkinter import *
from PIL import ImageTk, Image
import glob
files = glob.glob('img\\*.jpg')
class App:
def __init__(self, root):
self.l = Listbox(root, width = 50, height = 15)
self.l.pack()
self.l.bind('<<ListboxSelect>>', self.lol)
self.c = Label(root)
self.c.pack()
for f in files:
self.l.insert(END, f)
def lol(self, evt):
path = files[self.l.curselection()[0]]
img = ImageTk.PhotoImage(Image.open(path))
self.c.image = img
self.c.pack()
root = Tk()
App(root)
root.mainloop()
What am I missing?
You must use the configure method of the label, and store a reference to the image somewhere.
self.c.image = img # save reference
self.c.configure(image=img) # configure the label
I would like to be able to swap out an image on a Tkinter label, but I'm not sure how to do it, except for replacing the widget itself.
Currently, I can display an image like so:
import Tkinter as tk
import ImageTk
root = tk.Tk()
img = ImageTk.PhotoImage(Image.open(path))
panel = tk.Label(root, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
root.mainloop()
However, when the user hits, say the ENTER key, I'd like to change the image.
import Tkinter as tk
import ImageTk
root = tk.Tk()
img = ImageTk.PhotoImage(Image.open(path))
panel = tk.Label(root, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
def callback(e):
# change image
root.bind("<Return>", callback)
root.mainloop()
Is this possible?
The method label.configure does work in panel.configure(image=img).
What I forgot to do was include the panel.image=img, to prevent garbage collection from deleting the image.
The following is the new version:
import Tkinter as tk
import ImageTk
root = tk.Tk()
img = ImageTk.PhotoImage(Image.open(path))
panel = tk.Label(root, image=img)
panel.pack(side="bottom", fill="both", expand="yes")
def callback(e):
img2 = ImageTk.PhotoImage(Image.open(path2))
panel.configure(image=img2)
panel.image = img2
root.bind("<Return>", callback)
root.mainloop()
The original code works because the image is stored in the global variable img.
Another option to do it.
Using object-oriented programming and with an interactive interface to update the image.
from Tkinter import *
import tkFileDialog
from tkFileDialog import askdirectory
from PIL import Image
class GUI(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
w,h = 650, 650
master.minsize(width=w, height=h)
master.maxsize(width=w, height=h)
self.pack()
self.file = Button(self, text='Browse', command=self.choose)
self.choose = Label(self, text="Choose file").pack()
self.image = PhotoImage(file='cualitativa.gif')
self.label = Label(image=self.image)
self.file.pack()
self.label.pack()
def choose(self):
ifile = tkFileDialog.askopenfile(parent=self,mode='rb',title='Choose a file')
path = ifile.name
self.image2 = PhotoImage(file=path)
self.label.configure(image=self.image2)
self.label.image=self.image2
root = Tk()
app = GUI(master=root)
app.mainloop()
root.destroy()
Replace 'cualitativa.jpg' for the default image you want to use.
Another solution that might be of help.
In my case, I had two tk.Tk() windows. When using ImageTk.PhotoImage(), the object defaults to setting its tk window to being the first one created. A simple fix to this is to pass the tk window that you want as such ImageTk.PhotoImage(img, master=your_window)
import tkinter as tk
from PIL import ImageTk, Image
if __name__ == '__main__':
main_window = tk.Tk()
second_window = tk.Tk()
main_canvas = Canvas(second_window)
main_canvas.pack()
filename = 'test.png'
img = Image.open(filename)
img = img.resize((300, 100), Image.ANTIALIAS)
logo = ImageTk.PhotoImage(img, master=second_window)
logo_label = Label(master=main_canvas, image=logo)
logo_label.image = logo
logo_label.pack()
main_window.mainloop()