映像から物体検出し，物体が人であった場合は骨格検出も行うPythonコードを．
import cv2
import mediapipe as mp
from ultralytics import YOLO

# --------------------------------------------------
# 設定
# --------------------------------------------------
INPUT_VIDEO = "input.mp4"     # 入力動画
OUTPUT_VIDEO = "output.mp4"   # 出力動画
YOLO_MODEL = "yolov8n.pt"     # 軽量モデル（必要に応じて s/m/l/x に変更）
CONF_THRES = 0.4              # 物体検出の信頼度しきい値
PERSON_CLASS_NAME = "person"
PADDING_RATIO = 0.15          # 人領域を少し広めに切り出すための余白

# --------------------------------------------------
# モデル初期化
# --------------------------------------------------
yolo_model = YOLO(YOLO_MODEL)

mp_pose = mp.solutions.pose
pose = mp_pose.Pose(
    static_image_mode=False,
    model_complexity=1,
    enable_segmentation=False,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5
)

# 骨格線の接続情報
POSE_CONNECTIONS = mp_pose.POSE_CONNECTIONS

# --------------------------------------------------
# 補助関数
# --------------------------------------------------
def clamp(val, min_val, max_val):
    return max(min_val, min(val, max_val))

def draw_pose_on_frame(frame, landmarks, bbox):
    """
    landmarks: MediaPipe Pose の landmarks
    bbox: (x1, y1, x2, y2)  人領域（元画像座標）
    """
    x1, y1, x2, y2 = bbox
    w = x2 - x1
    h = y2 - y1

    points = []

    # 各ランドマークを ROI座標 -> 元フレーム座標 に変換
    for lm in landmarks.landmark:
        px = int(x1 + lm.x * w)
        py = int(y1 + lm.y * h)
        vis = lm.visibility
        points.append((px, py, vis))

    # ★間接点描画
    for px, py, vis in points:
        if vis > 0.3:
            cv2.circle(frame, (px, py), 4, (0, 255, 255), -1)

    # 骨格線描画
    for connection in POSE_CONNECTIONS:
        start_idx = connection[0]
        end_idx = connection[1]

        x_start, y_start, v_start = points[start_idx]
        x_end, y_end, v_end = points[end_idx]

        if v_start > 0.3 and v_end > 0.3:
            cv2.line(frame, (x_start, y_start), (x_end, y_end), (0, 255, 0), 2)

def expand_bbox(x1, y1, x2, y2, img_w, img_h, ratio=0.15):
    """
    bboxを少し広げる（骨格推定が安定しやすい）
    """
    bw = x2 - x1
    bh = y2 - y1
    pad_w = int(bw * ratio)
    pad_h = int(bh * ratio)

    nx1 = clamp(x1 - pad_w, 0, img_w - 1)
    ny1 = clamp(y1 - pad_h, 0, img_h - 1)
    nx2 = clamp(x2 + pad_w, 0, img_w - 1)
    ny2 = clamp(y2 + pad_h, 0, img_h - 1)

    return nx1, ny1, nx2, ny2

# --------------------------------------------------
# 動画処理
# --------------------------------------------------
cap = cv2.VideoCapture(INPUT_VIDEO)
if not cap.isOpened():
    raise RuntimeError(f"動画を開けませんでした: {INPUT_VIDEO}")

fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

fourcc = cv2.VideoWriter_fourcc(*"mp4v")
writer = cv2.VideoWriter(OUTPUT_VIDEO, fourcc, fps, (width, height))

class_names = yolo_model.names  # クラスID -> クラス名

while True:
    ret, frame = cap.read()
    if not ret:
        break

    # YOLOで物体検出
    results = yolo_model.predict(frame, conf=CONF_THRES, verbose=False)[0]

    if results.boxes is not None:
        for box in results.boxes:
            cls_id = int(box.cls[0].item())
            conf = float(box.conf[0].item())
            x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())

            label = class_names[cls_id]

            # 検出枠を描画（全物体）
            color = (255, 0, 0)
            if label == PERSON_CLASS_NAME:
                color = (0, 0, 255)

            cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
            cv2.putText(
                frame,
                f"{label} {conf:.2f}",
                (x1, max(20, y1 - 10)),
                cv2.FONT_HERSHEY_SIMPLEX,
                0.6,
                color,
                2
            )

            # person のときだけ骨格検出
            if label == PERSON_CLASS_NAME:
                ex1, ey1, ex2, ey2 = expand_bbox(x1, y1, x2, y2, width, height, PADDING_RATIO)
                person_roi = frame[ey1:ey2, ex1:ex2]

                if person_roi.size == 0:
                    continue

                # MediaPipe は RGB 入力
                roi_rgb = cv2.cvtColor(person_roi, cv2.COLOR_BGR2RGB)
                pose_result = pose.process(roi_rgb)

                if pose_result.pose_landmarks:
                    draw_pose_on_frame(frame, pose_result.pose_landmarks, (ex1, ey1, ex2, ey2))

    # 表示
    cv2.imshow("Object Detection + Human Pose", frame)

    # 保存
    writer.write(frame)

    # qキーで終了
    key = cv2.waitKey(1) & 0xFF
    if key == ord("q"):
        break

cap.release()
writer.release()
pose.close()
cv2.destroyAllWindows()

print(f"処理完了: {OUTPUT_VIDEO}")
