Cropping an image in tkinter - python

I'm using tkinter and I have a "sprite sheet" and I want to cut it into multiple images. I tried PIL:
img = Image.open("test.png").convert("RGBA")
img2 = img.crop([300,300,350,350])
image = ImageTk.PhotoImage(img2)
win = tk.Tk()
label = tk.Label(win, image = image)
label.pack()
but on my window, there is only an empty white rectangle and I don't understand why. Moreover I tried img2.show() just to make shure that img2 wasn't empty and it wasn't.

Here is your code, with a few changes. Note the call to Tk() at the top, and mainloop() at the bottom. The other modification is that it obtains the width and height of the image and then crops 25% from each of the four sides to leave the middle 50% of the image.
#!/usr/bin/python
from tkinter import *
from PIL import ImageTk,Image
root = Tk()
img = Image.open("test.png").convert("RGBA")
w, h = img.size
left = w/4
right = 3*w/4
upper = h/4
lower = 3*h/4
img2 = img.crop([ left, upper, right, lower])
image = ImageTk.PhotoImage(img2)
label = Label(root, image = image)
label.pack()
root.mainloop()

Related

How do I keep this image in the center of the window?

I'm making a hangman-like game; for that, I need all the different stages of the man to be visualized, hence images. I want the entire tkinter window to be an image, when I change the size it pushes the image right.
from tkinter import *
root=Tk()
root.geometry("600x350")
canvas = Canvas(root, width=1600, height=900)
canvas.pack()
img = PhotoImage(file="4.png")
canvas.create_image(470,190, image=img, )
root.mainloop()
If canvas is bigger than window then when you resize then it show more canvas but and it can looks like it moves image.
But if you use smaller canvas then pack() will try to keep centered horizontally. And if you add pack(expand=True) then it will try to keep it centered vertically.
In example code I added red background to window to show where is canvas
import tkinter as tk # PEP8: import *
root = tk.Tk()
root.geometry("600x350")
root['bg'] = 'red'
img = tk.PhotoImage(file="lenna.png")
canvas = tk.Canvas(root, width=600, height=350)
canvas.pack(expand=True)
canvas.create_image(300, 175, image=img)
root.mainloop()
Image Lenna from Wikipedia
PEP 8 -- Style Guide for Python Code
Before resizing:
After resizing:
If you want to draw only image then you could use Label(image=img)
import tkinter as tk # PEP8: import *
root = tk.Tk()
root.geometry("600x350")
root['bg'] = 'red'
img = tk.PhotoImage(file="lenna.png")
label = tk.Label(root, image=img)
label.pack(expand=True)
root.mainloop()
Before resizing:
After resizing:
BTW:
tkinter can bind() some function to event <Configure> and it will execute this function everytime when you resize window (and/or move window) - and this function may also move or resize image in window.
import tkinter as tk # PEP8: import *
from PIL import Image, ImageTk
def resize(event):
global img
lower = min(event.width, event.height)
#print(event.width, event.height, 'lower:', lower)
new_image = original_image.resize((lower, lower))
img = ImageTk.PhotoImage(new_image) # need to assign to global variable because there is bug in PhotoImage
label['image'] = img
# --- main ---
root = tk.Tk()
root.geometry("350x350")
root['bg'] = 'red'
original_image = Image.open("lenna.png")
img = ImageTk.PhotoImage(original_image)
label = tk.Label(root, image=img)
label.pack(expand=True)
root.bind('<Configure>', resize)
root.mainloop()
Before (it resized image at start to fit window):
After (it resized image to fit window):

why a .png file suddenly have black background in tkinter?

i wrote this code on the school computer, and it was totally fine. i wrote the same code on my personal pc and now it shows the picture with no transparency (with black background). the picture is the same picture(a png with no background)
from tkinter import *
from PIL import ImageTk, Image
root = Tk()
root.geometry("1300x731")
root.resizable(width=False, height=False)
photo = Image.open("logo.png")
zoom = 0.5
pixels_x, pixels_y = tuple([int(zoom * x) for x in photo.size])
img = ImageTk.PhotoImage(photo.resize((pixels_x, pixels_y)))
panel = Label(root, image = img).place(relx = 0.5, rely = 0.1, anchor = 'center')
#panel.grid(row=5000, column=3)
#panel.pack(side = "bottom", fill = "both", expand = "yes")
root.config(cursor="#curs.cur")
while True:
root.mainloop()
try it with another import method.
use photo = PhotoImage(file="logo.png")
this should remove the black background.
Remove the "while True:"
root.mainloop() is a loop by itself

Can you crop multiple areas from the same image with Wand?

I have two images and would like to extract multiple areas from the first image and overlay them on the second image. Is there a way to crop multiple areas from an image without loading the first image in again with Python Wand? Something like the opposite of +repage in ImageMagick.
bg_img = Image(filename = 'second_image.jpg')
fg_img = Image(filename = 'first_image.jpg')
left = 50
top = 600
width = 30
height = 30
fg_img.crop(left, top, width=width, height=height)
bg_img.composite(fg_img, left, top)
fg_img = Image(filename = 'first_image.jpg')
left = 500
top = 600
width = 100
height = 30
fg_img.crop(left, top, width=width, height=height)
bg_img.composite(fg_img, left, top)
bg_img.save(filename='second_image_plus_overlays.png')
You can do that in Python Wand by cloning the input.
Input:
from wand.image import Image
from wand.display import display
with Image(filename='lena.jpg') as img:
with img.clone() as copy1:
copy1.crop(left=50, top=100, width=100, height=50)
copy1.save(filename='lena_crop1.jpg')
display(copy1)
with img.clone() as copy2:
copy2.crop(left=100, top=50, width=50, height=100)
copy2.save(filename='lena_crop2.jpg')
display(copy2)
Result 1:
Result 2:

updating image in window using loop

from PIL import Image, ImageTk
import numpy as np
import tkinter as tk
import time
def put_pixel(row, col):
pixels[row, col] = [255, 255, 255]
width = 20
height = 10
pixels = np.full((height, width, 3), 0, dtype=np.uint8)
root = tk.Tk()
root.geometry("300x300")
root.configure(background='grey')
img = ImageTk.PhotoImage(Image.open("maze.png"))
panel = tk.Label(root, image=img)
panel.pack(side = "top")
b = tk.Button(root, text="Sure!")
b.pack(side="bottom", fill="both")
for i in range(1, width-2, 2):
put_pixel(5, i)
time.sleep(2)
img = Image.fromarray(pixels, 'RGB')
panel.configure(image=img)
panel.image = img
root.mainloop()
The script just adds white pixels on a black image. But I want it to be animated to see the adding of every pixel step by step. So I tried to update an image in a label after every single pixel being added. But I got an error
_tkinter.TclError: image "" doesn't exist
If I don't use loop and just put an image into a label it works fine. How do I fix that?
You need to convert the PIL.Image into a tkinter.PhotoImage:
img = Image.fromarray(pixels, 'RGB')
tkimg = ImageTk.PhotoImage(img)
panel.configure(image=tkimg)
panel.image = img
tkinter.Label will only accept this type, not PIL images.

tkinter - When resizing color image, it shows up in red scale only

I have the following piece of code:
from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk
import cv2
import os
import glob
import numpy as np
image_path = ""
image_list = []
class Proj:
def __init__(self, master):
self.master = master
#GUI height and width
w = 1250
h = 600
# open folder manager to select image folder
image_path = filedialog.askdirectory()
master.geometry("%dx%d%+d%+d" % (w ,h ,0,0))
master.resizable(True,True)
#read in images from folder
self.read_images(master, image_path)
#cv2.imshow('image',cv2.imread(image_list[0], 1))
self.img = cv2.imread(image_list[0])
self.img = Image.fromarray(np.array(self.img).copy())
self.img.thumbnail((w//2, w//2+10))
self.img = ImageTk.PhotoImage(self.img)
image_frame = Frame(master)
image_frame.grid(row = 0, column = 0, columnspan = 3, rowspan = 5)
left_panel = Canvas(image_frame, width=w//2, height=h-70)
left_panel.grid(row=0, column=0, columnspan=4)
imgA_handler = left_panel.create_image((0,0), image = self.img, anchor="nw")
right_panel = Canvas(image_frame, width=w//2, height=h-70)
right_panel.grid(row=0, column=5, columnspan=4)
def read_images(self, master, path):
images = path + '/*.tif'
for img in glob.glob(images): #will only read in tif images
image_list.append(img)
root = Tk()
example = Proj(root)
root.mainloop()
I am reading in color .tif images and then trying to display them in the left_panel. However, when I go to do that, it shows the normal color image only in red scale even though I never extracted just the red signal. I am completely unable to diagnose the issue. How do I fix this issue?
Ultimately, what I want to do is display two images on this GUI. An original image on the left and a modified image on the right. Currently my gui layout is set up as I've coded above. However, if you think there is an easier way to do this, then I'd be interested to hear.
This is because opencv uses BGR instead of RGB. When you are using this line: self.img = Image.fromarray(np.array(self.img).copy()) Blue and Red colors are being swapped. Just before you use the above code, convert the BGR to RGB in opencv and you should be good to go.
self.img = cv2.cvtColor(self.img,cv2.COLOR_BGR2RGB)
I see you are using opencv. Why don't you use the opencv command to resize.
It is very simple and works pretty well.
Take a look at this page:
OpenCV Resize
This is an example to make a image 50% smaller, or instead of the fx and fy, you can put the exact size you want.
thumbnail = cv2.resize(image, (0,0), fx=0.5, fy=0.5)

Categories