Python Raspbeyyi Pi プログラム 回路 電子工作 高専3年生

【Raspberry Pi】電子工作入門⑥~機械学習による物体認識~【Python】

これまでの授業では、カメラの使い方、画像処理、輪郭抽出など「古典的な画像処理」を学びました。

いよいよ、「機械学習(Machine Learning)」を使った物体認識に挑戦します。

機械学習とは?

人がルールを書く → コンピュータが学ぶへ

前回までは、人間があらかじめ

  • 「明るさが100より大きい→白」
  • 「頂点数が3→三角形」
    といったルールをプログラムとして書いていました。

一方、機械学習では

従来の手法機械学習
人間がルールを書くコンピュータがデータからルールを学ぶ
特定の条件に強い複雑な画像・多様な背景にも対応可能

つまり、犬や猫の画像をたくさん見せて「自分で特徴を見つけて分類できるようになる」のが機械学習です。

以下に、機械学習で良く扱う専門用の解説をしておきます。

用語やさしい説明
データセット学習に使う大量の例(例:猫画像100枚、犬画像100枚)
特徴量(Feature)データの特徴を数値で表したもの(画像ならピクセルやエッジなど)
モデル(Model)学習によって得られた「分類の仕組み」
学習(Training)データからモデルを作ること
推論(Inference)学習済みモデルで新しい画像を分類すること
クラス分類「これは○○です」と分類する処理

機械学習を体験

機械学習は以下のような流れで推論を行います。

📸 データ集め → 🧠 モデルを学習 → 📁 モデル保存

新しい画像 → 🤖 推論(分類) → 📝 結果

しかし、ゼロからモデルを作るのは時間がかかるので、今回は OpenCV に付属する「学習済みモデル(Haar Cascade)」を使います。

これは顔や目などを素早く検出できる古典的な機械学習モデルです。

ライブラリをインストールします。

ターミナルで以下のコマンドを実行してください。

sudo apt update
sudo apt install -y libopencv-dev opencv-data

以下の顔認識のサンプルコードを実行してみてください

from picamera2 import Picamera2
import cv2
import time

# Haar Cascadeファイルのパスを直接書く
cascade_path = "/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(cascade_path)

# カメラ設定
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(main={"size": (640, 360)}))
picam2.start()
time.sleep(0.2)

while True:
    # カメラから画像を取得
    rgb = picam2.capture_array()
    bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
    gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)

    # 顔を検出(複数同時対応)
    faces = face_cascade.detectMultiScale(
        gray,
        scaleFactor=1.2,   # スケールファクタ(小さいと精度↑、計算量↑)
        minNeighbors=5,    # 誤検出削減(大きいほど厳しく)
        minSize=(30, 30)   # 最小検出サイズ(顔が遠い場合は小さくする)
    )

    # 検出結果の描画
    for (x, y, w, h) in faces:
        cv2.rectangle(bgr, (x, y), (x+w, y+h), (0, 255, 0), 2)

    cv2.imshow("Face Detection", bgr)

    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break

cv2.destroyAllWindows()
picam2.stop()

コードのポイント

処理内容
CascadeClassifier顔検出用モデル(学習済みXML)を読み込む
detectMultiScale画像内の顔の位置を自動検出する関数
scaleFactor顔の大きさを変えながら探索する倍率(1.05〜1.3程度)
minNeighbors誤検出を減らすパラメータ(大きいほど厳しい)
minSize検出対象の最小サイズ(距離によって調整)
rectangle検出した領域を緑の四角で表示

問題10

プログラムを実行し、顔が検出されることを確認しよう。複数人で写るとどうなるかも試してみよう。

観察ポイント:

  • 明るさや角度によって検出精度が変わる
  • scaleFactorminNeighbors を調整すると検出数が変わる

問題11

複数の顔が映ったとき、それぞれに Face 1, Face 2 のようなラベルを付けて表示しよう。

ヒント:

for i, (x, y, w, h) in enumerate(faces):
    cv2.rectangle(bgr, (x, y), (x+w, y+h), (0, 255, 0), 2)
    cv2.putText(bgr, f"Face {i+1}", (x, y-10),
                cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
解答例はこちら
# task2_face_numbering.py
# 複数の顔を検出して番号をつけて表示する

from picamera2 import Picamera2
import cv2
import time

# Haar Cascadeの読み込み
cascade_path = "/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(cascade_path)

# カメラ初期化
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(main={"size": (640, 360)}))
picam2.start()
time.sleep(0.2)

while True:
    # カメラ画像の取得
    rgb = picam2.capture_array()
    bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
    gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)

    # 顔検出
    faces = face_cascade.detectMultiScale(
        gray,
        scaleFactor=1.2,
        minNeighbors=5,
        minSize=(30, 30)
    )

    # 検出した顔に番号をつけて描画
    for i, (x, y, w, h) in enumerate(faces):
        # 顔の矩形
        cv2.rectangle(bgr, (x, y), (x+w, y+h), (0, 255, 0), 2)
        # 番号ラベル(Face 1, Face 2,...)
        label = f"Face {i+1}"
        cv2.putText(bgr, label, (x, y - 10),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)

    cv2.putText(bgr, f"Detected: {len(faces)} faces",
                (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)

    cv2.imshow("Face Numbering", bgr)

    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break

cv2.destroyAllWindows()
picam2.stop()
処理内容
enumerate(faces)検出した顔リストをインデックス付きで繰り返し処理できる
label = f"Face {i+1}"0から始まる番号に+1して、人間が見やすい番号にする
cv2.putText()検出した顔の矩形の上に番号ラベルを描画する

こうすることで、複数人が同時に映っていても「どの枠が誰のものか」を区別できます。
特に複数人を同時に認識して動作するロボットを作るときに必須のテクニックです

問題12

OpenCV には顔以外にも様々なHaarモデルがあります。

ほかのモデルを使ったプログラムを作成し、動作を確かめてください。

モデルファイル検出対象
haarcascade_eye.xml
haarcascade_smile.xml笑顔
haarcascade_fullbody.xml全身
解答例はこちら

解答例①:顔と目を同時に検出

from picamera2 import Picamera2
import cv2
import time

# モデル読み込み
face_path = "/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml"
eye_path  = "/usr/share/opencv4/haarcascades/haarcascade_eye.xml"

face_cascade = cv2.CascadeClassifier(face_path)
eye_cascade  = cv2.CascadeClassifier(eye_path)

# カメラ初期化
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(main={"size": (640, 360)}))
picam2.start()
time.sleep(0.2)

while True:
    rgb = picam2.capture_array()
    bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
    gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)

    # 顔検出
    faces = face_cascade.detectMultiScale(gray, 1.2, 5, minSize=(30, 30))

    for (x, y, w, h) in faces:
        # 顔領域を描画
        cv2.rectangle(bgr, (x, y), (x+w, y+h), (0, 255, 0), 2)

        # 顔領域だけ切り出して目を検出(誤検出を減らす)
        roi_gray  = gray[y:y+h, x:x+w]
        roi_color = bgr[y:y+h, x:x+w]

        eyes = eye_cascade.detectMultiScale(roi_gray, 1.2, 10, minSize=(15, 15))
        for (ex, ey, ew, eh) in eyes:
            cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (255, 0, 0), 2)

    cv2.imshow("Face + Eyes", bgr)
    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break

cv2.destroyAllWindows()
picam2.stop()
処理内容
roi_gray = gray[y:y+h, x:x+w]顔領域を切り出して、その中だけで目を検出
eye_cascade.detectMultiScale()目の位置を検出(誤検出を防ぐため顔の中だけで処理)
rectangle顔は緑、目は青で描画して区別

解答例②:笑顔(スマイル)検出

from picamera2 import Picamera2
import cv2
import time

face_path  = "/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml"
smile_path = "/usr/share/opencv4/haarcascades/haarcascade_smile.xml"

face_cascade  = cv2.CascadeClassifier(face_path)
smile_cascade = cv2.CascadeClassifier(smile_path)

picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(main={"size": (640, 360)}))
picam2.start()
time.sleep(0.2)

while True:
    rgb = picam2.capture_array()
    bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
    gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)

    faces = face_cascade.detectMultiScale(gray, 1.2, 5, minSize=(30, 30))
    for (x, y, w, h) in faces:
        cv2.rectangle(bgr, (x, y), (x+w, y+h), (0, 255, 0), 2)

        roi_gray  = gray[y:y+h, x:x+w]
        roi_color = bgr[y:y+h, x:x+w]

        smiles = smile_cascade.detectMultiScale(
            roi_gray,
            scaleFactor=1.8,   # 笑顔検出はスケールを大きめにすると安定
            minNeighbors=20,   # 高めにすると誤検出が減る
            minSize=(25, 25)
        )
        for (sx, sy, sw, sh) in smiles:
            cv2.rectangle(roi_color, (sx, sy), (sx+sw, sy+sh), (0, 0, 255), 2)

    cv2.imshow("Smile Detection", bgr)
    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break

cv2.destroyAllWindows()
picam2.stop()

Haar の笑顔検出モデルはやや誤検出が多いため、

  • scaleFactor1.7〜1.9
  • minNeighbors15〜25
    にすると安定します。

実際に笑顔になると、口元に赤い四角が表示されます

次回はこちら

Comming Soon

Follow me!

-Python, Raspbeyyi Pi, プログラム, 回路, 電子工作, 高専3年生
-, , , , ,

PAGE TOP