ovkit 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. ovkit-0.2.0/README.md → ovkit-0.3.0/PKG-INFO +100 -0
  2. ovkit-0.2.0/PKG-INFO → ovkit-0.3.0/README.md +44 -45
  3. {ovkit-0.2.0 → ovkit-0.3.0}/pyproject.toml +4 -2
  4. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/__init__.py +11 -1
  5. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/__main__.py +52 -1
  6. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/i18n.py +8 -0
  7. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/results.py +1 -1
  8. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/__init__.py +14 -0
  9. ovkit-0.3.0/src/ovkit/pipelines/classroom.py +380 -0
  10. ovkit-0.3.0/src/ovkit/pipelines/teach.py +452 -0
  11. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/detect.py +4 -1
  12. ovkit-0.3.0/src/ovkit/rtdetr/__init__.py +218 -0
  13. ovkit-0.3.0/src/ovkit/rtdetr/data/__init__.py +1 -0
  14. ovkit-0.3.0/src/ovkit/rtdetr/data/dataset.py +127 -0
  15. ovkit-0.3.0/src/ovkit/rtdetr/exporter.py +44 -0
  16. ovkit-0.3.0/src/ovkit/rtdetr/nn/__init__.py +1 -0
  17. ovkit-0.3.0/src/ovkit/rtdetr/nn/backbone.py +107 -0
  18. ovkit-0.3.0/src/ovkit/rtdetr/nn/decoder.py +145 -0
  19. ovkit-0.3.0/src/ovkit/rtdetr/nn/encoder.py +113 -0
  20. ovkit-0.3.0/src/ovkit/rtdetr/nn/rtdetr_net.py +45 -0
  21. ovkit-0.3.0/src/ovkit/rtdetr/trainer.py +150 -0
  22. ovkit-0.3.0/src/ovkit/rtdetr/utils/__init__.py +1 -0
  23. ovkit-0.3.0/src/ovkit/rtdetr/utils/loss.py +111 -0
  24. ovkit-0.3.0/src/ovkit/rtdetr/utils/ops.py +63 -0
  25. ovkit-0.3.0/src/ovkit/rtdetr/validator.py +119 -0
  26. {ovkit-0.2.0 → ovkit-0.3.0}/.gitignore +0 -0
  27. {ovkit-0.2.0 → ovkit-0.3.0}/LICENSE +0 -0
  28. {ovkit-0.2.0 → ovkit-0.3.0}/examples/README.md +0 -0
  29. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/audio/__init__.py +0 -0
  30. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/audio/ops.py +0 -0
  31. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/audio/plot.py +0 -0
  32. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/__init__.py +0 -0
  33. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/backend.py +0 -0
  34. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/constants.py +0 -0
  35. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/convert.py +0 -0
  36. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/download.py +0 -0
  37. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/errors.py +0 -0
  38. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/model.py +0 -0
  39. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/registry.py +0 -0
  40. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/core/tasks.py +0 -0
  41. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/data/imagenet1000.txt +0 -0
  42. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/face/__init__.py +0 -0
  43. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/face/analyzer.py +0 -0
  44. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/genai/__init__.py +0 -0
  45. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/genai/pipelines.py +0 -0
  46. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/gui/__init__.py +0 -0
  47. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/gui/app.py +0 -0
  48. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/gui/controller.py +0 -0
  49. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/image/__init__.py +0 -0
  50. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/image/ops.py +0 -0
  51. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/manifests/aliases.yaml +0 -0
  52. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/manifests/genai.yaml +0 -0
  53. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/manifests/labels.yaml +0 -0
  54. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/manifests/models.yaml +0 -0
  55. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/manifests/omz.yaml +0 -0
  56. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/analyze.py +0 -0
  57. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/attention.py +0 -0
  58. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/base.py +0 -0
  59. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/gaze.py +0 -0
  60. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/plates.py +0 -0
  61. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/privacy.py +0 -0
  62. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/reid.py +0 -0
  63. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/scene.py +0 -0
  64. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/temporal.py +0 -0
  65. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/text.py +0 -0
  66. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/pipelines/tracking.py +0 -0
  67. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/py.typed +0 -0
  68. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/__init__.py +0 -0
  69. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/audio.py +0 -0
  70. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/base.py +0 -0
  71. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/classify.py +0 -0
  72. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/face.py +0 -0
  73. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/generic.py +0 -0
  74. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/ocr.py +0 -0
  75. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/pose.py +0 -0
  76. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/recognize/segment.py +0 -0
  77. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/solutions/__init__.py +0 -0
  78. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/solutions/anomaly.py +0 -0
  79. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/solutions/ocr.py +0 -0
  80. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/solutions/reid.py +0 -0
  81. {ovkit-0.2.0 → ovkit-0.3.0}/src/ovkit/solutions/tracking.py +0 -0
@@ -1,3 +1,59 @@
1
+ Metadata-Version: 2.5
2
+ Name: ovkit
3
+ Version: 0.3.0
4
+ Summary: A simple Python inference API for OpenVINO: one import, one Model class, clean Results — with AUTO/NPU, async, and INT8.
5
+ Project-URL: Homepage, https://github.com/leeyunjai82/ovkit
6
+ Project-URL: Documentation, https://leeyunjai82.github.io/ovkit/
7
+ Project-URL: Repository, https://github.com/leeyunjai82/ovkit
8
+ Project-URL: Issues, https://github.com/leeyunjai82/ovkit/issues
9
+ Project-URL: Models, https://huggingface.co/leeyunjai/ovkit-models
10
+ Author: ovkit contributors
11
+ License: Apache-2.0
12
+ License-File: LICENSE
13
+ Keywords: computer-vision,detection,inference,npu,openvino,quantization
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: huggingface-hub>=0.20
23
+ Requires-Dist: numpy>=1.21
24
+ Requires-Dist: opencv-python-headless>=4.5
25
+ Requires-Dist: openvino>=2024.0
26
+ Requires-Dist: pillow>=9.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Provides-Extra: all
29
+ Requires-Dist: anomalib; extra == 'all'
30
+ Requires-Dist: nncf; extra == 'all'
31
+ Requires-Dist: onnx; extra == 'all'
32
+ Requires-Dist: openvino-genai; extra == 'all'
33
+ Requires-Dist: optimum-intel; extra == 'all'
34
+ Requires-Dist: scipy; extra == 'all'
35
+ Requires-Dist: torch>=2.0; extra == 'all'
36
+ Requires-Dist: torchvision>=0.15; extra == 'all'
37
+ Provides-Extra: anomaly
38
+ Requires-Dist: anomalib; extra == 'anomaly'
39
+ Provides-Extra: dev
40
+ Requires-Dist: black; extra == 'dev'
41
+ Requires-Dist: pytest>=7; extra == 'dev'
42
+ Requires-Dist: ruff; extra == 'dev'
43
+ Provides-Extra: genai
44
+ Requires-Dist: openvino-genai; extra == 'genai'
45
+ Requires-Dist: optimum-intel; extra == 'genai'
46
+ Provides-Extra: hand
47
+ Requires-Dist: mediapipe; extra == 'hand'
48
+ Provides-Extra: quant
49
+ Requires-Dist: nncf; extra == 'quant'
50
+ Provides-Extra: train
51
+ Requires-Dist: onnx; extra == 'train'
52
+ Requires-Dist: scipy; extra == 'train'
53
+ Requires-Dist: torch>=2.0; extra == 'train'
54
+ Requires-Dist: torchvision>=0.15; extra == 'train'
55
+ Description-Content-Type: text/markdown
56
+
1
57
  <div align="center">
2
58
 
3
59
  <img src="https://raw.githubusercontent.com/leeyunjai82/ovkit/main/docs/_static/logo.svg" width="110" alt="ovkit logo"/>
@@ -93,6 +149,11 @@ camera index).
93
149
  | `attention` | `1 person looking at: laptop` | gaze + object detection (ray-cast into the boxes) |
94
150
  | `anonymize` | the picture with every face pixelated | face (and plate) detection + redaction |
95
151
  | `face_match` | `('yunjai', 0.81)` — who this is | embedding + cosine matching against your gallery |
152
+ | `count` | `pencil 3 · cup 1` (optionally one kind only) | detection + per-kind tally |
153
+ | `posture` | `neck 32° — sit up (6s)` | pose + neck angle **over time** |
154
+ | `exercise` | `squat x 12 (down)` | pose + joint-angle hysteresis (squat, push-up) |
155
+ | `attendance` | `present 24/26` + `roll.csv` | face detection + roster matching |
156
+ | `teach` | your own classes, from example photos | embedding + cosine k-NN (5 modes) |
96
157
 
97
158
  ```python
98
159
  from ovkit import Model, list_pipelines
@@ -104,6 +165,45 @@ Model("face_analyze", attributes=("age_gender",)) # configure what runs
104
165
  ```
105
166
 
106
167
  Aliases: `ocr`, `anpr`, `blur`, `driver`, `describe`, `faces`, `people`, `vehicle`, `tracking`, `reid`.
168
+
169
+ ## Teach your own AI (no GPU)
170
+
171
+ A Teachable Machine in five lines — an embedding model turns examples into
172
+ vectors, new inputs match the nearest ones. Five modes: `photo` (default),
173
+ `face` (expressions), `hand` (needs `ovkit[hand]`), `upper`, `body`:
174
+
175
+ ```python
176
+ ai = Model("teach") # or Model("가르치기")
177
+ ai.learn("can", "photos/cans/") # a folder per thing to recognise
178
+ ai.learn("bottle", "photos/bottles/")
179
+ print(ai.guess("new_photo.jpg")) # ('can', 0.93)
180
+ print(ai.score("test_photos/")) # accuracy + what it confuses
181
+ ai.save("recycling") # -> Documents/ovkit/recycling.json
182
+ for r in ai.predict(0, stream=True): ... # webcam over YOUR classes
183
+ ```
184
+
185
+ Korean method names work too: `배우기`, `맞혀봐`, `점수`, `저장`. Collect
186
+ examples with the webcam: `from ovkit.pipelines.teach import collect; collect("가위", 30)`.
187
+
188
+ ## Train your own detector
189
+
190
+ RT-DETR, trainable, Apache-2.0 end to end — an Ultralytics-style workflow with
191
+ no AGPL code or weights anywhere (`pip install "ovkit[train]"`):
192
+
193
+ ```python
194
+ from ovkit import RTDETR
195
+
196
+ model = RTDETR("rtdetr-r18") # or RTDETR("best.pt") to resume
197
+ model.train(data="data.yaml", epochs=100) # the YOLO-format labels you already have
198
+ model.val(data="data.yaml") # mAP50 / mAP50-95
199
+ model.export(half=True) # -> IR + labels.txt
200
+
201
+ r = model("bus.jpg", conf=0.5) # ovkit Results: print(r), r.found, r.save()
202
+ ```
203
+
204
+ The exported IR drops straight into `Model("path/to/rtdetr-r18.xml")` — the
205
+ `labels.txt` written next to it means your classes answer by name. CLI:
206
+ `ovkit train --data data.yaml`, `ovkit val`, `ovkit export`.
107
207
  `ovkit capabilities` prints the list; **`ovkit gui` opens a window** where you can
108
208
  click through them against your webcam or a picture.
109
209
 
@@ -1,48 +1,3 @@
1
- Metadata-Version: 2.5
2
- Name: ovkit
3
- Version: 0.2.0
4
- Summary: A simple Python inference API for OpenVINO: one import, one Model class, clean Results — with AUTO/NPU, async, and INT8.
5
- Project-URL: Homepage, https://github.com/leeyunjai82/ovkit
6
- Project-URL: Documentation, https://leeyunjai82.github.io/ovkit/
7
- Project-URL: Repository, https://github.com/leeyunjai82/ovkit
8
- Project-URL: Issues, https://github.com/leeyunjai82/ovkit/issues
9
- Project-URL: Models, https://huggingface.co/leeyunjai/ovkit-models
10
- Author: ovkit contributors
11
- License: Apache-2.0
12
- License-File: LICENSE
13
- Keywords: computer-vision,detection,inference,npu,openvino,quantization
14
- Classifier: Development Status :: 3 - Alpha
15
- Classifier: License :: OSI Approved :: Apache Software License
16
- Classifier: Operating System :: OS Independent
17
- Classifier: Programming Language :: Python :: 3.10
18
- Classifier: Programming Language :: Python :: 3.11
19
- Classifier: Programming Language :: Python :: 3.12
20
- Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
- Requires-Python: >=3.10
22
- Requires-Dist: huggingface-hub>=0.20
23
- Requires-Dist: numpy>=1.21
24
- Requires-Dist: opencv-python-headless>=4.5
25
- Requires-Dist: openvino>=2024.0
26
- Requires-Dist: pillow>=9.0
27
- Requires-Dist: pyyaml>=6.0
28
- Provides-Extra: all
29
- Requires-Dist: anomalib; extra == 'all'
30
- Requires-Dist: nncf; extra == 'all'
31
- Requires-Dist: openvino-genai; extra == 'all'
32
- Requires-Dist: optimum-intel; extra == 'all'
33
- Provides-Extra: anomaly
34
- Requires-Dist: anomalib; extra == 'anomaly'
35
- Provides-Extra: dev
36
- Requires-Dist: black; extra == 'dev'
37
- Requires-Dist: pytest>=7; extra == 'dev'
38
- Requires-Dist: ruff; extra == 'dev'
39
- Provides-Extra: genai
40
- Requires-Dist: openvino-genai; extra == 'genai'
41
- Requires-Dist: optimum-intel; extra == 'genai'
42
- Provides-Extra: quant
43
- Requires-Dist: nncf; extra == 'quant'
44
- Description-Content-Type: text/markdown
45
-
46
1
  <div align="center">
47
2
 
48
3
  <img src="https://raw.githubusercontent.com/leeyunjai82/ovkit/main/docs/_static/logo.svg" width="110" alt="ovkit logo"/>
@@ -138,6 +93,11 @@ camera index).
138
93
  | `attention` | `1 person looking at: laptop` | gaze + object detection (ray-cast into the boxes) |
139
94
  | `anonymize` | the picture with every face pixelated | face (and plate) detection + redaction |
140
95
  | `face_match` | `('yunjai', 0.81)` — who this is | embedding + cosine matching against your gallery |
96
+ | `count` | `pencil 3 · cup 1` (optionally one kind only) | detection + per-kind tally |
97
+ | `posture` | `neck 32° — sit up (6s)` | pose + neck angle **over time** |
98
+ | `exercise` | `squat x 12 (down)` | pose + joint-angle hysteresis (squat, push-up) |
99
+ | `attendance` | `present 24/26` + `roll.csv` | face detection + roster matching |
100
+ | `teach` | your own classes, from example photos | embedding + cosine k-NN (5 modes) |
141
101
 
142
102
  ```python
143
103
  from ovkit import Model, list_pipelines
@@ -149,6 +109,45 @@ Model("face_analyze", attributes=("age_gender",)) # configure what runs
149
109
  ```
150
110
 
151
111
  Aliases: `ocr`, `anpr`, `blur`, `driver`, `describe`, `faces`, `people`, `vehicle`, `tracking`, `reid`.
112
+
113
+ ## Teach your own AI (no GPU)
114
+
115
+ A Teachable Machine in five lines — an embedding model turns examples into
116
+ vectors, new inputs match the nearest ones. Five modes: `photo` (default),
117
+ `face` (expressions), `hand` (needs `ovkit[hand]`), `upper`, `body`:
118
+
119
+ ```python
120
+ ai = Model("teach") # or Model("가르치기")
121
+ ai.learn("can", "photos/cans/") # a folder per thing to recognise
122
+ ai.learn("bottle", "photos/bottles/")
123
+ print(ai.guess("new_photo.jpg")) # ('can', 0.93)
124
+ print(ai.score("test_photos/")) # accuracy + what it confuses
125
+ ai.save("recycling") # -> Documents/ovkit/recycling.json
126
+ for r in ai.predict(0, stream=True): ... # webcam over YOUR classes
127
+ ```
128
+
129
+ Korean method names work too: `배우기`, `맞혀봐`, `점수`, `저장`. Collect
130
+ examples with the webcam: `from ovkit.pipelines.teach import collect; collect("가위", 30)`.
131
+
132
+ ## Train your own detector
133
+
134
+ RT-DETR, trainable, Apache-2.0 end to end — an Ultralytics-style workflow with
135
+ no AGPL code or weights anywhere (`pip install "ovkit[train]"`):
136
+
137
+ ```python
138
+ from ovkit import RTDETR
139
+
140
+ model = RTDETR("rtdetr-r18") # or RTDETR("best.pt") to resume
141
+ model.train(data="data.yaml", epochs=100) # the YOLO-format labels you already have
142
+ model.val(data="data.yaml") # mAP50 / mAP50-95
143
+ model.export(half=True) # -> IR + labels.txt
144
+
145
+ r = model("bus.jpg", conf=0.5) # ovkit Results: print(r), r.found, r.save()
146
+ ```
147
+
148
+ The exported IR drops straight into `Model("path/to/rtdetr-r18.xml")` — the
149
+ `labels.txt` written next to it means your classes answer by name. CLI:
150
+ `ovkit train --data data.yaml`, `ovkit val`, `ovkit export`.
152
151
  `ovkit capabilities` prints the list; **`ovkit gui` opens a window** where you can
153
152
  click through them against your webcam or a picture.
154
153
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ovkit"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "A simple Python inference API for OpenVINO: one import, one Model class, clean Results — with AUTO/NPU, async, and INT8."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -33,7 +33,9 @@ dependencies = [
33
33
  genai = ["openvino-genai", "optimum-intel"]
34
34
  anomaly = ["anomalib"]
35
35
  quant = ["nncf"]
36
- all = ["openvino-genai", "optimum-intel", "anomalib", "nncf"]
36
+ train = ["torch>=2.0", "torchvision>=0.15", "scipy", "onnx"]
37
+ hand = ["mediapipe"]
38
+ all = ["openvino-genai", "optimum-intel", "anomalib", "nncf", "torch>=2.0", "torchvision>=0.15", "scipy", "onnx"]
37
39
  dev = ["pytest>=7", "ruff", "black"]
38
40
 
39
41
  [project.urls]
@@ -40,10 +40,20 @@ from .core.registry import list_models
40
40
  from .core.results import Boxes, Keypoints, Masks, Probs, Results
41
41
  from .pipelines import Pipeline, list_pipelines
42
42
 
43
- __version__ = "0.2.0"
43
+ __version__ = "0.3.0"
44
+
45
+
46
+ def __getattr__(name: str): # lazy: keeps `import ovkit` free of the train stack
47
+ if name == "RTDETR":
48
+ from .rtdetr import RTDETR
49
+
50
+ return RTDETR
51
+ raise AttributeError(f"module 'ovkit' has no attribute {name!r}")
52
+
44
53
 
45
54
  __all__ = [
46
55
  "Model",
56
+ "RTDETR",
47
57
  "Pipeline",
48
58
  "list_pipelines",
49
59
  "Results",
@@ -1,4 +1,4 @@
1
- """``ovkit`` command-line interface: ``gui``, ``run``, ``list``, ``info``, ``download``, ``devices``."""
1
+ """``ovkit`` CLI: ``gui``, ``run``, ``train``, ``val``, ``export``, ``list``, ``info``, ``download``, ``devices``."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -132,6 +132,33 @@ def _cmd_gui(args: argparse.Namespace) -> int:
132
132
  return gui_main(device=args.device, camera=args.camera)
133
133
 
134
134
 
135
+ def _cmd_train(args: argparse.Namespace) -> int:
136
+ """Train RT-DETR on YOLO-format data: ``ovkit train --data data.yaml``."""
137
+ from .rtdetr import RTDETR
138
+
139
+ model = RTDETR(args.model, device=args.device)
140
+ best = model.train(
141
+ data=args.data, epochs=args.epochs, imgsz=args.imgsz, batch=args.batch, lr=args.lr
142
+ )
143
+ print(f"best checkpoint: {best}")
144
+ return 0
145
+
146
+
147
+ def _cmd_val(args: argparse.Namespace) -> int:
148
+ from .rtdetr import RTDETR
149
+
150
+ RTDETR(args.model, device=args.device).val(data=args.data, imgsz=args.imgsz)
151
+ return 0
152
+
153
+
154
+ def _cmd_export(args: argparse.Namespace) -> int:
155
+ from .rtdetr import RTDETR
156
+
157
+ out = RTDETR(args.model).export(imgsz=args.imgsz, half=args.half, out_dir=args.out)
158
+ print(f"exported: {out} (+ labels.txt)")
159
+ return 0
160
+
161
+
135
162
  def main(argv: list[str] | None = None) -> int:
136
163
  """CLI entry point. Returns a process exit code."""
137
164
  parser = argparse.ArgumentParser(prog="ovkit", description="ovkit model utilities")
@@ -158,6 +185,30 @@ def main(argv: list[str] | None = None) -> int:
158
185
  p_dl.add_argument("--no-convert", action="store_true", help="skip IR conversion")
159
186
  p_dl.set_defaults(func=_cmd_download)
160
187
 
188
+ p_train = sub.add_parser("train", help="train RT-DETR on your own data (needs ovkit[train])")
189
+ p_train.add_argument("--data", required=True, help="data.yaml (YOLO format)")
190
+ p_train.add_argument("--model", default="rtdetr-r18", help="variant or a .pt to resume")
191
+ p_train.add_argument("--epochs", type=int, default=100)
192
+ p_train.add_argument("--imgsz", type=int, default=640)
193
+ p_train.add_argument("--batch", type=int, default=8)
194
+ p_train.add_argument("--lr", type=float, default=1e-4)
195
+ p_train.add_argument("--device", default=None)
196
+ p_train.set_defaults(func=_cmd_train)
197
+
198
+ p_val = sub.add_parser("val", help="mAP on the val split of a data.yaml")
199
+ p_val.add_argument("--model", required=True, help="a trained .pt")
200
+ p_val.add_argument("--data", required=True)
201
+ p_val.add_argument("--imgsz", type=int, default=640)
202
+ p_val.add_argument("--device", default=None)
203
+ p_val.set_defaults(func=_cmd_val)
204
+
205
+ p_exp = sub.add_parser("export", help="export a trained .pt to OpenVINO IR + labels.txt")
206
+ p_exp.add_argument("--model", required=True, help="a trained .pt")
207
+ p_exp.add_argument("--imgsz", type=int, default=640)
208
+ p_exp.add_argument("--half", action="store_true", help="FP16 IR")
209
+ p_exp.add_argument("--out", default=".", help="output directory")
210
+ p_exp.set_defaults(func=_cmd_export)
211
+
161
212
  p_dev = sub.add_parser("devices", help="list OpenVINO devices")
162
213
  p_dev.set_defaults(func=_cmd_devices)
163
214
 
@@ -46,6 +46,14 @@ KO_CAPS: dict[str, str] = {
46
46
  "얼굴가리기": "anonymize",
47
47
  "모자이크": "anonymize",
48
48
  "누구지": "face_match",
49
+ "가르치기": "teach",
50
+ "내가가르치기": "teach",
51
+ "개수세기": "count",
52
+ "거북목": "posture",
53
+ "거북목알림": "posture",
54
+ "운동횟수": "exercise",
55
+ "출석체크": "attendance",
56
+ "출석": "attendance",
49
57
  # single-model aliases (registry)
50
58
  "물체찾기": "detect",
51
59
  "이건뭐야": "classify",
@@ -429,7 +429,7 @@ class Results:
429
429
  if self.masks is not None and len(self.masks):
430
430
  parts.append(self._mask_summary(max_items))
431
431
 
432
- if self.keypoints is not None:
432
+ if self.keypoints is not None and not self.text:
433
433
  n, k = self.keypoints.data.shape[0], self.keypoints.data.shape[1]
434
434
  parts.append(f"{n} instance(s), {k} keypoints")
435
435
 
@@ -25,11 +25,13 @@ from typing import Any
25
25
  from .analyze import FaceAnalyzer, PersonAnalyzer, VehicleAnalyzer
26
26
  from .attention import AttentionAnalyzer
27
27
  from .base import Pipeline
28
+ from .classroom import Attendance, Counter, PostureCoach, RepCounter
28
29
  from .gaze import GazeEstimator
29
30
  from .plates import PlateReader
30
31
  from .privacy import Anonymizer
31
32
  from .reid import ReID
32
33
  from .scene import SceneReport
34
+ from .teach import Teach
33
35
  from .temporal import DrowsinessMonitor, GestureRecognizer
34
36
  from .text import TextReader
35
37
  from .tracking import Tracker
@@ -54,6 +56,13 @@ PIPELINES: dict[str, type[Pipeline]] = {
54
56
  # identity: match it, or remove it
55
57
  "face_match": ReID,
56
58
  "anonymize": Anonymizer,
59
+ # make your own
60
+ "teach": Teach,
61
+ # classroom
62
+ "count": Counter,
63
+ "posture": PostureCoach,
64
+ "exercise": RepCounter,
65
+ "attendance": Attendance,
57
66
  }
58
67
 
59
68
  #: Friendlier spellings people reach for first.
@@ -162,4 +171,9 @@ __all__ = [
162
171
  "GestureRecognizer",
163
172
  "PlateReader",
164
173
  "SceneReport",
174
+ "Teach",
175
+ "Attendance",
176
+ "Counter",
177
+ "PostureCoach",
178
+ "RepCounter",
165
179
  ]