見出し画像

【Python】動画内の指定オブジェクトを追跡して自動トリミング(2)

【状況】バウンディングボックス群を内包する長方形を求めたい
【対処】バウンディングボックス座標の最大値,最小値を求める

前回,指定したオブジェクトが動く範囲のバウンディングボックス群を求めているので,その続き.最大値・最小値を求めればよいので簡単ですね.

領域の初期値を設定

最初のフレームの幅と高さの情報(frame.shape)を用いて,最大値・最小値の初期値を設定しておきます.frame.shape[1]にはフレームの幅,frame.shape[0]にはフレームの高さの数値が入っています.

# トラッキングしたオブジェクトの存在領域の初期値を設定(minには最大値,maxには最小値を入れる)
min_x, min_y, max_x, max_y = frame.shape[1], frame.shape[0], 0, 0

領域の最大値・最小値を更新

box_x1, box_y1, box_x2, box_y2にバウンディングボックスの対角の座標値が入っています.これらを用いて最大値・最小値を更新します.対角の座標値は,左上と右下なので,左上が最小値候補,右下が最大値候補となります(画像は左上が原点のため).

# 最小値と最大値を更新
min_x = min(box_x1, min_x)
min_y = min(box_y1, min_y)
max_x = max(box_x2, max_x)
max_y = max(box_y2, max_y)

求めた領域の表示と保存

動画読み出しループ終了後に,求めた領域を白線で表示し,確認のため,画像としても保存します.

# トラッキング領域全てを内包する長方形    
cv2.rectangle(tracking_frame, (min_x, min_y), (max_x, max_y), (255, 255, 255), 2) 

# トラッキング結果を画像に保存
cv2.imwrite(f"clip_box.jpg", tracking_frame)

ファイルに保存した画像は,以下の通りです.

id1を全て含む領域
id2を全て含む領域

今回はここまで.

コード

import cv2
from ultralytics import YOLO

# Load the YOLOv8 model
model = YOLO('yolov8n.pt')

# Open the video file
video_path = "walk.mp4"
cap = cv2.VideoCapture(video_path)

success, frame = cap.read()
if not success :    # 読み込みに失敗したら終了
    exit()
    
# 最初のフレームから,トラッキング対象を選択する
results = model.track(frame, persist=True)  # オブジェクト抽出結果を得る

cv2.imshow("YOLOv8 Tracking", results[0].plot())
cv2.waitKey(1)  # ウェイトを入れないと画面が更新されない

print("処理対象の[番号]を入力:")
select_id = int(input())  # 数値を入力する 

# 最初のフレームをコピーして,以降ここに描き込む
tracking_frame = frame.copy()

# トラッキングしたオブジェクトの存在領域の初期値を設定(minには最大値,maxには最小値を入れる)
min_x, min_y, max_x, max_y = frame.shape[1], frame.shape[0], 0, 0

# Loop through the video frames
while cap.isOpened():
    # Read a frame from the video
    success, frame = cap.read()

    if success:
        # Run YOLOv8 tracking on the frame, persisting tracks between frames
        results = model.track(frame, persist=True)
        
        # 検出したオブジェクト群から,トラッキング対象を探してバウンディングボックスを記録
        #  boxes.xyxyがxy座標のセット,boxes.idが識別番号を保持
        for box, id in zip(results[0].boxes.xyxy, results[0].boxes.id):  
            if id == select_id: # 選択したオブジェクトのid
                box_x1, box_y1, box_x2, box_y2 = map(int, box)   # バウンディングボックスの座標を保存
            
                # バウンディングボックスを青線で表示
                cv2.rectangle(tracking_frame, (box_x1, box_y1), (box_x2, box_y2), (255, 0, 0), 2)
                
                # 最小値と最大値を更新
                min_x = min(box_x1, min_x)
                min_y = min(box_y1, min_y)
                max_x = max(box_x2, max_x)
                max_y = max(box_y2, max_y)
                break

        # 検出過程を描画
        cv2.imshow("YOLOv8 Tracking", tracking_frame)
        cv2.waitKey(1)  # ウェイトを入れないと画面が更新されない

    else:
        # Break the loop if the end of the video is reached
        break
    
# トラッキング領域全てを内包する長方形    
cv2.rectangle(tracking_frame, (min_x, min_y), (max_x, max_y), (255, 255, 255), 2) 

# トラッキング結果を画像に保存
cv2.imwrite(f"clip_box.jpg", tracking_frame)

# Release the video capture object and close the display window
cap.release()
cv2.destroyAllWindows()

この記事が気に入ったらサポートをしてみませんか?