docs: trace heatmap spec v1.0.0 — spatial + temporal + combined
This commit is contained in:
183
docs_v1.0/API_V1.0.0/TRACE/TRACE_HEATMAP_SPEC_V1.0.0.md
Normal file
183
docs_v1.0/API_V1.0.0/TRACE/TRACE_HEATMAP_SPEC_V1.0.0.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# Trace Heatmap Specification v1.0.0
|
||||||
|
|
||||||
|
## Concept
|
||||||
|
|
||||||
|
將臉部追蹤資料標準化為熱力圖格式,包含空間(畫面位置)和時間(影片進度)兩個維度。
|
||||||
|
|
||||||
|
## Data Model
|
||||||
|
|
||||||
|
### 1. Spatial Heatmap — 臉在哪裡?
|
||||||
|
|
||||||
|
將畫面划分為 grid,計算每個 cell 的 face 活動量:
|
||||||
|
|
||||||
|
```
|
||||||
|
frame (1920×1080)
|
||||||
|
┌──────────────────────┐
|
||||||
|
│ ░░ ░░ ░░░░ │ y
|
||||||
|
│ ░░░░░░░░░░░░░░ │
|
||||||
|
│ ░░░░░░░░░░░░ │
|
||||||
|
│ ░░░░░░░░ │ ← 活動集中在畫面中央
|
||||||
|
│ ░░ │
|
||||||
|
└──────────────────────┘
|
||||||
|
x →
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Temporal Heatmap — 什麼時候有臉?
|
||||||
|
|
||||||
|
```
|
||||||
|
face_density
|
||||||
|
│ ██ ████ ██
|
||||||
|
│ ██ ██ ████ ██ ██
|
||||||
|
│ ██ ██ ██████ ██ ██
|
||||||
|
└──────────────────────────→ time
|
||||||
|
0s 3000s 6000s
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Design
|
||||||
|
|
||||||
|
### GET /api/v1/file/:file_uuid/face_trace/heatmap
|
||||||
|
|
||||||
|
回傳標準化熱力圖資料。
|
||||||
|
|
||||||
|
#### Query Parameters
|
||||||
|
|
||||||
|
| Param | Type | Default | Description |
|
||||||
|
|-------|------|---------|-------------|
|
||||||
|
| `type` | enum | `spatial` | `spatial` \| `temporal` \| `combined` |
|
||||||
|
| `grid_x` | int | 20 | Spatial: X axis grid cells |
|
||||||
|
| `grid_y` | int | 12 | Spatial: Y axis grid cells |
|
||||||
|
| `bin_sec` | int | 60 | Temporal: time bucket in seconds |
|
||||||
|
| `time_start` | float | 0 | Time range start (seconds) |
|
||||||
|
| `time_end` | float | — | Time range end (default: video duration) |
|
||||||
|
| `min_confidence` | float | 0.5 | Minimum detection confidence |
|
||||||
|
| `trace_ids` | string | — | Comma-separated trace_id filter (optional) |
|
||||||
|
|
||||||
|
#### Response: Spatial
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "spatial",
|
||||||
|
"frame_width": 1920,
|
||||||
|
"frame_height": 1080,
|
||||||
|
"grid_x": 20,
|
||||||
|
"grid_y": 12,
|
||||||
|
"cell_w": 96,
|
||||||
|
"cell_h": 90,
|
||||||
|
"data": [
|
||||||
|
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0, 0, 1, 2, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
[0, 0, 0, 1, 3, 5, 8, 12, 14, 10, 6, 3, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
[0, 0, 1, 4, 8, 15, 25, 35, 40, 32, 20, 10, 4, 1, 0, 0, 0, 0, 0],
|
||||||
|
...
|
||||||
|
],
|
||||||
|
"max_value": 40,
|
||||||
|
"total_detections": 108204,
|
||||||
|
"total_traces": 6892
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Response: Temporal
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "temporal",
|
||||||
|
"bin_sec": 60,
|
||||||
|
"duration": 5954,
|
||||||
|
"bins": [
|
||||||
|
{"t_start": 0, "t_end": 60, "face_count": 45, "trace_count": 12, "avg_confidence": 0.82},
|
||||||
|
{"t_start": 60, "t_end": 120, "face_count": 120, "trace_count": 28, "avg_confidence": 0.79},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Response: Combined
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "combined",
|
||||||
|
"bin_sec": 60,
|
||||||
|
"grid_x": 20,
|
||||||
|
"grid_y": 12,
|
||||||
|
"duration": 5954,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"t_start": 0,
|
||||||
|
"t_end": 60,
|
||||||
|
"heatmap": [[...], [...]],
|
||||||
|
"max_cell": 8,
|
||||||
|
"face_count": 45
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Standardization Rules
|
||||||
|
|
||||||
|
1. **Normalization**: All values normalized to 0.0–1.0 range with `max_value` for rendering
|
||||||
|
2. **Resolution independence**: Grid size configurable, always returns `cell_w`/`cell_h`
|
||||||
|
3. **Temporal bucketing**: Default 60s bins, adjustable
|
||||||
|
4. **Filterable**: By time range, confidence, specific traces
|
||||||
|
5. **Cachable**: Response includes `file_uuid` + query hash for CDN/Redis cache
|
||||||
|
|
||||||
|
## Frontend Rendering
|
||||||
|
|
||||||
|
### Spatial Heatmap (Canvas)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function renderHeatmap(canvas, data) {
|
||||||
|
const cellW = canvas.width / data.grid_x;
|
||||||
|
const cellH = canvas.height / data.grid_y;
|
||||||
|
for (let y = 0; y < data.grid_y; y++) {
|
||||||
|
for (let x = 0; x < data.grid_x; x++) {
|
||||||
|
const intensity = data.data[y][x] / data.max_value;
|
||||||
|
ctx.fillStyle = `rgba(255, 0, 0, ${intensity})`;
|
||||||
|
ctx.fillRect(x * cellW, y * cellH, cellW, cellH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Temporal Heatmap (SVG)
|
||||||
|
|
||||||
|
```svg
|
||||||
|
<rect x="0" y="0" width="10" height="100" fill="rgba(255,0,0,0.1)" />
|
||||||
|
<rect x="10" y="0" width="10" height="100" fill="rgba(255,0,0,0.3)" />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
### Backend (src/api/trace_agent_api.rs)
|
||||||
|
|
||||||
|
Add new route:
|
||||||
|
```rust
|
||||||
|
.route("/api/v1/file/:file_uuid/face_trace/heatmap", get(list_trace_heatmap))
|
||||||
|
```
|
||||||
|
|
||||||
|
### SQL (spatial)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
FLOOR(x / $grid_w) AS cell_x,
|
||||||
|
FLOOR(y / $grid_h) AS cell_y,
|
||||||
|
COUNT(*) AS intensity
|
||||||
|
FROM dev.face_detections
|
||||||
|
WHERE file_uuid = $1 AND confidence >= $2
|
||||||
|
GROUP BY cell_x, cell_y
|
||||||
|
ORDER BY cell_x, cell_y;
|
||||||
|
```
|
||||||
|
|
||||||
|
### SQL (temporal)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
FLOOR(frame_number / ($fps * $bin_sec)) AS bin,
|
||||||
|
COUNT(*) AS face_count,
|
||||||
|
COUNT(DISTINCT trace_id) AS trace_count,
|
||||||
|
AVG(confidence) AS avg_confidence
|
||||||
|
FROM dev.face_detections
|
||||||
|
WHERE file_uuid = $1 AND confidence >= $2
|
||||||
|
GROUP BY bin
|
||||||
|
ORDER BY bin;
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user