@syuji syuji / human_detect_harr_text.py
Created at Sat Jun 10 17:54:42 JST 2023
動画に映ってる人間を検出し、代表フレームをファイル出力する
human_detect_harr_text.py
Raw
import numpy as np
import cv2
import time
from skimage.metrics import structural_similarity as ssim

# 体全体のカスケードファイル
fullbody_detector = cv2.CascadeClassifier("./haarcascade_fullbody.xml")
# サンプル画像
cap = cv2.VideoCapture('merged_camera.mp4')

# Shi-Tomasiのコーナー検出パラメータ
feature_params = dict( maxCorners = 100,
                       qualityLevel = 0.3,
                       minDistance = 7,
                       blockSize = 7 )

# Lucas-Kanade法のパラメータ
lk_params = dict( winSize  = (15,15),
                  maxLevel = 2,
                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

# ランダムに色を100個生成(値0~255の範囲で100行3列のランダムなndarrayを生成)
color = np.random.randint(0, 255, (100, 3))

# 最初のフレームの処理
end_flag, frame = cap.read()
# グレースケール変換
gray_prev = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 追跡に向いた特徴
feature_prev = cv2.goodFeaturesToTrack(gray_prev, mask = None, **feature_params)
# 元の配列と同じ形にして0を代入
mask = np.zeros_like(frame)
frame_number = 0  # フレーム番号を追跡するための変数を追加します
prev_img = None
threshold = 0.98  # Set your desired threshold

while(end_flag):
    # グレースケールに変換
    gray_next = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    start = time.time()  
    # 全身の人を検出 
    body = fullbody_detector.detectMultiScale(gray_next,scaleFactor=1.1, minNeighbors=3, minSize=(80, 80))
    end = time.time()  

    # オプティカルフロー検出
    feature_next, status, err = cv2.calcOpticalFlowPyrLK(gray_prev, gray_next, feature_prev, None, **lk_params)
    good_prev = feature_prev[status == 1]
    good_next = feature_next[status == 1]

    # オプティカルフローを描画
    for i, (next_point, prev_point) in enumerate(zip(good_next, good_prev)):
        prev_x, prev_y = prev_point.ravel()
        prev_x = int(prev_x)
        prev_y = int(prev_y)
        next_x, next_y = next_point.ravel()
        next_x = int(next_x)
        next_y = int(next_y)
        mask = cv2.line(mask, (next_x, next_y), (prev_x, prev_y), color[i].tolist(), 2)
        frame = cv2.circle(frame, (next_x, next_y), 5, color[i].tolist(), -1)
    img = cv2.add(frame, mask)
    
    # 人検出した数表示のため変数初期化
    human_cnt = 0
    # 人検出した部分を長方形で囲う
    for (x, y, w, h) in body:
        cv2.rectangle(img, (x, y),(x+w, y+h),(255,0,0),2)
        print(f"Detected human at: x={x}, y={y}, w={w}, h={h}")
        human_cnt += 1

    # 人検出した数を表示
    if human_cnt > 0:
        print(f"frame: {frame_number}")
        print(f"Human Count: {human_cnt}")

        # フレーム間の差異が小さい場合、画像を描き出さない
        if prev_img is not None:
            grayA = cv2.cvtColor(prev_img, cv2.COLOR_BGR2GRAY)
            grayB = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            score = ssim(grayA, grayB)
            if score > threshold:
                print(f"Skipping this frame due to low difference with previous frame (SSIM: {score})")
            else:
                # 人間が検出された場合、画像を保存します
                cv2.imwrite(f'output/frame_{frame_number}.png', img)
                prev_img = img.copy()  # 保存した画像を比較用として保持

    # ESCキー
    k = cv2.waitKey(1)
    if k == 27:
        break

    # 次のフレーム、ポイントの準備
    gray_prev = gray_next.copy()
    feature_prev = good_next.reshape(-1, 1, 2)
    end_flag, frame = cap.read()
    frame_number += 1  # フレーム番号をインクリメントします

cap.release()