InsightFaceによる68点3Dランドマーク検出

【概要】 InsightFaceフレームワークの68点3Dランドマーク検出技術を用いた顔解析プログラムの実装と実験を行う。68点3Dランドマーク検出は顔の主要な 特徴点を3次元座標で特定する技術である。Webカメラから顔と68点ランドマークを検出する。Windows環境での実行手順、プログラムコード、実験アイデアを含む。

目次

1. はじめに

68点3Dランドマーク検出技術

InsightFaceは顔認識・解析のための統合フレームワークであり、68点3Dランドマーク検出はその中で使用される顔特徴点抽出アルゴリズムの一つである。ランドマーク検出は画像から顔の主要な解剖学的特徴点の位置を特定する技術であり、顔認識、表情解析、3D顔面復元の前段階として使用される。

技術名: 1k3d68(68点3次元顔面ランドマーク検出)
フレームワーク: InsightFace(深層学習ベースの顔解析ツールボックス)
GitHub: https://github.com/deepinsight/insightface

68点3Dランドマーク検出は顔の主要な解剖学的特徴点を3次元座標(x, y, z)で特定することを特徴とする顔解析技術である。Webカメラからの映像をリアルタイムで処理し、顔検出と68点ランドマーク(顎のライン、眉毛、目、鼻、口の詳細な特徴点)の検出を実行する。

68点ランドマークの構成

2. Python開発環境,ライブラリ類

Python 3.12 のインストール

インストール済みの場合は実行不要。

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。

REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul

関連する外部ページ

Python の公式ページ: https://www.python.org/

AI エディタ Windsurf のインストール

Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは,Windsurfのインストールを説明する。

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。

winget install --scope machine Codeium.Windsurf -e --silent

関連する外部ページ

Windsurf の公式ページ: https://windsurf.com/

CMakeのインストール

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。


REM CMake をシステム領域にインストール
winget install --scope machine --id Kitware.CMake -e --silent
REM CMake のパス設定
set "GMAKE_PATH=C:\Program Files\CMake\bin"
if exist "%GMAKE_PATH%" (
    echo "%PATH%" | find /i "%GMAKE_PATH%" >nul
    if errorlevel 1 setx PATH "%PATH%;%GMAKE_PATH%" /M >nul
)

Visual Studio 2022 Build Toolsとランタイムのインストール

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。


REM Visual Studio 2022 Build Toolsとランタイムのインストール
winget install --scope machine Microsoft.VisualStudio.2022.BuildTools Microsoft.VCRedist.2015+.x64
set VS_INSTALLER="C:\Program Files (x86)\Microsoft Visual Studio\Installer\setup.exe"
set VS_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"
REM C++開発ワークロードのインストール
%VS_INSTALLER% modify --installPath %VS_PATH% ^
--add Microsoft.VisualStudio.Workload.VCTools ^
--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ^
--add Microsoft.VisualStudio.Component.Windows11SDK.22621 ^
--includeRecommended --quiet --norestart

3. プログラムコード


# InsightFace 68点3Dランドマーク検出プログラム(Webカメラ対応版)
#   Webカメラからのリアルタイム顔検出と68点3Dランドマーク抽出
#   フレームワーク: InsightFace(深層学習ベースの顔解析ツールボックス)
#   GitHub: https://github.com/deepinsight/insightface
#   特徴: 68点3Dランドマーク検出、CNN基盤の深層学習手法(画像認識に特化したニューラルネットワーク)
#         3次元座標系での特徴点検出、顔の詳細な解剖学的構造解析
#   学習済モデル: landmark_3d_68(68点3次元顔面ランドマーク検出モデル)
#                 顔の主要な解剖学的特徴点を3次元座標で高精度検出
#   前準備: pip install insightface opencv-python onnxruntime
#
# 利用可能な学習済みモデル:
# - buffalo_l: 大規模モデル、最高精度
# - buffalo_sc: 小規模モデル、高速処理
# - buffalo_s: 小規模モデル、軽量型
# - buffalo_m: 中規模モデル、バランス型

import cv2
import numpy as np
from insightface.app import FaceAnalysis

# 定数定義
CTX_ID = 0
DET_SIZE = (640, 640)
CAMERA_INDEX = 0
FONT_SCALE = 0.6
FONT_COLOR_INFO = (0, 255, 0)
FONT_COLOR_COUNT = (0, 255, 255)
BBOX_COLOR = (255, 0, 0)
LM_COLOR = (0, 255, 0)
LM_RADIUS = 2

# 68点ランドマークの色分け定義
LANDMARK_COLORS = {
    'jawline': (255, 0, 0),      # 顎のライン (1-17) - 赤
    'right_eyebrow': (0, 255, 0), # 右眉毛 (18-22) - 緑
    'left_eyebrow': (0, 255, 0),  # 左眉毛 (23-27) - 緑
    'nose': (255, 255, 0),        # 鼻 (28-36) - 黄
    'right_eye': (255, 0, 255),   # 右目 (37-42) - マゼンタ
    'left_eye': (255, 0, 255),    # 左目 (43-48) - マゼンタ
    'mouth': (0, 255, 255)        # 口 (49-68) - シアン
}

print("InsightFace 68点3Dランドマーク検出プログラムを開始します")
print("landmark_3d_68(68点3次元顔面ランドマーク検出)")
print("終了するには 'q' キーを押してください")

# 顔解析用アプリケーション初期化(68点3Dランドマーク検出を有効化)
app = FaceAnalysis(name='buffalo_l', allowed_modules=['detection', 'landmark_3d_68'])
app.prepare(ctx_id=CTX_ID, det_size=DET_SIZE)
print("68点3Dランドマーク検出モデル(1k3d68)をロードしました")

# カメラ初期化(DirectShowバックエンド使用)
cap = cv2.VideoCapture(CAMERA_INDEX, cv2.CAP_DSHOW)
if not cap.isOpened():
    print(f"カメラ {CAMERA_INDEX} のオープンに失敗しました")
    print("プログラムを終了します")
    exit(1)

# バッファサイズを1に設定してリアルタイム性を向上
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
print(f"カメラ {CAMERA_INDEX} を初期化しました")

frame_count = 0

def get_landmark_color(landmark_idx):
    """ランドマークインデックスに応じた色を返す"""
    if 1 <= landmark_idx <= 17:
        return LANDMARK_COLORS['jawline']
    elif 18 <= landmark_idx <= 22:
        return LANDMARK_COLORS['right_eyebrow']
    elif 23 <= landmark_idx <= 27:
        return LANDMARK_COLORS['left_eyebrow']
    elif 28 <= landmark_idx <= 36:
        return LANDMARK_COLORS['nose']
    elif 37 <= landmark_idx <= 42:
        return LANDMARK_COLORS['right_eye']
    elif 43 <= landmark_idx <= 48:
        return LANDMARK_COLORS['left_eye']
    elif 49 <= landmark_idx <= 68:
        return LANDMARK_COLORS['mouth']
    else:
        return LM_COLOR

# メイン処理
while True:
    # バッファをクリア(最新フレームのみ取得)
    cap.grab()
    ret, frame = cap.retrieve()
    if not ret:
        break

    frame_count += 1

    # 顔検出・ランドマーク検出実行
    faces = app.get(frame)

    # 検出結果の描画とコンソール出力
    for face_idx, face in enumerate(faces):
        # 境界ボックス描画
        bbox = face.bbox.astype(int)
        cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), BBOX_COLOR, 2)

        # 検出信頼度表示
        confidence = face.det_score if hasattr(face, 'det_score') else 0.0
        conf_text = f"Conf: {confidence:.3f}"
        cv2.putText(frame, conf_text, (bbox[0], bbox[1] - 5),
                   cv2.FONT_HERSHEY_SIMPLEX, 0.5, BBOX_COLOR, 1)

        # 68点3Dランドマーク検出処理
        landmarks_detected = False
        landmark_count = 0
        landmarks = None

        # landmark_3d_68属性を確認
        if hasattr(face, 'landmark_3d_68') and face.landmark_3d_68 is not None:
            landmarks = face.landmark_3d_68
            landmarks_detected = True
            landmark_count = len(landmarks)
            print(f"Using landmark_3d_68 with {landmark_count} points")

        if landmarks_detected and landmarks is not None:
            print(f"\n=== Face {face_idx + 1} (Frame {frame_count}) ===")
            print(f"Detection Confidence: {confidence:.4f}")
            print(f"Total Landmarks: {landmark_count}")
            print("Landmark Details (ID, X, Y, Z):")

            # 各ランドマークを色分けして描画・出力
            for i, landmark in enumerate(landmarks):
                if len(landmark) >= 2:
                    x, y = int(landmark[0]), int(landmark[1])
                    z = landmark[2] if len(landmark) > 2 else 0.0

                    # 68点用の色分け
                    color = get_landmark_color(i + 1)
                    cv2.circle(frame, (x, y), LM_RADIUS, color, -1)

                    # コンソール出力(最初の20点のみ)
                    if i < 20:
                        print(f"  {i+1:2d}: ({x:3d}, {y:3d}, {z:6.2f})")
                    elif i == 20:
                        print(f"  ... (残り{landmark_count - 20}点は省略) ...")

                    # ランドマーク番号表示
                    if frame_count % 30 == 0:
                        cv2.putText(frame, str(i + 1), (x + 3, y - 3),
                                   cv2.FONT_HERSHEY_SIMPLEX, 0.3, color, 1)
        else:
            print(f"\n=== Face {face_idx + 1} (Frame {frame_count}) ===")
            print(f"Detection Confidence: {confidence:.4f}")
            print("Landmarks: landmark_3d_68 not detected")

    # フレーム情報表示
    info_text = f"Frame: {frame_count} | 68-Point 3D Landmark Detection"
    cv2.putText(frame, info_text, (10, 30),
                cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, FONT_COLOR_INFO, 2)

    # 検出された顔の数を表示
    face_count_text = f"Detected faces: {len(faces)}"
    cv2.putText(frame, face_count_text, (10, 60),
                cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, FONT_COLOR_COUNT, 2)

    # ランドマーク点数を表示
    total_landmarks = 0

    for face in faces:
        if hasattr(face, 'landmark_3d_68') and face.landmark_3d_68 is not None:
            total_landmarks += len(face.landmark_3d_68)
            break

    landmark_text = f"Total landmarks: {total_landmarks}"
    cv2.putText(frame, landmark_text, (10, 90),
                cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, FONT_COLOR_COUNT, 2)

    # 色分け凡例表示
    legend_y = 120
    legend_items = [
        ("Jawline", LANDMARK_COLORS['jawline']),
        ("Eyebrows", LANDMARK_COLORS['right_eyebrow']),
        ("Nose", LANDMARK_COLORS['nose']),
        ("Eyes", LANDMARK_COLORS['right_eye']),
        ("Mouth", LANDMARK_COLORS['mouth'])
    ]

    for i, (label, color) in enumerate(legend_items):
        y_pos = legend_y + i * 25
        cv2.circle(frame, (15, y_pos), 5, color, -1)
        cv2.putText(frame, label, (30, y_pos + 5),
                   cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)

    # 結果出力
    cv2.imshow("InsightFace 68-Point 3D Landmark Detection", frame)

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

# 終了処理
cap.release()
cv2.destroyAllWindows()
print("プログラムを終了しました")

4. 使用方法

  1. 上記のプログラムを実行する
  2. Webカメラの映像が表示され、検出された顔に赤色の境界ボックスと色分けされた68点ランドマークが表示される。
  3. ランドマークは以下のように色分けされる:
    • 顎のライン(1-17点): 赤色
    • 眉毛(18-27点): 緑色
    • 鼻(28-36点): 黄色
    • 目(37-48点): マゼンタ色
    • 口(49-68点): シアン色
  4. 各顔の上部に検出信頼度(0.000~1.000)が表示される。検出信頼度は0.0から1.0の値で、1.0に近いほど顔である確信度が高い。0.5以上を閾値として使用することが多い。
  5. 画面左側に色分け凡例が表示される。
  6. 'q'キーを押すとプログラムが終了する。

5. 実験・探求のアイデア

AIモデル選択による比較実験

プログラム内のname='buffalo_sc'を以下のモデルに変更して、性能の違いを確認する。

検出サイズの変更実験

DET_SIZE = (640, 640)の値を変更して、検出精度と処理速度への影響を確認する。

様々な条件での検出性能テスト

68点ランドマーク活用の探求

検出された68点ランドマークの座標を利用して、以下の解析を実行する:

ランドマーク精度評価実験