0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【第3回】RaspberryPi + OpenCV で 複数物体の認識 と 複数色の認識

0
Last updated at Posted at 2026-05-08

こんにちは.若尾です.
今回は前回のトラッキングを発展させて「複数物体の認識」と「複数色の認識」を行いました.今時,AI無しでやってるのもどうかと思いますが,クラシックなシステムも楽しんでいきましょう.
SSLの真似事とかやってみる方が面白味あるんですかね.教えてくださいセンスのある人.

前の記事

目次

対象読者
1. 複数物体の認識
2. コード解説
3. 複数色の認識
4. コード解説
5. まとめ

対象読者

  • OpenCV 初心者
  • RaspberryPi で画像処理をしたい人
  • カラートラッキングを発展させたい人
  • ロボット制御へ応用したい人

1. 複数物体の認識

できること

  • 同じ色の物体を複数個検出
  • それぞれを個別に矩形表示
  • 中心座標表示
  • 物体番号表示

単一物体追跡との違い

前回のコードでは,

largest = max(contours, key=cv2.contourArea)

としていたため,「最も大きい物体1つ」のみを追跡していました.

今回は,全ての輪郭に対して処理を行うことで,複数物体を追跡します.

ファイル作成

nano multi_tracking.py

コード

import cv2
import numpy as np

drawing = False
ix, iy = -1, -1
selected = False

hsv_lower = None
hsv_upper = None

frame_for_select = None


def select_color(event, x, y, flags, param):

    global ix, iy, drawing
    global hsv_lower, hsv_upper
    global selected
    global frame_for_select

    if event == cv2.EVENT_LBUTTONDOWN:

        drawing = True
        ix, iy = x, y

    elif event == cv2.EVENT_LBUTTONUP:

        drawing = False

        x1, y1 = min(ix, x), min(iy, y)
        x2, y2 = max(ix, x), max(iy, y)

        roi = frame_for_select[y1:y2, x1:x2]

        if roi.size == 0:
            return

        hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)

        h_mean = np.mean(hsv_roi[:, :, 0])
        s_mean = np.mean(hsv_roi[:, :, 1])
        v_mean = np.mean(hsv_roi[:, :, 2])

        hsv_lower = np.array([
            max(h_mean - 15, 0),
            max(s_mean - 60, 50),
            max(v_mean - 60, 50)
        ])

        hsv_upper = np.array([
            min(h_mean + 15, 179),
            min(s_mean + 60, 255),
            min(v_mean + 60, 255)
        ])

        selected = True

        print("HSV Lower:", hsv_lower)
        print("HSV Upper:", hsv_upper)


cap = cv2.VideoCapture(0)

cv2.namedWindow("Multi Tracking")
cv2.setMouseCallback("Multi Tracking", select_color)

while True:

    ret, frame = cap.read()

    if not ret:
        break

    frame = cv2.resize(frame, (640, 480))

    frame_for_select = frame.copy()

    if selected:

        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

        mask = cv2.inRange(hsv, hsv_lower, hsv_upper)

        kernel = np.ones((5, 5), np.uint8)

        mask = cv2.morphologyEx(
            mask,
            cv2.MORPH_OPEN,
            kernel
        )

        mask = cv2.morphologyEx(
            mask,
            cv2.MORPH_CLOSE,
            kernel
        )

        contours, _ = cv2.findContours(
            mask,
            cv2.RETR_EXTERNAL,
            cv2.CHAIN_APPROX_SIMPLE
        )

        object_id = 0

        for contour in contours:

            area = cv2.contourArea(contour)

            # 小さいノイズ除去
            if area < 500:
                continue

            x, y, w, h = cv2.boundingRect(contour)

            cx = x + w // 2
            cy = y + h // 2

            # 矩形
            cv2.rectangle(
                frame,
                (x, y),
                (x + w, y + h),
                (0, 255, 0),
                2
            )

            # 中心点
            cv2.circle(
                frame,
                (cx, cy),
                5,
                (0, 0, 255),
                -1
            )

            # ID表示
            cv2.putText(
                frame,
                f"ID:{object_id}",
                (x, y - 30),
                cv2.FONT_HERSHEY_SIMPLEX,
                0.6,
                (255, 0, 0),
                2
            )

            # 座標表示
            cv2.putText(
                frame,
                f"({cx}, {cy})",
                (x, y - 10),
                cv2.FONT_HERSHEY_SIMPLEX,
                0.6,
                (0, 255, 0),
                2
            )

            object_id += 1

    cv2.imshow("Multi Tracking", frame)

    key = cv2.waitKey(1)

    if key == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

実行

python multi_tracking.py

Multi Tracking_screenshot_08.05.2026.png

2. コード解説

最大輪郭を使わない

largest = max(contours, key=cv2.contourArea)

単一物体追跡では,上記の通り処理していました.
これにより,最も大きい物体のみを取得していました.

全輪郭を処理

for contour in contours:

全ての輪郭を処理しています.

面積フィルタ

if area < 500:
    continue

小さなノイズまで追跡しないため,一定以上の面積のみを対象にしています.

ID付与

object_id += 1

各物体に番号を振っています.

3. 複数色の認識

できること

  • 複数色を同時認識
  • 色ごとに矩形表示
  • 中心座標表示
  • 色ラベル表示

前回からの変更点

前回までは,

1種類のHSV範囲

のみを使用していました.

今回は,

赤
緑
青

それぞれに対してHSV範囲を設定し,複数色を同時検出します.

ファイル作成

nano multi_color_tracking.py

コード

import cv2
import numpy as np

cap = cv2.VideoCapture(0)

# 色範囲(HSV)

# 赤
red_lower = np.array([0, 120, 70])
red_upper = np.array([10, 255, 255])

# 緑
green_lower = np.array([40, 50, 50])
green_upper = np.array([80, 255, 255])

# 青
blue_lower = np.array([100, 100, 50])
blue_upper = np.array([130, 255, 255])

colors = [
    ("Red", red_lower, red_upper, (0, 0, 255)),
    ("Green", green_lower, green_upper, (0, 255, 0)),
    ("Blue", blue_lower, blue_upper, (255, 0, 0))
]

while True:

    ret, frame = cap.read()

    if not ret:
        break

    frame = cv2.resize(frame, (640, 480))

    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    kernel = np.ones((5, 5), np.uint8)

    for color_name, lower, upper, draw_color in colors:

        # 色抽出
        mask = cv2.inRange(hsv, lower, upper)

        # ノイズ除去
        mask = cv2.morphologyEx(
            mask,
            cv2.MORPH_OPEN,
            kernel
        )

        mask = cv2.morphologyEx(
            mask,
            cv2.MORPH_CLOSE,
            kernel
        )

        contours, _ = cv2.findContours(
            mask,
            cv2.RETR_EXTERNAL,
            cv2.CHAIN_APPROX_SIMPLE
        )

        for contour in contours:

            area = cv2.contourArea(contour)

            if area < 500:
                continue

            x, y, w, h = cv2.boundingRect(contour)

            cx = x + w // 2
            cy = y + h // 2

            # 矩形
            cv2.rectangle(
                frame,
                (x, y),
                (x + w, y + h),
                draw_color,
                2
            )

            # 中心点
            cv2.circle(
                frame,
                (cx, cy),
                5,
                draw_color,
                -1
            )

            # 色名表示
            cv2.putText(
                frame,
                color_name,
                (x, y - 30),
                cv2.FONT_HERSHEY_SIMPLEX,
                0.7,
                draw_color,
                2
            )

            # 座標表示
            cv2.putText(
                frame,
                f"({cx}, {cy})",
                (x, y - 10),
                cv2.FONT_HERSHEY_SIMPLEX,
                0.6,
                draw_color,
                2
            )

    cv2.imshow("Multi Color Tracking", frame)

    key = cv2.waitKey(1)

    if key == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

実行

python multi_color_tracking.py

Multi Color Tracking_screenshot_08.05.2026.png

4. コード解説

色範囲を複数定義

red_lower = np.array([0, 120, 70])
red_upper = np.array([10, 255, 255])

今回は,色ごとに HSV範囲を定義しています.

colors リスト

colors = [
    ("Red", red_lower, red_upper, (0, 0, 255)),
]

以下の情報をまとめています.

  • 色名
  • HSV下限
  • HSV上限
  • 描画色(BGR)

for文で色ごと処理

for color_name, lower, upper, draw_color in colors:

各色に対して,

  • 色抽出
  • 輪郭検出
  • 描画

を行っています.

描画色

draw_color

OpenCVでは BGR 順です.

(0, 0, 255) → 赤
(0, 255, 0) → 緑
(255, 0, 0) → 青

となります.

赤色検出の注意点

赤色は HSV 空間で両端に存在するため,環境によっては追加範囲が必要です.

例えば:

red_lower2 = np.array([170, 120, 70])
red_upper2 = np.array([179, 255, 255])

を追加して,2つのマスクを合成する方法もあります.

5. まとめ

今回は OpenCV を用いて,

  • 複数物体の同時追跡
  • 複数色の同時認識

を行いました.

単一物体追跡では,

largest = max(contours, key=cv2.contourArea)

によって最大物体のみを対象としていましたが,

for contour in contours:

を使用することで,複数物体を同時に処理できるようになりました.
また,HSV範囲を複数用意することで,色ごとの認識も実装できました.

次回は,

  • ロボットアームの手先座標の取得
  • 固定したマーカに手先を近づける
  • 動いているボールを手先で追跡する

を実施したいと思います.

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?