こんにちはSHINです。
未経験からシステム業務をしています。
全くの初心者からPythonを勉強中です。
今回はPythonが得意な画像の判定に必要な画像内の座標を取得してくれるコードを紹介します。
画像解析は、多くの分野で重要な役割を果たしてますよね?
今回はその第一歩として
Pythonで画像から座標を取得する方法
を紹介しますので、この記事を読むことで画像解析の基礎に触れることが可能です。
やりたいこと
・画像の座標を取得したい
話題のChatGPTを使ったプログラミングをするなら下の書籍がおススメです。
画像解析の為には座標が必要
画像解析をする上で、画像上の特定の位置の座標を取得することがよくあります。例えば、以下のようなケースが考えられます。
- 特定の物体の位置を特定する
- 関心のある領域を切り出す
- 加工する対象を指定する
このように、画像の座標を取得できる機能は画像解析の基本的な操作として重要です。今回は Python で画像の座標を取得する方法についてご紹介します。
ポイント
・画像解析は「対象」を指定する必要がある
必要なツールとライブラリの紹介
Pythonで画像解析を行う上で重要なのが、適切なツールとライブラリを選ぶことです。
ここでは、特に広く使用されている二つのライブラリ、OpenCVとPillow(PIL)に加えて、GUI作成に役立つtkinterについても紹介します。
OpenCV (Open Source Computer Vision Library)
OpenCVは、画像処理やコンピュータビジョンに関連する幅広いタスクをサポートする
オープンソースのライブラリです。
リアルタイムでの画像処理にも強く、機械学習、顔認識、オブジェクト検出などの高度な機能を提供します。
インストールするには下のコードを入力します↓↓
pip install opencv-python
Pillow (PIL Fork)
Pillowは、Python Imaging Library (PIL)のフォークで、画像ファイルの読み込み、処理、保存
を簡単に行うことができます。特に、画像の基本的な操作や変換、フィルタリングなどを行う際に役立ちます。
インストールするには下のコードを入力します↓↓
pip install pillow
tkinter
tkinterは、Pythonの標準GUIツールキットで、クロスプラットフォームに対応したシンプルで使いやすいインターフェースを提供します。
GUIとはグラフィカルユーザーインターフェースの略称でコンピューターにおいて、マウスやタッチパネルを使って視覚的に操作するインターフェースのことです。
つまりtkinterを使うことでユーザーが直感的に操作できるグラフィカルなユーザーインターフェースを簡単に作成できます。
tkinterはPythonに標準で含まれているため、別途インストールする必要は通常ありません。
ただし何らかの理由でインストールされていない場合は、以下のコマンドでインストールできます。
pip install tk
実際のコード(サンプルコード)
※コピペでは使えないのであくまで参考にしてください
import tkinter as tk from tkinter import filedialog from PIL import Image, ImageTk def select_area(event): global start_x, start_y start_x, start_y = event.x, event.y def release_area(event): end_x, end_y = event.x, event.y print(f"Selected area: ({start_x}, {start_y}) to ({end_x}, {end_y})") def load_image(): root = tk.Tk() root.withdraw() # メインウィンドウを隠す file_path = filedialog.askopenfilename() if file_path: # ファイルが選択された場合 image = Image.open(file_path) root.deiconify() # メインウィンドウを再表示 root.lift() root.attributes('-topmost', True) return image, root else: root.destroy() # ファイルが選択されなかった場合、プログラムを終了 return None, None def display_image(image, root): if image and root: # 画像とrootが有効な場合のみ canvas = tk.Canvas(root, width=image.width, height=image.height) canvas.pack() tk_image = ImageTk.PhotoImage(image) canvas.create_image(0, 0, anchor="nw", image=tk_image) canvas.bind("", select_area) canvas.bind("", release_area) root.mainloop() image, root = load_image() if image and root: # 画像が正しく読み込まれた場合のみ表示 display_image(image, root)
このコードで実行すると読み込んだ画像が表示され、表示した画像をクリックするとクリックした箇所の座標がターミナル上で表示されるようになります。
コードの細かな説明
ではここでは上記のコードを分割して順番に解説していきます。
まずはとっても大切なインポート文から
それではまず最初にPythonのコードを書く際に必ず必要なインポート文の説明をしていきます。
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
この部分です。
import tkinter as tk
:- Tkinterモジュールを
tk
としてインポートします。TkinterはPythonの標準GUIライブラリで、ウィンドウ、ボタン、テキストボックスなどを作成するのに使用します。as tk
は以後このモジュールをtk
という短縮名で参照できるようにするためのものです。
- Tkinterモジュールを
from tkinter import filedialog
:- Tkinterライブラリの
filedialog
モジュールをインポートします。このモジュールはファイルを開く、保存するダイアログを表示する機能を提供します。
- Tkinterライブラリの
from PIL import Image, ImageTk
:- Pillowライブラリ(Python Imaging Libraryのフォーク)から
Image
とImageTk
をインポートします。Image
は画像を開いたり操作したりするためのクラス、ImageTk
はTkinterウィジェットで画像を使うためのクラスです。
- Pillowライブラリ(Python Imaging Libraryのフォーク)から
ユーザーがマウスを使って範囲を選択する
次に紹介するのは座標を取得する際にマウスで範囲を選択する為のコードです。
def select_area(event):
global start_x, start_y
start_x, start_y = event.x, event.y
def release_area(event):
end_x, end_y = event.x, event.y
print(f"Selected area: ({start_x}, {start_y}) to ({end_x}, {end_y})")
ここです。
select_area(event)
- この関数はユーザーがマウスボタンを押したときに呼び出されることを想定しています(通常、"マウスボタンを押下する"イベントにバインドされます)。
global start_x, start_y
は、start_x
とstart_y
変数をグローバル変数として扱うことを指示します。これにより、これらの変数に格納された値は関数の外でも参照可能になります。start_x, start_y = event.x, event.y
は、マウスの押下された位置(x座標とy座標)を変数start_x
とstart_y
に代入します。これらは選択領域の開始点(左上角など)を表します。
release_area(event)
- この関数はユーザーがマウスボタンを放したときに呼び出されることを想定しています(通常、"マウスボタンを放す"イベントにバインドされます)。
end_x, end_y = event.x, event.y
は、マウスを放した位置(x座標とy座標)を変数end_x
とend_y
に代入します。これらは選択領域の終了点(右下角など)を表します。print(f"Selected area: ({start_x}, {start_y}) to ({end_x}, {end_y})")
は、選択された領域の開始点と終了点をコンソールに出力します。
画像を読み込む
つづいては画像ファイルを選択して読み込む部分になります。
def load_image():
root = tk.Tk()
root.withdraw() # メインウィンドウを隠す
file_path = filedialog.askopenfilename()
if file_path: # ファイルが選択された場合
image = Image.open(file_path)
root.deiconify() # メインウィンドウを再表示
root.lift()
root.attributes('-topmost', True)
return image, root
else:
root.destroy() # ファイルが選択されなかった場合、プログラムを終了
return None, None
↑↑この部分
このコードは、ユーザーがファイルダイアログを使って画像ファイルを選択し、その画像をロードするための関数load_image()
を定義しています。関数はTkinterとPillowライブラリを使用しています。
1. Tkinterウィンドウの初期化:
root = tk.Tk()
: Tkinterで新しいウィンドウ(ルートウィンドウ)を作成します。root.withdraw()
: メインウィンドウを隠します。これはファイルダイアログを表示する前に、不要なメインウィンドウが表示されるのを防ぐためです。
2. ファイルダイアログの表示:
file_path = filedialog.askopenfilename()
: ファイル選択ダイアログを開き、ユーザーがファイルを選択するのを待ちます。選択されたファイルのパスはfile_path
に格納されます。
3. 画像のロード:
if file_path
: ファイルが選択された場合(file_path
が空でない場合)、以下の処理を行います:image = Image.open(file_path)
: Pillowライブラリを使用して、選択されたファイルの画像を開きます。root.deiconify()
: 先に隠したメインウィンドウを再表示します。root.lift()
: メインウィンドウを他のウィンドウの前面に持ってきます。root.attributes('-topmost', True)
: メインウィンドウを常に最前面に表示します。return image, root
: 開いた画像オブジェクトとメインウィンドウオブジェクトをタプルとして返します。
4. ファイルが選択されなかった場合の処理:
else
: ファイルが選択されなかった場合(file_path
が空の場合)、以下の処理を行います:root.destroy()
: メインウィンドウを破棄し、リソースを解放します。return None, None
: 画像オブジェクトとメインウィンドウオブジェクトの代わりにNoneを返します。
この関数は、GUIアプリケーションでよく見られるユーザーが画像ファイルを選択してロードする一連のプロセスを簡単に行うためのものです。通常、これは画像を編集するアプリケーションや画像を分析するプログラムなど、ユーザーが画像ファイルを提供する必要がある場合に使われます。
読み込んだ画像を表示する
次に先程読み込んだ画像を表示させます。
def display_image(image, root):
if image and root: # 画像とrootが有効な場合のみ
canvas = tk.Canvas(root, width=image.width, height=image.height)
canvas.pack()
tk_image = ImageTk.PhotoImage(image)
canvas.create_image(0, 0, anchor="nw", image=tk_image)
canvas.bind("", select_area)
canvas.bind("", release_area)
root.mainloop()
この部分です。
このdisplay_image(image, root)
関数は、先に定義されたload_image()
関数で読み込まれた画像を表示するためのコードです。この関数はTkinterを使用してGUIウィンドウ内に画像を表示し、一定のユーザーインタラクション(特定のエリアの選択)を可能にします。以下は、関数の各ステップの説明です:
1. 画像とウィンドウの確認:
if image and root
: この条件は、有効な画像オブジェクトとTkinterのrootオブジェクトが関数に渡された場合にのみ中のコードを実行するようにしています。これは、画像やGUIのrootが正しく提供されていない場合を排除するためのものです。
2. キャンバスの作成と設定:
canvas = tk.Canvas(root, width=image.width, height=image.height)
: TkinterのCanvasウィジェットを作成します。Canvasは、画像や図形を表示するための領域を提供します。この行では、画像の幅と高さに合わせてキャンバスのサイズを設定しています。canvas.pack()
: このメソッドを使用して、キャンバスをrootウィンドウに配置します。
3. 画像の表示:
tk_image = ImageTk.PhotoImage(image)
: Pillowの画像をTkinterのウィジェットで表示できる形式に変換します。canvas.create_image(0, 0, anchor="nw", image=tk_image)
: 変換された画像をキャンバスの左上隅に配置します(anchor="nw"
はNorth Westの略で、左上を意味します)。
4. イベントハンドラのバインディング(未完成):
canvas.bind("", select_area)
とcanvas.bind("", release_area)
: これらは、特定のイベントが発生したときに関数を呼び出すためのものですが、イベントの種類を指定するための文字列(例:"<Button-1>"
)が抜けています。これらは通常、マウスボタンの押下や放出などのイベントに対応する関数を指定するために使用されます。
5. GUIの実行:
root.mainloop()
: このメソッドは、イベントループを開始し、ウィンドウが開いたままにしてユーザーのインタラクションを待ち受けます。このメソッドが呼び出されると、プログラムはユーザーがウィンドウを閉じるか、何らかのアクションを取るまで待機状態になります。
この関数は、画像表示のための基本的なフレームワークを提供し、ユーザーが画像上で何らかの操作を行う際に用いられることが想定されています。ただし、イベントハンドラのバインディング部分が未完成であるため、実際にselect_area
やrelease_area
関数を使用するためには、正しいイベントの種類をbind
メソッドに指定する必要があります。
最後の部分
image, root = load_image()
if image and root: # 画像が正しく読み込まれた場合のみ表示
display_image(image, root)
このコードは、前述のload_image()
関数とdisplay_image(image, root)
関数を組み合わせて使用するためのものです。ここでは、まず画像を読み込み、それが成功した場合にその画像を表示するプロセスが行われます。以下はコードの流れです:
1. 画像の読み込み:
image, root = load_image()
:load_image()
関数を呼び出して、ユーザーにファイルダイアログを表示させ、画像ファイルを選択させます。選択された画像はimage
に、Tkinterのrootウィンドウはroot
に格納されます。
2. 画像の表示条件チェック:
if image and root
: この条件文は、load_image()
関数から返されたimage
とroot
が有効である(つまり、ユーザーが画像を選択し、何らかの画像が正しく読み込まれた)場合にのみ、display_image(image, root)
関数を呼び出します。これにより、何も選択されなかった場合やエラーが発生した場合には何もしないようにしています。
3. 画像の表示:
display_image(image, root)
: 画像とrootが正しく設定されている場合、この関数を使用して画像を表示します。この関数は先に説明したように、画像をTkinterウィンドウ上に表示し、必要に応じてユーザーインタラクションを許可するための設定を行います。
このコードは、GUIベースのアプリケーションで画像を読み込んで表示する一連の処理を実現するためのもので、これによりユーザーはファイルダイアログを通じて画像を選択し、アプリケーションはその画像をウィンドウ上に表示することができます。また、エラーハンドリングやユーザーが何も選択しなかった場合の処理も適切に行われるようにしています。
コードを実行したらこうなる
試しに読み込んでみると
こんな感じでウィンドウで表示されて取得した場所をマウスでクリックすることで
こんな感じでターミナル上で座標を教えてくれます。
ちなみにマンホールの真ん中の部分の座標です。
こんな感じでPythonでできるのでぜひ試してみてください♪
まとめ
今回は、Pythonを使った画像からの座標取得方法について解説しました。
この記事がこれからPythonを習得する人の役に立てばうれしいです。これからも一緒に頑張っていきましょう!
Pythonを本気で学びたい人はUdemyでの勉強がおススメです。私も実際に入ってますし、なによりPythonのコースが豊富です。
これからの必須スキルであるPythonを本気で学んで今後の仕事に活かして生きましょう♪