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.
Files changed (64) hide show
  1. {pixelflow-0.5.0 → pixelflow-0.7.0}/LICENSE +1 -1
  2. {pixelflow-0.5.0 → pixelflow-0.7.0}/PKG-INFO +27 -13
  3. {pixelflow-0.5.0 → pixelflow-0.7.0}/README.md +20 -5
  4. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/__init__.py +6 -2
  5. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/classifications/classifications.py +76 -0
  6. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/detections/detections.py +334 -5
  7. pixelflow-0.7.0/pixelflow/masks.py +212 -0
  8. pixelflow-0.7.0/pixelflow/serialization.py +72 -0
  9. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/validators.py +0 -23
  10. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/PKG-INFO +27 -13
  11. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/SOURCES.txt +2 -0
  12. {pixelflow-0.5.0 → pixelflow-0.7.0}/pyproject.toml +6 -8
  13. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/__init__.py +0 -0
  14. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/anchors.py +0 -0
  15. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/blur.py +0 -0
  16. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/box.py +0 -0
  17. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/classification.py +0 -0
  18. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/crossing.py +0 -0
  19. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/dot.py +0 -0
  20. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/filled_box.py +0 -0
  21. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/fps_counter.py +0 -0
  22. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/grid_overlay.py +0 -0
  23. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/heatmap.py +0 -0
  24. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/keypoint.py +0 -0
  25. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/keypoint_skeleton.py +0 -0
  26. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/label.py +0 -0
  27. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/mask.py +0 -0
  28. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/motion_dots.py +0 -0
  29. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/motion_trails.py +0 -0
  30. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/oval.py +0 -0
  31. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/pixelate.py +0 -0
  32. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/polygon.py +0 -0
  33. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/scale_bar.py +0 -0
  34. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/utils.py +0 -0
  35. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/annotators/zones.py +0 -0
  36. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/arrays.py +0 -0
  37. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/buffer.py +0 -0
  38. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/classifications/__init__.py +0 -0
  39. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/classifications/converters.py +0 -0
  40. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/colors.py +0 -0
  41. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/crossings.py +0 -0
  42. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/detections/__init__.py +0 -0
  43. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/detections/converters.py +0 -0
  44. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/detections/filters.py +0 -0
  45. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/labels.py +0 -0
  46. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/media.py +0 -0
  47. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/slicer.py +0 -0
  48. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/smoother.py +0 -0
  49. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/strategies.py +0 -0
  50. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/timer.py +0 -0
  51. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/__init__.py +0 -0
  52. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/bytetrack.py +0 -0
  53. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/kalman_filter.py +0 -0
  54. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/matching.py +0 -0
  55. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/tracker/track.py +0 -0
  56. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/transforms/__init__.py +0 -0
  57. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/transforms/detections.py +0 -0
  58. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/transforms/image.py +0 -0
  59. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/transforms/inverse.py +0 -0
  60. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow/zones.py +0 -0
  61. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/dependency_links.txt +0 -0
  62. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/requires.txt +0 -0
  63. {pixelflow-0.5.0 → pixelflow-0.7.0}/pixelflow.egg-info/top_level.txt +0 -0
  64. {pixelflow-0.5.0 → pixelflow-0.7.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 datamarkin
3
+ Copyright (c) 2025 Emrah NAZIF
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixelflow
3
- Version: 0.5.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>, Datamarkin <support@datamarkin.com>
5
+ Author-email: Emrah Nazif <emrah@datamarkin.com>
6
6
  License: MIT
7
- Project-URL: Homepage, https://github.com/datamarkin/pixelflow
8
- Project-URL: Repository, https://github.com/datamarkin/pixelflow
9
- Project-URL: Issues, https://github.com/datamarkin/pixelflow/issues
10
- Project-URL: Documentation, https://pixelflow.datamarkin.com
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.9
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
  [![PyPI version](https://badge.fury.io/py/pixelflow.svg)](https://badge.fury.io/py/pixelflow)
42
- [![CI](https://github.com/datamarkin/pixelflow/actions/workflows/ci.yml/badge.svg)](https://github.com/datamarkin/pixelflow/actions/workflows/ci.yml)
43
- [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
41
+ [![CI](https://github.com/emrahnazif/pixelflow/actions/workflows/ci.yml/badge.svg)](https://github.com/emrahnazif/pixelflow/actions/workflows/ci.yml)
42
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
44
43
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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://datamarkin.com/docs/pixelflow/](https://datamarkin.com/docs/pixelflow/)
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 [Datamarkin](https://datamarkin.com)
486
+ Built with love by [Emrah Nazif](https://emrah.fr)
@@ -1,8 +1,8 @@
1
1
  # PixelFlow
2
2
 
3
3
  [![PyPI version](https://badge.fury.io/py/pixelflow.svg)](https://badge.fury.io/py/pixelflow)
4
- [![CI](https://github.com/datamarkin/pixelflow/actions/workflows/ci.yml/badge.svg)](https://github.com/datamarkin/pixelflow/actions/workflows/ci.yml)
5
- [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
4
+ [![CI](https://github.com/emrahnazif/pixelflow/actions/workflows/ci.yml/badge.svg)](https://github.com/emrahnazif/pixelflow/actions/workflows/ci.yml)
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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://datamarkin.com/docs/pixelflow/](https://datamarkin.com/docs/pixelflow/)
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 [Datamarkin](https://datamarkin.com)
449
+ Built with love by [Emrah Nazif](https://emrah.fr)
@@ -1,5 +1,5 @@
1
- __version__ = "0.5.0"
2
- __author__ = "Datamarkin"
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)"