1
0
forked from HQU-gxy/CVTH3PE
Files
CVTH3PE/play.ipynb

3219 lines
98 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from copy import deepcopy\n",
"from datetime import datetime, timedelta\n",
"from pathlib import Path\n",
"from typing import (\n",
" Any,\n",
" Generator,\n",
" Optional,\n",
" Sequence,\n",
" TypeAlias,\n",
" TypedDict,\n",
" cast,\n",
" overload,\n",
")\n",
"\n",
"import awkward as ak\n",
"import jax\n",
"import jax.numpy as jnp\n",
"import numpy as np\n",
"import orjson\n",
"from beartype import beartype\n",
"from cv2 import undistortPoints\n",
"from jaxtyping import Array, Float, Num, jaxtyped\n",
"from matplotlib import pyplot as plt\n",
"from numpy.typing import ArrayLike\n",
"from scipy.spatial.transform import Rotation as R\n",
"\n",
"from app.camera import Camera, CameraParams, Detection\n",
"from app.visualize.whole_body import visualize_whole_body\n",
"from filter_object_by_box import *"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<pre>[{name: &#x27;AF_01&#x27;, port: 5601, intrinsic: {...}, extrinsic: {...}, ...},\n",
" {name: &#x27;AF_02&#x27;, port: 5602, intrinsic: {...}, extrinsic: {...}, ...},\n",
" {name: &#x27;AF_03&#x27;, port: 5603, intrinsic: {...}, extrinsic: {...}, ...},\n",
" {name: &#x27;AF_04&#x27;, port: 5604, intrinsic: {...}, extrinsic: {...}, ...},\n",
" {name: &#x27;AF_05&#x27;, port: 5605, intrinsic: {...}, extrinsic: {...}, ...},\n",
" {name: &#x27;AF_06&#x27;, port: 5606, intrinsic: {...}, extrinsic: {...}, ...},\n",
" {name: &#x27;AE_01&#x27;, port: 5607, intrinsic: {...}, extrinsic: {...}, ...},\n",
" {name: &#x27;AE_1A&#x27;, port: 5608, intrinsic: {...}, extrinsic: {...}, ...},\n",
" {name: &#x27;AE_08&#x27;, port: 5609, intrinsic: {...}, extrinsic: {...}, ...}]\n",
"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n",
"backend: cpu\n",
"nbytes: 2.3 kB\n",
"type: 9 * {\n",
" name: string,\n",
" port: int64,\n",
" intrinsic: {\n",
" camera_matrix: var * var * float64,\n",
" distortion_coefficients: var * float64\n",
" },\n",
" extrinsic: {\n",
" rvec: var * float64,\n",
" tvec: var * float64\n",
" },\n",
" resolution: {\n",
" width: int64,\n",
" height: int64\n",
" }\n",
"}</pre>"
],
"text/plain": [
"<Array [{name: 'AF_01', port: 5601, ...}, ...] type='9 * {name: string, por...'>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"CAMERA_PATH = Path(\n",
" \"/home/admin/Documents/ActualTest_QuanCheng/camera_ex_params_1_2025_4_20/camera_params\"\n",
")\n",
"AK_CAMERA_DATASET: ak.Array = ak.from_parquet(CAMERA_PATH / \"camera_params.parquet\")\n",
"display(AK_CAMERA_DATASET)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"np.int64(5604)"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre>{rvec: [-2.24, 0.0917, -2.14],\n",
" tvec: [0.165, 0.217, 5.12]}\n",
"----------------------------------------------------------\n",
"backend: cpu\n",
"nbytes: 592 B\n",
"type: {\n",
" rvec: var * float64,\n",
" tvec: var * float64\n",
"}</pre>"
],
"text/plain": [
"<Record {rvec: [-2.24, ...], tvec: [...]} type='{rvec: var * float64, tvec:...'>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"camera_data_5604 = AK_CAMERA_DATASET[3]\n",
"display(camera_data_5604[\"port\"])\n",
"display(camera_data_5604[\"extrinsic\"])"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class Resolution(TypedDict):\n",
" width: int\n",
" height: int\n",
"\n",
"\n",
"class Intrinsic(TypedDict):\n",
" camera_matrix: Num[Array, \"3 3\"]\n",
" \"\"\"\n",
" K\n",
" \"\"\"\n",
" distortion_coefficients: Num[Array, \"N\"]\n",
" \"\"\"\n",
" distortion coefficients; usually 5\n",
" \"\"\"\n",
"\n",
"\n",
"class Extrinsic(TypedDict):\n",
" rvec: Num[NDArray, \"3\"]\n",
" tvec: Num[NDArray, \"3\"]\n",
"\n",
"\n",
"class ExternalCameraParams(TypedDict):\n",
" name: str\n",
" port: int\n",
" intrinsic: Intrinsic\n",
" extrinsic: Extrinsic\n",
" resolution: Resolution"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"DATASET_PATH = Path(\n",
" \"/home/admin/Documents/ActualTest_QuanCheng/camera_ex_params_1_2025_4_20/detect_result/segement_1\"\n",
")\n",
"\n",
"\n",
"def read_dataset_by_port(port: int) -> ak.Array:\n",
" # P = DATASET_PATH / f\"{port}.parquet\"\n",
" P = DATASET_PATH / f\"filter_{port}.parquet\"\n",
" return ak.from_parquet(P)\n",
"\n",
"\n",
"KEYPOINT_DATASET = {\n",
" int(p): read_dataset_by_port(p) for p in ak.to_numpy(AK_CAMERA_DATASET[\"port\"]) if p in [5603, 5605, 5608, 5609]\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{5603: <Array [{frame_index: 1650, ...}, ..., {...}] type='63 * {frame_index: int6...'>,\n",
" 5605: <Array [{frame_index: 1650, ...}, ..., {...}] type='63 * {frame_index: int6...'>,\n",
" 5608: <Array [{frame_index: 1650, ...}, ..., {...}] type='63 * {frame_index: int6...'>,\n",
" 5609: <Array [{frame_index: 1650, ...}, ..., {...}] type='63 * {frame_index: int6...'>}"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"KEYPOINT_DATASET"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"class KeypointDataset(TypedDict):\n",
" frame_index: int\n",
" boxes: Num[NDArray, \"N 4\"]\n",
" kps: Num[NDArray, \"N J 2\"]\n",
" kps_scores: Num[NDArray, \"N J\"]\n",
"\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def to_transformation_matrix(\n",
" rvec: Num[NDArray, \"3\"], tvec: Num[NDArray, \"3\"]\n",
") -> Num[NDArray, \"4 4\"]:\n",
" res = np.eye(4)\n",
" res[:3, :3] = R.from_rotvec(rvec).as_matrix()\n",
" res[:3, 3] = tvec\n",
" return res\n",
"\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def undistort_points(\n",
" points: Num[NDArray, \"M 2\"],\n",
" camera_matrix: Num[NDArray, \"3 3\"],\n",
" dist_coeffs: Num[NDArray, \"N\"],\n",
") -> Num[NDArray, \"M 2\"]:\n",
" K = camera_matrix\n",
" dist = dist_coeffs\n",
" res = undistortPoints(points, K, dist, P=K) # type: ignore\n",
" return res.reshape(-1, 2)\n",
"\n",
"\n",
"def from_camera_params(camera: ExternalCameraParams) -> Camera:\n",
" rt = jnp.array(\n",
" to_transformation_matrix(\n",
" ak.to_numpy(camera[\"extrinsic\"][\"rvec\"]),\n",
" ak.to_numpy(camera[\"extrinsic\"][\"tvec\"]),\n",
" )\n",
" )\n",
" K = jnp.array(camera[\"intrinsic\"][\"camera_matrix\"]).reshape(3, 3)\n",
" dist_coeffs = jnp.array(camera[\"intrinsic\"][\"distortion_coefficients\"])\n",
" image_size = jnp.array(\n",
" (camera[\"resolution\"][\"width\"], camera[\"resolution\"][\"height\"])\n",
" )\n",
" return Camera(\n",
" id=camera[\"name\"],\n",
" params=CameraParams(\n",
" K=K,\n",
" Rt=rt,\n",
" dist_coeffs=dist_coeffs,\n",
" image_size=image_size,\n",
" ),\n",
" )\n",
"\n",
"\n",
"def preprocess_keypoint_dataset(\n",
" dataset: Sequence[KeypointDataset],\n",
" camera: Camera,\n",
" fps: float,\n",
" start_timestamp: datetime,\n",
") -> Generator[Detection, None, None]:\n",
" frame_interval_s = 1 / fps\n",
" for el in dataset:\n",
" frame_index = el[\"frame_index\"]\n",
" timestamp = start_timestamp + timedelta(seconds=frame_index * frame_interval_s)\n",
" for kp, kp_score, boxes in zip(el[\"kps\"], el[\"kps_scores\"], el[\"boxes\"]):\n",
" kp = undistort_points(\n",
" np.asarray(kp),\n",
" np.asarray(camera.params.K),\n",
" np.asarray(camera.params.dist_coeffs),\n",
" )\n",
"\n",
" yield Detection(\n",
" keypoints=jnp.array(kp),\n",
" confidences=jnp.array(kp_score),\n",
" camera=camera,\n",
" timestamp=timestamp,\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"from typing import Any, Generator\n",
"\n",
"\n",
"from app.camera import Detection\n",
"\n",
"\n",
"DetectionGenerator: TypeAlias = Generator[Detection, None, None]\n",
"\n",
"\n",
"def sync_batch_gen(gens: list[DetectionGenerator], diff: timedelta) -> Generator[list[Detection], Any, None]:\n",
" \"\"\"\n",
" given a list of detection generators, return a generator that yields a batch of detections\n",
"\n",
" Args:\n",
" gens: list of detection generators\n",
" diff: maximum timestamp difference between detections to consider them part of the same batch\n",
" \"\"\"\n",
" N = len(gens)\n",
" last_batch_timestamp: Optional[datetime] = None\n",
" next_batch_timestamp: Optional[datetime] = None\n",
" current_batch: list[Detection] = []\n",
" next_batch: list[Detection] = []\n",
" paused: list[bool] = [False] * N\n",
" finished: list[bool] = [False] * N\n",
"\n",
" def reset_paused():\n",
" \"\"\"\n",
" reset paused list based on finished list\n",
" \"\"\"\n",
" for i in range(N):\n",
" if not finished[i]:\n",
" paused[i] = False\n",
" else:\n",
" paused[i] = True\n",
"\n",
" EPS = 1e-6\n",
" # a small epsilon to avoid floating point precision issues\n",
" diff_esp = diff - timedelta(seconds=EPS)\n",
" while True:\n",
" for i, gen in enumerate(gens):\n",
" try:\n",
" if finished[i] or paused[i]:\n",
" continue\n",
" val = next(gen)\n",
" if last_batch_timestamp is None:\n",
" last_batch_timestamp = val.timestamp\n",
" current_batch.append(val)\n",
" else:\n",
" if abs(val.timestamp - last_batch_timestamp) >= diff_esp:\n",
" next_batch.append(val)\n",
" if next_batch_timestamp is None:\n",
" next_batch_timestamp = val.timestamp\n",
" paused[i] = True\n",
" if all(paused):\n",
" yield current_batch\n",
" current_batch = next_batch\n",
" next_batch = []\n",
" last_batch_timestamp = next_batch_timestamp\n",
" next_batch_timestamp = None\n",
" reset_paused()\n",
" else:\n",
" current_batch.append(val)\n",
" except StopIteration:\n",
" finished[i] = True\n",
" paused[i] = True\n",
" if all(finished):\n",
" if len(current_batch) > 0:\n",
" # All generators exhausted, flush remaining batch and exit\n",
" yield current_batch\n",
" break"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"@overload\n",
"def to_projection_matrix(\n",
" transformation_matrix: Num[NDArray, \"4 4\"], camera_matrix: Num[NDArray, \"3 3\"]\n",
") -> Num[NDArray, \"3 4\"]: ...\n",
"\n",
"\n",
"@overload\n",
"def to_projection_matrix(\n",
" transformation_matrix: Num[Array, \"4 4\"], camera_matrix: Num[Array, \"3 3\"]\n",
") -> Num[Array, \"3 4\"]: ...\n",
"\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def to_projection_matrix(\n",
" transformation_matrix: Num[Any, \"4 4\"],\n",
" camera_matrix: Num[Any, \"3 3\"],\n",
") -> Num[Any, \"3 4\"]:\n",
" return camera_matrix @ transformation_matrix[:3, :]\n",
"\n",
"\n",
"to_projection_matrix_jit = jax.jit(to_projection_matrix)\n",
"\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def dlt(\n",
" H1: Num[NDArray, \"3 4\"],\n",
" H2: Num[NDArray, \"3 4\"],\n",
" p1: Num[NDArray, \"2\"],\n",
" p2: Num[NDArray, \"2\"],\n",
") -> Num[NDArray, \"3\"]:\n",
" \"\"\"\n",
" Direct Linear Transformation\n",
" \"\"\"\n",
" A = [\n",
" p1[1] * H1[2, :] - H1[1, :],\n",
" H1[0, :] - p1[0] * H1[2, :],\n",
" p2[1] * H2[2, :] - H2[1, :],\n",
" H2[0, :] - p2[0] * H2[2, :],\n",
" ]\n",
" A = np.array(A).reshape((4, 4))\n",
"\n",
" B = A.transpose() @ A\n",
" from scipy import linalg\n",
"\n",
" U, s, Vh = linalg.svd(B, full_matrices=False)\n",
" return Vh[3, 0:3] / Vh[3, 3]\n",
"\n",
"\n",
"@overload\n",
"def homogeneous_to_euclidean(points: Num[NDArray, \"N 4\"]) -> Num[NDArray, \"N 3\"]: ...\n",
"\n",
"\n",
"@overload\n",
"def homogeneous_to_euclidean(points: Num[Array, \"N 4\"]) -> Num[Array, \"N 3\"]: ...\n",
"\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def homogeneous_to_euclidean(\n",
" points: Num[Any, \"N 4\"],\n",
") -> Num[Any, \"N 3\"]:\n",
" \"\"\"\n",
" 将齐次坐标转换为欧几里得坐标\n",
"\n",
" Args:\n",
" points: homogeneous coordinates (x, y, z, w) in numpy array or jax array\n",
"\n",
" Returns:\n",
" euclidean coordinates (x, y, z) in numpy array or jax array\n",
" \"\"\"\n",
" return points[..., :-1] / points[..., -1:]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"camera_list = [\n",
" 5601,\n",
" 5602,\n",
" 5603,\n",
" 5604,\n",
" 5605,\n",
" 5606,\n",
" 5607,\n",
" 5608,\n",
" 5609,\n",
"]\n",
"# compute camera extrinsic matrix and intrinsic matrix \n",
"cameras = list(map(lambda x: from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == x][0]),camera_list))\n",
"\n",
"for element_camera in cameras:\n",
" with jnp.printoptions(precision=4, suppress=True):\n",
" # display(element_camera)\n",
" # display(element_camera.params.Rt.reshape(-1))\n",
" # display(element_camera.params.K.reshape(-1))\n",
"\n",
" # compute camera to object point distance\n",
" transistion = element_camera.params.pose_matrix[:3, -1]\n",
" # display(transistion)\n",
" # display(jnp.linalg.norm(transistion).item())"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"@jaxtyped(typechecker=beartype)\n",
"def triangulate_one_point_from_multiple_views_linear(\n",
" proj_matrices: Float[Array, \"N 3 4\"],\n",
" points: Num[Array, \"N 2\"],\n",
" confidences: Optional[Float[Array, \"N\"]] = None,\n",
") -> Float[Array, \"3\"]:\n",
" \"\"\"\n",
" Args:\n",
" proj_matrices: 形状为(N, 3, 4)的投影矩阵序列\n",
" points: 形状为(N, 2)的点坐标序列\n",
" confidences: 形状为(N,)的置信度序列,范围[0.0, 1.0]\n",
"\n",
" Returns:\n",
" point_3d: 形状为(3,)的三角测量得到的3D点\n",
" \"\"\"\n",
" assert len(proj_matrices) == len(points)\n",
"\n",
" N = len(proj_matrices)\n",
" confi: Float[Array, \"N\"]\n",
"\n",
" if confidences is None:\n",
" confi = jnp.ones(N, dtype=np.float32)\n",
" else:\n",
" # Use square root of confidences for weighting - more balanced approach\n",
" confi = jnp.sqrt(jnp.clip(confidences, 0, 1))\n",
"\n",
" # 将置信度小于0.1点的置信度均设置为0\n",
" # valid_mask = confidences >= 0.1\n",
" # confi = jnp.sqrt(jnp.clip(confidences * valid_mask, 0.0, 1.0))\n",
" \n",
"\n",
" A = jnp.zeros((N * 2, 4), dtype=np.float32)\n",
" for i in range(N):\n",
" x, y = points[i]\n",
" A = A.at[2 * i].set(proj_matrices[i, 2] * x - proj_matrices[i, 0])\n",
" A = A.at[2 * i + 1].set(proj_matrices[i, 2] * y - proj_matrices[i, 1])\n",
" A = A.at[2 * i].mul(confi[i])\n",
" A = A.at[2 * i + 1].mul(confi[i])\n",
"\n",
" # https://docs.jax.dev/en/latest/_autosummary/jax.numpy.linalg.svd.html\n",
" _, _, vh = jnp.linalg.svd(A, full_matrices=False)\n",
" point_3d_homo = vh[-1] # shape (4,)\n",
"\n",
" # replace the Python `if` with a jnp.where\n",
" point_3d_homo = jnp.where(\n",
" point_3d_homo[3] < 0, # predicate (scalar bool tracer)\n",
" -point_3d_homo, # if True\n",
" point_3d_homo, # if False\n",
" )\n",
"\n",
" point_3d = point_3d_homo[:3] / point_3d_homo[3]\n",
" return point_3d\n",
"\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def triangulate_points_from_multiple_views_linear(\n",
" proj_matrices: Float[Array, \"N 3 4\"],\n",
" points: Num[Array, \"N P 2\"],\n",
" confidences: Optional[Float[Array, \"N P\"]] = None,\n",
") -> Float[Array, \"P 3\"]:\n",
" \"\"\"\n",
" Batchtriangulate P points observed by N cameras, linearly via SVD.\n",
"\n",
" Args:\n",
" proj_matrices: (N, 3, 4) projection matrices\n",
" points: (N, P, 2) image-coordinates per view\n",
" confidences: (N, P, 1) optional per-view confidences in [0,1]\n",
"\n",
" Returns:\n",
" (P, 3) 3D point for each of the P tracks\n",
" \"\"\"\n",
" N, P, _ = points.shape\n",
" assert proj_matrices.shape[0] == N\n",
" \n",
" conf = jnp.array(confidences)\n",
" \n",
" # vectorize your onepoint routine over P\n",
" vmap_triangulate = jax.vmap(\n",
" triangulate_one_point_from_multiple_views_linear,\n",
" in_axes=(None, 1, 1), # proj_matrices static, map over points[:,p,:], conf[:,p]\n",
" out_axes=0,\n",
" )\n",
"\n",
" # returns (P, 3)\n",
" return vmap_triangulate(proj_matrices, points, conf)\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def triangulate_one_point_from_multiple_views_linear_time_weighted(\n",
" proj_matrices: Float[Array, \"N 3 4\"],\n",
" points: Num[Array, \"N 2\"],\n",
" delta_t: Num[Array, \"N\"],\n",
" lambda_t: float = 10.0,\n",
" confidences: Optional[Float[Array, \"N\"]] = None,\n",
") -> Float[Array, \"3\"]:\n",
" \"\"\"\n",
" Triangulate one point from multiple views with time-weighted linear least squares.\n",
"\n",
" Implements the incremental reconstruction method from \"Cross-View Tracking for Multi-Human 3D Pose\"\n",
" with weighting formula: w_i = exp(-λ_t(t-t_i)) / ||c^i^T||_2\n",
"\n",
" Args:\n",
" proj_matrices: Shape (N, 3, 4) projection matrices sequence\n",
" points: Shape (N, 2) point coordinates sequence\n",
" delta_t: Time differences between current time and each observation (in seconds)\n",
" lambda_t: Time penalty rate (higher values decrease influence of older observations)\n",
" confidences: Shape (N,) confidence values in range [0.0, 1.0]\n",
"\n",
" Returns:\n",
" point_3d: Shape (3,) triangulated 3D point\n",
" \"\"\"\n",
" assert len(proj_matrices) == len(points)\n",
" assert len(delta_t) == len(points)\n",
"\n",
" N = len(proj_matrices)\n",
"\n",
" # Prepare confidence weights\n",
" confi: Float[Array, \"N\"]\n",
" if confidences is None:\n",
" confi = jnp.ones(N, dtype=np.float32)\n",
" else:\n",
" confi = jnp.sqrt(jnp.clip(confidences, 0, 1))\n",
"\n",
" A = jnp.zeros((N * 2, 4), dtype=np.float32)\n",
"\n",
" # First build the coefficient matrix without weights\n",
" for i in range(N):\n",
" x, y = points[i]\n",
" A = A.at[2 * i].set(proj_matrices[i, 2] * x - proj_matrices[i, 0])\n",
" A = A.at[2 * i + 1].set(proj_matrices[i, 2] * y - proj_matrices[i, 1])\n",
"\n",
" # Then apply the time-based and confidence weights\n",
" for i in range(N):\n",
" # Calculate time-decay weight: e^(-λ_t * Δt)\n",
" time_weight = jnp.exp(-lambda_t * delta_t[i])\n",
"\n",
" # Calculate normalization factor: ||c^i^T||_2\n",
" row_norm_1 = jnp.linalg.norm(A[2 * i])\n",
" row_norm_2 = jnp.linalg.norm(A[2 * i + 1])\n",
"\n",
" # Apply combined weight: time_weight / row_norm * confidence\n",
" w1 = (time_weight / row_norm_1) * confi[i]\n",
" w2 = (time_weight / row_norm_2) * confi[i]\n",
"\n",
" A = A.at[2 * i].mul(w1)\n",
" A = A.at[2 * i + 1].mul(w2)\n",
"\n",
" # Solve using SVD\n",
" _, _, vh = jnp.linalg.svd(A, full_matrices=False)\n",
" point_3d_homo = vh[-1] # shape (4,)\n",
"\n",
" # Ensure homogeneous coordinate is positive\n",
" point_3d_homo = jnp.where(\n",
" point_3d_homo[3] < 0,\n",
" -point_3d_homo,\n",
" point_3d_homo,\n",
" )\n",
"\n",
" # Convert from homogeneous to Euclidean coordinates\n",
" point_3d = point_3d_homo[:3] / point_3d_homo[3]\n",
" return point_3d\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def triangulate_points_from_multiple_views_linear_time_weighted(\n",
" proj_matrices: Float[Array, \"N 3 4\"],\n",
" points: Num[Array, \"N P 2\"],\n",
" delta_t: Num[Array, \"N\"],\n",
" lambda_t: float = 10.0,\n",
" confidences: Optional[Float[Array, \"N P\"]] = None,\n",
") -> Float[Array, \"P 3\"]:\n",
" \"\"\"\n",
" Vectorized version that triangulates P points from N camera views with time-weighting.\n",
"\n",
" This function uses JAX's vmap to efficiently triangulate multiple points in parallel.\n",
"\n",
" Args:\n",
" proj_matrices: Shape (N, 3, 4) projection matrices for N cameras\n",
" points: Shape (N, P, 2) 2D points for P keypoints across N cameras\n",
" delta_t: Shape (N,) time differences between current time and each camera's timestamp (seconds)\n",
" lambda_t: Time penalty rate (higher values decrease influence of older observations)\n",
" confidences: Shape (N, P) confidence values for each point in each camera\n",
"\n",
" Returns:\n",
" points_3d: Shape (P, 3) triangulated 3D points\n",
" \"\"\"\n",
" N, P, _ = points.shape\n",
" assert (\n",
" proj_matrices.shape[0] == N\n",
" ), \"Number of projection matrices must match number of cameras\"\n",
" assert delta_t.shape[0] == N, \"Number of time deltas must match number of cameras\"\n",
"\n",
" if confidences is None:\n",
" # Create uniform confidences if none provided\n",
" conf = jnp.ones((N, P), dtype=jnp.float32)\n",
" else:\n",
" conf = confidences\n",
"\n",
" # Define the vmapped version of the single-point function\n",
" # We map over the second dimension (P points) of the input arrays\n",
" vmap_triangulate = jax.vmap(\n",
" triangulate_one_point_from_multiple_views_linear_time_weighted,\n",
" in_axes=(\n",
" None,\n",
" 1,\n",
" None,\n",
" None,\n",
" 1,\n",
" ), # proj_matrices and delta_t static, map over points\n",
" out_axes=0, # Output has first dimension corresponding to points\n",
" )\n",
"\n",
" # For each point p, extract the 2D coordinates from all cameras and triangulate\n",
" return vmap_triangulate(\n",
" proj_matrices, # (N, 3, 4) - static across points\n",
" points, # (N, P, 2) - map over dim 1 (P)\n",
" delta_t, # (N,) - static across points\n",
" lambda_t, # scalar - static\n",
" conf, # (N, P) - map over dim 1 (P)\n",
" )\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"FPS = 24\n",
"# image_gen_5601 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5601], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5601][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"# image_gen_5602 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5602], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5602][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"image_gen_5603 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5603], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5603][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"# image_gen_5604 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5604], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5604][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"image_gen_5605 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5605], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5605][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"# image_gen_5606 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5606], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5606][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"# image_gen_5607 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5607], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5607][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"image_gen_5608 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5608], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5608][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"image_gen_5609 = preprocess_keypoint_dataset(KEYPOINT_DATASET[5609], from_camera_params(AK_CAMERA_DATASET[AK_CAMERA_DATASET[\"port\"] == 5609][0]), FPS, datetime(2024, 4, 2, 12, 0, 0)) # type: ignore\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.041666666666666664"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display(1 / FPS)\n",
"sync_gen = sync_batch_gen(\n",
" [\n",
" # image_gen_5601,\n",
" # image_gen_5602,\n",
" image_gen_5603,\n",
" # image_gen_5604,\n",
" image_gen_5605,\n",
" # image_gen_5607,\n",
" # image_gen_5606,\n",
" image_gen_5608,\n",
" image_gen_5609\n",
" ],\n",
" timedelta(seconds=1 / FPS),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[Detection(<Camera id=AF_03>, 2024-04-02 12:01:08.750000),\n",
" Detection(<Camera id=AF_05>, 2024-04-02 12:01:08.750000),\n",
" Detection(<Camera id=AE_1A>, 2024-04-02 12:01:08.750000),\n",
" Detection(<Camera id=AE_08>, 2024-04-02 12:01:08.750000),\n",
" Detection(<Camera id=AE_08>, 2024-04-02 12:01:08.750000)]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"detections = next(sync_gen)\n",
"display(detections)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"from app.tracking import AffinityResult, Tracking, TrackingState\n",
"from copy import copy as shallow_copy\n",
"from pyrsistent import v, pvector\n",
"from beartype.typing import Mapping, Sequence\n",
"from app.camera import (\n",
" Camera,\n",
" CameraID,\n",
" CameraParams,\n",
" Detection,\n",
" calculate_affinity_matrix_by_epipolar_constraint,\n",
" classify_by_camera,\n",
")\n",
"from app.tracking import (\n",
" TrackingID,\n",
" AffinityResult,\n",
" LastDifferenceVelocityFilter,\n",
" Tracking,\n",
" TrackingState,\n",
")\n",
"from pyrsistent import pvector, v, m, pmap, PMap, freeze, thaw\n",
"from optax.assignment import hungarian_algorithm as linear_sum_assignment\n",
"from itertools import chain\n",
"\n",
"DELTA_T_MIN = timedelta(milliseconds=10)\n",
"\n",
"def group_by_cluster_by_camera(\n",
" cluster: Sequence[Detection],\n",
") -> PMap[CameraID, Detection]:\n",
" \"\"\"\n",
" group the detections by camera, and preserve the latest detection for each camera\n",
" \"\"\"\n",
" r: dict[CameraID, Detection] = {}\n",
" for el in cluster:\n",
" if el.camera.id in r:\n",
" eld = r[el.camera.id]\n",
" preserved = max([eld, el], key=lambda x: x.timestamp)\n",
" r[el.camera.id] = preserved\n",
" return pmap(r)\n",
"\n",
"class GlobalTrackingState:\n",
" _last_id: int\n",
" _trackings: dict[int, Tracking]\n",
"\n",
" def __init__(self):\n",
" self._last_id = 0\n",
" self._trackings = {}\n",
"\n",
" def __repr__(self) -> str:\n",
" return (\n",
" f\"GlobalTrackingState(last_id={self._last_id}, trackings={self._trackings})\"\n",
" )\n",
"\n",
" @property\n",
" def trackings(self) -> dict[int, Tracking]:\n",
" return shallow_copy(self._trackings)\n",
"\n",
" def remove(self, id:int):\n",
" del self._trackings[id]\n",
"\n",
" def add_tracking(self, cluster: Sequence[Detection]) -> Tracking:\n",
" if len(cluster) < 2:\n",
" raise ValueError(\n",
" \"cluster must contain at least 2 detections to form a tracking\"\n",
" )\n",
" kps_3d, latest_timestamp = triangle_from_cluster(cluster)\n",
" next_id = self._last_id + 1\n",
" tracking_state = TrackingState(\n",
" keypoints=kps_3d,\n",
" last_active_timestamp=latest_timestamp,\n",
" historical_detections_by_camera=group_by_cluster_by_camera(cluster),\n",
" )\n",
" tracking = Tracking(\n",
" id=next_id,\n",
" state=tracking_state,\n",
" velocity_filter=LastDifferenceVelocityFilter(kps_3d, latest_timestamp),\n",
" )\n",
" self._trackings[next_id] = tracking\n",
" self._last_id = next_id\n",
" return tracking\n",
"\n",
"\n",
"@jaxtyped(typechecker=beartype)\n",
"def triangle_from_cluster(\n",
" cluster: Sequence[Detection],\n",
") -> tuple[Float[Array, \"N 3\"], datetime]:\n",
" proj_matrices = jnp.array([el.camera.params.projection_matrix for el in cluster])\n",
" points = jnp.array([el.keypoints_undistorted for el in cluster])\n",
" confidences = jnp.array([el.confidences for el in cluster])\n",
" latest_timestamp = max(el.timestamp for el in cluster)\n",
" return (\n",
" triangulate_points_from_multiple_views_linear(\n",
" proj_matrices, points, confidences=confidences\n",
" ),\n",
" latest_timestamp,\n",
" )\n",
"\n",
"@beartype\n",
"def calculate_camera_affinity_matrix_jax(\n",
" trackings: Sequence[Tracking],\n",
" camera_detections: Sequence[Detection],\n",
" w_2d: float,\n",
" alpha_2d: float,\n",
" w_3d: float,\n",
" alpha_3d: float,\n",
" lambda_a: float,\n",
") -> Float[Array, \"T D\"]:\n",
" \"\"\"\n",
" Vectorized implementation to compute an affinity matrix between *trackings*\n",
" and *detections* coming from **one** camera.\n",
"\n",
" Compared with the simple double-for-loop version, this leverages `jax`'s\n",
" broadcasting + `vmap` facilities and avoids Python loops over every\n",
" (tracking, detection) pair. The mathematical definition of the affinity\n",
" is **unchanged**, so the result remains bit-identical to the reference\n",
" implementation used in the tests.\n",
" \"\"\"\n",
"\n",
" # ------------------------------------------------------------------\n",
" # Quick validations / early-exit guards\n",
" # ------------------------------------------------------------------\n",
" if len(trackings) == 0 or len(camera_detections) == 0:\n",
" # Return an empty affinity matrix with appropriate shape.\n",
" return jnp.zeros((len(trackings), len(camera_detections))) # type: ignore[return-value]\n",
"\n",
" cam = next(iter(camera_detections)).camera\n",
" # Ensure every detection truly belongs to the same camera (guard clause)\n",
" cam_id = cam.id\n",
" if any(det.camera.id != cam_id for det in camera_detections):\n",
" raise ValueError(\n",
" \"All detections passed to `calculate_camera_affinity_matrix` must come from one camera.\"\n",
" )\n",
"\n",
" # We will rely on a single `Camera` instance (all detections share it)\n",
" w_img_, h_img_ = cam.params.image_size\n",
" w_img, h_img = float(w_img_), float(h_img_)\n",
"\n",
" # ------------------------------------------------------------------\n",
" # Gather data into ndarray / DeviceArray batches so that we can compute\n",
" # everything in a single (or a few) fused kernels.\n",
" # ------------------------------------------------------------------\n",
"\n",
" # === Tracking-side tensors ===\n",
" kps3d_trk: Float[Array, \"T J 3\"] = jnp.stack(\n",
" [trk.state.keypoints for trk in trackings]\n",
" ) # (T, J, 3)\n",
" J = kps3d_trk.shape[1]\n",
" # === Detection-side tensors ===\n",
" kps2d_det: Float[Array, \"D J 2\"] = jnp.stack(\n",
" [det.keypoints for det in camera_detections]\n",
" ) # (D, J, 2)\n",
"\n",
" # ------------------------------------------------------------------\n",
" # Compute Δt matrix shape (T, D)\n",
" # ------------------------------------------------------------------\n",
" # Epoch timestamps are ~1.7 × 10⁹; storing them in float32 wipes out\n",
" # subsecond detail (resolution ≈ 200 ms). Keep them in float64 until\n",
" # after subtraction so we preserve Δtontheorderofmilliseconds.\n",
" # --- timestamps ----------\n",
" t0 = min(\n",
" chain(\n",
" (trk.state.last_active_timestamp for trk in trackings),\n",
" (det.timestamp for det in camera_detections),\n",
" )\n",
" ).timestamp() # common origin (float)\n",
" ts_trk = jnp.array(\n",
" [trk.state.last_active_timestamp.timestamp() - t0 for trk in trackings],\n",
" dtype=jnp.float32, # now small, ms-scale fits in fp32\n",
" )\n",
" ts_det = jnp.array(\n",
" [det.timestamp.timestamp() - t0 for det in camera_detections],\n",
" dtype=jnp.float32,\n",
" )\n",
" # Δt in seconds, fp32 throughout\n",
" delta_t = ts_det[None, :] - ts_trk[:, None] # (T,D)\n",
" min_dt_s = float(DELTA_T_MIN.total_seconds())\n",
" delta_t = jnp.clip(delta_t, a_min=min_dt_s, a_max=None)\n",
"\n",
" # ------------------------------------------------------------------\n",
" # ---------- 2D affinity -------------------------------------------\n",
" # ------------------------------------------------------------------\n",
" # Project each tracking's 3D keypoints onto the image once.\n",
" # `Camera.project` works per-sample, so we vmap over the first axis.\n",
"\n",
" proj_fn = jax.vmap(cam.project, in_axes=0) # maps over the keypoint sets\n",
" kps2d_trk_proj: Float[Array, \"T J 2\"] = proj_fn(kps3d_trk) # (T, J, 2)\n",
"\n",
" # Normalise keypoints by image size so absolute units do not bias distance\n",
" norm_trk = kps2d_trk_proj / jnp.array([w_img, h_img])\n",
" norm_det = kps2d_det / jnp.array([w_img, h_img])\n",
"\n",
" # L2 distance for every (T, D, J)\n",
" # reshape for broadcasting: (T,1,J,2) vs (1,D,J,2)\n",
" diff2d = norm_trk[:, None, :, :] - norm_det[None, :, :, :]\n",
" dist2d: Float[Array, \"T D J\"] = jnp.linalg.norm(diff2d, axis=-1)\n",
"\n",
" # Compute per-keypoint 2D affinity\n",
" delta_t_broadcast = delta_t[:, :, None] # (T, D, 1)\n",
" affinity_2d = (\n",
" w_2d\n",
" * (1 - dist2d / (alpha_2d * delta_t_broadcast))\n",
" * jnp.exp(-lambda_a * delta_t_broadcast)\n",
" )\n",
"\n",
" # ------------------------------------------------------------------\n",
" # ---------- 3D affinity -------------------------------------------\n",
" # ------------------------------------------------------------------\n",
" # For each detection pre-compute back-projected 3D points lying on z=0 plane.\n",
"\n",
" backproj_points_list = [\n",
" det.camera.unproject_points_to_z_plane(det.keypoints, z=0.0)\n",
" for det in camera_detections\n",
" ] # each (J,3)\n",
" backproj: Float[Array, \"D J 3\"] = jnp.stack(backproj_points_list) # (D, J, 3)\n",
"\n",
" zero_velocity = jnp.zeros((J, 3))\n",
" trk_velocities = jnp.stack(\n",
" [\n",
" trk.velocity if trk.velocity is not None else zero_velocity\n",
" for trk in trackings\n",
" ]\n",
" )\n",
"\n",
" predicted_pose: Float[Array, \"T D J 3\"] = (\n",
" kps3d_trk[:, None, :, :] # (T,1,J,3)\n",
" + trk_velocities[:, None, :, :] * delta_t[:, :, None, None] # (T,D,1,1)\n",
" )\n",
"\n",
" # Camera center shape (3,) -> will broadcast\n",
" cam_center = cam.params.location\n",
"\n",
" # Compute perpendicular distance using vectorized formula\n",
" # p1 = cam_center (3,)\n",
" # p2 = backproj (D, J, 3)\n",
" # P = predicted_pose (T, D, J, 3)\n",
" # Broadcast plan: v1 = P - p1 → (T, D, J, 3)\n",
" # v2 = p2[None, ...]-p1 → (1, D, J, 3)\n",
" # Shapes now line up; no stray singleton axis.\n",
" p1 = cam_center\n",
" p2 = backproj\n",
" P = predicted_pose\n",
" v1 = P - p1\n",
" v2 = p2[None, :, :, :] - p1 # (1, D, J, 3)\n",
" cross = jnp.cross(v1, v2) # (T, D, J, 3)\n",
" num = jnp.linalg.norm(cross, axis=-1) # (T, D, J)\n",
" den = jnp.linalg.norm(v2, axis=-1) # (1, D, J)\n",
" dist3d: Float[Array, \"T D J\"] = num / den\n",
"\n",
" affinity_3d = (\n",
" w_3d * (1 - dist3d / alpha_3d) * jnp.exp(-lambda_a * delta_t_broadcast)\n",
" )\n",
"\n",
" # ------------------------------------------------------------------\n",
" # Combine and reduce across keypoints → (T, D)\n",
" # ------------------------------------------------------------------\n",
" total_affinity: Float[Array, \"T D\"] = jnp.sum(affinity_2d + affinity_3d, axis=-1)\n",
" return total_affinity # type: ignore[return-value]\n",
"\n",
"\n",
"\n",
"@beartype\n",
"def calculate_affinity_matrix(\n",
" trackings: Sequence[Tracking],\n",
" detections: Sequence[Detection] | Mapping[CameraID, list[Detection]],\n",
" w_2d: float,\n",
" alpha_2d: float,\n",
" w_3d: float,\n",
" alpha_3d: float,\n",
" lambda_a: float,\n",
") -> dict[CameraID, AffinityResult]:\n",
" \"\"\"\n",
" Calculate the affinity matrix between a set of trackings and detections.\n",
"\n",
" Args:\n",
" trackings: Sequence of tracking objects\n",
" detections: Sequence of detection objects or a group detections by ID\n",
" w_2d: Weight for 2D affinity\n",
" alpha_2d: Normalization factor for 2D distance\n",
" w_3d: Weight for 3D affinity\n",
" alpha_3d: Normalization factor for 3D distance\n",
" lambda_a: Decay rate for time difference\n",
" Returns:\n",
" A dictionary mapping camera IDs to affinity results.\n",
" \"\"\"\n",
" if isinstance(detections, Mapping):\n",
" detection_by_camera = detections\n",
" else:\n",
" detection_by_camera = classify_by_camera(detections)\n",
"\n",
" res: dict[CameraID, AffinityResult] = {}\n",
" for camera_id, camera_detections in detection_by_camera.items():\n",
" affinity_matrix = calculate_camera_affinity_matrix_jax(\n",
" trackings,\n",
" camera_detections,\n",
" w_2d,\n",
" alpha_2d,\n",
" w_3d,\n",
" alpha_3d,\n",
" lambda_a,\n",
" )\n",
" # row, col\n",
" indices_T, indices_D = linear_sum_assignment(affinity_matrix)\n",
" affinity_result = AffinityResult(\n",
" matrix=affinity_matrix,\n",
" trackings=trackings,\n",
" detections=camera_detections,\n",
" indices_T=indices_T,\n",
" indices_D=indices_D,\n",
" )\n",
" res[camera_id] = affinity_result\n",
" return res"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"\n",
"def update_tracking(\n",
" tracking: Tracking,\n",
" detections: Sequence[Detection],\n",
" max_delta_t: timedelta = timedelta(milliseconds=100),\n",
" lambda_t: float = 10.0,\n",
") -> None:\n",
" \"\"\"\n",
" update the tracking with a new set of detections\n",
"\n",
" Args:\n",
" tracking: the tracking to update\n",
" detections: the detections to update the tracking with\n",
" max_delta_t: the maximum time difference between the last active timestamp and the latest detection\n",
" lambda_t: the lambda value for the time difference\n",
"\n",
" Note:\n",
" the function would mutate the tracking object\n",
" \"\"\"\n",
" last_active_timestamp = tracking.state.last_active_timestamp\n",
" latest_timestamp = max(d.timestamp for d in detections)\n",
" d = thaw(tracking.state.historical_detections_by_camera)\n",
" for detection in detections:\n",
" d[detection.camera.id] = detection\n",
" for camera_id, detection in d.items():\n",
" if detection.timestamp - latest_timestamp > max_delta_t:\n",
" del d[camera_id]\n",
" new_detections = freeze(d)\n",
" new_detections_list = list(new_detections.values())\n",
" project_matrices = jnp.stack(\n",
" [detection.camera.params.projection_matrix for detection in new_detections_list]\n",
" )\n",
" delta_t = jnp.array(\n",
" [\n",
" detection.timestamp.timestamp() - last_active_timestamp.timestamp()\n",
" for detection in new_detections_list\n",
" ]\n",
" )\n",
" kps = jnp.stack([detection.keypoints for detection in new_detections_list])\n",
" conf = jnp.stack([detection.confidences for detection in new_detections_list])\n",
" kps_3d = triangulate_points_from_multiple_views_linear_time_weighted(\n",
" project_matrices, kps, delta_t, lambda_t, conf\n",
" )\n",
" new_state = TrackingState(\n",
" keypoints=kps_3d,\n",
" last_active_timestamp=latest_timestamp,\n",
" historical_detections_by_camera=new_detections,\n",
" )\n",
" tracking.update(kps_3d, latest_timestamp)\n",
" tracking.state = new_state"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dict_values([Tracking(1, 2024-04-02 12:01:08.750000)])"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 初始化追踪\n",
"global_tracking_state = GlobalTrackingState()\n",
"# detections = next(sync_gen)\n",
"global_tracking_state.add_tracking(detections)\n",
"display(global_tracking_state.trackings.values())"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[Tracking(1, 2024-04-02 12:01:08.750000)]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from app.tracking import Tracking\n",
"\n",
"\n",
"W_2D = 0.8\n",
"ALPHA_2D = 60.0\n",
"LAMBDA_A = 3.0\n",
"W_3D = 0.2\n",
"ALPHA_3D = 0.1\n",
"\n",
"# 获得当前追踪目标\n",
"trackings: list[Tracking] = sorted(global_tracking_state.trackings.values(), key=lambda x: x.id)\n",
"display(trackings)\n",
"# 3d数据键为追踪目标id值为该目标的所有3d数据\n",
"all_3d_kps: dict[str, list] = {}\n",
"# 初始化每个追踪目标的3d数据\n",
"for element_tracking in trackings:\n",
" all_3d_kps[str(element_tracking.id)] = [element_tracking.state.keypoints.tolist()]"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'AF_03': [], 'AF_05': [], 'AE_1A': [], 'AE_08': []}"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"affinity_matrix: dict[str, list] = {}\n",
"for element_camera in detections:\n",
" affinity_matrix[element_camera.camera.id] = []\n",
"display(affinity_matrix)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"'''使用已筛选过的数据采用跟踪获得获得每一帧的3d数据'''\n",
"count = 0\n",
"# 追踪相似度矩阵匹配阈值\n",
"affinities_threshold = 70\n",
"# 遍历59帧的2d数据测试追踪状态\n",
"while count < 62:\n",
" # 获得最新一帧的数据2d数据\n",
" detections = next(sync_gen)\n",
" # 计算相似度矩阵匹配结果\n",
" affinities: dict[str, AffinityResult] = calculate_affinity_matrix(\n",
" trackings,\n",
" detections,\n",
" w_2d=W_2D,\n",
" alpha_2d=ALPHA_2D,\n",
" w_3d=W_3D,\n",
" alpha_3d=ALPHA_3D,\n",
" lambda_a=LAMBDA_A,\n",
" )\n",
" # display(affinities)\n",
"\n",
" # 遍历追踪目标获得该目标的匹配2d数据\n",
" for element_tracking in trackings:\n",
"\n",
" tracking_detection = []\n",
" # 匹配检测目标的索引值\n",
" detection_index = None\n",
" # 遍历相机的追踪相似度匹配结果\n",
" for camera_name in affinities.keys():\n",
" # 获得与每个跟踪目标匹配的相似度矩阵\n",
" camera_matrix = np.array(affinities[camera_name].matrix).flatten()\n",
" camera_tracking = affinities[camera_name].trackings\n",
" detection_index = np.argmax(camera_matrix).item()\n",
"\n",
" # 判断相似度矩阵极大值是否大于阈值\n",
" # 目前只有一个跟踪目标,还未实现多跟踪目标的匹配-------------------------\n",
" affinity_matrix[camera_name].append(camera_matrix.tolist())\n",
" if camera_matrix[detection_index].item() > affinities_threshold:\n",
" # 保留应用的2d检测数据\n",
" tracking_detection.append(\n",
" affinities[camera_name].detections[detection_index])\n",
"\n",
" # 跟新追踪目标\n",
" if tracking_detection:\n",
" update_tracking(element_tracking, tracking_detection)\n",
" all_3d_kps[str(element_tracking.id)].append(\n",
" element_tracking.state.keypoints.tolist())\n",
" count += 1"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dict_values([Tracking(1, 2024-04-02 12:01:11.333333)])"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display(global_tracking_state.trackings.values())"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:91.75846099853516 min:-692.5421142578125 avg:-300.3918266296387'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:97.37450408935547 min:-701.7442626953125 avg:-302.1848793029785'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:84.19193267822266 min:-710.1654052734375 avg:-312.9867362976074'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:98.26692199707031 min:-715.652587890625 avg:-308.69283294677734'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:98.33988952636719 min:-709.0427856445312 avg:-305.35144805908203'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:102.15011596679688 min:-712.3077392578125 avg:-305.0788116455078'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:84.32078552246094 min:-713.1134033203125 avg:-314.3963088989258'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:91.96778106689453 min:-717.167236328125 avg:-312.59972763061523'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:95.12872314453125 min:-705.86962890625 avg:-305.3704528808594'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:100.19415283203125 min:-702.752197265625 avg:-301.2790222167969'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:101.8935775756836 min:-707.0585327148438 avg:-302.5824775695801'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:103.80628204345703 min:-705.786376953125 avg:-300.990047454834'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:104.1606674194336 min:-701.741943359375 avg:-298.7906379699707'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:82.00521850585938 min:-701.8954467773438 avg:-309.9451141357422'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:103.97581481933594 min:-703.419189453125 avg:-299.72168731689453'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:92.57843017578125 min:-708.9879760742188 avg:-308.20477294921875'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:89.26778411865234 min:-698.5325927734375 avg:-304.6324043273926'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:85.52945709228516 min:-714.3911743164062 avg:-314.43085861206055'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:99.84005737304688 min:-713.117919921875 avg:-306.63893127441406'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:99.94195556640625 min:-704.6619873046875 avg:-302.3600158691406'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:106.76197814941406 min:-706.7772827148438 avg:-300.00765228271484'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:107.28811645507812 min:-707.5064086914062 avg:-300.10914611816406'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:106.60488891601562 min:-708.0799560546875 avg:-300.73753356933594'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:103.49193572998047 min:-707.2576293945312 avg:-301.8828468322754'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:102.64285278320312 min:-707.6041259765625 avg:-302.4806365966797'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:104.58334350585938 min:-708.3157348632812 avg:-301.86619567871094'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:105.00214385986328 min:-706.1616821289062 avg:-300.5797691345215'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:107.25581359863281 min:-707.894287109375 avg:-300.3192367553711'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:91.92869567871094 min:-708.345703125 avg:-308.20850372314453'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:94.95275115966797 min:-711.0690307617188 avg:-308.0581398010254'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:100.63902282714844 min:-709.3521728515625 avg:-304.35657501220703'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:99.76637268066406 min:-708.1904907226562 avg:-304.2120590209961'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:105.62733459472656 min:-713.6270141601562 avg:-303.99983978271484'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:93.55274200439453 min:-710.2616577148438 avg:-308.3544578552246'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:88.19427490234375 min:-702.3078002929688 avg:-307.0567626953125'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:88.83548736572266 min:-712.48876953125 avg:-311.8266410827637'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:98.555908203125 min:-707.012939453125 avg:-304.228515625'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:104.69906616210938 min:-727.013671875 avg:-311.1573028564453'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:96.18646240234375 min:-730.3177490234375 avg:-317.0656433105469'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:95.744140625 min:-734.6749267578125 avg:-319.46539306640625'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:99.74221801757812 min:-739.6990356445312 avg:-319.97840881347656'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:101.81022644042969 min:-742.320068359375 avg:-320.25492095947266'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:99.88671112060547 min:-756.2476196289062 avg:-328.1804542541504'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:38.53110885620117 min:-750.19970703125 avg:-355.8342990875244'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:104.7131118774414 min:-752.62158203125 avg:-323.9542350769043'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:93.6522216796875 min:-784.1400756835938 avg:-345.2439270019531'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:105.51091003417969 min:-780.3106689453125 avg:-337.3998794555664'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:101.53762817382812 min:-796.2106323242188 avg:-347.3365020751953'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:74.37679290771484 min:-804.722412109375 avg:-365.1728096008301'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:94.3597183227539 min:-815.316162109375 avg:-360.47822189331055'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:101.7551498413086 min:-817.5161743164062 avg:-357.8805122375488'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:103.37225341796875 min:-830.87451171875 avg:-363.7511291503906'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:92.28455352783203 min:-838.488037109375 avg:-373.1017417907715'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:93.99905395507812 min:-870.7958374023438 avg:-388.3983917236328'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:85.43528747558594 min:-881.697021484375 avg:-398.13086700439453'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:93.51964569091797 min:-877.5942993164062 avg:-392.03732681274414'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:85.93327331542969 min:-892.482666015625 avg:-403.27469635009766'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:96.98959350585938 min:-916.940673828125 avg:-409.9755401611328'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AF_05 max:61.17249298095703 min:-918.435546875 avg:-428.6315269470215'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:87.27909851074219 min:-562.9956665039062 avg:-331.4233856201172'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:106.9716796875 min:-528.57373046875 avg:-301.9154052734375'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:107.11510467529297 min:-536.5692138671875 avg:-307.2233708699544'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:93.48899841308594 min:-552.966552734375 avg:-374.3308448791504'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:103.23574829101562 min:-535.83837890625 avg:-308.0480550130208'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:106.07456970214844 min:-538.03369140625 avg:-308.54505920410156'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:98.90181732177734 min:-539.795166015625 avg:-311.97679901123047'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:95.51962280273438 min:-543.9681396484375 avg:-315.8877258300781'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:92.48377990722656 min:-545.2631225585938 avg:-368.86115646362305'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:88.98152923583984 min:-546.994140625 avg:-370.8902072906494'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:98.20276641845703 min:-543.2761840820312 avg:-365.798246383667'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:100.69371032714844 min:-548.6571044921875 avg:-369.0961112976074'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:102.2591781616211 min:-546.1829833984375 avg:-366.72947120666504'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:97.60616302490234 min:-547.6847534179688 avg:-370.0789279937744'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:96.1855239868164 min:-544.7774658203125 avg:-315.1464106241862'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:99.48007202148438 min:-551.33642578125 avg:-372.53141021728516'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:99.58531188964844 min:-549.2862548828125 avg:-314.1669667561849'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:100.73834228515625 min:-555.0045166015625 avg:-317.7935791015625'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:99.66900634765625 min:-556.7388305664062 avg:-376.3662796020508'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:103.73270416259766 min:-548.5020141601562 avg:-368.9901485443115'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:109.66616821289062 min:-551.77294921875 avg:-369.6998977661133'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:109.4511489868164 min:-540.73046875 avg:-308.72213490804035'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:110.51504516601562 min:-553.86279296875 avg:-371.0124740600586'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:107.7448501586914 min:-553.8038330078125 avg:-370.73373222351074'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:105.81243896484375 min:-550.396240234375 avg:-368.5989227294922'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:104.8551025390625 min:-550.5211791992188 avg:-369.7560272216797'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:108.66722106933594 min:-552.1442260742188 avg:-370.02383041381836'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:108.39226531982422 min:-552.2255249023438 avg:-370.1651782989502'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:107.8331069946289 min:-551.4797973632812 avg:-370.0543727874756'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:103.65431213378906 min:-555.32080078125 avg:-373.9909782409668'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:105.35424041748047 min:-552.9658813476562 avg:-371.9904270172119'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:106.91851806640625 min:-552.5498046875 avg:-371.22863006591797'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:102.81415557861328 min:-556.4279174804688 avg:-375.13155937194824'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:94.79095458984375 min:-553.989013671875 avg:-319.83946736653644'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:100.09913635253906 min:-553.2471313476562 avg:-374.2360420227051'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:98.82782745361328 min:-557.1586303710938 avg:-320.3986994425456'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:96.06672668457031 min:-550.5762939453125 avg:-316.5072886149089'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:102.7115478515625 min:-566.0664672851562 avg:-382.8135986328125'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:103.9891357421875 min:-566.9451904296875 avg:-382.7074279785156'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:87.90074920654297 min:-564.4805908203125 avg:-385.16259956359863'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:100.35246276855469 min:-577.6460571289062 avg:-391.45752334594727'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:96.91963195800781 min:-570.0296630859375 avg:-386.74848556518555'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:97.14323425292969 min:-575.503662109375 avg:-390.8108558654785'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:92.30701446533203 min:-566.9862060546875 avg:-386.1558208465576'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:87.41224670410156 min:-570.6748046875 avg:-390.05077743530273'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:101.1277084350586 min:-591.370849609375 avg:-402.21013832092285'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:99.28174591064453 min:-583.9794311523438 avg:-396.85587882995605'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:101.23909759521484 min:-575.0882568359375 avg:-389.88413429260254'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:99.14440155029297 min:-587.292236328125 avg:-400.210542678833'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:97.56256103515625 min:-595.4902954101562 avg:-406.7763977050781'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:98.55818176269531 min:-578.1148681640625 avg:-393.7174949645996'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:94.01976776123047 min:-586.1299438476562 avg:-400.9226551055908'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:99.00733947753906 min:-586.1040649414062 avg:-399.5240898132324'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:92.64148712158203 min:-591.7553100585938 avg:-404.43559074401855'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:99.34064483642578 min:-595.9686889648438 avg:-405.923246383667'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:95.45687866210938 min:-594.164794921875 avg:-346.78978474934894'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:87.71762084960938 min:-596.27783203125 avg:-409.9045639038086'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:88.7226333618164 min:-615.745361328125 avg:-424.6374568939209'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:77.17904663085938 min:-617.3456420898438 avg:-428.7466049194336'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:66.60687255859375 min:-602.0409545898438 avg:-419.9549255371094'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_1A max:68.06993865966797 min:-607.2240600585938 avg:-423.43663215637207'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:72.98019409179688 min:44.33061981201172 avg:58.6554069519043'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:73.14141845703125 min:-697.8825073242188 avg:-315.4262161254883'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.85009765625 min:-660.3069458007812 avg:-315.4896447956562'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.82398223876953 min:-658.5642700195312 avg:-312.5525437295437'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:110.17957305908203 min:-657.3428955078125 avg:-310.1627152959506'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:105.11672973632812 min:-659.6607666015625 avg:-312.9431072672208'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:109.0434341430664 min:-657.969970703125 avg:-311.08839579919976'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.46351623535156 min:-658.635986328125 avg:-311.37732477982837'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.73497009277344 min:-658.26123046875 avg:-310.1976529757182'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:105.22023010253906 min:-661.1139526367188 avg:-314.8850583235423'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:103.40608215332031 min:-663.711181640625 avg:-313.4423364897569'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:105.50698852539062 min:-657.6846923828125 avg:-314.7931199471156'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:105.07080078125 min:-662.5439453125 avg:-313.9543851216634'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:103.49508666992188 min:-664.4462890625 avg:-315.50828289985657'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:105.65170288085938 min:-666.6348876953125 avg:-314.0538353919983'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:95.19622802734375 min:-668.2849731445312 avg:-312.56264738241833'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:104.32560729980469 min:-662.8731689453125 avg:-311.1390511194865'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:103.47561645507812 min:-670.9737548828125 avg:-313.63718191782635'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.50050354003906 min:-660.7020263671875 avg:-310.0598319371541'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.558349609375 min:-663.382568359375 avg:-310.00783491134644'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:109.0615234375 min:-665.4400634765625 avg:-312.813982963562'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:109.49251556396484 min:-664.53662109375 avg:-311.62433036168414'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:110.06733703613281 min:-663.7449951171875 avg:-311.0591506958008'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.60169982910156 min:-665.211669921875 avg:-310.5984532038371'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.75912475585938 min:-664.94970703125 avg:-311.6798273722331'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:112.64541625976562 min:-661.4654541015625 avg:-311.6703574458758'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:110.4654541015625 min:-661.98388671875 avg:-311.4834980169932'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:110.18006134033203 min:-665.4888305664062 avg:-310.9275920391083'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.6728515625 min:-664.11328125 avg:-311.55293305714923'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:-5.211329460144043 min:-664.0961303710938 avg:-395.4391653060913'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:111.89119720458984 min:-663.6827392578125 avg:-309.35367314020795'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:104.90656280517578 min:-663.719482421875 avg:-310.86105783780414'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:110.03866577148438 min:-664.8309936523438 avg:-310.55614344278973'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:110.8860855102539 min:-662.5736083984375 avg:-308.9442750612895'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:101.48294067382812 min:-664.5765380859375 avg:-310.9180740515391'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.05557250976562 min:-670.8319091796875 avg:-310.54196349779767'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:107.17411804199219 min:-664.064453125 avg:-308.8870423634847'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.15419006347656 min:-663.8841552734375 avg:-310.5395113627116'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:105.54911804199219 min:-657.5277099609375 avg:-305.73939180374146'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:105.23336029052734 min:-654.2709350585938 avg:-305.56247663497925'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:111.20709228515625 min:-648.608154296875 avg:-305.1951592365901'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:105.93788146972656 min:-653.4193725585938 avg:-301.7647626399994'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:106.77233123779297 min:-645.1931762695312 avg:-302.77477573851746'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:108.84760284423828 min:-636.0089721679688 avg:-300.1654983361562'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:100.03377532958984 min:-635.2426147460938 avg:-304.09274355570477'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:107.90357971191406 min:-636.1097412109375 avg:-302.0796302159627'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:104.94806671142578 min:-622.2904663085938 avg:-293.53021081288654'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:103.79703521728516 min:-619.224365234375 avg:-296.3136118253072'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:96.04676055908203 min:-596.961669921875 avg:-297.86900329589844'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:101.1191635131836 min:-599.5789184570312 avg:-293.34946155548096'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:102.87995910644531 min:-595.3726806640625 avg:-289.6142177581787'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:101.22200012207031 min:-579.6573486328125 avg:-294.00013097127277'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:106.83589172363281 min:-573.9298095703125 avg:-290.5727895100911'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:101.11499786376953 min:-565.5689697265625 avg:-288.8283093770345'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:92.41999053955078 min:-537.0035400390625 avg:-286.43282953898114'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:87.60038757324219 min:-528.8983764648438 avg:-284.9327163696289'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:94.92108154296875 min:-532.5007934570312 avg:-284.06339772542316'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:85.56082153320312 min:-519.64501953125 avg:-283.5150324503581'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:92.7327880859375 min:-512.9339599609375 avg:-277.14007059733075'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:73.34950256347656 min:-509.7351989746094 avg:-349.01039123535156'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:-438.1300354003906 min:-488.1855773925781 avg:-467.0032196044922'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'camera_name:AE_08 max:80.35160064697266 min:-502.1229248046875 avg:-353.15750579833986'"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"for camera_name in affinity_matrix.keys():\n",
" # 所有帧的相似度矩阵\n",
" all_matrix = affinity_matrix[camera_name]\n",
" # 遍历每一帧的相似度矩阵(几个检测目标对应几个值)\n",
" for element_matrix in all_matrix:\n",
" if len(element_matrix) == 1:\n",
" continue\n",
" display(\n",
" f\"camera_name:{camera_name} max:{max(element_matrix)} min:{min(element_matrix)} avg:{sum(element_matrix)/len(element_matrix)}\"\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dict_keys(['1'])"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"(63, 133, 3)"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display(all_3d_kps.keys())\n",
"display(np.array(all_3d_kps['1']).shape)\n",
"# with open(\"samples/QuanCheng_res.json\", \"wb\") as f:\n",
"# f.write(orjson.dumps(all_3d_kps))\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'\\nall_frame_detections = []\\nfor i in range(800):\\n detections = next(sync_gen)\\n # 筛选关键点\\n\\n filter_detections = []\\n for element in detections:\\n filter_box_points_3d = calculater_box_3d_points()\\n box_points_2d = calculater_box_2d_points(filter_box_points_3d, element.camera)\\n box_triangles_all_points = calculater_box_common_scope(box_points_2d)\\n union_area, union_polygon = calculate_triangle_union(box_triangles_all_points)\\n contours = get_contours(union_polygon)\\n \\n # 筛选目标框里的数据\\n if filter_kps_box(element.keypoints, contours):\\n filter_detections.append(element)\\n # 判断筛选后的数据是否为空\\n if len(filter_detections)>2:\\n all_frame_detections.append(triangle_from_cluster(filter_detections).tolist())\\n\\n # 筛选只剩一个人的数据直接进行DLT\\n# res = {\"a\": all_frame_detections}\\n# display(res)\\nwith open(\"samples/QuanCheng_res.json\", \"wb\") as f:\\n f.write(orjson.dumps(all_frame_detections))\\n'"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 直接导入全部检测数据,在此处进行筛选\n",
"'''\n",
"all_frame_detections = []\n",
"for i in range(800):\n",
" detections = next(sync_gen)\n",
" # 筛选关键点\n",
"\n",
" filter_detections = []\n",
" for element in detections:\n",
" filter_box_points_3d = calculater_box_3d_points()\n",
" box_points_2d = calculater_box_2d_points(filter_box_points_3d, element.camera)\n",
" box_triangles_all_points = calculater_box_common_scope(box_points_2d)\n",
" union_area, union_polygon = calculate_triangle_union(box_triangles_all_points)\n",
" contours = get_contours(union_polygon)\n",
" \n",
" # 筛选目标框里的数据\n",
" if filter_kps_box(element.keypoints, contours):\n",
" filter_detections.append(element)\n",
" # 判断筛选后的数据是否为空\n",
" if len(filter_detections)>2:\n",
" all_frame_detections.append(triangle_from_cluster(filter_detections).tolist())\n",
"\n",
" # 筛选只剩一个人的数据直接进行DLT\n",
"# res = {\"a\": all_frame_detections}\n",
"# display(res)\n",
"with open(\"samples/QuanCheng_res.json\", \"wb\") as f:\n",
" f.write(orjson.dumps(all_frame_detections))\n",
"'''"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'display(len(detections))'"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"'''display(len(detections))'''"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"# 极限约束\n",
"# from app.camera import calculate_affinity_matrix_by_epipolar_constraint\n",
"\n",
"# sorted_detections, affinity_matrix = calculate_affinity_matrix_by_epipolar_constraint(\n",
"# detections, alpha_2d=3500\n",
"# )"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"# display(\n",
"# list(\n",
"# map(\n",
"# lambda x: {\n",
"# \"timestamp\": str(x.timestamp),\n",
"# \"camera\": x.camera.id,\n",
"# \"keypoint\": x.keypoints.shape,\n",
"# },\n",
"# sorted_detections,\n",
"# )\n",
"# )\n",
"# )\n",
"# with jnp.printoptions(precision=3, suppress=True):\n",
"# display(affinity_matrix)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"# from app.solver._old import GLPKSolver\n",
"\n",
"\n",
"# def clusters_to_detections(\n",
"# clusters: list[list[int]], sorted_detections: list[Detection]\n",
"# ) -> list[list[Detection]]:\n",
"# \"\"\"\n",
"# given a list of clusters (which is the indices of the detections in the sorted_detections list),\n",
"# extract the detections from the sorted_detections list\n",
"\n",
"# Args:\n",
"# clusters: list of clusters, each cluster is a list of indices of the detections in the `sorted_detections` list\n",
"# sorted_detections: list of SORTED detections\n",
"\n",
"# Returns:\n",
"# list of clusters, each cluster is a list of detections\n",
"# \"\"\"\n",
"# return [[sorted_detections[i] for i in cluster] for cluster in clusters]\n",
"\n",
"\n",
"# solver = GLPKSolver()\n",
"# aff_np = np.asarray(affinity_matrix).astype(np.float64)\n",
"# clusters, sol_matrix = solver.solve(aff_np)\n",
"# display(clusters)\n",
"# display(sol_matrix)"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"# WIDTH = 2560\n",
"# HEIGHT = 1440\n",
"\n",
"# clusters_detections = clusters_to_detections(clusters, sorted_detections)\n",
"# im = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)\n",
"# for el in clusters_detections[0]:\n",
"# im = visualize_whole_body(np.asarray(el.keypoints), im)\n",
"\n",
"# p = plt.imshow(im)\n",
"# display(p)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"# im_prime = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)\n",
"# for el in clusters_detections[1]:\n",
"# im_prime = visualize_whole_body(np.asarray(el.keypoints), im_prime)\n",
"\n",
"# p_prime = plt.imshow(im_prime)\n",
"# display(p_prime)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [],
"source": [
"# def triangle_from_cluster(cluster: list[Detection]) -> Float[Array, \"3\"]:\n",
"# proj_matrices = jnp.array([el.camera.params.projection_matrix for el in cluster])\n",
"# points = jnp.array([el.keypoints for el in cluster])\n",
"# confidences = jnp.array([el.confidences for el in cluster])\n",
"# return triangulate_points_from_multiple_views_linear(\n",
"# proj_matrices, points, confidences=confidences\n",
"# )\n",
"\n",
"\n",
"# res = {\n",
"# \"a\": triangle_from_cluster(clusters_detections[0]).tolist(),\n",
"# \"b\": triangle_from_cluster(clusters_detections[1]).tolist(),\n",
"# }\n",
"# with open(\"samples/QuanCheng_res.json\", \"wb\") as f:\n",
"# f.write(orjson.dumps(res))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}