"I want a GUI trimming tool that runs on Python!"
When dealing with images in Python, there are many people who want to crop with GUI operations.
I searched for a reference article on the net, but this is quite good! I couldn't meet anything like that, so I'll leave it here.
Tkinter is a kit that allows you to easily create GUI tools in Python. I usually use Jupyter Notebook and I used ipywidgets when I needed GUI operation, but this is not enough and I used Tkinter this time.
I will cut out a part of the image and save it in Python. I didn't just want to do this trimming part I wanted to do a process like [image processing → trimming → image processing]. The motivation for this time was that I wanted to do it consistently with Python.
crop.py
from tkinter import *
from PIL import Image
import os
os.chdir("c:\\users\\username")
#----------------------------------------------------------------------
def filenameMaker(num):
return "%03d.png " % num
class MainWindow():
#----------------
def __init__(self, main):
#Make a canvas to display the image
self.canvas = Canvas(main, width=200, height=200)
self.canvas.grid(row=0, column=0, columnspan=2, rowspan=4)
#image(000.png to 004.5 pieces of png)To capture
self.my_images = []
self.file_num = 0
for i in range(0, 5):
self.my_images.append(PhotoImage(file=filenameMaker(i)))
self.my_image_number = 0
#Secure a number for storage
self.save_file_num = 0
#Set the first image
self.image_on_canvas = self.canvas.create_image(
0, 0, anchor=NW, image=self.my_images[self.my_image_number])
#Make various buttons
#Button to display the next image
self.button_next = Button(
main, text="Next", command=self.onNextButton, width=20, height=5)
self.button_next.grid(row=2, column=4, columnspan=2, rowspan=2)
#Button to display the previous image
self.button_back = Button(
main, text="Back", command=self.onBackButton, width=20)
self.button_back.grid(row=4, column=4, columnspan=2)
#Button to save selection
self.button_save = Button(
main, text="Save", command=self.onSaveButton, width=25, height=5)
self.button_save.grid(row=2, column=6, columnspan=3, rowspan=2)
#Button to return one save number
self.button_saveb = Button(
main, text="Save Back", command=self.onSavebButton, width=25)
self.button_saveb.grid(row=4, column=6, columnspan=3)
#Make an Entry to display a message
#Entry to display the current image number
self.message_num = Entry(width=50)
self.message_num.insert(
END, ("This image is " + filenameMaker(self.my_image_number)))
self.message_num.grid(row=6, column=4, columnspan=5)
#Entry to display the next save number
self.message = Entry(width=50)
self.message.insert(END, ("Next save-name is " +
"save-" + filenameMaker(self.save_file_num)))
self.message.grid(row=7, column=4, columnspan=5)
#Reserve variables for sliders
self.left = 0
self.right = 0
self.top = 0
self.bottom = 0
#Draw a line for image cropping on the canvas
self.canvas.create_line(self.left, 0, self.left,
200, tag="left_line", fill='green')
self.canvas.create_line(self.right, 0, self.right,
200, tag="right_line", fill='red')
self.canvas.create_line(
0, self.top, 200, self.top, tag="top_line", fill='green')
self.canvas.create_line(0, self.bottom, 200,
self.bottom, tag="bottom_line", fill='red')
#Make a slider for image cropping
self.left = Scale(main, label='left', orient='h',
from_=0, to=200, length=200, command=self.onSliderLeft)
self.left.grid(row=4, column=0, columnspan=2, rowspan=2)
self.right = Scale(main, label='right', orient='h',
from_=0, to=200, length=200, command=self.onSliderRight)
self.right.grid(row=6, column=0, columnspan=2, rowspan=2)
self.top = Scale(main, label='top', orient='v',
from_=0, to=200, length=200, command=self.onSliderTop)
self.top.grid(row=4, column=2, rowspan=4)
self.bottom = Scale(main, label='bottom', orient='v',
from_=0, to=200, length=200, command=self.onSliderBottom)
self.bottom.grid(row=4, column=3, rowspan=4)
#Move the line for cropping the image according to the displayed image
self.left.set(0)
self.right.set(self.my_images[self.my_image_number].width())
self.top.set(0)
self.bottom.set(self.my_images[self.my_image_number].height())
#----------------
def onBackButton(self):
#Return to last image
if self.my_image_number == 0:
self.my_image_number = len(self.my_images) - 1
else:
#Go back one
self.my_image_number -= 1
#Update display image
self.canvas.itemconfig(self.image_on_canvas,
image=self.my_images[self.my_image_number])
#Updated the position of the line for cutting out the image according to the displayed image
self.left.set(0)
self.right.set(self.my_images[self.my_image_number].width())
self.top.set(0)
self.bottom.set(self.my_images[self.my_image_number].height())
#Update the contents of Entry
self.message_num.delete(0, END)
self.message_num.insert(
END, ("This image is " + filenameMaker(self.my_image_number)))
def onNextButton(self):
#Go one step forward
self.my_image_number += 1
#Return to first image
if self.my_image_number == len(self.my_images):
self.my_image_number = 0
#Update display image
self.canvas.itemconfig(self.image_on_canvas,
image=self.my_images[self.my_image_number])
#Updated the position of the line for cutting out the image according to the displayed image
self.left.set(0)
self.right.set(self.my_images[self.my_image_number].width())
self.top.set(0)
self.bottom.set(self.my_images[self.my_image_number].height())
#Update the contents of Entry
self.message_num.delete(0, END)
self.message_num.insert(
END, ("This image is " + filenameMaker(self.my_image_number)))
def onSaveButton(self):
#Capture the display image
self.temp_image = Image.open(filenameMaker(self.my_image_number))
#Cut out at the selected position
self.cropped_image = self.temp_image.crop(
(self.left.get(), self.top.get(), self.right.get(), self.bottom.get()))
#Save
self.cropped_image.save("save-" + filenameMaker(self.save_file_num))
self.save_file_num += 1
#Update the contents of Entry
self.message.delete(0, END)
self.message.insert(END, ("Next save-name is " +
"save-" + filenameMaker(self.save_file_num)))
def onSavebButton(self):
self.save_file_num -= 1
if self.save_file_num == -1:
self.save_file_num = 0
#Update the contents of Entry
self.message.delete(0, END)
self.message.insert(END, ("Next save-name is " +
"save-" + filenameMaker(self.save_file_num)))
def onSliderLeft(self, args):
# change line
self.canvas.delete("left_line")
self.canvas.create_line(
self.left.get(), 0, self.left.get(), 200, tag="left_line", fill='green')
def onSliderRight(self, args):
# change line
self.canvas.delete("right_line")
self.canvas.create_line(
self.right.get(), 0, self.right.get(), 200, tag="right_line", fill='red')
def onSliderTop(self, args):
# change line
self.canvas.delete("top_line")
self.canvas.create_line(0, self.top.get(), 200,
self.top.get(), tag="top_line", fill='green')
def onSliderBottom(self, args):
# change line
self.canvas.delete("bottom_line")
self.canvas.create_line(0, self.bottom.get(), 200,
self.bottom.get(), tag="bottom_line", fill='red')
#----------------------------------------------------------------------
root = Tk()
MainWindow(root)
root.mainloop()
filenameMaker (num)
. (2017.04.07)
ʻAutopep8 -i crop.py` for a clean copy. (2017.04.07)
Removed some unnecessary code. (2017.04.09)The execution screen is shown below. The operation content is to select the cutout position with each slider Display the next image with the Next button Display the previous image with the Back button Save the cutout range with the Save button Save back one image number with the Save Back button
Each widget is created with def __init __ (self, main):
to define the display position. .grid
is used to define the display position.
When loading an image, I use PhotoImage
, and when I save it withdef onSaveButton (self):
, I use PIL's ʻImage, which seems to be awkward. I couldn't do it, and I couldn't read it properly with ʻImage
.
↓ Saved image.
--Try using Python's Tkinter --Qiita http://qiita.com/nnahito/items/ad1428a30738b3d93762
--Introduction to Easy Python / Tkinter http://www.geocities.jp/m_hiroi/light/pytk01.html
Recommended Posts