From 33e987d8d9cadd852a68a9c95ad2b2e9b01ff255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EC=B0=BD=EC=9A=B1?= Date: Sat, 11 Jul 2026 20:13:00 +0900 Subject: [PATCH] feat(edge): data models (Keypoint, BBox, Person) + COCO indices --- edge/__init__.py | 0 edge/models.py | 51 ++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 12 +++++++++++ tests/test_models.py | 21 ++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 edge/__init__.py create mode 100644 edge/models.py create mode 100644 pyproject.toml create mode 100644 tests/test_models.py diff --git a/edge/__init__.py b/edge/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/edge/models.py b/edge/models.py new file mode 100644 index 0000000..c7fc616 --- /dev/null +++ b/edge/models.py @@ -0,0 +1,51 @@ +from dataclasses import dataclass + +# COCO-17 keypoint indices +NOSE = 0 +L_EYE, R_EYE, L_EAR, R_EAR = 1, 2, 3, 4 +L_SHOULDER, R_SHOULDER = 5, 6 +L_ELBOW, R_ELBOW, L_WRIST, R_WRIST = 7, 8, 9, 10 +L_HIP, R_HIP = 11, 12 +L_KNEE, R_KNEE, L_ANKLE, R_ANKLE = 13, 14, 15, 16 +CORE_JOINTS = (L_SHOULDER, R_SHOULDER, L_HIP, R_HIP) + + +@dataclass(frozen=True) +class Keypoint: + x: float + y: float + conf: float + + +@dataclass(frozen=True) +class BBox: + x1: float + y1: float + x2: float + y2: float + + @property + def width(self) -> float: + return self.x2 - self.x1 + + @property + def height(self) -> float: + return self.y2 - self.y1 + + @property + def aspect(self) -> float: + return self.width / self.height if self.height else 0.0 + + @property + def cx(self) -> float: + return (self.x1 + self.x2) / 2 + + @property + def cy(self) -> float: + return (self.y1 + self.y2) / 2 + + +@dataclass(frozen=True) +class Person: + bbox: BBox + keypoints: list # list[Keypoint], length 17 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a75cd4d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,12 @@ +[project] +name = "move-detect-edge" +version = "0.1.0" +requires-python = ">=3.11" +dependencies = ["numpy", "opencv-python", "requests"] + +[project.optional-dependencies] +dev = ["pytest"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "-q" diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..4f5e78d --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,21 @@ +from edge.models import Keypoint, BBox, Person, L_SHOULDER, R_HIP, CORE_JOINTS + +def test_bbox_derived_properties(): + b = BBox(10, 20, 30, 80) + assert b.width == 20 + assert b.height == 60 + assert b.aspect == 20 / 60 + assert b.cx == 20 and b.cy == 50 + +def test_bbox_zero_height_aspect_is_zero(): + assert BBox(0, 0, 10, 0).aspect == 0.0 + +def test_person_holds_17_keypoints(): + kps = [Keypoint(0, 0, 0.9) for _ in range(17)] + p = Person(BBox(0, 0, 1, 1), kps) + assert len(p.keypoints) == 17 + assert p.keypoints[L_SHOULDER].conf == 0.9 + +def test_coco_index_constants(): + assert CORE_JOINTS == (5, 6, 11, 12) + assert R_HIP == 12