I am trying to display a MatPlotLib Plot of a BMP Image in the same window or canvas as the image. The code can already display the image, and I already have the data graph, I am just having trouble embedding the graph into the GUI. I tried referencing http://matplotlib.org/examples/user_interfaces/embedding_in_tk2.html but I was a little stumped trying to impliment it into this code.
Ideally, I would have the plot display right underneath the image.
Here is my code:
import tkinter as tk
from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk
from scipy import misc
import os
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.pos = []
self.master.title("BMP Image GUI")
self.pack(fill=BOTH, expand=1)
self.counter = 0
menu = Menu(self.master)
self.master.config(menu=menu)
# File Bar
file = Menu(menu)
file.add_command(label="Open Image 1", command=self.openImage1)
file.add_command(label="Exit", command=self.client_exit)
menu.add_cascade(label="File", menu=file)
self.canvas = tk.Canvas(self)
self.canvas.pack(fill=tk.BOTH, expand=True)
self.image = None
self.image2 = None
def client_exit(self):
exit()
def openImage1(self):
filename = filedialog.askopenfilename(initialdir=os.getcwd(), title="Select BMP File",
filetypes=[("BMP Files", "*.bmp")])
if not filename:
return
# Image 1 Data Graph
image = misc.imread(filename, flatten=False, mode="RGB")
sumArray1 = []
for i in range(0, image.shape[0]-1):
sumArray1.append(np.sum(image[i]))
np.asarray(sumArray1)
fig = plt.figure(figsize=(10,3.75), dpi=96)
plt.plot(sumArray1)
# Image 1
load = Image.open(filename)
load1 = load.resize((960, 720), Image.ANTIALIAS)
w, h = load1.size
width, height = root.winfo_screenmmwidth(), root.winfo_screenheight()
if self.image is None:
self.render = ImageTk.PhotoImage(load1)
self.image = self.canvas.create_image((w / 2, h / 2), image=self.render)
root.geometry("%dx%d" % (w, height))
root = tk.Tk()
root.geometry("%dx%d" % (300, 300))
root.title("BMP Image GUI")
app = Window(root)
app.pack(fill=tk.BOTH, expand=1)
root.mainloop()
I don't know if this is efficient, but created a second canvas as canvas2 and it seems to do that job. Before, I was working on the same canvas as the BMP image and it wasn't showing up. Maybe there is a way to do it only using one canvas.
if self.image is None:
self.render = ImageTk.PhotoImage(load1)
self.image = self.canvas.create_image((w / 2, h / 2), image=self.render)
root.geometry("%dx%d" % (w, height))
self.canvas2 = FigureCanvasTkAgg(fig, master=root)
self.canvas2.show()
self.canvas2.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=0)
self.canvas2._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=0)
Related
I have class MainWindow for main window:
import custom_windows as cw
import tkinter as tk
class MainWindow(tk.Toplevel):
def __init__(self, master):
self.master = master
master.title("ORV application")
master.geometry("500x350")
# Set container for buttons
button_container = tk.Frame()
button_container.pack(side=tk.BOTTOM)
# Set get image button
get_image_button = tk.Button(button_container, text="Get image", command=self.click_get_image)
get_image_button.pack(padx=20, pady=10, side=tk.LEFT)
def click_get_image(self):
# Create window with image
image_window = tk.Toplevel(self.master)
cw.CustomWindow(image_window, "images/tour-de-france.jpg")
root = tk.Tk()
main_window = MainWindow(root)
root.mainloop()
From main class I called new window from class CustomWindow:
import tkinter as tk
import cv2 as cv
from PIL import Image as pilImage, ImageTk as pilImageTk
class CustomWindow(tk.Toplevel):
def __init__(self, master, image_path):
self.master = master
master.title("Image")
master.resizable(False, False)
# Open and prepare image
self.image = cv.cvtColor(cv.imread(image_path), cv.COLOR_BGR2RGB)
self.render = pilImageTk.PhotoImage(image=pilImage.fromarray(self.image))
self.height, self.width, self.no_channels = self.image.shape
# Create canvas to display image
canvas = tk.Canvas(master, width=self.width, height=self.height)
canvas.create_image(0, 0, image=self.render, anchor=tk.NW)
canvas.pack()
Image doesn't display in Canvas. I use self to save values from garbage collector.
I am trying to rotate images using canvas items. I was successful in doing it with one image. But if I want to perform rotations on multiple canvas items how can I do that? Can someone help? Thanks in advance.
Here is my code:
import tkinter as tk
from PIL import ImageTk
from PIL import Image
import time
class SimpleApp(object):
def __init__(self, master, filename, **kwargs):
self.master = master
self.filename = filename
self.canvas = tk.Canvas(master, width=500, height=500)
self.canvas.pack()
self.update = self.draw().__next__
master.after(100, self.update)
def draw(self):
image = Image.open(self.filename)
angle = 0
while (angle<90):
tkimage = ImageTk.PhotoImage(image.rotate(angle))
canvas_obj = self.canvas.create_image(
250, 250, image=tkimage)
self.master.after_idle(self.update)
yield
angle += 5
time.sleep(0.1)
else
yield
root = tk.Tk()
app = SimpleApp(root, 'cat.jpg')
root.mainloop()
I am trying to get an image to display in a tkinter canvas.
I know the Canvas works with shapes and text, but image isn't working.
I am using PIL ImageTK.PhotoImage, however it also doesn't work creating a Tkinter.PhotoImage using a '.ppm' image.
The 'png' image is stored in the same directory as the python file.
import tkinter as tk
from PIL import Image, ImageTk
class Window:
def __init__(self):
self.window = tk.Tk()
self.window.title("COMP")
self.window.geometry("1200x600")
topframe = tk.Frame(self.window, highlightbackground='black', highlightthickness=1)
topframe.pack(side='top')
self.noteview = NoteView(topframe, self.songString)
class NoteView:
def __init__(self, frame):
self.canvas = tk.Canvas(frame, width=60, height=200)
self.canvas.pack()
self.canvas.create_text(15, 190, text='hi')
im = Image.open('png.png')
self.image = ImageTk.PhotoImage(im)
self.canvas.create_image(20, 20, anchor='nw', image=self.image)
w = Window()
TypeError: 'PhotoImage' object is not callable
The proble is that the tkinter somehow bings the image to the window, not in your case. You should use self.canvas.image = ImageTk.PhotoImage(im) and self.canvas.create_image(20, 20, anchor='nw', image=self.canvas.image). Hope that's helpful!
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 have a programme with various controls, a live webcam feed and a matplotlib figure based on the webcam data. I would like all the controls to be located in a left column, and the webcam and matplotlib figure to be located in a right column.
Attempts to use .grid() methods, canvases and frames etc don't work - the python script just fails to execute and hangs indefinitely.
How can this be achieved?
Minimum working example:
import Tkinter as tk
import cv2
from PIL import Image, ImageTk
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
root = tk.Tk()
root.bind('<Escape>', lambda e: root.quit())
lmain = tk.Label(root)
lmain.pack()
class Controller(tk.Frame):
def __init__(self, parent=root, camera_index=0):
self.camera_index = 0
frame = tk.Frame.__init__(self, parent,relief=tk.GROOVE,width=100,height=100,bd=1)
self.pack()
self.parent = parent
self.var = tk.IntVar()
self.parent.title('Laser Beam Profiler')
labelframe = tk.LabelFrame(parent, text="This is a LabelFrame")
labelframe.pack(fill="both", expand="yes") #.grid(row=0, column=0)
self.plot = tk.Button(labelframe, text = "Plot", command = self.refresh_plot)
self.plot.pack()
self.exit = tk.Button(labelframe, text = "Exit", command = self.close_window, compound = tk.BOTTOM)
self.exit.pack()
self.init_camera()
self.show_frame() #initialise camera
self.make_fig()
def make_fig(self):
self.fig = Figure(figsize=(4,4), dpi=100)
self.ax = self.fig.add_subplot(111)
canvas = FigureCanvasTkAgg(self.fig, self)
canvas.show()
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
toolbar = NavigationToolbar2TkAgg(canvas, self)
toolbar.update()
canvas._tkcanvas.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
def refresh_plot(self):
self.ax.plot(self.img[0])
self.fig.canvas.draw()
self.ax.clear()
print 'updated plot'
def init_camera(self):
width, height = 400, 300
self.cap = cv2.VideoCapture(self.camera_index)
if not self.cap:
raise Exception("Camera not accessible")
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
def show_frame(self):
_, frame = self.cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
cv2.putText(cv2image,"Laser Beam profiler", (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255))
dim = np.shape(cv2image)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, self.show_frame)
self.img = frame
def close_window(self):
self.parent.quit()
self.parent.destroy()
Controller().mainloop()
For the minimum working example I am trying to get the 'plot' and 'exit' buttons on the left hand side, and the webcam view with the matplotlib figure on the right. Currently it just places the widgets in a long column that spills off the screen.
The line
labelframe = tk.LabelFrame(parent, text="This is a LabelFrame")
probably should have self instead of parent. After this
labelframe.pack(fill="both", expand="yes", tk.LEFT)
should work. Since the Controller and the labelframe had the same parent and pack method for the Controller was called first, it placed restrictions where the labelframe could appear.
In Controller.__init__() there is a call to self.pack() in a little bit unusual place, it is usually left to be called after the widget has been instantiated i.e.
c = Controller(root)
c.pack()
root.mainloop()