このページでは Python で Tkinter を用いて GUI アプリに画像を表示する方法について、サンプルスクリプトを用いて紹介していきます。
このページで紹介するサンプルスクリプトを実行すれば、下のように GUI アプリが起動し、
さらに「ファイル選択」ボタンから画像ファイル(.png や .gif など)を選択することで、画面の左側に画像が表示されるようになります。
また「縮小」ボタンを押せば、左側に表示されている画像を縮小したものが画面の右側に、「拡大」ボタンを押せば、左側に表示されている画像を拡大したものが画面の右側に表示されます。
Python で画像といえば Pillow や OpenCV などを利用するイメージが強いかもしれませんが、今回紹介するのは Tkinter(filedialog 含む)のみを利用して GUI アプリに表示する方法です。
サンプルスクリプトで利用している Tkinter については下記ページで、
PythonでTkinterを使ってめちゃくちゃ簡単にGUIアプリを作るファイル選択画面を表示する方法については下記ページで紹介しています。
Python でファイル選択画面を表示するこれらのページについても併せて読んでいただければと思います。
このページで紹介するサンプルスクリプトは下記環境で動作確認を行っています
- OS:macOS Catalina
- Python:3.8
- Tkinter:8.6
Contents
GUI アプリに画像を表示する方法
GUI アプリに画像を表示するには、Tkinter の PhotoImage
クラスを利用します。
画像オブジェクトの生成
PhotoImage
クラスのオブジェクトを生成時に画像ファイルへのファイルパスを指定すれば、その画像を Tkinter で利用するためのオブジェクトに変換することができます。
image = tkinter.PhotoImage(file="ファイルパス")
file
には画像ファイルへのパスを指定します。
ただし、Tkinter のみだと PhotoImage
に指定できる画像ファイルは下記の形式のみになります(2020/4/17 時点)。
- PNG
- PGM
- PPM
- GIF
Pillow を利用すればもっと多くの画像形式を利用できるようになりますが、Tkinter だけだと上記のみしかた対応していないようです。少ない!
スポンサーリンク
画像の描画
さらにその画像を Tkinter の Canvas
クラスのメソッド create_image
を利用して GUI アプリに画像を描画することが可能です。
canvas.create_image(
0, 0, image=image
)
第1引数には描画する画像の中心の x 座標、第2引数には描画する画像の中心の y 座標を指定します。
また image
には PhotoImage
クラスのオブジェクトを指定します。
画像のリサイズ
PhotoImage クラスに用意されたメソッドを利用すれば、画像のリサイズを行うこともできます。
縮小
また、この PhotoImage
クラスのオブジェクトに subsample
メソッドを実行させることで画像を縮小することができます。、zoom
メソッドを実行することで画像の拡大を行うことも可能です。
dst_image = src_image.subsample(2, 1)
第1引数には横方向の縮小率(大きい値ほど縮小される)、第2引数には縦方向の縮小率を指定します。第1引数のみを指定した場合、画像の縦横の両方向が、その縮小率に基づいて縮小されます。
ただし、引数に指定できるのは整数のみです…。細かいサイズの調整はできません…。
拡大
PhotoImage
クラスのオブジェクトに zoom
メソッドを実行することで画像の拡大も行うこともできます。
dst_image = src_image.zoom(2, 3)
第1引数には横方向の拡大率(大きい値ほど拡大される)、第2引数には縦方向の拡大率を指定します。
第1引数のみを指定した場合、画像の縦横の両方向が、その拡大率に基づいて縮小されます。
ただし、こちらも subsample
メソッド同様に引数に指定できるのは整数のみです…。
GUI アプリに画像を表示するサンプルスクリプト
ここまで紹介してきた PhotoImage
クラスを利用して GUI アプリに画像を表示するサンプルスクリプトは下記のようになります。
import tkinter
import tkinter.filedialog
class Application(tkinter.Tk):
def __init__(self):
super().__init__()
# キャンバスのサイズ
self.canvas_width = 400
self.canvas_height = 400
# アプリのウィンドウのサイズ設定
self.geometry("1000x430")
# 1つ目のキャンバスの作成と配置
self.before_canvas = tkinter.Canvas(
self,
width=self.canvas_width,
height=self.canvas_height,
bg="gray"
)
self.before_canvas.grid(row=1, column=1)
# 2つ目のキャンバスの作成と配置
self.after_canvas = tkinter.Canvas(
self,
width=self.canvas_width,
height=self.canvas_height,
bg="gray"
)
self.after_canvas.grid(row=1, column=2)
# ボタンを配置するフレームの作成と配置
self.button_frame = tkinter.Frame()
self.button_frame.grid(row=1, column=3)
# ファイル読み込みボタンの作成と配置
self.load_button = tkinter.Button(
self.button_frame,
text="ファイル選択",
command=self.push_load_button
)
self.load_button.pack()
# 画像縮小ボタンの作成と配置
self.subsample_button = tkinter.Button(
self.button_frame,
text="縮小",
command=self.push_subsample_button
)
self.subsample_button.pack()
# 画像拡大ボタンの作成と配置
self.zoom_button = tkinter.Button(
self.button_frame,
text="拡大",
command=self.push_zoom_button
)
self.zoom_button.pack()
# 画像オブジェクトの設定(初期はNone)
self.before_image = None
self.after_image = None
# キャンバスに描画中の画像(初期はNone)
self.before_canvas_obj= None
self.after_canvas_obj = None
def push_load_button(self):
'ファイル選択ボタンが押された時の処理'
# ファイル選択画面を表示
file_path = tkinter.filedialog.askopenfilename(
initialdir="."
)
if len(file_path) != 0:
# Tkinter用画像オブジェクトの作成
self.before_image = tkinter.PhotoImage(file=file_path)
# 画像の描画位置を調節
x = int(self.canvas_width / 2)
y = int(self.canvas_height / 2)
# キャンバスに描画中の画像を削除
if self.before_canvas_obj is not None:
self.before_canvas.delete(self.before_canvas_obj)
# 画像を1つ目のキャンバスに描画
self.before_canvas_obj = self.before_canvas.create_image(
x, y,
image=self.before_image
)
def push_subsample_button(self):
'縮小ボタンが押された時の処理'
if self.before_image is not None:
# 1つ目のキャンバスに描画している画像をコピー
tmp_image = self.before_image.copy()
# 画像を縮小(1/2)
self.after_image = tmp_image.subsample(2)
# 画像の描画位置を調節
x = int(self.canvas_width / 2)
y = int(self.canvas_height / 2)
# キャンバスに描画中の画像を削除
if self.after_canvas_obj is not None:
self.after_canvas.delete(self.after_canvas_obj)
# 画像を描画
self.after_canvas_obj = self.after_canvas.create_image(
x, y,
image=self.after_image
)
def push_zoom_button(self):
'拡大ボタンが押された時の処理'
if self.before_image is not None:
# 1つ目のキャンバスに描画している画像をコピー
tmp_image = self.before_image.copy()
#画像を拡大(2倍)
self.after_image = tmp_image.zoom(2)
# 画像の描画位置を調節
x = int(self.canvas_width / 2)
y = int(self.canvas_height / 2)
# キャンバスに描画中の画像を削除
if self.after_canvas_obj is not None:
self.after_canvas.delete(self.after_canvas_obj)
# 画像を描画
self.after_canvas_obj = self.after_canvas.create_image(
x, y,
image=self.after_image
)
app = Application()
app.mainloop()
このページの冒頭で説明した通り、このスクリプトを実行すると下の図のようなアプリが起動します。
アプリ起動後、「ファイル選択ボタン」から画像ファイルを選択すれば、その画像が画面の左側のキャンバスに描画されます。
また、画像が左側のキャンバスに描画された後に、「縮小」or「拡大」ボタンを押せば、リサイズ後の画像が右側のキャンバスに描画されます。
キャンバスのサイズは 400×400 に設定していますので、それより大きいサイズの画像を描画した場合は画像がキャンバスはみ出てしまう(表示されない)ので注意してください。
スポンサーリンク
サンプルスクリプトの解説
ここでは PhotoImage
クラスを活用している下記の3つのメソッドについて解説したいと思います。
その他の部分は主に Tkinter を利用したスクリプトになっていますので、詳しくは下記ページを参考にしていただければと思います。
PythonでTkinterを使ってめちゃくちゃ簡単にGUIアプリを作るこの push_load_button
は「ファイル選択」ボタンが押された時に実行されるメソッドです。
まず askopenfilename
関数によりファイル選択画面を表示し、ユーザーからの画像のファイルパス選択を受け付けます。
askopenfilename
関数については下記ページで解説していますので詳しく知りたい方はこちらを参考にしてください。ファイルパスが選択されれば、下記によりそのファイルパスの画像から Tkinter 用の画像オブジェクトが生成しています。
# Tkinter用画像オブジェクトの作成
self.before_image = tkinter.PhotoImage(file=file_path)
さらにオブジェクト生成後、Canvas
クラスの create_image
メソッドを利用してキャンバスに画像の描画を行っています。
# 画像を1つ目のキャンバスに描画
self.before_canvas.create_image(
self.before_image.width() / 2,
self.before_image.height() / 2,
image=self.before_image
)
self.before_canvas
は画面左側のキャンバスのオブジェクトですので、上記により指定された画像が画面左側のキャンバスに描画されることになります。
push_subsample_button
は「縮小」ボタンが押された時に実行されるメソッドです。
まず下記により、縮小する画像をコピーします。
# 1つ目のキャンバスに描画している画像をコピー
tmp_image = self.before_image.copy()
さらに下記により画像の縮小を行い、
# 画像を縮小(1/2)
self.after_image = tmp_image.subsample(2)
最後に下記により縮小後の画像をキャンバス描画しています(キャンバスの中心に画像が描画されるように x
と y
を計算しています)。
# 画像の描画位置を調節
x = self.canvas_width / 2
y = self.canvas_height / 2
# 画像を描画
self.after_canvas.create_image(
x, y,
image=self.after_image
)
self.after_canvas
は画面右側のキャンバスのオブジェクトですので、上記によりリサイズ後の画像が画面右側のキャンバスに描画されることになります。
スポンサーリンク
push_zoom_button
は「拡大」ボタンが押された時に実行されるメソッドで、基本的な処理は push_subsample_button
と同様です。
ただしこちらのメソッドでは画像の拡大を行いますので、subsample
メソッドではなく zoom
メソッドを使用しています。
# 画像を拡大(2倍)
self.after_image = tmp_image.zoom(2)
まとめ
このページでは Tkinter を利用して GUI アプリに画像を表示する方法について解説しました。
Tkinter を使って簡単な画像処理も行ってみましたが、あくまでもこのページの目的は GUI アプリに画像を表示することです。
もっと豊富な形式の画像を読み込めるようにしたり、より高度な画像処理を行うためには OpenCV や Pillow を利用する方が良いです。
ただし、画像処理アプリを作成して画像をアプリ上に表示したい場合(例えば OpenCV での画像処理前後の画像を GUI アプリに表示する等)は、このページで解説した内容は役に立つと思いますのでしっかり理解しておくのが良いと思います。
ちなみに、PhotoImage クラスには get メソッドと put メソッドが用意されており、これらを使用してピクセル単位で画像を加工することも可能です。これについては下記ページで解説していますので、こちらも是非読んでみてください!
【Python】Tkinter PhotoImage の get・put を利用してピクセル単位で画像処理を行う(透過処理も)オススメ参考書(PR)
「GUI アプリ作成に興味のある方」や「ゲーム開発に興味のある方」にはPythonでつくる ゲーム開発 入門講座がオススメです。
この本は、このページで紹介した Tkinter を中心に、「すごろく」や「RPG」・「落ちものゲーム」を開発しながら Python プログラミングを学べる参考書になります。 初心者向け解説も多く、 Python の基本から GUI アプリの開発・ゲーム開発について学ぶ事ができます。
また初心者の方にとっては、楽しく Python を学べる点がオススメの理由です。ゲーム開発を通して Python プログラミングを学ぶ事ができ、自分の作成したプログラムの動作を実際に目で確認できるので楽しく勉強できま。
楽しいのでプログラミング学習のモチベーション低下も防ぐ事ができます。
とっつきやすさという点で、Python 入門者向け参考書としてはナンバーワンだと思います。