【OpenCV応用編 完結編】合わせ技で実装!群衆の中から「笑顔の人」を見つけるスマートカメラを作ろう
「複数の検出器を、どうやって連携させればいいの?」
「『人を見つけて、その人が笑っていたら何かする』みたいな、条件分岐するプログラムを作りたい!」
「これまで学んだOpenCVの技術を全部使って、何か一つの完成品を作りたい!」
こんにちは! OpenCV探検隊、隊長のPythonistaです! 前回の第2回では、HOG特徴量という新しい武器を手にし、人物の「全身」を検出する方法をマスターしましたね。
3回にわたる応用編シリーズも、いよいよ今回が最終回です! これまで身につけた個別の検出技術――**全身検出、顔検出、笑顔検出**――を全て組み合わせ、**「群衆の中から人物を見つけ出し、その人が笑顔になった瞬間を捉える」**という、インテリジェントな「スマートスマイルカメラ」を開発します。
このプロジェクトを通して、あなたは複数のAIモデルを連携させ、より複雑で高度な判断を行うシステムの設計手法を体験することができます。さあ、これまでの冒険の集大成として、最高のアプリケーションを完成させましょう!
1. プロジェクトの設計思想:効率的な階層的アプローチ
今回のアプリケーションの目的は、「笑顔の人」を見つけることです。しかし、いきなり映像全体から「笑顔」という小さな特徴を探すのは非効率です。そこで、これまで学んだ知識を活かし、以下のような階層的な探索戦略を取ります。
- 【第1段階:全身探索】 まず、HOG検出器を使い、映像の中から大まかに**「全身」**を検出します。これにより、そもそも人がいない領域を探索対象から除外します。
- 【第2段階:顔探索】 次に、検出された「全身」の領域内でのみ、ハールカスケードの顔検出器を動かし、**「顔」**を特定します。これで、人物がカメラの方を向いている可能性が高いことが分かります。
- 【第3段階:笑顔探索】 最後に、特定された「顔」の領域内でのみ、笑顔検出器を動かし、**「笑顔」**があるかどうかを最終判断します。
このように、大きな枠から徐々に絞り込んでいくことで、処理の無駄をなくし、プログラム全体のパフォーマンスと精度を向上させることができます。
2. 実装:スマートスマイルカメラの全コード
それでは、この階層的ロジックを実装していきましょう。これまでの回で使ったカスケード分類器のXMLファイル(haarcascade_frontalface_default.xml と haarcascade_smile.xml)が、スクリプトと同じディレクトリにあることを確認してください。
import cv2
import sys
# --- 準備:HOG検出器とカスケード分類器を全てロード ---
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
face_cascade_path = 'haarcascade_frontalface_default.xml'
smile_cascade_path = 'haarcascade_smile.xml'
face_cascade = cv2.CascadeClassifier(face_cascade_path)
smile_cascade = cv2.CascadeClassifier(smile_cascade_path)
# Webカメラに接続
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("エラー: Webカメラを開けませんでした。")
sys.exit()
print("スマートスマイルカメラを開始...'q'キーで終了。")
# --- メインループ ---
while True:
ret, frame = cap.read()
if not ret:
break
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# --- 第1段階: 全身を検出 ---
found_rects, weights = hog.detectMultiScale(frame, winStride=(4, 4), padding=(8, 8), scale=1.05)
for i, (x, y, w, h) in enumerate(found_rects):
if weights[i] > 0.7: # ある程度信頼度の高いものだけを対象に
# まずは全身を青い矩形で囲む
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 全身領域のROIを切り出す
person_roi_gray = gray_frame[y:y+h, x:x+w]
person_roi_color = frame[y:y+h, x:x+w]
# --- 第2段階: 全身領域の中から顔を検出 ---
faces = face_cascade.detectMultiScale(person_roi_gray, scaleFactor=1.1, minNeighbors=5)
for (fx, fy, fw, fh) in faces:
# 顔を緑の矩形で囲む
cv2.rectangle(person_roi_color, (fx, fy), (fx+fw, fy+fh), (0, 255, 0), 2)
# 顔領域のROIを切り出す
face_roi_gray = person_roi_gray[fy:fy+fh, fx:fx+fw]
face_roi_color = person_roi_color[fy:fy+fh, fx:fx+fw]
# --- 第3段階: 顔領域の中から笑顔を検出 ---
smiles = smile_cascade.detectMultiScale(face_roi_gray, scaleFactor=1.8, minNeighbors=20)
if len(smiles) > 0:
# 笑顔が見つかったら、顔の矩形を黄色に変え、テキストを表示!
cv2.rectangle(person_roi_color, (fx, fy), (fx+fw, fy+fh), (0, 255, 255), 2)
cv2.putText(frame, "SMILE!", (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 255), 2)
# 結果を表示
cv2.imshow('Smart Smile Camera', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# --- 後片付け ---
cap.release()
cv2.destroyAllWindows()
このスクリプトを実行し、Webカメラの前で試してみてください。遠くにいるときは全身(青)、近づくと顔(緑)、そして笑うと(黄色+SMILE!)と、矩形の色や表示が変化するはずです。これは、プログラムが複数の条件を段階的に判断している証拠です。
まとめ:OpenCV応用編シリーズ、堂々完結!
3回にわたるOpenCV応用編、お疲れ様でした!このシリーズを通して、私たちは以下の重要なコンセプトを実践的に学びました。
- OpenCVが提供する**多様な学習済みモデル**を使い分けることで、顔、目、笑顔、全身といった様々なターゲットを検出できること。
- ハールカスケードだけでなく、**HOG特徴量**といった異なるアプローチの検出手法があること。
- そして最も重要な、**複数の検出器を組み合わせる「階層的アプローチ」**により、より複雑で、より効率的な「賢い」アプリケーションを構築できること。
あなたはもはや、単一のAIモデルを使うだけでなく、それらをオーケストレーションし、一つのシステムとして機能させるための基本的な設計思想を手に入れました。この考え方は、より複雑なAIシステムやロボットの制御など、あらゆる分野に応用できる非常に強力なものです。
OpenCVの世界は、まだまだ奥深く、魅力的なテーマ(物体追跡、文字認識、ARなど)で満ち溢れています。このシリーズで得た自信とスキルを武器に、ぜひあなた自身の好奇心に従って、さらなる冒険の旅を続けてください!
これまでの探検、ありがとうございました! Happy Computer Vision! 🤖
コメント
コメントを投稿