pixelflow 0.5.0__tar.gz → 0.7.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.
- {pixelflow-0.5.0 → pixelflow-0.7.0}/LICENSE +1 -1
- {pixelflow-0.5.0 → pixelflow-0.7.0}/PKG-INFO +27 -13
- {pixelflow-0.5.0 → pixelflow-0.7.0}/README.md +20 -5
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/__init__.py +6 -2
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/classifications/classifications.py +76 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/detections/detections.py +334 -5
- pixelflow-0.7.0/pixelflow/masks.py +212 -0
- pixelflow-0.7.0/pixelflow/serialization.py +72 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/validators.py +0 -23
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/PKG-INFO +27 -13
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/SOURCES.txt +2 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pyproject.toml +6 -8
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/__init__.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/anchors.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/blur.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/box.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/classification.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/crossing.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/dot.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/filled_box.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/fps_counter.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/grid_overlay.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/heatmap.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/keypoint.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/keypoint_skeleton.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/label.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/mask.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/motion_dots.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/motion_trails.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/oval.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/pixelate.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/polygon.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/scale_bar.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/utils.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/zones.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/arrays.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/buffer.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/classifications/__init__.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/classifications/converters.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/colors.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/crossings.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/detections/__init__.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/detections/converters.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/detections/filters.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/labels.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/media.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/slicer.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/smoother.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/strategies.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/timer.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/__init__.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/bytetrack.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/kalman_filter.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/matching.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/track.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/transforms/__init__.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/transforms/detections.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/transforms/image.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/transforms/inverse.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/zones.py +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/dependency_links.txt +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/requires.txt +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/top_level.txt +0 -0
- {pixelflow-0.5.0 → pixelflow-0.7.0}/setup.cfg +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pixelflow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Computer vision processing library for visualizing and analyzing detection results from ML models
|
|
5
|
-
Author-email: Emrah Nazif <emrah@datamarkin.com
|
|
5
|
+
Author-email: Emrah Nazif <emrah@datamarkin.com>
|
|
6
6
|
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
-
Project-URL: Repository, https://github.com/
|
|
9
|
-
Project-URL: Issues, https://github.com/
|
|
10
|
-
Project-URL: Documentation, https://pixelflow
|
|
7
|
+
Project-URL: Homepage, https://github.com/emrahnazif/pixelflow
|
|
8
|
+
Project-URL: Repository, https://github.com/emrahnazif/pixelflow
|
|
9
|
+
Project-URL: Issues, https://github.com/emrahnazif/pixelflow/issues
|
|
10
|
+
Project-URL: Documentation, https://emrah.fr/pixelflow/
|
|
11
11
|
Keywords: computer-vision,visualization,annotation,post-processing,tracking,opencv,yolo,detectron2,mayaku,ml-results
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
@@ -15,14 +15,13 @@ Classifier: Intended Audience :: Science/Research
|
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
21
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
22
|
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
24
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
-
Requires-Python: >=3.
|
|
24
|
+
Requires-Python: >=3.10
|
|
26
25
|
Description-Content-Type: text/markdown
|
|
27
26
|
License-File: LICENSE
|
|
28
27
|
Requires-Dist: shapely>=2.0.0
|
|
@@ -39,8 +38,8 @@ Dynamic: license-file
|
|
|
39
38
|
# PixelFlow
|
|
40
39
|
|
|
41
40
|
[](https://badge.fury.io/py/pixelflow)
|
|
42
|
-
[](https://github.com/emrahnazif/pixelflow/actions/workflows/ci.yml)
|
|
42
|
+
[](https://www.python.org/downloads/)
|
|
44
43
|
[](https://opensource.org/licenses/MIT)
|
|
45
44
|
|
|
46
45
|
**The computer vision library that gets out of your way.**
|
|
@@ -132,6 +131,17 @@ detections = pf.from_easyocr(reader.readtext("sign.jpg"))
|
|
|
132
131
|
detections = pf.from_arrays(boxes, scores, class_ids, labels=model.class_names)
|
|
133
132
|
```
|
|
134
133
|
|
|
134
|
+
Segmentation models answer with raster masks. One call turns them into polygons,
|
|
135
|
+
whichever model they came from:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
detections = pf.from_arrays(boxes, scores, masks=masks) # boolean (N, H, W)
|
|
139
|
+
detections.masks_to_segments() # fills det.segments
|
|
140
|
+
detections.masks_to_segments(keep_masks=False) # ...and drops the rasters
|
|
141
|
+
|
|
142
|
+
polygon = pf.mask_to_polygon(mask) # or one mask at a time
|
|
143
|
+
```
|
|
144
|
+
|
|
135
145
|
### Classifications - When the Model Only Names
|
|
136
146
|
|
|
137
147
|
A classifier localises nothing, so its result carries no geometry at all:
|
|
@@ -146,7 +156,7 @@ result = pf.from_ultralytics_classification(model.predict("dog.jpg"))
|
|
|
146
156
|
|
|
147
157
|
result.top1.class_name # 'golden retriever'
|
|
148
158
|
result.top_k(5) # -> Classifications, best first
|
|
149
|
-
result.to_json()
|
|
159
|
+
result.to_json() # pf.Classifications.from_json() reads it back
|
|
150
160
|
|
|
151
161
|
# Plain scores - CLIP zero-shot, a vendored ResNet, anything with a score vector
|
|
152
162
|
prompts = ["a photo of a cat", "a photo of a dog"]
|
|
@@ -435,6 +445,10 @@ df = pd.DataFrame(data)
|
|
|
435
445
|
|
|
436
446
|
# With metrics
|
|
437
447
|
report = detections.to_json_with_metrics()
|
|
448
|
+
|
|
449
|
+
# And back - masks decoded, keypoints rebuilt, every field restored
|
|
450
|
+
detections = pf.Detections.from_json(json_str)
|
|
451
|
+
detections = pf.Detections.from_dict(data)
|
|
438
452
|
```
|
|
439
453
|
|
|
440
454
|
## Supported Frameworks
|
|
@@ -457,7 +471,7 @@ report = detections.to_json_with_metrics()
|
|
|
457
471
|
|
|
458
472
|
## Documentation
|
|
459
473
|
|
|
460
|
-
Full documentation available at [https://
|
|
474
|
+
Full documentation available at [https://emrah.fr/pixelflow/](https://emrah.fr/pixelflow/)
|
|
461
475
|
|
|
462
476
|
## Contributing
|
|
463
477
|
|
|
@@ -469,4 +483,4 @@ MIT License - see LICENSE file for details.
|
|
|
469
483
|
|
|
470
484
|
---
|
|
471
485
|
|
|
472
|
-
Built with love by [
|
|
486
|
+
Built with love by [Emrah Nazif](https://emrah.fr)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# PixelFlow
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/py/pixelflow)
|
|
4
|
-
[](https://github.com/emrahnazif/pixelflow/actions/workflows/ci.yml)
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
8
|
**The computer vision library that gets out of your way.**
|
|
@@ -94,6 +94,17 @@ detections = pf.from_easyocr(reader.readtext("sign.jpg"))
|
|
|
94
94
|
detections = pf.from_arrays(boxes, scores, class_ids, labels=model.class_names)
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
Segmentation models answer with raster masks. One call turns them into polygons,
|
|
98
|
+
whichever model they came from:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
detections = pf.from_arrays(boxes, scores, masks=masks) # boolean (N, H, W)
|
|
102
|
+
detections.masks_to_segments() # fills det.segments
|
|
103
|
+
detections.masks_to_segments(keep_masks=False) # ...and drops the rasters
|
|
104
|
+
|
|
105
|
+
polygon = pf.mask_to_polygon(mask) # or one mask at a time
|
|
106
|
+
```
|
|
107
|
+
|
|
97
108
|
### Classifications - When the Model Only Names
|
|
98
109
|
|
|
99
110
|
A classifier localises nothing, so its result carries no geometry at all:
|
|
@@ -108,7 +119,7 @@ result = pf.from_ultralytics_classification(model.predict("dog.jpg"))
|
|
|
108
119
|
|
|
109
120
|
result.top1.class_name # 'golden retriever'
|
|
110
121
|
result.top_k(5) # -> Classifications, best first
|
|
111
|
-
result.to_json()
|
|
122
|
+
result.to_json() # pf.Classifications.from_json() reads it back
|
|
112
123
|
|
|
113
124
|
# Plain scores - CLIP zero-shot, a vendored ResNet, anything with a score vector
|
|
114
125
|
prompts = ["a photo of a cat", "a photo of a dog"]
|
|
@@ -397,6 +408,10 @@ df = pd.DataFrame(data)
|
|
|
397
408
|
|
|
398
409
|
# With metrics
|
|
399
410
|
report = detections.to_json_with_metrics()
|
|
411
|
+
|
|
412
|
+
# And back - masks decoded, keypoints rebuilt, every field restored
|
|
413
|
+
detections = pf.Detections.from_json(json_str)
|
|
414
|
+
detections = pf.Detections.from_dict(data)
|
|
400
415
|
```
|
|
401
416
|
|
|
402
417
|
## Supported Frameworks
|
|
@@ -419,7 +434,7 @@ report = detections.to_json_with_metrics()
|
|
|
419
434
|
|
|
420
435
|
## Documentation
|
|
421
436
|
|
|
422
|
-
Full documentation available at [https://
|
|
437
|
+
Full documentation available at [https://emrah.fr/pixelflow/](https://emrah.fr/pixelflow/)
|
|
423
438
|
|
|
424
439
|
## Contributing
|
|
425
440
|
|
|
@@ -431,4 +446,4 @@ MIT License - see LICENSE file for details.
|
|
|
431
446
|
|
|
432
447
|
---
|
|
433
448
|
|
|
434
|
-
Built with love by [
|
|
449
|
+
Built with love by [Emrah Nazif](https://emrah.fr)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
__version__ = "0.
|
|
2
|
-
__author__ = "
|
|
1
|
+
__version__ = "0.7.0"
|
|
2
|
+
__author__ = "Emrah NAZIF"
|
|
3
3
|
|
|
4
4
|
# Import core modules
|
|
5
5
|
from . import media
|
|
@@ -29,6 +29,7 @@ from .media import (
|
|
|
29
29
|
read_image, read_video, encode_image, display_video, display_image, save_image,
|
|
30
30
|
close_display, to_pil, from_pil,
|
|
31
31
|
)
|
|
32
|
+
from .masks import mask_to_polygon
|
|
32
33
|
from .zones import Zones
|
|
33
34
|
from .crossings import Crossings
|
|
34
35
|
from .slicer import SlicedInference, auto_slice_size
|
|
@@ -95,6 +96,9 @@ __all__ = [
|
|
|
95
96
|
"to_pil",
|
|
96
97
|
"from_pil",
|
|
97
98
|
|
|
99
|
+
# Mask geometry
|
|
100
|
+
"mask_to_polygon",
|
|
101
|
+
|
|
98
102
|
# Spatial analysis
|
|
99
103
|
"zones",
|
|
100
104
|
"Zones",
|
|
@@ -11,6 +11,7 @@ localisation that never happened.
|
|
|
11
11
|
import copy as copy_module
|
|
12
12
|
import json
|
|
13
13
|
|
|
14
|
+
from pixelflow.serialization import constructor_fields, own
|
|
14
15
|
from pixelflow.validators import round_to_decimal
|
|
15
16
|
from typing import Any, Dict, Iterator, List, Optional, Union
|
|
16
17
|
|
|
@@ -94,6 +95,10 @@ class Classification:
|
|
|
94
95
|
>>> import pixelflow as pf
|
|
95
96
|
>>> pf.Classification(207, "golden retriever", 0.94).to_dict()
|
|
96
97
|
{'class_id': 207, 'class_name': 'golden retriever', 'confidence': 0.94, 'metadata': None}
|
|
98
|
+
|
|
99
|
+
Notes:
|
|
100
|
+
- `metadata` is the classification's own dictionary, not a copy. Treat
|
|
101
|
+
the result as read-only, or rebuild with `from_dict()`, which copies it
|
|
97
102
|
"""
|
|
98
103
|
return {
|
|
99
104
|
"class_id": self.class_id,
|
|
@@ -102,6 +107,29 @@ class Classification:
|
|
|
102
107
|
"metadata": self.metadata,
|
|
103
108
|
}
|
|
104
109
|
|
|
110
|
+
@classmethod
|
|
111
|
+
def from_dict(cls, data: Dict[str, Any]) -> "Classification":
|
|
112
|
+
"""
|
|
113
|
+
Rebuild a Classification from the dictionary `to_dict()` produces.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
data (Dict[str, Any]): A classification dictionary. Unknown keys are
|
|
117
|
+
ignored and missing keys take the constructor's defaults, so
|
|
118
|
+
dictionaries written by other pixelflow versions still read.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Classification: A new classification with its own metadata.
|
|
122
|
+
|
|
123
|
+
Example:
|
|
124
|
+
>>> import pixelflow as pf
|
|
125
|
+
>>> row = pf.Classification(class_id=207, class_name="golden retriever", confidence=0.94)
|
|
126
|
+
>>> pf.Classification.from_dict(row.to_dict()).to_dict() == row.to_dict()
|
|
127
|
+
True
|
|
128
|
+
>>> pf.Classification.from_dict({"class_name": "cat"}).confidence is None
|
|
129
|
+
True
|
|
130
|
+
"""
|
|
131
|
+
return cls(**own(constructor_fields(cls, data)))
|
|
132
|
+
|
|
105
133
|
def __repr__(self) -> str:
|
|
106
134
|
return (f"Classification(class_id={self.class_id!r}, "
|
|
107
135
|
f"class_name={self.class_name!r}, confidence={self.confidence!r})")
|
|
@@ -310,5 +338,53 @@ class Classifications:
|
|
|
310
338
|
"""
|
|
311
339
|
return json.dumps(self.to_dict(), indent=4)
|
|
312
340
|
|
|
341
|
+
@classmethod
|
|
342
|
+
def from_dict(cls, items: List[Dict[str, Any]]) -> "Classifications":
|
|
343
|
+
"""
|
|
344
|
+
Rebuild a Classifications collection from the list `to_dict()` produces.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
items (List[Dict[str, Any]]): Classification dictionaries, each read
|
|
348
|
+
with `Classification.from_dict`.
|
|
349
|
+
|
|
350
|
+
Returns:
|
|
351
|
+
Classifications: A new collection holding the rows in the order given.
|
|
352
|
+
|
|
353
|
+
Example:
|
|
354
|
+
>>> import pixelflow as pf
|
|
355
|
+
>>> result = pf.from_scores([0.1, 0.9], labels=["cat", "dog"])
|
|
356
|
+
>>> restored = pf.Classifications.from_dict(result.to_dict())
|
|
357
|
+
>>> restored.top1.class_name
|
|
358
|
+
'dog'
|
|
359
|
+
|
|
360
|
+
Notes:
|
|
361
|
+
- `to_dict()` writes the rows only. The collection's own `inference_id`
|
|
362
|
+
and `metadata` are not part of it, so they come back as None; set
|
|
363
|
+
them on the result if you stored them yourself.
|
|
364
|
+
"""
|
|
365
|
+
return cls([Classification.from_dict(item) for item in items])
|
|
366
|
+
|
|
367
|
+
@classmethod
|
|
368
|
+
def from_json(cls, text: Union[str, bytes]) -> "Classifications":
|
|
369
|
+
"""
|
|
370
|
+
Rebuild a Classifications collection from the JSON string `to_json()` produces.
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
text (Union[str, bytes]): JSON array of classification dictionaries.
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
Classifications: A new collection holding the rows in the order given.
|
|
377
|
+
|
|
378
|
+
Raises:
|
|
379
|
+
json.JSONDecodeError: If `text` is not valid JSON.
|
|
380
|
+
|
|
381
|
+
Example:
|
|
382
|
+
>>> import pixelflow as pf
|
|
383
|
+
>>> result = pf.from_scores([0.1, 0.9], labels=["cat", "dog"])
|
|
384
|
+
>>> pf.Classifications.from_json(result.to_json()).top1.class_name
|
|
385
|
+
'dog'
|
|
386
|
+
"""
|
|
387
|
+
return cls.from_dict(json.loads(text))
|
|
388
|
+
|
|
313
389
|
def __repr__(self) -> str:
|
|
314
390
|
return f"Classifications({len(self.classifications)} rows)"
|