今回は Tkinter の PhotoImage
クラスが提供する get
・put
メソッドを利用してピクセル単位で画像処理を行う方法について解説していきたいと思います。
Tkinter は GUI アプリの開発に非常に便利なモジュールです。
さらに、Tkinter が提供する PhotoImage
クラスを利用することで、画像ファイルの読み込みを行い、簡単な画像処理(リサイズ)を行うことも可能です。
この辺りについては下記ページで解説していますので、是非こちらも読んでみてください。
【Python】Tkinter のみで GUI アプリに画像を表示するただし、PhotoImage
クラスが提供する画像処理の機能自体は非常に少ないです。
一方で、PhotoImage
クラスでは get
メソッドにより画像のピクセルデータを取得し、put
メソッドにより画像のピクセルデータを更新することができるようになっています。
そして、これを利用すれば様々な画像処理機能を実現することもできます(画像処理機能は自分でプログラミングする必要があります)。
このページでは主に get
メソッドと put
メソッドを利用して画像処理を行う方法について解説していきたいと思います。
このページで紹介するサンプルスクリプトは下記環境で動作確認を行っています
- OS:macOS Catalina
- Python:3.8
- Tkinter:8.6
Contents
get
メソッドによるピクセルデータの取得
PhotoImage
クラスが提供する get
メソッドは、指定した座標のピクセルデータ(R, G, B の3つの値が格納されたタプル)を取得するメソッドになります。
座標(x
, y
)のピクセルデータを取得する際には、get
メソッドを下記のように実行します。
# image は PhotoImage クラスのインスタンス
pixel = image.get(x, y)
put
メソッドによるピクセルデータの更新
PhotoImage
クラスが提供する put
メソッドは、指定したカラーコードの色を指定した座標に設定するメソッドになります。
カラーコードとは色を「#FFDD00」などのように、「#」と6桁の16進数の英数字で表現したものになります。
6桁の英数字はそれぞれ下記を表します。
- 最初の2桁 :赤色の強さ(0〜255の値を16進数で表現)
- 真ん中の2桁:緑色の強さ(0〜255の値を16進数で表現)
- 最後の2桁 :青色の強さ(0〜255の値を16進数で表現)
座標(x
, y
)の色を color
に設定する際には、put
メソッドを下記のように実行します。
# image は PhotoImage クラスのインスタンス
color = "#FFDD00"
pixel = image.putt(color, to=(x, y))
引数 to
には color
を設定する座標をタプル形式で指定します。
スポンサーリンク
ピクセルデータに対する透過処理
画像フォーマットによっては各ピクセルに対して透過設定を行うことが可能です(例えば GIF や PNG など)。透過設定が ON のピクセルは画像を表示すると透けて見えます。
これらの透過設定を行うために、PhotoImage
クラスでは transparency_get
メソッドと transparency_set
メソッドが用意されています。
transparency_get
メソッドによる透過設定の取得
transparency_get
メソッドは指定した座標の透過設定を取得するメソッドです。
座標(x
, y
)の透過設定を取得する際には、transparency_get
メソッドを下記のように実行します。
# image は PhotoImage クラスのインスタンス
transparency = image.transparency_get(x, y)
座標(x
, y
)の透過設定が ON の場合は transparency
に True
が格納され、OFF の場合は False
が格納されます。
transparency_get
では「完全に透明」 or 「それ以外の情報」しか取得できないようです(PNG 画像で確認・Tkinter version 8.6 で確認)
完全に透明の場合は True
が返却され、それ以外は False
が返却されます
半分程度だけ透明に設定されていても False
が返却されるので注意してください
transparency_set
メソッドによる透過設定の更新
transparency_set
メソッドは指定した座標に透過設定を行うメソッドです。
座標(x
, y
)に透過設定を ON にする際には、transparency_set
メソッドを下記のように実行します。
# image は PhotoImage クラスのインスタンス
image.transparency_set(x, y, True)
スポンサーリンク
ピクセル単位で画像処理を行うアプリのサンプルスクリプト
最後にピクセル単位で画像処理を行うアプリのサンプルスクリプトを紹介しておきます。
サンプルスクリプト
下記の Python スクリプトは、ここまで解説してきた get
メソッド、put
メソッド、transparency_get
メソッド、transparency_set
メソッドを利用し、画像の左右反転を行うアプリになります。
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="red"
)
self.before_canvas.grid(row=1, column=1)
# 2つ目のキャンバスの作成と配置
self.after_canvas = tkinter.Canvas(
self,
width=self.canvas_width,
height=self.canvas_height,
bg="blue"
)
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.flip_button = tkinter.Button(
self.button_frame,
text="反転",
command=self.push_flip_button
)
self.flip_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_flip_button(self):
'反転ボタンが押された時の処理'
if self.before_image is not None:
# 1つ目のキャンバスに描画している画像をコピー
self.after_image = self.before_image.copy()
# ここから画像の反転処理
# 画像の幅と高さを取得
width = self.before_image.width()
height = self.before_image.height()
# 全ピクセルに対するループ
for y in range(height):
for x in range(width):
# (x,y)座標のピクセルデータを取得
pixel = self.before_image.get(x, y)
# (x,y)座標の透過設定を取得
transparency = self.before_image.transparency_get(x, y)
# ピクセルデータを r, g, b に分解
r, g, b = pixel
# r, g, b 値をカラーコードに変換
color = "#" + format(r, '02x') + format(g, '02x') + format(b, '02x')
# 取得した色と透過設定を左右方向に反転した座標のピクセルデータに設定
self.after_image.put(color, to=(width - x - 1, y))
self.after_image.transparency_set(width - x - 1, y, transparency)
# 画像の描画位置を調節
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()
スクリプトの解説
まずアプリ全体の解説をしておきます。
スクリプトを実行すると、下のようなアプリが起動します。
「ファイル選択」から画像ファイル(GIF や PNG など)を選択すると、その画像が右側のキャンバスに描画されます(透過 GIF を選択すると下の図のように背景が透けて見えます)。
さらに「反転」ボタンを押すと、画像を左右反転した結果が右側のキャンバスに描画されます。
猫以外のピクセルは透過設定を ON にしていますので、左右のキャンバスの背景の色が透けて見えているのが確認できると思います。
この「反転」ボタンを押した時には push_flip_button
メソッドが実行されます。
下記のように全ピクセルに対してループを行い、
# 画像の幅と高さを取得
width = self.before_image.width()
height = self.before_image.height()
# 全ピクセルに対するループ
for y in range(width):
for x in range(height):
このループの中では、下記のように座標(x
, y
)のピクセルデータと透過設定を取得しています。
# (x,y)座標のピクセルデータを取得
pixel = self.before_image.get(x, y)
# (x,y)座標の透過設定を取得
transparency = self.before_image.transparency_get(x, y)
さらに、下記により取得したピクセルデータをカラーコードに変換後、そのカラーコードと透過設定を座標(x
, y
)を左右反転した座標(width - x - 1
, y
)に設定しています。
# 画素値を r, g, b に分解
r, g, b = pixel
# r, g, b 値をカラーコードに変換
color = "#" + format(r, '02x') + format(g, '02x') + format(b, '02x')
# 取得した色と透過設定を左右方向に反転した位置の画素に設定
self.after_image.put(color, to=(width - x - 1, y))
self.after_image.transparency_set(width - x - 1, y, transparency)
こんな感じで、各座標のピクセルデータと透過設定を取得し、その取得した情報を左右反転した位置となる座標に設定することで、画像の左右反転を行っています。
スポンサーリンク
まとめ
このページでは、PhotoImage
クラスが提供する get
メソッドと set
メソッド、さらには transparency_get
メソッドと transparency_set
メソッドを利用し、各座標の情報の取得と設定を行うことで画像処理を行う方法について解説しました。
今回は画像の左右反転する例を用いましたが、同様にして画像のリサイズや回転なども自分でプログラミングすれば Tkinter だけで様々な画像処理を行えるアプリを作ることができます。
でも処理速度はめちゃめちゃ遅いですね…。実用性を考えると素直に OpenCV や PIL を利用する方が良いと思います。
ただ、今回紹介した方法は Tkinter のみで気軽に画像処理アプリが作成できるメリットもあります。
まずはアプリ開発の入門として参考にしてみてはいかがでしょう?!