argus-cv 1.3.0__tar.gz → 1.5.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.
Potentially problematic release.
This version of argus-cv might be problematic. Click here for more details.
- {argus_cv-1.3.0 → argus_cv-1.5.0}/CHANGELOG.md +16 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/PKG-INFO +9 -2
- {argus_cv-1.3.0 → argus_cv-1.5.0}/README.md +8 -1
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/getting-started/installation.md +5 -5
- argus_cv-1.5.0/docs/guides/datasets.md +142 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/guides/listing.md +1 -1
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/guides/splitting.md +1 -7
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/guides/stats.md +3 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/guides/viewer.md +9 -1
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/index.md +5 -4
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/reference/cli.md +2 -3
- {argus_cv-1.3.0 → argus_cv-1.5.0}/mkdocs.yml +1 -1
- {argus_cv-1.3.0 → argus_cv-1.5.0}/pyproject.toml +1 -1
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/__init__.py +1 -1
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/cli.py +157 -14
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/core/__init__.py +12 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/core/coco.py +46 -8
- argus_cv-1.5.0/src/argus/core/convert.py +277 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/core/yolo.py +29 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/tests/conftest.py +86 -0
- argus_cv-1.5.0/tests/test_convert.py +541 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/tests/test_list_command.py +73 -0
- argus_cv-1.3.0/docs/guides/datasets.md +0 -68
- {argus_cv-1.3.0 → argus_cv-1.5.0}/.github/workflows/ci.yml +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/.github/workflows/docs.yml +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/.github/workflows/release.yml +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/.gitignore +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/.pre-commit-config.yaml +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/assets/javascripts/extra.js +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/assets/stylesheets/extra.css +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/docs/getting-started/quickstart.md +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/__main__.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/commands/__init__.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/core/base.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/core/mask.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/src/argus/core/split.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/tests/test_classification.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/tests/test_mask.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/tests/test_split_command.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/tests/test_stats_command.py +0 -0
- {argus_cv-1.3.0 → argus_cv-1.5.0}/uv.lock +0 -0
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v1.5.0 (2026-01-28)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- Support Roboflow COCO format and improve YOLO classification detection
|
|
10
|
+
([`902a59f`](https://github.com/pirnerjonas/argus/commit/902a59fbb506aa586d8677312d21ae240585b511))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## v1.4.0 (2026-01-26)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- **view**: Show polygon vertices and hide bbox for segmentation
|
|
18
|
+
([`03b34f7`](https://github.com/pirnerjonas/argus/commit/03b34f78fdafefd35a8b2594bf1296007716d6c9))
|
|
19
|
+
|
|
20
|
+
|
|
5
21
|
## v1.3.0 (2026-01-24)
|
|
6
22
|
|
|
7
23
|
### Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: argus-cv
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: CLI tool for working with vision AI datasets
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: numpy>=1.24.0
|
|
@@ -12,7 +12,7 @@ Description-Content-Type: text/markdown
|
|
|
12
12
|
|
|
13
13
|
# argus-cv
|
|
14
14
|
|
|
15
|
-
Vision AI dataset toolkit for working with YOLO and
|
|
15
|
+
Vision AI dataset toolkit for working with YOLO, COCO, and semantic mask datasets.
|
|
16
16
|
|
|
17
17
|
**[Documentation](https://pirnerjonas.github.io/argus/)**
|
|
18
18
|
|
|
@@ -22,6 +22,13 @@ Vision AI dataset toolkit for working with YOLO and COCO datasets.
|
|
|
22
22
|
uvx argus-cv
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Highlights
|
|
26
|
+
|
|
27
|
+
- Detects YOLO, COCO, and folder-based semantic mask datasets.
|
|
28
|
+
- Reports per-class stats (pixel coverage for mask datasets).
|
|
29
|
+
- Interactive viewer with bounding boxes, polygons, or mask overlays.
|
|
30
|
+
- Split unsplit YOLO/COCO datasets into train/val/test.
|
|
31
|
+
|
|
25
32
|
## Usage
|
|
26
33
|
|
|
27
34
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# argus-cv
|
|
2
2
|
|
|
3
|
-
Vision AI dataset toolkit for working with YOLO and
|
|
3
|
+
Vision AI dataset toolkit for working with YOLO, COCO, and semantic mask datasets.
|
|
4
4
|
|
|
5
5
|
**[Documentation](https://pirnerjonas.github.io/argus/)**
|
|
6
6
|
|
|
@@ -10,6 +10,13 @@ Vision AI dataset toolkit for working with YOLO and COCO datasets.
|
|
|
10
10
|
uvx argus-cv
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
- Detects YOLO, COCO, and folder-based semantic mask datasets.
|
|
16
|
+
- Reports per-class stats (pixel coverage for mask datasets).
|
|
17
|
+
- Interactive viewer with bounding boxes, polygons, or mask overlays.
|
|
18
|
+
- Split unsplit YOLO/COCO datasets into train/val/test.
|
|
19
|
+
|
|
13
20
|
## Usage
|
|
14
21
|
|
|
15
22
|
```bash
|
|
@@ -6,7 +6,7 @@ workflow.
|
|
|
6
6
|
## Quick install with uv
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
uvx argus
|
|
9
|
+
uvx argus-cv
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
`uvx` runs the package in an isolated environment and keeps it up to date.
|
|
@@ -14,19 +14,19 @@ uvx argus
|
|
|
14
14
|
Verify it works:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
argus --help
|
|
17
|
+
argus-cv --help
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## pipx
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
pipx install argus
|
|
23
|
+
pipx install argus-cv
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Verify it works:
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
argus --help
|
|
29
|
+
argus-cv --help
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
## From source
|
|
@@ -40,7 +40,7 @@ pip install -e .
|
|
|
40
40
|
Verify it works:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
argus --help
|
|
43
|
+
argus-cv --help
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
## Requirements
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Dataset formats
|
|
2
|
+
|
|
3
|
+
Argus supports YOLO, COCO, and folder-based semantic mask datasets. Detection
|
|
4
|
+
and segmentation are handled out of the box.
|
|
5
|
+
|
|
6
|
+
## YOLO
|
|
7
|
+
|
|
8
|
+
Argus looks for a YAML config file with a `names` key. It uses that file to
|
|
9
|
+
extract class names and verify the dataset layout.
|
|
10
|
+
|
|
11
|
+
Typical structure:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
dataset/
|
|
15
|
+
├── data.yaml
|
|
16
|
+
├── images/
|
|
17
|
+
│ ├── train/
|
|
18
|
+
│ ├── val/
|
|
19
|
+
│ └── test/
|
|
20
|
+
└── labels/
|
|
21
|
+
├── train/
|
|
22
|
+
├── val/
|
|
23
|
+
└── test/
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Unsplit YOLO datasets are also supported:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
dataset/
|
|
30
|
+
├── data.yaml
|
|
31
|
+
├── images/
|
|
32
|
+
└── labels/
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Argus infers the task type by scanning a few label files:
|
|
36
|
+
|
|
37
|
+
- 5 values per line: detection
|
|
38
|
+
- more than 5 values per line: segmentation polygons
|
|
39
|
+
|
|
40
|
+
## COCO
|
|
41
|
+
|
|
42
|
+
Argus looks for COCO annotation JSON files in `annotations/` or at the dataset
|
|
43
|
+
root.
|
|
44
|
+
|
|
45
|
+
Typical structure:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
dataset/
|
|
49
|
+
├── annotations/
|
|
50
|
+
│ ├── instances_train.json
|
|
51
|
+
│ ├── instances_val.json
|
|
52
|
+
│ └── instances_test.json
|
|
53
|
+
└── images/
|
|
54
|
+
├── train/
|
|
55
|
+
├── val/
|
|
56
|
+
└── test/
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If your annotation filenames include `train`, `val`, or `test`, Argus will treat
|
|
60
|
+
those as splits. Otherwise it defaults to `train`.
|
|
61
|
+
|
|
62
|
+
### Roboflow COCO
|
|
63
|
+
|
|
64
|
+
Argus also supports the Roboflow variant of COCO format, where annotations live
|
|
65
|
+
inside split directories:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
dataset/
|
|
69
|
+
├── train/
|
|
70
|
+
│ ├── _annotations.coco.json
|
|
71
|
+
│ └── *.jpg
|
|
72
|
+
├── valid/
|
|
73
|
+
│ ├── _annotations.coco.json
|
|
74
|
+
│ └── *.jpg
|
|
75
|
+
└── test/
|
|
76
|
+
├── _annotations.coco.json
|
|
77
|
+
└── *.jpg
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Splits are detected from directory names (`train`, `valid`/`val`, `test`).
|
|
81
|
+
|
|
82
|
+
## Mask (semantic segmentation)
|
|
83
|
+
|
|
84
|
+
Mask datasets are simple image + mask folders. Argus detects a few common
|
|
85
|
+
patterns:
|
|
86
|
+
|
|
87
|
+
- `images/` + `masks/`
|
|
88
|
+
- `img/` + `gt/`
|
|
89
|
+
- `leftImg8bit/` + `gtFine/` (Cityscapes-style)
|
|
90
|
+
|
|
91
|
+
Split-aware layout:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
dataset/
|
|
95
|
+
├── images/
|
|
96
|
+
│ ├── train/
|
|
97
|
+
│ └── val/
|
|
98
|
+
├── masks/
|
|
99
|
+
│ ├── train/
|
|
100
|
+
│ └── val/
|
|
101
|
+
└── classes.yaml # Optional for grayscale, required for RGB palette masks
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Unsplit layout:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
dataset/
|
|
108
|
+
├── images/
|
|
109
|
+
├── masks/
|
|
110
|
+
└── classes.yaml
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Mask encoding
|
|
114
|
+
|
|
115
|
+
- Grayscale masks: each pixel value is the class ID. Argus will auto-detect
|
|
116
|
+
class IDs if no `classes.yaml` is provided.
|
|
117
|
+
- RGB palette masks: each class maps to a color. A `classes.yaml` is required.
|
|
118
|
+
- Mask files should be `.png` and match the image stem (e.g., `frame.png`), or
|
|
119
|
+
use common suffixes like `_mask`, `_gt`, or `_label`.
|
|
120
|
+
|
|
121
|
+
Example `classes.yaml`:
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
names:
|
|
125
|
+
- background
|
|
126
|
+
- road
|
|
127
|
+
- sidewalk
|
|
128
|
+
ignore_index: 255
|
|
129
|
+
palette:
|
|
130
|
+
- id: 0
|
|
131
|
+
name: background
|
|
132
|
+
- id: 1
|
|
133
|
+
name: road
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Detection heuristics
|
|
137
|
+
|
|
138
|
+
If Argus does not detect your dataset, check the following:
|
|
139
|
+
|
|
140
|
+
- The dataset root is correct and readable.
|
|
141
|
+
- YOLO: the YAML file includes `names` as a list or dict.
|
|
142
|
+
- COCO: `images`, `annotations`, and `categories` exist in the JSON.
|
|
@@ -8,7 +8,7 @@ Use `argus-cv split` to create train/val/test splits from an unsplit dataset.
|
|
|
8
8
|
argus-cv split -d /datasets/animals -o /datasets/animals_splits
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Argus uses a 0.8/0.1/0.1 ratio and stratified sampling by default.
|
|
12
12
|
|
|
13
13
|
## Custom ratio
|
|
14
14
|
|
|
@@ -18,12 +18,6 @@ argus-cv split -d /datasets/animals -o /datasets/animals_splits -r 0.7,0.2,0.1
|
|
|
18
18
|
|
|
19
19
|
Ratios can sum to 1.0 or 100.
|
|
20
20
|
|
|
21
|
-
## Disable stratification
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
argus-cv split -d /datasets/animals -o /datasets/animals_splits --no-stratify
|
|
25
|
-
```
|
|
26
|
-
|
|
27
21
|
## Set a seed for determinism
|
|
28
22
|
|
|
29
23
|
```bash
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Stats and counts
|
|
2
2
|
|
|
3
3
|
`argus-cv stats` provides per-class instance counts and image totals by split.
|
|
4
|
+
For mask datasets, it reports pixel coverage and how many images contain each
|
|
5
|
+
class.
|
|
4
6
|
|
|
5
7
|
## Example
|
|
6
8
|
|
|
@@ -25,3 +27,4 @@ If Argus prints "No annotations found", check:
|
|
|
25
27
|
|
|
26
28
|
- YOLO: `labels/` exists and matches `images/`.
|
|
27
29
|
- COCO: annotation JSON files are valid and contain `annotations`.
|
|
30
|
+
- Mask: masks are `.png` files and match the image file names.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Visual inspection
|
|
2
2
|
|
|
3
|
-
The viewer overlays boxes and masks for quick spot checks.
|
|
3
|
+
The viewer overlays boxes and masks for quick spot checks. For mask datasets,
|
|
4
|
+
it blends the segmentation mask over the image.
|
|
4
5
|
|
|
5
6
|
## Launching the viewer
|
|
6
7
|
|
|
@@ -14,6 +15,12 @@ argus-cv view -d /datasets/retail
|
|
|
14
15
|
argus-cv view -d /datasets/retail --split val
|
|
15
16
|
```
|
|
16
17
|
|
|
18
|
+
### Adjust mask opacity
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
argus-cv view -d /datasets/roads --opacity 0.3
|
|
22
|
+
```
|
|
23
|
+
|
|
17
24
|
## Controls
|
|
18
25
|
|
|
19
26
|
- Right arrow or `N`: next image
|
|
@@ -22,6 +29,7 @@ argus-cv view -d /datasets/retail --split val
|
|
|
22
29
|
- Drag: pan while zoomed
|
|
23
30
|
- `R`: reset zoom
|
|
24
31
|
- `Q` or `Esc`: quit
|
|
32
|
+
- `T`: toggle annotations or mask overlay
|
|
25
33
|
|
|
26
34
|
## Notes
|
|
27
35
|
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
<p class="hero__eyebrow">Argus</p>
|
|
4
4
|
<h1>Vision AI dataset work, without the friction.</h1>
|
|
5
5
|
<p>
|
|
6
|
-
Argus is a focused CLI for YOLO and
|
|
7
|
-
class balance, view annotations, and split cleanly for
|
|
6
|
+
Argus is a focused CLI for YOLO, COCO, and semantic mask datasets. List
|
|
7
|
+
datasets, inspect class balance, view annotations, and split cleanly for
|
|
8
|
+
training.
|
|
8
9
|
</p>
|
|
9
10
|
<div class="hero__actions">
|
|
10
11
|
<a class="md-button md-button--primary" href="getting-started/quickstart/">Get started</a>
|
|
@@ -30,7 +31,7 @@ argus-cv view -d /data/animals --split val
|
|
|
30
31
|
<div class="grid cards">
|
|
31
32
|
<div class="card">
|
|
32
33
|
<h3>Format-aware</h3>
|
|
33
|
-
<p>Detects YOLO and
|
|
34
|
+
<p>Detects YOLO, COCO, and mask datasets by structure and metadata.</p>
|
|
34
35
|
</div>
|
|
35
36
|
<div class="card">
|
|
36
37
|
<h3>Readable statistics</h3>
|
|
@@ -38,7 +39,7 @@ argus-cv view -d /data/animals --split val
|
|
|
38
39
|
</div>
|
|
39
40
|
<div class="card">
|
|
40
41
|
<h3>Annotation viewer</h3>
|
|
41
|
-
<p>Browse images with boxes and
|
|
42
|
+
<p>Browse images with boxes, polygons, and mask overlays. Pan and zoom included.</p>
|
|
42
43
|
</div>
|
|
43
44
|
<div class="card">
|
|
44
45
|
<h3>Clean splits</h3>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Global
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
argus --help
|
|
6
|
+
argus-cv --help
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Argus uses subcommands: `list`, `stats`, `view`, and `split`.
|
|
@@ -45,6 +45,7 @@ Options:
|
|
|
45
45
|
|
|
46
46
|
- `--dataset-path`, `-d`: dataset root path
|
|
47
47
|
- `--split`, `-s`: split to view (train, val, test)
|
|
48
|
+
- `--opacity`, `-o`: mask overlay opacity (mask datasets only)
|
|
48
49
|
|
|
49
50
|
## split
|
|
50
51
|
|
|
@@ -54,7 +55,6 @@ Create train/val/test splits from an unsplit dataset.
|
|
|
54
55
|
argus-cv split --dataset-path /datasets/animals \
|
|
55
56
|
--output-path /datasets/animals_splits \
|
|
56
57
|
--ratio 0.8,0.1,0.1 \
|
|
57
|
-
--stratify \
|
|
58
58
|
--seed 42
|
|
59
59
|
```
|
|
60
60
|
|
|
@@ -63,5 +63,4 @@ Options:
|
|
|
63
63
|
- `--dataset-path`, `-d`: dataset root path
|
|
64
64
|
- `--output-path`, `-o`: output directory (default: "splits" inside dataset path)
|
|
65
65
|
- `--ratio`, `-r`: train/val/test ratio (default: 0.8,0.1,0.1)
|
|
66
|
-
- `--stratify/--no-stratify`: enable or disable stratified splitting (default: enabled)
|
|
67
66
|
- `--seed`: random seed (default: 42)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
site_name: Argus
|
|
2
|
-
site_description: Vision AI dataset toolkit for YOLO and
|
|
2
|
+
site_description: Vision AI dataset toolkit for YOLO, COCO, and mask datasets.
|
|
3
3
|
site_author: Argus
|
|
4
4
|
site_url: https://pirnerjonas.github.io/argus/
|
|
5
5
|
repo_name: pirnerjonas/argus
|
|
@@ -8,11 +8,18 @@ import cv2
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
import typer
|
|
10
10
|
from rich.console import Console
|
|
11
|
-
from rich.progress import
|
|
11
|
+
from rich.progress import (
|
|
12
|
+
BarColumn,
|
|
13
|
+
Progress,
|
|
14
|
+
SpinnerColumn,
|
|
15
|
+
TaskProgressColumn,
|
|
16
|
+
TextColumn,
|
|
17
|
+
)
|
|
12
18
|
from rich.table import Table
|
|
13
19
|
|
|
14
20
|
from argus.core import COCODataset, Dataset, MaskDataset, YOLODataset
|
|
15
21
|
from argus.core.base import DatasetFormat, TaskType
|
|
22
|
+
from argus.core.convert import convert_mask_to_yolo_seg
|
|
16
23
|
from argus.core.split import (
|
|
17
24
|
is_coco_unsplit,
|
|
18
25
|
parse_ratio,
|
|
@@ -534,13 +541,6 @@ def split_dataset(
|
|
|
534
541
|
help="Train/val/test ratio (e.g. 0.8,0.1,0.1).",
|
|
535
542
|
),
|
|
536
543
|
] = "0.8,0.1,0.1",
|
|
537
|
-
stratify: Annotated[
|
|
538
|
-
bool,
|
|
539
|
-
typer.Option(
|
|
540
|
-
"--stratify/--no-stratify",
|
|
541
|
-
help="Stratify by class distribution when splitting.",
|
|
542
|
-
),
|
|
543
|
-
] = True,
|
|
544
544
|
seed: Annotated[
|
|
545
545
|
int,
|
|
546
546
|
typer.Option(
|
|
@@ -593,9 +593,7 @@ def split_dataset(
|
|
|
593
593
|
) as progress:
|
|
594
594
|
progress.add_task("Creating YOLO splits...", total=None)
|
|
595
595
|
try:
|
|
596
|
-
counts = split_yolo_dataset(
|
|
597
|
-
dataset, output_path, ratios, stratify, seed
|
|
598
|
-
)
|
|
596
|
+
counts = split_yolo_dataset(dataset, output_path, ratios, True, seed)
|
|
599
597
|
except ValueError as exc:
|
|
600
598
|
console.print(f"[red]Error: {exc}[/red]")
|
|
601
599
|
raise typer.Exit(1) from exc
|
|
@@ -628,7 +626,7 @@ def split_dataset(
|
|
|
628
626
|
annotation_file,
|
|
629
627
|
output_path,
|
|
630
628
|
ratios,
|
|
631
|
-
|
|
629
|
+
True,
|
|
632
630
|
seed,
|
|
633
631
|
)
|
|
634
632
|
except ValueError as exc:
|
|
@@ -641,6 +639,148 @@ def split_dataset(
|
|
|
641
639
|
)
|
|
642
640
|
|
|
643
641
|
|
|
642
|
+
@app.command(name="convert")
|
|
643
|
+
def convert_dataset(
|
|
644
|
+
input_path: Annotated[
|
|
645
|
+
Path,
|
|
646
|
+
typer.Option(
|
|
647
|
+
"--input-path",
|
|
648
|
+
"-i",
|
|
649
|
+
help="Path to the source dataset.",
|
|
650
|
+
),
|
|
651
|
+
] = Path("."),
|
|
652
|
+
output_path: Annotated[
|
|
653
|
+
Path,
|
|
654
|
+
typer.Option(
|
|
655
|
+
"--output-path",
|
|
656
|
+
"-o",
|
|
657
|
+
help="Output directory for converted dataset.",
|
|
658
|
+
),
|
|
659
|
+
] = Path("converted"),
|
|
660
|
+
to_format: Annotated[
|
|
661
|
+
str,
|
|
662
|
+
typer.Option(
|
|
663
|
+
"--to",
|
|
664
|
+
help="Target format (currently only 'yolo-seg' is supported).",
|
|
665
|
+
),
|
|
666
|
+
] = "yolo-seg",
|
|
667
|
+
epsilon_factor: Annotated[
|
|
668
|
+
float,
|
|
669
|
+
typer.Option(
|
|
670
|
+
"--epsilon-factor",
|
|
671
|
+
"-e",
|
|
672
|
+
help="Polygon simplification factor (Douglas-Peucker algorithm).",
|
|
673
|
+
min=0.0,
|
|
674
|
+
max=1.0,
|
|
675
|
+
),
|
|
676
|
+
] = 0.005,
|
|
677
|
+
min_area: Annotated[
|
|
678
|
+
float,
|
|
679
|
+
typer.Option(
|
|
680
|
+
"--min-area",
|
|
681
|
+
"-a",
|
|
682
|
+
help="Minimum contour area in pixels to include.",
|
|
683
|
+
min=0.0,
|
|
684
|
+
),
|
|
685
|
+
] = 100.0,
|
|
686
|
+
) -> None:
|
|
687
|
+
"""Convert a dataset from one format to another.
|
|
688
|
+
|
|
689
|
+
Currently supports converting MaskDataset to YOLO segmentation format.
|
|
690
|
+
|
|
691
|
+
Example:
|
|
692
|
+
uvx argus-cv convert -i /path/to/masks -o /path/to/output --to yolo-seg
|
|
693
|
+
"""
|
|
694
|
+
# Validate format
|
|
695
|
+
if to_format != "yolo-seg":
|
|
696
|
+
console.print(
|
|
697
|
+
f"[red]Error: Unsupported target format '{to_format}'.[/red]\n"
|
|
698
|
+
"[yellow]Currently only 'yolo-seg' is supported.[/yellow]"
|
|
699
|
+
)
|
|
700
|
+
raise typer.Exit(1)
|
|
701
|
+
|
|
702
|
+
# Resolve and validate input path
|
|
703
|
+
input_path = input_path.resolve()
|
|
704
|
+
if not input_path.exists():
|
|
705
|
+
console.print(f"[red]Error: Path does not exist: {input_path}[/red]")
|
|
706
|
+
raise typer.Exit(1)
|
|
707
|
+
if not input_path.is_dir():
|
|
708
|
+
console.print(f"[red]Error: Path is not a directory: {input_path}[/red]")
|
|
709
|
+
raise typer.Exit(1)
|
|
710
|
+
|
|
711
|
+
# Detect source dataset - must be MaskDataset for yolo-seg conversion
|
|
712
|
+
dataset = MaskDataset.detect(input_path)
|
|
713
|
+
if not dataset:
|
|
714
|
+
console.print(
|
|
715
|
+
f"[red]Error: No MaskDataset found at {input_path}[/red]\n"
|
|
716
|
+
"[yellow]Ensure the path contains images/ + masks/ directories "
|
|
717
|
+
"(or equivalent patterns like img/+gt/ or leftImg8bit/+gtFine/).[/yellow]"
|
|
718
|
+
)
|
|
719
|
+
raise typer.Exit(1)
|
|
720
|
+
|
|
721
|
+
# Resolve output path
|
|
722
|
+
if not output_path.is_absolute():
|
|
723
|
+
output_path = input_path.parent / output_path
|
|
724
|
+
output_path = output_path.resolve()
|
|
725
|
+
|
|
726
|
+
# Check if output already exists
|
|
727
|
+
if output_path.exists() and any(output_path.iterdir()):
|
|
728
|
+
console.print(
|
|
729
|
+
f"[red]Error: Output directory already exists and is not empty: "
|
|
730
|
+
f"{output_path}[/red]"
|
|
731
|
+
)
|
|
732
|
+
raise typer.Exit(1)
|
|
733
|
+
|
|
734
|
+
# Show conversion info
|
|
735
|
+
console.print("[cyan]Converting MaskDataset to YOLO segmentation format[/cyan]")
|
|
736
|
+
console.print(f" Source: {input_path}")
|
|
737
|
+
console.print(f" Output: {output_path}")
|
|
738
|
+
console.print(f" Classes: {dataset.num_classes}")
|
|
739
|
+
splits_str = ", ".join(dataset.splits) if dataset.splits else "unsplit"
|
|
740
|
+
console.print(f" Splits: {splits_str}")
|
|
741
|
+
console.print()
|
|
742
|
+
|
|
743
|
+
# Run conversion with progress bar
|
|
744
|
+
with Progress(
|
|
745
|
+
SpinnerColumn(),
|
|
746
|
+
TextColumn("[progress.description]{task.description}"),
|
|
747
|
+
BarColumn(),
|
|
748
|
+
TaskProgressColumn(),
|
|
749
|
+
console=console,
|
|
750
|
+
) as progress:
|
|
751
|
+
task = progress.add_task("Processing images...", total=None)
|
|
752
|
+
|
|
753
|
+
def update_progress(current: int, total: int) -> None:
|
|
754
|
+
progress.update(task, completed=current, total=total)
|
|
755
|
+
|
|
756
|
+
try:
|
|
757
|
+
stats = convert_mask_to_yolo_seg(
|
|
758
|
+
dataset=dataset,
|
|
759
|
+
output_path=output_path,
|
|
760
|
+
epsilon_factor=epsilon_factor,
|
|
761
|
+
min_area=min_area,
|
|
762
|
+
progress_callback=update_progress,
|
|
763
|
+
)
|
|
764
|
+
except Exception as exc:
|
|
765
|
+
console.print(f"[red]Error during conversion: {exc}[/red]")
|
|
766
|
+
raise typer.Exit(1) from exc
|
|
767
|
+
|
|
768
|
+
# Show results
|
|
769
|
+
console.print()
|
|
770
|
+
console.print("[green]Conversion complete![/green]")
|
|
771
|
+
console.print(f" Images processed: {stats['images']}")
|
|
772
|
+
console.print(f" Labels created: {stats['labels']}")
|
|
773
|
+
console.print(f" Polygons extracted: {stats['polygons']}")
|
|
774
|
+
|
|
775
|
+
if stats["skipped"] > 0:
|
|
776
|
+
skipped = stats["skipped"]
|
|
777
|
+
console.print(f" [yellow]Skipped: {skipped} (no mask or empty)[/yellow]")
|
|
778
|
+
if stats["warnings"] > 0:
|
|
779
|
+
console.print(f" [yellow]Warnings: {stats['warnings']}[/yellow]")
|
|
780
|
+
|
|
781
|
+
console.print(f"\n[cyan]Output dataset: {output_path}[/cyan]")
|
|
782
|
+
|
|
783
|
+
|
|
644
784
|
class _ImageViewer:
|
|
645
785
|
"""Interactive image viewer with zoom and pan support."""
|
|
646
786
|
|
|
@@ -1352,9 +1492,12 @@ def _draw_annotations(
|
|
|
1352
1492
|
overlay = img.copy()
|
|
1353
1493
|
cv2.fillPoly(overlay, [pts], color)
|
|
1354
1494
|
cv2.addWeighted(overlay, 0.3, img, 0.7, 0, img)
|
|
1495
|
+
# Draw small points at polygon vertices
|
|
1496
|
+
for pt in pts:
|
|
1497
|
+
cv2.circle(img, tuple(pt), radius=3, color=color, thickness=-1)
|
|
1355
1498
|
|
|
1356
|
-
# Draw bounding box
|
|
1357
|
-
if bbox:
|
|
1499
|
+
# Draw bounding box (only for detection, not segmentation)
|
|
1500
|
+
if bbox and not polygon:
|
|
1358
1501
|
x, y, w, h = bbox
|
|
1359
1502
|
x1, y1 = int(x), int(y)
|
|
1360
1503
|
x2, y2 = int(x + w), int(y + h)
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from argus.core.base import Dataset
|
|
4
4
|
from argus.core.coco import COCODataset
|
|
5
|
+
from argus.core.convert import (
|
|
6
|
+
ConversionParams,
|
|
7
|
+
Polygon,
|
|
8
|
+
convert_mask_to_yolo_labels,
|
|
9
|
+
convert_mask_to_yolo_seg,
|
|
10
|
+
mask_to_polygons,
|
|
11
|
+
)
|
|
5
12
|
from argus.core.mask import ConfigurationError, MaskDataset
|
|
6
13
|
from argus.core.split import split_coco_dataset, split_yolo_dataset
|
|
7
14
|
from argus.core.yolo import YOLODataset
|
|
@@ -14,4 +21,9 @@ __all__ = [
|
|
|
14
21
|
"ConfigurationError",
|
|
15
22
|
"split_coco_dataset",
|
|
16
23
|
"split_yolo_dataset",
|
|
24
|
+
"ConversionParams",
|
|
25
|
+
"Polygon",
|
|
26
|
+
"mask_to_polygons",
|
|
27
|
+
"convert_mask_to_yolo_labels",
|
|
28
|
+
"convert_mask_to_yolo_seg",
|
|
17
29
|
]
|