エッジAI

物体検出

画像中の対象を見つけるAIタスク。

概要

物体検出(Object Detection)とは、画像や動画フレームの中から特定のオブジェクト(人・車・製品・動物など)を見つけ出し、その位置(バウンディングボックス)とカテゴリ(クラスラベル)を同時に出力するAIタスクです。単純な画像分類(画像全体に一つのラベルを付与)とは異なり、画像内に複数の物体が存在する場合もそれぞれを個別に検出します。

物体検出の出力は以下の要素で構成されます。

出力 = [
  {
    "class": "person",           // 物体のクラス名
    "confidence": 0.94,          // 確信度(0〜1)
    "bbox": [x_min, y_min,       // バウンディングボックス
             x_max, y_max]       // (ピクセル座標)
  },
  {
    "class": "car",
    "confidence": 0.87,
    "bbox": [320, 150, 580, 380]
  },
  // ...
]

組み込み・エッジシステムにおける物体検出は、工場の外観検査・自動車のADAS(先進運転支援)・スマートカメラ・農業用ドローンなど幅広い実用途に展開されています。

歴史・背景

物体検出の発展は画像認識AIの進化と密接に連動しています。

前ディープラーニング時代(〜2012年):

HOG(方向勾配ヒストグラム)特徴量とSVM(サポートベクターマシン)を組み合わせたDPM(Deformable Part Model)などが主流でした。精度は低く、リアルタイム処理も困難でした。

ディープラーニング時代の進化:

モデル特徴
2014年R-CNN領域提案+CNNで精度向上、ただし速度が遅い
2015年Fast R-CNNROIプーリングで高速化
2015年Faster R-CNNRPN(領域提案ネットワーク)で統合化
2016年YOLO v1リアルタイム検出(端末で45FPS)の先駆け
2016年SSD多スケール特徴マップで精度向上
2017年Feature Pyramid Networkマルチスケール特徴の標準化
2020年YOLOv5実用化・軽量化の到達点
2022年YOLOv8モデルファミリーの最新標準
2023年RT-DETRTransformer based リアルタイム検出

技術仕様

物体検出の分類

物体検出アルゴリズム
├── 2段階検出器(Two-Stage Detectors)
│   ├── R-CNN系(R-CNN、Fast R-CNN、Faster R-CNN、Mask R-CNN)
│   └── 特徴:高精度、遅い(10〜20FPS)

├── 1段階検出器(One-Stage Detectors)
│   ├── YOLO系(v1〜v8、YOLO-NAS)
│   ├── SSD系(SSD、MobileNet-SSD)
│   └── 特徴:高速(30〜数百FPS)、実用的

└── Transformerベース
    ├── DETR、DINO、RT-DETR
    └── 特徴:アンカー不要、最先端精度

バウンディングボックスの表現形式

バウンディングボックスの座標は様々な形式で表現されます。

# 形式1: [x_min, y_min, x_max, y_max](ONNX標準)
bbox_xyxy = [100, 50, 300, 250]

# 形式2: [x_center, y_center, width, height](YOLO形式)
bbox_xywh = [200, 150, 200, 200]

# 形式3: 正規化座標(0〜1.0)
bbox_normalized = [0.1, 0.2, 0.5, 0.7]  # 画像サイズに依存しない

def xyxy_to_xywh(bbox):
    x1, y1, x2, y2 = bbox
    cx = (x1 + x2) / 2
    cy = (y1 + y2) / 2
    w = x2 - x1
    h = y2 - y1
    return [cx, cy, w, h]

評価指標(mAP)

物体検出の精度はmAP(mean Average Precision)で評価します。

IoU(Intersection over Union):
  IoU = 検出BOXと正解BOXの重なり面積 / 和集合面積
  
  IoU > 閾値(通常0.5)→ True Positive(正検出)
  IoU < 閾値 → False Positive(誤検出)

AP(Average Precision):
  Precision-Recall曲線の面積(各クラス)

mAP = 全クラスのAPの平均

mAP@0.5: IoU閾値0.5でのmAP(COCOでの標準指標)
mAP@0.5:0.95: IoU閾値0.5〜0.95の平均(より厳格)

主要モデルの性能比較

モデルmAP@0.5FPS(RTX4090)モデルサイズ
YOLOv8n(nano)37.3%500+6.2MB
YOLOv8s44.9%300+22.4MB
YOLOv8m50.2%150+52.0MB
YOLOv8l52.9%80+87.7MB
RT-DETR-L53.0%114136MB
Faster R-CNN42.0%25160MB+

動作原理

YOLOの動作原理

YOLOv8を例に、1段階検出器の動作を説明します。

入力画像(例: 640×640×3)

  バックボーン(特徴抽出)
  CSPDarknet、EfficientNet等

  ネック(マルチスケール特徴統合)
  FPN + PAN(Feature Pyramid Network)
  ┌──────────────────────────┐
  │  大きい特徴マップ → 小物体 │
  │  中間特徴マップ → 中物体  │
  │  小さい特徴マップ → 大物体 │
  └──────────────────────────┘

  検出ヘッド(Decoupled Head)
  各スケールで予測:
  - バウンディングボックス(x,y,w,h)
  - 確信度スコア
  - クラス確率

  NMS(非最大値抑制)
  重複する検出を除去

  最終検出結果

後処理:NMS(Non-Maximum Suppression)

import numpy as np

def non_max_suppression(boxes, scores, iou_threshold=0.45):
    """非最大値抑制:重複する検出ボックスを除去"""
    # スコアで降順ソート
    sorted_idx = np.argsort(scores)[::-1]
    keep = []
    
    while len(sorted_idx) > 0:
        # 最高スコアのボックスを保持
        best_idx = sorted_idx[0]
        keep.append(best_idx)
        
        if len(sorted_idx) == 1:
            break
        
        # 残りのボックスとのIoUを計算
        rest_idx = sorted_idx[1:]
        ious = compute_iou(boxes[best_idx], boxes[rest_idx])
        
        # IoUが閾値未満のボックスのみ残す
        sorted_idx = rest_idx[ious < iou_threshold]
    
    return keep

def compute_iou(box1, box2):
    """IoU(Intersection over Union)を計算"""
    x1 = np.maximum(box1[0], box2[:, 0])
    y1 = np.maximum(box1[1], box2[:, 1])
    x2 = np.minimum(box1[2], box2[:, 2])
    y2 = np.minimum(box1[3], box2[:, 3])
    
    intersection = np.maximum(0, x2 - x1) * np.maximum(0, y2 - y1)
    area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
    area2 = (box2[:, 2] - box2[:, 0]) * (box2[:, 3] - box2[:, 1])
    union = area1 + area2 - intersection
    
    return intersection / (union + 1e-6)

エッジデバイスでの推論実装

# YOLOv8をONNX Runtimeで推論(エッジLinux向け)
import onnxruntime as ort
import numpy as np
import cv2

class EdgeObjectDetector:
    def __init__(self, model_path, conf_thres=0.5, iou_thres=0.45):
        # ONNX Runtimeセッション初期化
        self.session = ort.InferenceSession(
            model_path,
            providers=['CPUExecutionProvider']
        )
        self.conf_thres = conf_thres
        self.iou_thres = iou_thres
        self.input_name = self.session.get_inputs()[0].name
        
    def preprocess(self, image, input_size=640):
        """前処理:リサイズと正規化"""
        h, w = image.shape[:2]
        scale = input_size / max(h, w)
        new_h, new_w = int(h * scale), int(w * scale)
        
        resized = cv2.resize(image, (new_w, new_h))
        
        # パディング
        pad_h = (input_size - new_h) // 2
        pad_w = (input_size - new_w) // 2
        padded = np.zeros((input_size, input_size, 3), dtype=np.uint8)
        padded[pad_h:pad_h+new_h, pad_w:pad_w+new_w] = resized
        
        # BGR→RGB、HWC→CHW、0-255→0-1
        input_tensor = padded[:, :, ::-1].transpose(2, 0, 1)
        input_tensor = input_tensor[np.newaxis].astype(np.float32) / 255.0
        
        return input_tensor, scale, pad_h, pad_w
    
    def detect(self, image):
        """物体検出実行"""
        input_tensor, scale, pad_h, pad_w = self.preprocess(image)
        
        # 推論実行
        outputs = self.session.run(
            None, {self.input_name: input_tensor}
        )
        
        # 後処理(NMS等)
        return self.postprocess(outputs, scale, pad_h, pad_w, image.shape)

用途・ユースケース

製造・品質管理

カメラ → エッジAIボード(Jetson Nano等)→ 欠陥検出
                                        → 異物検出
                                        → 寸法計測
処理速度: 30〜60FPS(リアルタイム)

外観検査では検出精度と速度のバランスが重要です。YOLOv8nのような軽量モデルが多く採用されています。

自動車・ADAS

  • 歩行者検出:緊急ブレーキシステム(AEBS)
  • 車線・標識検出:車線維持支援・標識認識
  • 障害物検出:駐車支援・低速自動走行

農業・スマート農業

  • 病害検出:葉の変色・斑点パターンの検出
  • 害虫検出:カメラドローンによる広域モニタリング
  • 収穫時期判定:果実の色・形状からの熟度判定

セキュリティ・監視

  • 不審者検出:侵入検知システム
  • マスク着用確認(COVID-19対応等)
  • 人数カウント:混雑管理システム

実装・開発のポイント

エッジ向けモデルの選択

モデル推奨用途デプロイ先
YOLOv8n低遅延必須Raspberry Pi, MCU+NPU
YOLOv8sバランス重視Jetson Nano, Coral
MobileNet-SSD超軽量MCU, スマホ
EfficientDet-D0精度重視軽量組み込みLinux

学習データの収集と前処理

# データ拡張(Augmentation)の実装例
import albumentations as A

transform = A.Compose([
    A.RandomCrop(width=640, height=640),
    A.HorizontalFlip(p=0.5),
    A.RandomBrightnessContrast(p=0.3),
    A.GaussNoise(p=0.2),
    A.Blur(blur_limit=3, p=0.1),
    A.CLAHE(p=0.2),
], bbox_params=A.BboxParams(
    format='yolo',
    label_fields=['class_labels']
))

# 拡張適用
transformed = transform(
    image=image,
    bboxes=bboxes,
    class_labels=labels
)

他技術との比較

タスク入力出力計算コスト
画像分類画像クラスラベル1つ
物体検出画像BOX + クラス(複数)
セマンティックセグメンテーション画像ピクセル単位クラス
インスタンスセグメンテーション画像物体ごとのマスク最高
キーポイント検出画像関節点座標(姿勢推定)中〜高

物体検出はエッジAIの中でも最も産業応用が多い分野です。推論アクセラレータNPUNVIDIA Jetsonなどのハードウェアと、TensorFlow LiteONNX量子化などの最適化技術を組み合わせることでリアルタイム処理を実現します。

関連用語

参考リンク