File size: 3,452 Bytes
aa975a2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# video_utils.py
# -*- coding: utf-8 -*-
"""
视频可视化:
- 原视频检查:采样帧上画红色矩形框(线宽可见)
- 黑底 mask:采样帧填充白色 bbox 区域,其它帧纯黑
- 编解码兜底:mp4v 打不开则自动降级到 XVID + .avi
"""

import cv2
import numpy as np
from typing import List, Dict

RED   = (0, 0, 255)     # BGR
WHITE = (255, 255, 255)

def _to_xyxy(bbox, W, H):
    x1, y1, x2, y2 = bbox
    return int(round(x1 * W)), int(round(y1 * H)), int(round(x2 * W)), int(round(y2 * H))

def _make_writer(path: str, W: int, H: int, fps: float):
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    vw = cv2.VideoWriter(path, fourcc, fps, (W, H))
    if not vw.isOpened():
        # fallback
        fourcc = cv2.VideoWriter_fourcc(*'XVID')
        path = path.rsplit('.', 1)[0] + '.avi'
        vw = cv2.VideoWriter(path, fourcc, fps, (W, H))
    return vw, path

def draw_inspection_video(src_path: str, out_path: str, sampled_idx: List[int],
                          tasks_json: Dict[str, List[Dict]], thickness: int = 4) -> None:
    cap = cv2.VideoCapture(src_path)
    if not cap.isOpened():
        raise RuntimeError(f"cannot open video: {src_path}")
    W = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    H = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fps = cap.get(cv2.CAP_PROP_FPS) or 25.0

    vw, out_path = _make_writer(out_path, W, H, fps)

    # [帧号 -> 多任务 bbox 列表](按采样顺序对齐:seq 下标 k 对应 sampled_idx[k])
    bbox_by_frame = {}
    for _, seq in tasks_json.items():
        for k, e in enumerate(seq):
            if k >= len(sampled_idx):
                break
            bb = e.get("bbox")
            if bb is None:
                continue
            frm = sampled_idx[k]
            bbox_by_frame.setdefault(frm, []).append(bb)

    cur = 0
    while True:
        ok, frame = cap.read()
        if not ok:
            break
        if cur in bbox_by_frame:
            for bb in bbox_by_frame[cur]:
                x1, y1, x2, y2 = _to_xyxy(bb, W, H)
                cv2.rectangle(frame, (x1, y1), (x2, y2), RED, thickness)
        vw.write(frame)
        cur += 1

    cap.release()
    vw.release()

def draw_mask_video(src_path: str, out_path: str, sampled_idx: List[int],
                    tasks_json: Dict[str, List[Dict]]) -> None:
    cap = cv2.VideoCapture(src_path)
    if not cap.isOpened():
        raise RuntimeError(f"cannot open video: {src_path}")
    W = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    H = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fps = cap.get(cv2.CAP_PROP_FPS) or 25.0
    total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    vw, out_path = _make_writer(out_path, W, H, fps)
    black = np.zeros((H, W, 3), dtype=np.uint8)

    bbox_by_frame = {}
    for _, seq in tasks_json.items():
        for k, e in enumerate(seq):
            if k >= len(sampled_idx):
                break
            bb = e.get("bbox")
            if bb is None:
                continue
            frm = sampled_idx[k]
            bbox_by_frame.setdefault(frm, []).append(bb)

    for cur in range(total):
        frame = black.copy()
        if cur in bbox_by_frame:
            for bb in bbox_by_frame[cur]:
                x1, y1, x2, y2 = _to_xyxy(bb, W, H)
                # 白色填充作为 mask
                cv2.rectangle(frame, (x1, y1), (x2, y2), WHITE, thickness=-1)
        vw.write(frame)

    cap.release()
    vw.release()