#1.はじめに
前回の記事に、**Tkinterのテンプレート化**についてご紹介しました。
今回の記事では、このテンプレートを元に、Image Viewerのアプリケーションの作り方をご紹介します。
###環境
Windows 10 64 bit
Python 3.7
IDE : Pycharm
#2.Image Viewerの概要
次の図に、今回作成するImage Viewerアプリケーションのポンチ絵を示します。。
このアプリケーションの機能は、画像ファイルを選択し、その画像を表示することだけです。
そして、表示画面を消す機能とアプリケーションを終了する機能を追加します。
#3.Image Viewerの設計
次の図に、Image Viewerのレイアウトを示します。
アプリケーションの部品であるWidgetを用意します。
1.Canvas Widget : Imageを表示するための入れ箱。
2.Label Frame Widget : ボタンを三つ用意しますが、それらのボタンをまとめるための入れ箱。
3.Button : Load Image, Clear Image, Quit Applicationの三つのボタン。
###Tkinter テンプレートの説明
**Tkinterのテンプレート化記事に紹介されたテンプレートのプログラムコードです。
テンプレートの構成
- Applicationクラス
Widget設定&配置, Event Callback関数を定義 - main関数
このテンプレートに、前章に説明したWidgetの設定・配置、そしてEvent Callback関数を記入する手順で、コードを組み立てます。 (骨組み→肉付け)
import tkinter as tk
from tkinter import ttk
class Application(tk.Frame):
def __init__(self,master):
super().__init__(master)
self.pack()
self.master.geometry("300x300")
self.master.title("Tkinter with Class Template")
self.create_widgets()
def create_widgets(self):
pass
def callBack(self):
pass
def main():
root = tk.Tk()
app = Application(master=root)#Inherit
app.mainloop()
if __name__ == "__main__":
main()
##3.1.Canvasの設定
Class Applicationのcreate_widgetsメソッド部分にCanvas Widgetを設定、配置します。
配置には、Gridメソッドを利用します。
def create_widgets(self):
#Canvas
self.canvas1 = tk.Canvas(self)
self.canvas1.configure(width=640, height=480, bg='orange')
self.canvas1.create_rectangle(0,0,120, 70, fill='green')
self.canvas1.grid(column=1, row=0)
self.canvas1.grid(padx=20, pady=20)
##3.2.File Open -> Image Load
ファイルを開き、Imageファイルをロードする部分です。
Buttonを設定した後、Event Callback関数のloadImage()を定義します。
LoadImage()の内部のif文は、画像の縦横比を見て、Canvasのサイズに合わせ、元画像をリサイズするために追加しました。
そして、画像ファイルの変換として、openCVのRGB変換、PILに変換、imageTKに変換する部分が続きます。
最後に、self.canvas1.create_image
で画像をCanvas Widgetに表示します。
def create_widgets(self):
#File open and Load Image
self.button_open = ttk.Button(self.frame_button)
self.button_open.configure(text = 'Load Image')
self.button_open.grid(column=0, row=1)
self.button_open.configure(command=self.loadImage)
# Event Call Back
def loadImage(self):
self.filename = filedialog.askopenfilename()
self.image_bgr = cv2.imread(self.filename)
self.height, self.width = self.image_bgr.shape[:2]
if self.width > self.height:
self.new_size = (640,480)
else:
self.new_size = (480,480)
self.image_bgr_resize = cv2.resize(self.image_bgr, self.new_size, interpolation=cv2.INTER_AREA)
self.image_rgb = cv2.cvtColor( self.image_bgr_resize, cv2.COLOR_BGR2RGB ) # imreadはBGRなのでRGBに変換
self.image_PIL = Image.fromarray(self.image_rgb) # RGBからPILフォーマットへ変換
self.image_tk = ImageTk.PhotoImage(self.image_PIL) # ImageTkフォーマットへ変換
self.canvas1.create_image(320,240, image=self.image_tk)
下記の図は、ファイルを開くときにキャプチャした画像です。この機能を使うため、filedialog.askopenfilename()
を利用します。
しかし、フォルダー名に日本語文字が(UTF-8)ある場合、エラーが出ます。今回は、画像ファイルが格納されるフォルダー名は、英語にするようにお願いします。(もし、この問題の解決方法のご存知の方は、メッセージを残してください。)
##3.3.画面クリア
Canvas上の画面を消す機能です。canvas.delete()
メソッドを利用します。
def clearImage(self):
self.canvas1.delete("all")
##3.4.Quitボタン
終了の際に、MessageBoxを表示させ「本当に終了するの?」とユーザーの判断をもう一度確認する部分です。
def quit_app(self):
self.Msgbox = tk.messagebox.askquestion("Exit Applictaion", "Are you sure?", icon="warning")
if self.Msgbox == "yes":
self.master.destroy()
else:
tk.messagebox.showinfo("Return", "you will now return to application screen")
#4.実行結果
次の図に、実行結果を表示します。設計通りに動作することが確認できました。
Clear ImageやQuitもOKであることが確認できました。
#5.まとめ
- Tkinterの基本テンプレートを利用して、Image Viewer Applicationを作成しました。
- 基本テンプレートに、必要なWidgetを追加することで、様々な目的のアプリケーションの作成が可能であることを確認しました。
- なかなか優れものですね。Tkinter。
#6.全体コード
import tkinter as tk
from tkinter import ttk
import sys
import os
from tkinter import *
from tkinter import messagebox,filedialog
import numpy as np
from PIL import Image, ImageTk
import cv2
# coding: utf-8
# Folder名に日本語文字を入れたらダメでした。
class Application(tk.Frame):
def __init__(self,master):
super().__init__(master)
self.pack()
self.master.geometry("800x600")
self.master.title("Tkinter with Class Template")
self.create_widgets()
def create_widgets(self):
#Canvas
self.canvas1 = tk.Canvas(self)
self.canvas1.configure(width=640, height=480, bg='orange')
self.canvas1.create_rectangle(0,0,120, 70, fill='green')
self.canvas1.grid(column=1, row=0)
self.canvas1.grid(padx=20, pady=20)
#Frame
self.frame_button = ttk.LabelFrame(self)
self.frame_button.configure(text=' Button Frame ')
self.frame_button.grid(column=1,row=1)
self.frame_button.grid(padx=20, pady=20)
#File open and Load Image
self.button_open = ttk.Button(self.frame_button)
self.button_open.configure(text = 'Load Image')
self.button_open.grid(column=0, row=1)
self.button_open.configure(command=self.loadImage)
# Clear Button
self.button_clear = ttk.Button( self.frame_button )
self.button_clear.configure( text='Clear Image' )
self.button_clear.grid( column=1, row=1 )
self.button_clear.configure(command=self.clearImage)
# Quit Button
self.button_quit = ttk.Button( self.frame_button )
self.button_quit.config( text='Quit' )
self.button_quit.grid( column=2, row=1 )
self.button_quit.configure(command = self.quit_app)
# Event Call Back
def loadImage(self):
#self.folder_name = filedialog.askdirectory()
self.filename = filedialog.askopenfilename()
#print(self.folder_name)
print(self.filename)
self.image_bgr = cv2.imread(self.filename)
self.height, self.width = self.image_bgr.shape[:2]
print(self.height, self.width)
if self.width > self.height:
self.new_size = (640,480)
else:
self.new_size = (480,480)
self.image_bgr_resize = cv2.resize(self.image_bgr, self.new_size, interpolation=cv2.INTER_AREA)
self.image_rgb = cv2.cvtColor( self.image_bgr_resize, cv2.COLOR_BGR2RGB ) # imreadはBGRなのでRGBに変換
# self.image_rgb = cv2.cvtColor(self.image_bgr, cv2.COLOR_BGR2RGB) # imreadはBGRなのでRGBに変換
self.image_PIL = Image.fromarray(self.image_rgb) # RGBからPILフォーマットへ変換
self.image_tk = ImageTk.PhotoImage(self.image_PIL) # ImageTkフォーマットへ変換
self.canvas1.create_image(320,240, image=self.image_tk)
def clearImage(self):
self.canvas1.delete("all")
def quit_app(self):
self.Msgbox = tk.messagebox.askquestion("Exit Applictaion", "Are you sure?", icon="warning")
if self.Msgbox == "yes":
self.master.destroy()
else:
tk.messagebox.showinfo("Return", "you will now return to application screen")
def main():
root = tk.Tk()
app = Application(master=root)#Inherit
app.mainloop()
if __name__ == "__main__":
main()
#7.参考資料
1.Tkinterのクラス化のテンプレート
2.【Python】Tkinterのcanvasを使ってみる
2.Tkinterで作成したウインドウにOpenCV-Pythonの画像を表示