Python Lab #4 ― 顔認識 on GUI
GUI 上に写真ファイルをドラッグ・ドロップしたら写真の中の人間の顔を認識するという Python スクリプトを開発してみました。
ただし、ざっと開発してみただけなので、認識精度の調整などはしていません。
開発に至った動機
OpenCV を採用すれば十数行ほどで簡単な顔認識が開発できるということを知り、AI 技術の習得への第一歩を踏み出してみたいと考えました。
CUI だと色々な写真を試すのが面倒なので、GUI で顔認識処理をラップすることにしました。GUI 部分は Tkinter を採用しました(注)。
注)flet ではファイルのドラッグ・ドロップは実現できないとのことです。残念。
実行イメージ
GUI 起動時
真っ白い部分に写真ファイルをドラッグ・ドロップすると、顔認識を開始する。
顔認識
顔認識をした写真を表示する。
別の写真ファイルをドラッグ・ドロップして、再度、顔認識をさせることもできる。
見ての通り、認識精度がイマイチ...。
とはいえ、頭に被り物をしていても、人間の顔であることを認識できるらしい。
写真は、https://www.pexels.com/ja-jp/photo/22643338/ からダウンロードしたもの。
エラー時
エラー画面を表示する。
フォルダー名がマルチバイト文字のとき、エラーになってしまう。
認識している残課題
認識精度がイマイチ
認識技術を学習して実装していく必要があります。
そもそも、今のソースコードに不備があるのかもしれない...。
画面スクロール機能なし、画面リサイズに未対応
tkinter の知識不足のため、まだ対処方法が分かっていません。
フォルダー名やファイル名がマルチバイト文字のときに動作できず
- PIL ライブラリの “Image.open()” において、フォルダー名がマルチバイト文字のファイルの読み込みができないようです。
- OpenCV ライブラリの “cv2.imread()” において、フォルダー名やファイル名がマルチバイト文字のファイルの読み込みができないようです。
対処方法として、一時的に “C:\temp” 等にコピーして読み込むという手を使えばできそうと考えています。試していません。
学習データのダウンロード
事前に XML ファイル “haarcascade_frontalface_default.xml” をフォルダー “.\xml” 配下に置く必要があります。
XML ファイル “haarcascade_frontalface_default.xml” の取出し方法
- OpenCV のホームページ “https://opencv.org” にアクセスします。
- ホームページ “https://opencv.org” のメニューの [Library] - [Releases] をクリックします。
- リリースページ “https://opencv.org/releases/” の [OpenCV - 4.9.0] - [Sources] をクリックします。
- “opencv-4.9.0.zip” のダウンロードが開始されます。
- “opencv-4.9.0.zip” を解凍します。
- フォルダー “.\opencv-4.9.0\data\haarcascades” から XML ファイル “haarcascade_frontalface_default.xml” を取り出します。
ソースコードの簡単な説明
- face_recognizer.py
face_recognizer.py
#!/usr/bin/env python3 ・・・ # Import Libraries import cv2 import tkinter as tk from tkinter import Label, messagebox from tkinterdnd2 import * from PIL import Image, ImageTk, ImageOps # Constants XML_FILE_PATH = '.\\xml\\haarcascade_frontalface_default.xml' WINDOW_RATIO = 60 WINDOW_WIDTH = 16 * WINDOW_RATIO WINDOW_HEIGHT = 10 * WINDOW_RATIO LINE_GAP = 70 # Recognize Face def recognize_face(file_name: str): try: cascade = cv2.CascadeClassifier(XML_FILE_PATH) image_org = cv2.imread(file_name) image_gray = cv2.cvtColor(image_org, cv2.COLOR_BGR2GRAY) face_list = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1)) for (x, y, w, h) in face_list: red = (0, 0, 255) cv2.rectangle(image_org, (x, y), (x + w, y + h), red, thickness=5) rgb_image = cv2.cvtColor(image_org, cv2.COLOR_BGR2RGB) return rgb_image except Exception as ex: raise Exception(ex) # Image Data global disp_image # Main def main() -> None: def drop_file(event): global disp_image canvas.delete('all') canvas_width = canvas.winfo_width() canvas_height = canvas.winfo_height() try: rgb_image = recognize_face(event.data) pil_image = Image.fromarray(rgb_image) align_image = ImageOps.pad(pil_image, (canvas_width, canvas_height), color='gray') disp_image = ImageTk.PhotoImage(image=align_image) canvas.create_image(0, 0, image=disp_image, anchor=tk.NW) except Exception as ex: # noqa canvas.create_line(0 + LINE_GAP, 0 + LINE_GAP, canvas_width - LINE_GAP, canvas_height - LINE_GAP, fill='red') canvas.create_line(canvas_width - LINE_GAP, 0 + LINE_GAP, 0 + LINE_GAP, canvas_height - LINE_GAP, fill='red') canvas.create_text(canvas_width / 2, canvas_height / 2, text='Read file error has occurred.') canvas.create_text(canvas_width / 2, canvas_height / 2 + 20, text='( %s )' % ex) messagebox.showerror('Error', 'Read file error has occurred.\n( %s )' % ex) return event.action root = TkinterDnD.Tk() root.title('Face Recognizer') root.geometry(f'{WINDOW_WIDTH}x{WINDOW_HEIGHT}') label = Label(root, text='Please drag and drop image file on below.') label.pack() root.drop_target_register(DND_FILES) root.dnd_bind('<<Drop>>', drop_file) canvas = tk.Canvas(root, bg='white') canvas.pack(expand=True, fill=tk.BOTH) root.mainloop() # Goto Main if __name__ == '__main__': main()
OpenCV を使用して学習済データ “.\xml\haarcascade_frontalface_default.xml” をもとに顔認識を行う。
drop_file()
ファイルがドラッグ・ドロップされたとき、“recognize_face()” を呼び出し、認識後の画像を画面に描画する。
main()
メイン処理。画面にドラッグ・ドロップのエリアを設定したり、ドラッグ・ドロップのイベント関数 “drop_file” を設定したりなどする。
ソースコードの置き場所
参考
顔認識
ただし、XML ファイル “haarcascade_frontalface_default.xml” は、OpenCV ホームページからダウンロードしたほうがよさそうです。
XML ファイル “haarcascade_frontalface_default.xml” のダウンロード
私も下記のようにハマり、下記と同じように対処しました。
GitHubからhaarcascade_frontalface_default.xmlをダウンロードしてどこかのフォルダに保存。
https://github.com/opencv/opencv/tree/master/data/haarcascades
こちらから拝借しました。
フォルダを保存したパスで、cascade_pathを変えてみるが・・・。エラーが。解決策
色々調べていると、OpenCVの公式サイトがあるらしいので、そこからダウンロードする。
OpenCV の新しい顔検出
今後は、こちらにチャレンジしてみるかな?
デモで使用した写真が置いてある場所
https://www.pexels.com/ja-jp/license/
シンプルな法的規律
Pexels のすべての写真や動画は、無料でダウンロードして利用できます。