Image display issue - python

When I load a transparent image with:
def load_image(path):
img = Image.open(path)
return ImageTk.PhotoImage(img)
class Home_Screen(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.home = Tk()
self.home.resizable(width = False,height = False)
self.home.geometry("700x500+300+100")
self.start()
def run(self):
self.images()
Label(self.home, image = self.background).pack() # Put it in the display window
button_instructions = Label(self.home,image = self.b_instructions).place(x = 300,y = 200)
self.home.mainloop()
def images(self):
self.background = load_image("Images/night-sky.jpg")
self.b_instructions = load_image("button_instructions.png")
def start_game(self):
self.home.destroy()
Home = Home_Screen()
I get an image with a white border around it. Does anyone know why the original transparency was not retained? If so could you please offer a solution.

Use a Canvas instead of Label widgets. The transparency isn't getting lost, because what you see is the background of the widget.
def run(self):
img_sky = ImageTk.PhotoImage(file="Images/night-sky.jpg")
img_button = ImageTk.PhotoImage(file="button_instructions.png")
self.canvas = Canvas(self.home, width=700, height=500)
self.canvas.create_image(0, 0, image=img_sky)
self.canvas.create_image(300, 200, image=img_button)
self.canvas.pack()
self.home.mainloop()

Related

How to display the whole image on this canvas?

The code provided here is:
import tkinter as tk
from PIL import Image, ImageTk
from pathlib import Path
class App(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('600x600')
self.img_path = Path(r'D:\Python\Lena.jpg')
self.img = Image.open(self.img_path)
self.img_rgb = self.img.convert('RGB')
dim_x, dim_y = self.img_rgb.size
self.img_tk = ImageTk.PhotoImage(self.img_rgb.resize((dim_x, dim_y)))
self.canvas = tk.Canvas(self)
self.canvas.create_image(dim_x // 2, dim_y // 2, image=self.img_tk)
self.canvas.pack(expand=True, fill=tk.BOTH)
self.rgb_var = tk.StringVar(self, '0 0 0')
self.rgb_label = tk.Label(self, textvariable=self.rgb_var)
self.rgb_label.pack()
self.bind('<Motion>', lambda e: self.get_rgb(e))
def get_rgb(self, event):
x, y = event.x, event.y
try:
rgb = self.img_rgb.getpixel((x, y))
self.rgb_var.set(rgb)
except IndexError:
pass # ignore errors if the cursor is outside the image
if __name__ == '__main__':
app = App()
app.mainloop()
It displays an image with the RGB value of the pixel under the mouse pointer under the image (when the mouse pointer is over the image). The image used is this.
However, only the upper left quadrant of the image is displayed on the canvas. You can see that in the screenshot below.
How can I display the whole image and still have the RGB values of the pixel under the mouse pointer displayed (when the mouse pointer is over the image)?
I can see two possible solutions:
Expand image to fit window
Wrap window around image
To expand image to fit window
dim_x, dim_y = 600, 600
self.img_tk = ImageTk.PhotoImage(self.img_rgb.resize((dim_x, dim_y)))
OR
To wrap window around image
dim_x, dim_y = self.img_rgb.size
self.img_tk = ImageTk.PhotoImage(self.img_rgb)
Both approaches will display the entire image.
Here is the complete code with both options available via select flag.
import tkinter as tk
from PIL import Image, ImageTk
from pathlib import Path
class App(tk.Tk):
def __init__(self, select = True):
super().__init__()
self.img_path = Path('D:\Lenna.jpg')
self.img = Image.open(self.img_path)
self.img_rgb = self.img.convert('RGB')
if select:
# resize image to fit window
dim_x, dim_y = 600, 600
self.img_tk = ImageTk.PhotoImage(self.img_rgb.resize((dim_x, dim_y)))
else:
# resize window to fit image
dim_x, dim_y = self.img_rgb.size
self.img_tk = ImageTk.PhotoImage(self.img_rgb)
self.geometry(f'{dim_x}x{dim_y+21}')
self.canvas = tk.Canvas(self, borderwidth = 0, highlightthickness = 0)
self.canvas.create_image(0, 0, image = self.img_tk, anchor= tk.NW)
self.canvas.pack(expand=True, fill=tk.BOTH)
self.rgb_var = tk.StringVar(self, '0 0 0')
self.rgb_label = tk.Label(self, textvariable=self.rgb_var)
self.rgb_label.pack()
self.bind('<Motion>', lambda e: self.get_rgb(e))
def get_rgb(self, event):
x, y = event.x, event.y
try:
rgb = self.img_rgb.getpixel((x, y))
self.rgb_var.set(rgb)
except IndexError:
pass # ignore errors if the cursor is outside the image
if __name__ == '__main__':
app = App(False)
app.mainloop()
Everything works as expected when borderwidth and highlightthickness are removed.

Memory Error & AttributeError in Python when move OpenCV's frame to Tkinter

I trying to move OpenCV's frame to Tkinter
Code Following...
import tkinter as tk
import time
from PIL import ImageTk, Image
from cv2 import cv2
To show the video
class CamWindow:
def __init__(self, window, title:str, cam_plug = 0, delay = 15):
self.delay = delay
self.window = window
self.title = title
self.window.title(self.title)
self.cam = MyVideoCapture(cam_plug)
self.canvas = tk.Canvas(self.window, width = self.cam.width, height = self.cam.height)
self.canvas.pack()
self.photoButton = tk.Button(self.window, text="SnapShot", width=30, command=self.shot)
self.photoButton.pack(anchor=tk.CENTER, expand=True)
self.update()
self.window.mainloop()
def shot(self):
ret, frame = self.cam.getPic()
if ret:
cv2.imwrite(time.strftime("%d-%m-%Y-%H-%M-%S")+".jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
def update(self):
ret, frame = self.cam.getPic()
if ret:
self.photo = ImageTk.PhotoImage(image=Image.fromarray(frame))
self.canvas.create_image(0, 0, image = self.photo, anchor = tk.NW)
self.window.after(self.delay, self.update())
class MyVideoCapture:
def __init__(self, cam_plug = 0):
self.cam = cv2.VideoCapture(cam_plug, cv2.CAP_DSHOW)
if not self.cam.isOpened():
raise ValueError("cannot open camera at %d", cam_plug)
self.width = self.cam.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.cam.get(cv2.CAP_PROP_FRAME_HEIGHT)
def getPic(self):
if self.cam.isOpened():
ret, frame = self.cam.read()
if ret:
return ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
else:
return ret, None
else:
return None, None
def __del__(self):
if self.cam.isOpened:
self.cam.release()
the terminal shows memory error, but everything seems to make sense.
and also I met "Attributeerror: 'photoimage' object has no attribute '_photoimage__photo'"
if there's any method or codes having problems please tell me as well
==========================edit===========================
my main file.py is:
from module.UI import CamWindow
def main():
CamWindow(tk.Tk(), title = "camera window", delay = 30)
if __name__ == '__main__':
main()

use threading in tkinter

I have two class and use tkinter demo.
class App:
def __init__(self, window, window_title, video_source=0):
self.window = window
self.window.title(window_title)
self.video_source = video_source
# open video source (by default this will try to open the computer webcam)
self.vid = MyVideoCapture(self.video_source)
# Create a canvas that can fit the above video source size
self.canvas = tkinter.Canvas(window).place(x=50, y=0)
# set plot parameter
self.fig = Figure(figsize=(7, 4), dpi=100)
self.fresh = FigureCanvasTkAgg(self.fig, master=self.window)
self.ax1 = self.fig.add_subplot(211)
self.ax2 = self.fig.add_subplot(212)
self.fresh.get_tk_widget().place(x=700, y=0)
self.window.geometry('1500x550')
# Camera thread
self.photo = None
self.delay = 15
self.t = threading.Thread(target=self.update, args=())
self.t.setDaemon(True)
self.t.start()
def refresh(self, data):
sample_track = pd.read_csv('/home/share/sample_track.csv')
x = [i for i in range(len(sample_track))]
y = sample_track['0']
xdata = [i for i in range(len(data))]
ydata = data
self.ax1.plot(x, y, 'bo--')
self.ax2.plot(xdata, ydata, 'ro--')
self.fresh.draw()
def update(self):
# Get a frame from the video source
ret, frame = self.vid.get_frame()
if ret:
self.photo = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(frame))
self.canvas.create_image(0, 0, image=self.photo, anchor=tkinter.NW)
self.window.after(self.delay, self.update)
class MyVideoCapture:
def __init__(self, video_source=0):
# Open the video source
self.vid = cv2.VideoCapture(video_source)
if not self.vid.isOpened():
raise ValueError("Unable to open video source", video_source)
self.ret = None
def get_frame(self):
if self.vid.isOpened():
self.ret, frame = self.vid.read()
if self.ret:
# Return a boolean success flag and the current frame converted to BGR
return self.ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
else:
return self.ret, None
if __name__ == '__main__':
win = tkinter.Tk()
panel = App(win, "Dance")
value = []
for i in range(15):
value.append(np.random.randint(0, 800))
panel.refresh(data=value)
time.sleep(0.1)
win.mainloop()
I want to start the Webcam and refresh the figure at the same time.
I tried to use the thread but still failed.
The following error occurred:
RuntimeError: main thread is not in main loop
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
How can I solve it?
Here is a working tkinter camera taken straight from here (found by a quick search for 'tkinter camera'):
import tkinter
import cv2
import PIL.Image, PIL.ImageTk
import time
class App:
def __init__(self, window, window_title, video_source=0):
self.window = window
self.window.title(window_title)
self.video_source = video_source
# open video source (by default this will try to open the computer webcam)
self.vid = MyVideoCapture(self.video_source)
# Create a canvas that can fit the above video source size
self.canvas = tkinter.Canvas(window, width = self.vid.width, height = self.vid.height)
self.canvas.pack()
# Button that lets the user take a snapshot
self.btn_snapshot=tkinter.Button(window, text="Snapshot", width=50, command=self.snapshot)
self.btn_snapshot.pack(anchor=tkinter.CENTER, expand=True)
# After it is called once, the update method will be automatically called every delay milliseconds
self.delay = 15
self.update()
self.window.mainloop()
def snapshot(self):
# Get a frame from the video source
ret, frame = self.vid.get_frame()
if ret:
cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
def update(self):
# Get a frame from the video source
ret, frame = self.vid.get_frame()
if ret:
self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
self.canvas.create_image(0, 0, image = self.photo, anchor = tkinter.NW)
self.window.after(self.delay, self.update)
class MyVideoCapture:
def __init__(self, video_source=0):
# Open the video source
self.vid = cv2.VideoCapture(video_source)
if not self.vid.isOpened():
raise ValueError("Unable to open video source", video_source)
# Get video source width and height
self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
def get_frame(self):
if self.vid.isOpened():
ret, frame = self.vid.read()
if ret:
# Return a boolean success flag and the current frame converted to BGR
return (ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
else:
return (ret, None)
else:
return (ret, None)
# Release the video source when the object is destroyed
def __del__(self):
if self.vid.isOpened():
self.vid.release()
# Create a window and pass it to the Application object
App(tkinter.Tk(), "Tkinter and OpenCV")

TK Image Not Appearing

I am trying to put an image on a TKinter canvas with other buttons under the image. For some reason I can not get this picture to appear. I have not yet implemented the buttons. Here is my code thus far.
class GUI_Control:
def __init__(self, player):
self.player = player
self.map = Tk()
self.MAP_WIDTH = 600
self.MAP_HEIGHT = 375
#define map gui here
self.canvas = Canvas(self.map, width=self.MAP_WIDTH, height=self.MAP_HEIGHT)
self.map_picture = PhotoImage(file=r"images/archipelago.gif")
self.canvas.create_image(0, 0, image=self.map_picture)
#define level gui's here
def open(self):
self.map.mainloop()
def hide_map(self):
self.map.destroy()
#debugging
if __name__ == "__main__":
gui = GUI_Control(Player.Player())
gui.open()
You'll need to use one of Tk’s geometry-management mechanisms to tell it where to render the canvas within it's container.
the simplest way would be to add self.canvas.pack() like so:
#define map gui here
self.canvas = Canvas(self.map, width=self.MAP_WIDTH, height=self.MAP_HEIGHT)
self.canvas.pack()
self.map_picture = PhotoImage(file=r"images/archipelago.gif")
self.canvas.create_image(0, 0, image=self.map_picture)
#define level gui's here
You need to call the pack() (or grid()) method of widgets for them to be displayed:
class GUI_Control:
def __init__(self, player):
self.player = player
self.map = Tk()
self.MAP_WIDTH = 600
self.MAP_HEIGHT = 375
#define map gui here
self.canvas = Canvas(self.map, width=self.MAP_WIDTH, height=self.MAP_HEIGHT)
self.canvas.pack(expand=YES, fill=BOTH) # ADDED
self.map_picture = PhotoImage(file="images/archipelago.gif")
self.canvas.create_image(0, 0, image=self.map_picture, anchor='nw')
#define level gui's here
def open(self):
self.map.mainloop()
def hide_map(self):
self.map.destroy()
#debugging
if __name__ == "__main__":
gui = GUI_Control(Player.Player())
gui.open()

How to use transform from PIL in Python

That's my code and I get the error message:
... return getattr(self.tk, attr)
AttributeError: temp_pic"...
I need to program two buttons: [zoom in] and [zoom out].
If you have any better ideas for doing that, please, just say it.
I'm going to use this image to develop maps through graphs (structure)
from Tkinter import *
from PIL import Image, ImageTk, ImageDraw, ImageOps, ImageEnhance
bairro = "botafogo.jpg"
class Painel(Tk):
def __init__(self):
Tk.__init__(self) #create ui
self.zoom = Frame(self)
self.zoom.pack()
self.zin = Button(self.zoom, command = self.zoom_in, text = "Zoom In")
self.zin.pack()
self.zout = Button(self.zoom, command = self.zoom_out, text = "Zoom Out")
self.zout.pack()
self.c = Canvas(self, bd=0, highlightthickness=0, width=100, height=100)
self.c.pack(fill='both', expand=1)
self.main_pic = Image.open(bairro) #load image
self.main_pic.thumbnail((800, 600))
self.tkphoto = ImageTk.PhotoImage(self.main_pic)
self.canvasItem = self.c.create_image(0, 0, anchor='nw', image = self.tkphoto)
self.c.config(width = self.main_pic.size[0], height = self.main_pic.size[1])
self.temp = self.main_pic.copy() # 'working' image
def update_painel(self):
self.tkphoto = ImageTk.PhotoImage(self.temp_pic)
self.c.itemconfigure(self.canvasItem, image = self.tkphoto)
def zoom_in(self):
self.temp_pic = self.temp_pic.transform( ( self.temp_pic.size[0]/2,
self.temp_pic.size[0]/2
),
Image.EXTEND,
( 0, 0, self.temp_pic[0], self.temp_pic[1]
)
)
self.update_painel()
def zoom_out(self):
self.temp_pic = self.main_pic
self.update_painel()
app = Painel()
app.mainloop()
a deep-copy instruction shall read
self.temp_pic = self.main_pic.copy() # 'working' image
instead of
self.temp = self.main_pic.copy() # 'working' image**

Categories