レポートに載っけるように改造

main
KoyoNoguchi 1 week ago
parent 2e70ad5ede
commit 944de9e013
  1. 66
      3_10_bg_subtraction.py
  2. 42
      3_11_tracking.py

@ -1,5 +1,5 @@
# 実験課題10
# 3.10 背景差分法(ラベリング・ノイズ処理含む)
# 3.10 背景差分法
import cv2
import numpy as np
@ -8,56 +8,42 @@ import numpy as np
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("カメラを開けませんでした")
print("カメラを開けませんでした")
else:
print("背景差分法を開始します。")
print("'q': 終了, 'r': 背景画像を現フレームで更新")
# 最初のフレームを背景画像として取得するための準備
bg_gray = None
background = None
while True:
ret, frame = cap.read()
if not ret:
print("フレームを取得できませんでした")
print("フレームを取得できませんでした")
break
# 差分計算を安定させるため現フレームをグレースケール化
# 差分計算を安定させるため現フレームをグレースケール化
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# ガウシアンブラ(平滑化)を適用して、カメラ特有の細かいノイズを低減
# ガウシアンブラーを適用してカメラの細かいノイズを低減
gray = cv2.GaussianBlur(gray, (21, 21), 0)
# 起動直後、または 'r' キーが押された場合に背景画像を保存・更新する
if bg_gray is None:
bg_gray = gray
print("背景画像を保存しました。カメラの前から離れてください。")
if background is None:
background = gray
continue
# --- 3.101 背景差分法:背景画像と現フレームの絶対差分を計算 ---
frame_diff = cv2.absdiff(bg_gray, gray)
# 背景画像と現フレームの絶対差分を計算
frame_diff = cv2.absdiff(background, gray)
# 差分画像を2値化して、動いている領域(前景)を白(255)にする
# 閾値は環境に合わせて調整(ここでは例として 25)
# 差分画像を2値化して動いている領域を白(255)にする
_, thresh = cv2.threshold(frame_diff, 25, 255, cv2.THRESH_BINARY)
# --- 3.102 ノイズ処理(モルフォロジー演算:オープニング) ---
# 3.7で学んだ手法を使い、背景に散らばる小さなチラツキノイズを消去
# ノイズ処理
kernel = np.ones((5, 5), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
# 領域内の穴を埋めて結合を強める(クロージング)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# --- 3.102 ラベリング処理 ---
# 2値化画像から、繋がっている白い領域(動体)を検出してラベルを貼る
# nlabels: ラベルの総数(背景含む)
# labels: 各画素にラベル番号(0, 1, 2...)が割り当てられた画像
# stats: 各領域の矩形座標や面積[x, y, w, h, area]の行列
# centroids: 各領域の中心座標
# ラベリング処理
nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh)
# 各ラベルごとに色分けするためのランダムな色マップを作成(背景の0は黒にする)
# 乱数のシードを固定して、フレーム間で色が激しく変わるのを防ぐ
# 各ラベルごとに色分けするためのランダムな色マップを作成
np.random.seed(42)
colors = np.random.randint(0, 255, (nlabels, 3), dtype=np.uint8)
colors[0] = [0, 0, 0] # ラベル0(背景)は黒に固定
@ -65,33 +51,13 @@ else:
# 画素ごとのラベル番号に対応する色を割り当てて、色分け画像(ラベリング画像)を作成
labeled_img = colors[labels]
# 動体領域に矩形(枠線)を描画する
for i in range(1, nlabels): # 0は背景なので1からループ
x = stats[i, cv2.CC_STAT_LEFT]
y = stats[i, cv2.CC_STAT_TOP]
w = stats[i, cv2.CC_STAT_WIDTH]
h = stats[i, cv2.CC_STAT_HEIGHT]
area = stats[i, cv2.CC_STAT_AREA]
# 面積が小さすぎる領域(微小なノイズの残り)は無視する
if area > 500:
# 動体を緑色の矩形で囲む
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
# ラベル番号を画像上に描画
cv2.putText(frame, f"ID:{i}", (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
# --- 結果の表示 ---
cv2.imshow('Original Frame (Motion Detection)', frame)
cv2.imshow('Foreground Mask (Thresh)', thresh)
cv2.imshow('Labeled Components', labeled_img)
# キー入力の受付
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
# 'q' キーが押されたら終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
elif key == ord('r'):
bg_gray = None # 次のループで背景が再キャプチャされる
cap.release()
cv2.destroyAllWindows()

@ -1,5 +1,5 @@
# 実験課題11
# 3.11 トラッキング(任意)
# 3.11 トラッキング
import cv2
@ -7,62 +7,40 @@ import cv2
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("カメラを開けませんでした")
print("カメラを開けませんでした")
else:
print("トラッキングテストを開始します。")
# 最初の1フレームを読み込む
ret, frame = cap.read()
if not ret:
print("フレームを取得できませんでした")
print("フレームを取得できませんでした")
else:
# --- 追跡対象の選択(ROI) ---
print("【操作方法】")
print("1. 追跡したい物体をマウスでドラッグして四角く囲んでください。")
print("2. 囲んだら Enter または Space キーを押して決定します。")
print("3. やり直す場合は 'c' キーを押してください。")
# ユーザーに追跡対象をマウスで選択させるウィンドウを表示
# bbox には選択された領域の (x, y, w, h) が格納される
# 追跡対象の選択
while True:
# ユーザーに追跡対象をマウスで選択させる
bbox = cv2.selectROI("Tracking", frame, fromCenter=False, showCrosshair=True)
# 幅(bbox[2]) または 高さ(bbox[3]) が 0 の場合
# ('c'キーが押された、または未選択のままEnterが押された場合)
# 幅 または が 0 の場合
if bbox[2] == 0 or bbox[3] == 0:
print("領域がリセットされました。やり直します。")
print("もう一度マウスをドラッグして対象を囲み、Enterキーを押してください。")
# continueによってループの先頭に戻り、再度selectROIを実行する
continue
else:
# 正しく領域が選択されたらループを抜けてトラッキング処理へ進む
print("領域が確定しました。トラッキングを開始します。")
break
# --- トラッカーの生成と初期化 ---
# 拡張モジュールに含まれる高精度なトラッカー「CSRT」を生成
# ※OpenCVのバージョンによっては legacy に分類されるため、try-exceptで安全に呼び出す
try:
# トラッカーの生成
tracker = cv2.TrackerCSRT_create()
except AttributeError:
tracker = cv2.legacy.TrackerCSRT_create()
# 最初のフレームと選択した領域(bbox)を渡してトラッカーに学習(初期化)させる
# 最初のフレームと選択した領域を渡してトラッカーに学習させる
tracker.init(frame, bbox)
print("追跡中... 終了するには 'q' キーを押してください。")
# --- トラッキングのループ処理 ---
# トラッキングのループ処理
while True:
ret, frame = cap.read()
if not ret:
break
# 新しいフレームをトラッカーに渡し、対象がどこに移動したか推測させる
# success: 追跡成功(True) / 失敗(False)
# bbox: 新しい座標とサイズ (x, y, w, h)
# 新しいフレームをトラッカーに渡し,対象がどこに移動したか推測させる
success, bbox = tracker.update(frame)
if success:
@ -75,13 +53,11 @@ else:
# 追跡失敗時(画面外に出た、何かの裏に完全に隠れた等):赤い警告文を表示
cv2.putText(frame, "Lost", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# 結果の表示
cv2.imshow("Tracking", frame)
# 'q' キーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 終了処理
cap.release()
cv2.destroyAllWindows()
Loading…
Cancel
Save