So ive been tinkering with Tkinter and Pillow for a project of mine and have so far come up with a clickable image. When i click the image it prints image has been clicked. However i want the image to get destroyed before the text is displayed. I have tried img.destroy() but that throws and error saying img is not defined so i suspect the problem is that i dont understand where things have been renamed and such. any and all help is greatly appreciated :)
from tkinter import *
from PIL import Image, ImageTk
SWH = Tk()
SWH.geometry("1024x950+130+0")
SWH.title("ServiceWhiz.")
def printimage():
load = Image.open("hello.gif")
render = ImageTk.PhotoImage(load)
img = Button(SWH, image=render,command=imgpress)
img.image = render
img.place(x=0,y=0)
return;
def imgpress():
img.destroy()
Label1 = Label(SWH, text="Image has been clicked",fg="#0094FF",font=('Arial',20)).pack()
return;
SWTitle = Label(SWH, text="ServiceWhiz.",fg="#0094FF",font=('Arial',20)).pack()
MyButtonTest = Button(SWH, text="Click Me.",fg="White",bg="#0094FF",command=printimage).pack()
You need to define "img" variable outside of your printimage function (on the same layer as for SWH). If you defined img inside of the function it will be accessible only there. By adding global img we specify that img inside of function should refer to that global-level value. It's a generally bad idea to have it like this so think about moving your handlers into class which will retain state and store img for you.
Try to make like this:
from tkinter import *
from PIL import Image, ImageTk
SWH = Tk()
SWH.geometry("1024x950+130+0")
SWH.title("ServiceWhiz.")
img = None
def printimage():
global img
load = Image.open("hello.gif")
render = ImageTk.PhotoImage(load)
img = Button(SWH, image=render,command=imgpress)
img.image = render
img.place(x=0,y=0)
return;
def imgpress():
global img
img.destroy()
Label1 = Label(SWH, text="Image has been clicked",fg="#0094FF",font=('Arial',20)).pack()
return;
SWTitle = Label(SWH, text="ServiceWhiz.",fg="#0094FF",font=('Arial',20)).pack()
MyButtonTest = Button(SWH, text="Click Me.",fg="White",bg="#0094FF",command=printimage).pack()
Related
I am trying to make a GUI-based face recognition program with tkinter and opencv. I have used the function cv2.VideoCapture() before, but usually NOT inside a function and it worked successfully.
This time, though, I wanted to use it inside a function, but the program just does not run. I got no errors in the terminal, and the window just froze.
Here is my code (I haven't yet added the face recognition functionality)
import tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
root.configure(bg='#3d3d3d')
f1 = tk.LabelFrame(root, bg='#3d3d3d')
f1.place(relx=0.5, rely=0.53, anchor=tk.CENTER)
feed = tk.Label(f1)
feed.pack()
cap = cv2.VideoCapture(0)
def capture():
while cap.isOpened():
img = cap.read()[1]
img = cv2.flip(img, 1)
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # changing color to RGB
img = ImageTk.PhotoImage(Image.fromarray(img1))
feed['image'] = img # putting the webcam feed in the 'feed' LabelFrame
capture()
root.mainloop()
I tried to input values 0, 1, -1 for the VideoCapture() function, but the problem persisted
Note that this is not my full code and I have just included the important parts. I am asking this question because I want to implement this functionality on a Toplevel() window which is opened by clicking a button. The code for the Toplevel() window is indside a function.
Thanks in advance!
There are mainly two issues in your code:
using while loop which will block root.mainloop() from executing. Use after() instead.
image created inside a function will be garbage collected if its reference is not saved
Below is a modified code to fix the above issues:
import tkinter as tk
from PIL import Image, ImageTk
import cv2
root = tk.Tk()
root.configure(bg='#3d3d3d')
root.geometry('800x600')
f1 = tk.LabelFrame(root, bg='#3d3d3d')
f1.place(relx=0.5, rely=0.53, anchor=tk.CENTER)
feed = tk.Label(f1)
feed.pack()
cap = cv2.VideoCapture(0)
# used after() instead of while loop
def capture():
if cap.isOpened():
ret, img = cap.read()
if ret:
img = cv2.flip(img, 1)
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # changing color to RGB
img = ImageTk.PhotoImage(Image.fromarray(img1))
feed['image'] = img # putting the webcam feed in the 'feed' LabelFrame
feed.image = img # save reference of the image
root.after(10, capture)
capture()
root.mainloop()
I'm learning the tkinter module and I got a problem. I did a fonction to show an image from my folder but my image won't show up but the resolution of the window is the same as my image. Anybody have a solution ?
from tkinter import *
from PIL import ImageTk, Image
root = Tk()
def my_image(img, row, column) :
pic = ImageTk.PhotoImage(Image.open("C:/Users/Mark/Downloads/test/" + img))
my_img = Label(image=pic)
return my_img.grid(row=row, column=column)
# Create image
image1 = my_image("luigi_icon.png", 0, 1)
root.mainloop()
This problem was many times on Stackoverflow.
There is bug in PhotoImage which removes image from memory when it is assigned to local variable. You have to assign it to global variable or to some object
Common solution is to assign pic to label which displays it.
my_img.pic = pic
See Note at the end of page PhotoImage
(it is archived version on Wayback Machine because original version was removed)
BTW:
You have other problem. grid() gives None. You should return my_img if you want to access label later (ie. to replace image).
Currently original tk.PhotoImage can work with png so you don't need PIL. But if you want to work with some less popular image format then you may need pillow.
import os
#from tkinter import *
import tkinter as tk # PEP8: `import *` is not preferred
from PIL import ImageTk, Image
# --- functions ---
def my_image(img, row, column) :
fullpath = os.path.join("C:/Users/Mark/Downloads/test/", img)
#pic = ImageTk.PhotoImage(Image.open(fullpath))
# or
#pic = ImageTk.PhotoImage(file=fullpath)
# or even without `PIL/pillow` for `png`
pic = tk.PhotoImage(file=fullpath)
my_img = tk.Label(image=pic)
my_img.grid(row=row, column=column)
my_img.pic = pic # solution for bug in `PhotoImage`
return my_img
# --- main ---
root = tk.Tk()
image1 = my_image("luigi_icon.png", 0, 1)
root.mainloop()
I am a beginner in python and learning about PIL and tkinter.
Now what I am trying is to edit a image and I am struggling from blur and rotate.
When I blur an image, I cannot get rid of it without rotating it. (I want to make a button to on/off blur)
And if I blur/rotate an image,
Another one doesn't work at the same time.
How can I solve this problem? here is my code
import tkinter as tk
from PIL import Image, ImageTk, ImageFilter
from tkinter import filedialog as fd
img=None
tk_img=None
angle=0
def open():
global img, tk_img
filename=fd.askopenfilename()
img=Image.open(filename)
tk_img=ImageTk.PhotoImage(img)
canvas.create_image(250,250,image=tk_img)
window.update()
def quit():
window.destroy()
def image_rotate():
global img,tk_img,angle
angle=angle+45
tk_img=ImageTk.PhotoImage(img.rotate(angle))
canvas.create_image(250,250,image=tk_img)
window.update()
def image_blur():
global img,tk_img
tk_img=ImageTk.PhotoImage(img.filter(ImageFilter.BLUR))
canvas.create_image(250,250,image=tk_img)
window.update()
window = tk.Tk() #윈도우 생성
canvas=tk.Canvas(window,width=500,height=500)
canvas.pack()
menubar = tk.Menu(window) #메뉴바 생성
filemenu = tk.Menu(menubar) #파일메뉴를 메뉴바에 달아줌
filemenu.add_command(label="picture", command=open)
filemenu.add_command(label="exit", command=quit)
menubar.add_cascade(label="파일", menu=filemenu)
imagemenu=tk.Menu(menubar)
imagemenu.add_command(label="rotate",command=image_rotate)
imagemenu.add_command(label="blur",command=image_blur)
menubar.add_cascade(label="movement", menu=imagemenu)
window.config(menu=menubar)
window.mainloop()
The reason is quite obvious, your img object as seen is only defined/updated in open(), so the image will always refer to the original image selected and not the new edited image, so to show the change store it in a new variable and then globalize it.
Also note that you are creating a new canvas image every time you call the function, which is not efficient, so make a single canvas image and then update it each time, inside the function using itemconfig() method.
def open():
global img, tk_img
filename = fd.askopenfilename()
img = Image.open(filename)
tk_img = ImageTk.PhotoImage(img)
canvas.itemconfig('img',image=tk_img) # Update image
def image_rotate():
global tk_img, angle, img
angle += 45 # More pythonic to always use += rather than a = a + 10
img = img.rotate(angle)
tk_img = ImageTk.PhotoImage(img)
canvas.itemconfig('img',image=tk_img) # Update image
angle -= 45
def image_blur():
global tk_img, img
img = img.filter(ImageFilter.BLUR)
tk_img = ImageTk.PhotoImage(img)
canvas.itemconfig('img',image=tk_img) # Update image
canvas = tk.Canvas(window,width=500,height=500)
canvas.create_image(250,250,tag='img') # Create initial canvas object
canvas.pack()
Also take a look at how I formatted your code to make it look more near, follow PEP 8 -- Style Guide for Python Code for more.
You can blur the image using opencv package
import cv2
img = cv2.imread('imagepath')
blurImg = cv2.blur(img,(10,10))
cv2.imshow('blurred image',blurImg)
cv2.waitKey(0)
cv2.destroyAllWindows()
Or u can check the documentation of opencv to blurr the image.
U can also rotate image using opencv
# importing cv2
import cv2
src = cv2.imread(path)
window_name = 'Image'
image = cv2.rotate(src, cv2.ROTATE_90_COUNTERCLOCKWISE)
# Displaying the image
cv2.imshow(window_name, image)
cv2.waitKey(0)
I'm trying to place a .png image within a LabelFrame in a Tkinter window. I imported PIL so .png image types should be supported (right?). I can't seem to get the image to show up.
Here is my revised code:
import Tkinter
from Tkinter import *
from PIL import Image, ImageTk
root = Tk()
make_frame = LabelFrame(root, text="Sample Image", width=150, height=150)
make_frame.pack()
stim = "image.png"
width = 100
height = 100
stim1 = stim.resize((width, height), Image.ANTIALIAS)
img = ImageTk.PhotoImage(image.open(stim1))
in_frame = Label(make_frame, image = img)
in_frame.pack()
root.mainloop()
With this code, I got an AttributeError that reads: "'str' has no attribute 'resize'"
#Mickey,
You have to call the .resize method on the PIL.Image object and not the filename, which is a string. Also, you may prefer to use PIL.Image.thumbnail instead of PIL.Image.resize, for reasons described clearly here. Your code was close, but this might be what you need:
import Tkinter
from Tkinter import *
from PIL import Image, ImageTk
root = Tk()
make_frame = LabelFrame(root, text="Sample Image", width=100, height=100)
make_frame.pack()
stim_filename = "image.png"
# create the PIL image object:
PIL_image = Image.open(stim_filename)
width = 100
height = 100
# You may prefer to use Image.thumbnail instead
# Set use_resize to False to use Image.thumbnail
use_resize = True
if use_resize:
# Image.resize returns a new PIL.Image of the specified size
PIL_image_small = PIL_image.resize((width,height), Image.ANTIALIAS)
else:
# Image.thumbnail converts the image to a thumbnail, in place
PIL_image_small = PIL_image
PIL_image_small.thumbnail((width,height), Image.ANTIALIAS)
# now create the ImageTk PhotoImage:
img = ImageTk.PhotoImage(PIL_image_small)
in_frame = Label(make_frame, image = img)
in_frame.pack()
root.mainloop()
I'm currently using PIL to display images in Tkinter. I'd like to temporarily resize these images so that they can be viewed more easily. How can I go about this?
Snippet:
self.pw.pic = ImageTk.PhotoImage(Image.open(self.pic_file))
self.pw.pic_label = TK.Label(self.pw , image=self.pw.pic,borderwidth=0)
self.pw.pic_label.grid(column=0,row=0)
Here's what I do and it works pretty well...
image = Image.open(Image_Location)
image = image.resize((250, 250), Image.ANTIALIAS) ## The (250, 250) is (height, width)
self.pw.pic = ImageTk.PhotoImage(image)
There you go :)
EDIT:
Here is my import statement:
from Tkinter import *
import tkFont
from PIL import Image
And here is the complete working code I adapted this example from:
im_temp = Image.open(Image_Location)
im_temp = im_temp.resize((250, 250), Image.ANTIALIAS)
im_temp.save("ArtWrk.ppm", "ppm") ## The only reason I included this was to convert
## The image into a format that Tkinter woulden't complain about
self.photo = PhotoImage(file="ArtWrk.ppm") ## Open the image as a tkinter.PhotoImage class()
self.Artwork.destroy() ## Erase the last drawn picture (in the program the picture I used was changing)
self.Artwork = Label(self.frame, image=self.photo) ## Sets the image too the label
self.Artwork.photo = self.photo ## Make the image actually display (If I don't include this it won't display an image)
self.Artwork.pack() ## Repack the image
And here are the PhotoImage class docs: http://www.pythonware.com/library/tkinter/introduction/photoimage.htm
Note...
After checking the pythonware documentation on ImageTK's PhotoImage class (Which is very sparse) I appears that if your snippet works than this should as well as long as you import the PIL "Image" Library an the PIL "ImageTK" Library and that both PIL and tkinter are up-to-date. On another side-note I can't even find the "ImageTK" module life for the life of me. Could you post your imports?
if you don't want save it you can try it:
from Tkinter import *
from PIL import Image, ImageTk
root = Tk()
same = True
#n can't be zero, recommend 0.25-4
n=2
path = "../img/Stalin.jpeg"
image = Image.open(path)
[imageSizeWidth, imageSizeHeight] = image.size
newImageSizeWidth = int(imageSizeWidth*n)
if same:
newImageSizeHeight = int(imageSizeHeight*n)
else:
newImageSizeHeight = int(imageSizeHeight/n)
image = image.resize((newImageSizeWidth, newImageSizeHeight), Image.ANTIALIAS)
img = ImageTk.PhotoImage(image)
Canvas1 = Canvas(root)
Canvas1.create_image(newImageSizeWidth/2,newImageSizeHeight/2,image = img)
Canvas1.config(bg="blue",width = newImageSizeWidth, height = newImageSizeHeight)
Canvas1.pack(side=LEFT,expand=True,fill=BOTH)
root.mainloop()
the easiest might be to create a new image based on the original, then swap out the original with the larger copy. For that, a tk image has a copy method which lets you zoom or subsample the original image when making the copy. Unfortunately it only lets you zoom/subsample in factors of 2.