Creating Blank Images in Python (allowing pixel by pixel manipulation) - python

I have this code here that creates a Tkinter Canvas widget, then embeds an image within it.
import Tkinter
from PIL import ImageTk, Image
class image_manip(Tkinter.Tk):
def __init__(self):
Tkinter.Tk.__init__(self)
self.configure(bg='red')
self.ImbImage = Tkinter.Canvas(self, highlightthickness=0, bd=0, bg='blue')
self.ImbImage.pack()
self.i = ImageTk.PhotoImage(Image.open(r'test.png'))
self.ImbImage.create_image(150, 100, image=self.i)
def run():
image_manip().mainloop()
if __name__ == "__main__":
run()
I'd like to be able to create a blank image within the Canvas widget, so that I could do pixel by pixel manipulation within the widget. How would one go about this?

To create a new blank image (rather than opening one), you can use the Image.new(...) method in place of your Image.open(...). It is described in The Image Module.
Then call self.i.put(...) to do pixel-by-pixel manipulation. (i is the PhotoImage object as in your example.)
Here's some general information on The Tkinter PhotoImage Class.

Related

How to customize the contains-function of tkinter canvas elements/images?

I added a png image with transparent regions (alpha=0) to a tkinter canvas (see minimal example below). A mouse-click is recognized when clicking somewhere in the rectangle that contains the tkinter image.
How do I adjust the functionality such that any mouse binding (clicking, moving, etc.) is only called when the mouse is located on pixels with non-zero alpha values of the image?
Tux (linux mascot) example image :
try:
# Tkinter for Python 2.xx
import Tkinter as tk
except ImportError:
# Tkinter for Python 3.xx
import tkinter as tk
image_path = "./tux.png"
class Application(tk.Frame):
def __init__(self, master):
self.master = master
tk.Frame.__init__(self, master)
self.canvas = tk.Canvas(self, width=600, height=600)
self.canvas.pack(fill="both", expand=True)
# create an example image
self.tk_image = tk.PhotoImage(file=image_path)
self.image_obj= self.canvas.create_image(200, 200, anchor = 'center',
image=self.tk_image)
self.canvas.tag_bind(self.image_obj, '<Button-1>', self.clicked)
def clicked(self, event):
print("I am tux.")
def main():
app_win = tk.Tk()
app = Application(app_win).pack(fill='both', expand=True)
app_win.mainloop()
if __name__ == '__main__':
main()
How do I adjust the functionality such that any mouse binding (clicking, moving, etc.) is only called when the mouse is located on pixels with non-zero alpha values of the image?
You can't. That's simply not something that tkinter directly supports. Unfortunately, tkinter's support of transparency is a bit lacking.
What you might be able to do, however, is have the bound function get the image object, compute which pixel was clicked on, and then query the image instance to get the color of that pixel.

Unable to put transparent PNG over a normal image Python Tkinter

So I have 2 images, 1 image is supposed to be the background and the other 1 is just an image of a character.
I am able to put one image over the other but the image has white borders even though it's a PNG file.
This is how it looks like:
This is how I want it to look like:
Here are the two separte images:
https://imgur.com/a/SmE5lgC
Sorry that I didnt post the images directly but I can not since I do no have 10 reputation points.
I've tried converting it to RGBA but same thing happened.
from tkinter import *
from PIL import Image
root = Tk()
root.title("Game")
background = PhotoImage(file="back.png")
backgroundlabel = Label(root, image=background)
backgroundlabel.pack()
character = PhotoImage(file="hero.png")
characterlabel = Label(root, image=character)
characterlabel.place(x=0,y=0)
root.mainloop()
You just need to use the canvas widget in Tkinter. Only the canvas widget supports transparency. This has to do with how Tkinter draws the display. As of right now, your code is just overlaying two images. Tkinter does not know how to compose them with transparency unless you use the canvas widget.
See the following code:
from tkinter import *
from PIL import Image
root = Tk()
root.title("Game")
frame = Frame(root)
frame.pack()
canvas = Canvas(frame, bg="black", width=700, height=400)
canvas.pack()
background = PhotoImage(file="background.png")
canvas.create_image(350,200,image=background)
character = PhotoImage(file="hero.png")
canvas.create_image(30,30,image=character)
root.mainloop()
All I did was download the images you provided. I did not modify the images. So, the bottom line is that you just need to use the canvas widget.
Voilà!
Note: The question asked is a duplicate of How do I make Tkinter support PNG transparency?

How to display multiple images inside tkinter window?

I want to display 7 different images and plot them inside tkinter window. I only know to display it using OpenCV which actually displays the image outside the Tkinter GUI window. How to plot the images inside the GUI window?
Tkinter GUI:
I advise you read the documentation of tkinter as it has tons of example on how to achieve a soluction to your problem. I have made a sample GUI which updates image on the GUI with a randomized pixel picture. Note that there are a lot of different approaches how to do this. In my case I have made a class in which I display a frame and a button. The button calls a function to randomize the image (or changes to the next one in your case) and calls the function to update the frame with a new image. Hope it gives you a jump start. Cheers!
P.S.: for multiple images use more labels and functions;)
Code:
import tkinter as tk
from tkinter import *
import cv2
import numpy as np
from PIL import Image, ImageTk
class DisplayImage:
def __init__(self, master):
self.master = master
master.title("GUI")
self.image_frame = Frame(master, borderwidth=0, highlightthickness=0, height=20, width=30, bg='white')
self.image_frame.pack()
self.image_label = Label(self.image_frame, highlightthickness=0, borderwidth=0)
self.image_label.pack()
self.Next_image = Button(master, command=self.read_image, text="Next image", width=17, default=ACTIVE, borderwidth=0)
self.Next_image.pack()
def display_image(self, event=None):
self.cv2image = cv2.cvtColor(self.img, cv2.COLOR_BGR2RGBA)
self.from_array = Image.fromarray(self.cv2image)
self.imgt = ImageTk.PhotoImage(image=self.from_array)
self.image_label.configure(image=self.imgt)
def read_image(self, event=None):
self.img = np.random.randint(255, size=(250,250,3),dtype=np.uint8)
self.master.after(10, self.display_image)
def main():
root = tk.Tk()
GUI = DisplayImage(root)
GUI.read_image()
root.mainloop()
if __name__ == '__main__':
main()
Output:
If you are OK with using a wrapper with tkinter, then PySimpleGUI is a good choice.
There was a new Demo application posted this week that demonstrates how to show a webcam in a GUI window. There's another Demo posted that plays back a video file using OpenCV, again in a GUI window.
The code that generated that screen shot can be found here:
Open and Play Video Using PySimpleGU + OpenCV
You can start with the Demo and expand it by adding more buttons.

Displaying an image in python via Button and Canvas

I am a begginer in python, tkinter. I have written a code that should normally display an image in a canvas.
What happens is that the main frame (gui) is displayed with the menu bar, then when I click on load image, the gui window shrinks (to 100x100 I guess) but nothing is displayed within.
Could you please explain to me why this is happening so I can understand where the error occurs, and how to correct it?
# -*- coding:utf-8 -*-
# Imports
from tkinter import Tk, Menu, Canvas
from PIL import Image, ImageTk
# Function definitions
def deleteImage(canvas):
canvas.delete("all")
return
def loadImage(canvas, img):
filename = ImageTk.PhotoImage(img)
canvas.image = filename
canvas.create_image(0,0,anchor='nw',image=filename)
return
def quitProgram():
gui.destroy()
# Main window
gui = Tk()
# Inside the main gui window
#Creating an object containing an image
# A canvas with borders that adapt to the image within it
img = Image.open("fleur.jpg")
canvas = Canvas(gui,height=img.size[0],width=img.size[0])
canvas.pack()
# Menu bar
menubar = Menu(gui)
# Adding a cascade to the menu bar:
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Files", menu=filemenu)
# Adding a load image button to the cascade menu "File"
filemenu.add_command(label="Load an image", command=loadImage)
# Adding a delete image button to the cascade menu "File"
filemenu.add_command(label="Delete image", command=deleteImage)
filemenu.add_separator()
filemenu.add_command(label="Quit", command=quitProgram)
menubar.add_separator()
menubar.add_cascade(label="?")
# Display the menu bar
gui.config(menu=menubar)
gui.mainloop()
EDIT:
The second problem is that I want to create a canvas and the image in the main gui window, and pass them as arguments to the menu buttons (See code above, where img and canvas are created separately from the function loadImage). Seeing as putting parenthesis in the command=loadImage() created a problem on its own.
Another point that rises a question in my head : Regarding the first problem which was solved by keeping a reference to the filename=ImageTk.PhotoImage(img). Wouldn't it normally be pointless to keep a reference inside the function since it's a local variable anyway?
As stated in effbot's PhotoImage page, you have to keep a reference of your image to ensure it's not garbage collected.
You must keep a reference to the image object in your Python program,
either by storing it in a global variable, or by attaching it to
another object.
Note: When a PhotoImage object is garbage-collected by Python (e.g.
when you return from a function which stored an image in a local
variable), the image is cleared even if it’s being displayed by a
Tkinter widget.
To avoid this, the program must keep an extra reference to the image
object. A simple way to do this is to assign the image to a widget
attribute, like this:
Your loadImage() method should look like below.
def loadImage():
img = Image.open("fleur.jpg")
filename = ImageTk.PhotoImage(img)
canvas = Canvas(gui,height=100,width=100)
canvas.image = filename # <--- keep reference of your image
canvas.create_image(0,0,anchor='nw',image=filename)
canvas.pack()

Ttk background image

Is there any way to import an image into python using PIL and set it as the background for a ttk mainframe that spans the entirety of a Tkinter root window? As of now I have only seen ways to do this is a Tkinter root. Also is there any way to make ttk self adjust the size of the image so that even if it's small it covers the entire screen?
So to sum up I want an image to cover the entire ttk mainframe box without messing with me putting anything else in the ttk frame.
for example
if the pic covered the entire window, a command,
ttk.Button(root, text="Hello").grid(column=0, row=0, sticky=(N,S,W,E))
would still insert a button in the mainframe. Thanks :)
You can't set an image background to a ttk frame, they don't accept image options. So you could make a ttk frame and put a label or something inside it and then have it span the frame adapting the below example.
Here's a small example demonstrating what you want. We load an image with pil, notice the image linked will be smaller (I hope) than your screensize.
So, we set the geometry of the root window to be the entire screen the image is less than this so we resize it to cover the entire width. You can override the max and min height and then set it according to this. Just a sample value. We then place the bg label and grid widgets on top of it. The label has a lower stacking order than the other widgets you will place with grid so they appear on top. Alternatively you could use a canvas, or another widget. With a canvas you'll have to use create_window to place widgets in the canvas.
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
root = tk.Tk()
width, height = root.winfo_screenwidth(), root.winfo_screenheight()
#print(root.winfo_screenheight(), root.winfo_screenwidth())
root.geometry("%dx%d" % (width, height))
#URL FOR BACKGROUND
#https://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&ved=0ahUKEwiVroCiyZHMAhXKeT4KHQHpDVAQjBwIBA&url=http%3A%2F%2Fwallpaperswide.com%2Fdownload%2Fblack_background_metal_hole_very_small-wallpaper-800x480.jpg&psig=AFQjCNEjZ7GDbjG9sFie-yXW3fP85_p0VQ&ust=1460840934258935
image = Image.open("background.jpg")
if image.size != (width, height):
image = image.resize((width, height), Image.ANTIALIAS)
#print("DONE RESIZING")
# image.save("background.jpg")
#print(image.size)
image = ImageTk.PhotoImage(image)
bg_label = tk.Label(root, image = image)
bg_label.place(x=0, y=0, relwidth=1, relheight=1)
bg_label.image = image
your_button = ttk.Button(root, text='This is a button')
your_button.grid()
root.mainloop()

Categories