Unable To Save Tkinter PhotoImage - python

I am trying to convert colour images into Grayscale images and then save the output.
The code works fine as expected (I am able to import images and perfrom grayscale operations on it)
However, I am unable to save the tk PhotoImage, hence, getting the error
'PhotoImage' object has no attribute 'save'
This is the code
from tkinter import *
from PIL import Image
from PIL import ImageTk
from tkinter import filedialog
import cv2
gray = None
def select_image():
global left_side, right_side
f_types = [
("Jpg Files", "*.jpg"),
("PNG Files", "*.png"),
] # type of files to select
path = filedialog.askopenfilename(multiple=False, filetypes=f_types)
# ensure a file path was selected
if len(path) > 0:
image = cv2.imread(path)
print(path)
global gray
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# convert the images to PIL format...
image = Image.fromarray(image)
gray = Image.fromarray(gray)
# ...and then to ImageTk format
image = ImageTk.PhotoImage(image)
gray = ImageTk.PhotoImage(gray)
# if the sections are None, initialize them
if left_side is None or right_side is None:
# the first section will store our original image
left_side = Label(image=image)
left_side.image = image
left_side.pack(side="left", padx=10, pady=10)
# while the second section will store the edge map
right_side = Label(image=gray)
right_side.image = gray
right_side.pack(side="right", padx=10, pady=10)
# otherwise, update the image sections
else:
# update the sections
left_side.configure(image=image)
right_side.configure(image=gray)
left_side.image = image
right_side.image = gray
# save bw
def savefile():
filename = filedialog.asksaveasfile(mode="w", defaultextension=".jpg")
if not filename:
return
gray.save(filename)
# print(gray)
window = Tk()
window.geometry("1080x720")
window.title("Colored Image To Black & White")
icon = PhotoImage(file="logo1.png")
window.iconphoto(True, icon)
image = PhotoImage(file="logo1.png")
intro = Label(
window,
text="This program converts Colored Images into Grayscale Images",
font=("Comic Sans", 20,),
fg="#FF6405",
bg="black",
compound="right",
)
intro.pack()
left_side = None
right_side = None
btn = Button(
window,
text="select image",
command=select_image,
font=("Comic Sans", 30),
fg="red",
bg="black",
)
btn1 = Button(
window,
text="select image",
command=savefile,
font=("Comic Sans", 30),
fg="red",
bg="black",
)
img = PhotoImage(file="select.png")
btn.config(image=img)
btn.pack(side="left", fill="both", expand="no", padx="10", pady="10")
img2 = PhotoImage(file="save.png")
btn1.config(image=img2)
btn1.pack(side="right", fill="both", expand="no", padx="10", pady="10")
window.config(background="#FF6405")
# window.resizable(False, False)
window.mainloop()

Related

Tkinter will only display the first photo I select via filedialog.askopenfilename

I have a program that allows the user to select an image from their PC and then displays it. The problem is that it only works once. The first photo is displayed but if I select/open another, I would think that this photo would then appear on top of the original but it doesn't.
Any idea why?
root = tk.Tk()
root.geometry("500x500")
root.title('Color Comparer')
picture_chooser_btn = tk.Button(master=root, text='Select Image', command= lambda: open_image())
picture_chooser_btn.pack()
base_color_picker_btn = tk.Button(master=root, text='Choose Base Color', command= lambda: selectBaseColor())
base_color_picker_btn.pack()
canvas = Canvas(root, width=80, height=50, bg="#F8F9F9")
base_color_rect = canvas.create_rectangle(0, 0, 85, 85, fill="red")
canvas_label = canvas.create_text((42, 20), text="Base Color")
canvas.pack()
label = tk.Label(root, anchor="w")
label.pack(side="top", fill="x")
root.bind('<ButtonPress-1>', on_click)
root.mainloop()
The function used to grab the photo from PC:
def open_image():
global image_selected
path=filedialog.askopenfilename(filetypes=[("Image File",'.jpg .png .jpeg')])
im = Image.open(path)
im = im.resize((400, 400), Image.ANTIALIAS)
tkimage = ImageTk.PhotoImage(im)
myvar=Label(root,image = tkimage)
myvar.image = tkimage
myvar.pack()
myvar.lift()
label.configure(text="you selected an image")
print("you selected an image")
print(str(tkimage))
image_selected = True
You need to destroy the old label widget containing the previous image before you can display a new one.
I made some minor modifications to your function that allows the code to work as you described
myvar = None
def open_image():
global myvar
if myvar is not None:
myvar.destroy()
path=filedialog.askopenfilename(filetypes=[("Image File",'.jpg .png .jpeg')])
im = Image.open(path)
im = im.resize((400, 400), Image.ANTIALIAS)
tkimage = ImageTk.PhotoImage(im)
myvar=Label(root,image = tkimage)
myvar.image = tkimage
myvar.pack()
myvar.lift()
label.configure(text="you selected an image")
print("you selected an image")
print(str(tkimage))

Fit canvas to windows

I have an image (1200 x 2064) from a videp:
I want to display it with Tkinter. So I did that:
cap = cv2.VideoCapture(path_video)
cap.set(1, 1)
ret, frame = cap.read()
self._root = tk.Tk()
self._root.minsize(height=frame.shape[0], width=frame.shape[1] + 150)
self._root.title("Image")
image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
image = Image.fromarray(image)
image = ImageTk.PhotoImage(image)
canvas_1 = tk.Canvas( self._root, height=frame.shape[0], width=150)
canvas_1.grid(row=0, column=0)
canvas_1.create_text(10, 10, anchor='nw', text='Pixel: ')
canvas_2 = tk.Canvas( self._root, height=frame.shape[0], width=frame.shape[1])
canvas_2.grid(row=0, column=1)
canvas_2.image = image
canvas_2.create_image(0, 0, anchor='nw', image=image)
self._root.mainloop()
The image is cropped at the bottom (or my laptop screen is too small). I want to have the whole image in the canvas_2. How can I do that ?
Here is the real image

PIL Python Module throwing error when saving image with Tkinter

Whenever I try to save an image selected from tkinter, I get an error like this:
raise ValueError("unknown file extension: {}".format(ext)) from e
ValueError: unknown file extension:
I'm using tkinter to open up the file browser to select an image file. The user can choose to flip the image horizontally and vertically. After that, they can choose to save as a variety of image formats. However, this returns the above error. I don't really see what is wrong. The name variable in the save() function contains the name after the file is picked. PIL's save function should be able to take that name and save it in the current working directory.
from tkinter import *
from tkinter import filedialog
from PIL import Image
def open_image():
global img
img = Image.open(
filedialog.askopenfilename(title="Select file", filetypes=(("jpeg files", "*.jpg"), ("all files", "*.*"))))
save_button.config(bg=default_color)
flip_horizontal_button.config(bg=default_color)
flip_vertical_button.config(bg=default_color)
def flip_horizontal():
global img
if img:
img = img.transpose(Image.FLIP_LEFT_RIGHT)
def flip_vertical():
global img
if img:
img = img.transpose(Image.FLIP_TOP_BOTTOM)
def save():
global img
if img:
#os.chdir("/")
default_name = "Untitled"
""" print(default_name+"."+img.format)
print(os.path.isfile(default_name+"."+img.format))
print(os.path)
if os.path.isfile(default_name+"."+img.format):
expand = 1
while True:
expand += 1
expanded_name = default_name+str(expand)
if os.path.isfile(expanded_name):
continue
else:
default_name = expanded_name
break"""
name = filedialog.asksaveasfilename(title="Save As", filetypes=(
('JPEG', ('*.jpg', '*.jpeg', '*.jpe')), ('PNG', '*.png'), ('GIF', '*.gif')),
initialfile=default_name+"."+img.format)
img.save(name)
img = None
root = Tk()
root.title("Meme Deep Fryer")
root.geometry('600x500')
default_color = root.cget('bg')
open_button = Button(text='Open Image', font=('Arial', 20), command=open_image)
flip_horizontal_button = Button(text='Flip Horizontal', font=('Arial', 10), command=flip_horizontal, bg="gray")
flip_vertical_button = Button(text='Flip Vertical', font=('Arial', 10), command=flip_vertical, bg="gray")
save_button = Button(text='Save', font=('Arial', 20), command=save, bg="gray")
open_button.pack(anchor='nw', side=LEFT)
save_button.pack(anchor='nw', side=LEFT)
flip_horizontal_button.pack(anchor='w')
flip_vertical_button.pack(anchor='w')
root.mainloop()
You could pass argument typevariable in asksaveasfilename:
ext = tkinter.StringVar()
name = filedialog.asksaveasfilename(title="Select file", typevariable=ext, filetypes=(('JPEG', ('*.jpg', '*.jpeg', '*.jpe')), ('PNG', '*.png'), ('BMP', ('*.bmp', '*.jdib')), ('GIF', '*.gif')))
if name:
img.save(os.path.basename(name)+"."+ext.get().lower()) # splice the string and the extension.

Dynamically changing images connected to the item in listbox

I would like to dynamically display image of selected item in listbox.
The name of the image store in folder is exactly like item with index [0] from my tuple in listbox
list1= Listbox(ViewFrame, height=15, width=75)
files = glob.glob('img\\*.jpg')
ImageFrame = LabelFrame(page1, text="Podgląd i parametry")
ImageFrame.grid(row=6, column=6, pady=10, padx=5)
path = files[list1.curselection()[0]]
img = ImageTk.PhotoImage(Image.open(path))
label = Label(ImageFrame)
label.image = img
label.configure(image=img)
Error:
path = files[list1.curselection()[0]]
IndexError: tuple index out of range
It seems to me that before I open the app nothing is selected, but I do not know how to fix it.
check is something is selected before load images.
when create the listbox add
list1.bind("<<ListboxSelect>>", on_item_selected)
then add the function
def (on_item_selected):
path = files[list1.curselection()[0]]
img = ImageTk.PhotoImage(Image.open(path))
label = Label(ImageFrame)
label.image = img
label.configure(image=img)
on open....
if list1.curselection():
path = files[list1.curselection()[0]]
img = ImageTk.PhotoImage(Image.open(path))
label = Label(ImageFrame)
label.image = img
label.configure(image=img)
Here's runnable code, but it's merely a more complete version of #1966bc's answer which I created because you have in your question isn't a MCVE:
import glob
from tkinter import *
from PIL import Image, ImageTk
def on_item_selected(event):
path = files[list1.curselection()[0]]
img = ImageTk.PhotoImage(Image.open(path))
label.image = img
label.configure(image=img)
root = Tk()
page1 = Frame(root)
page1.grid(row=0, column=0)
ViewFrame = Frame(page1)
ViewFrame.grid(row=0, column=0)
files = glob.glob('*.jpg')[:10] # Limit to first 10 for development.
listvar = StringVar(value=files)
list1= Listbox(ViewFrame, height=15, width=75, listvariable=listvar)
list1.grid()
ImageFrame = LabelFrame(page1, text="Podgląd i parametry")
ImageFrame.grid(row=6, column=6, pady=10, padx=5)
label = Label(ImageFrame) # Create placeholder.
label.grid()
list1.bind("<<ListboxSelect>>", on_item_selected)
root.mainloop()

How can i print some features in python opencv GUI?

I want to print the mean, height & width of an image in python openCV. Where i used two button (get photo and analysis image) and different GUI,one for getting the photo(def openphoto(): ) and another for printing those features(def feature(): ). But I'm getting error.
N.B. full code is too long.so, i used some part of it.
I've tried it in python openCV.
import tkinter as tk
from tkinter.filedialog import askopenfilename
import shutil
import os
from PIL import Image, ImageTk
window = tk.Tk()
window.title("Dr. Papaya")
window.geometry("500x510")
window.configure(background ="lightgreen")
title = tk.Label(text="Click below to choose picture for testing disease....", background = "lightgreen", fg="Brown", font=("", 15))
title.grid()
def feature():
window.destroy()
window1 = tk.Tk()
window1.title(" ")
window1.geometry("650x510")
window1.configure(background="lightgreen")
def exit():
window1.destroy()
#i want to print here
print("Mean : ",mean)
print("Heigth : ",heigth)
print("Width : ",width)
button = tk.Button(text="Exit", command=exit)
button.grid(column=0, row=9, padx=20, pady=20)
window1.mainloop()
def openphoto():
import cv2
import numpy as np
fileList = os.listdir(dirPath)
for fileName in fileList:
os.remove(dirPath + "/" + fileName)
fileName = askopenfilename(initialdir='', title='Select image for analysis ',
filetypes=[('image files', '.jpg')])
dst = " "
shutil.copy(fileName, dst)
load = Image.open(fileName)
#calculate the mean
mean=np.mean(load)
#calculate the height & width
height = np.size(load, 0)
width = np.size(load, 1)
render = ImageTk.PhotoImage(load)
img = tk.Label(image=render, height="250", width="500")
img.image = render
img.place(x=0, y=0)
img.grid(column=0, row=1, padx=10, pady = 10)
title.destroy()
button1.destroy()
button2 = tk.Button(text="Analyse Image", command=feature)
button2.grid(column=0, row=2, padx=10, pady = 10)
button1 = tk.Button(text="Get Photo", command = openphoto)
button1.grid(column=0, row=1, padx=10, pady = 10)
window.mainloop()
The variables are not in scope when you try to print them. This is an important programming principle so I suggest you read this introduction
You can make the variable global to make the them accessible outside of the function:
def openphoto():
global width, height, mean
[rest of code]

Categories