pixelflow 0.1.0__tar.gz → 0.1.2__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.1.0 → pixelflow-0.1.2}/LICENSE +1 -1
- pixelflow-0.1.2/PKG-INFO +374 -0
- pixelflow-0.1.2/README.md +337 -0
- pixelflow-0.1.2/pixelflow/__init__.py +68 -0
- pixelflow-0.1.2/pixelflow/annotators/__init__.py +60 -0
- pixelflow-0.1.2/pixelflow/annotators/anchors.py +158 -0
- pixelflow-0.1.2/pixelflow/annotators/blur.py +151 -0
- pixelflow-0.1.2/pixelflow/annotators/box.py +85 -0
- pixelflow-0.1.2/pixelflow/annotators/crossing.py +272 -0
- pixelflow-0.1.2/pixelflow/annotators/dot.py +11 -0
- pixelflow-0.1.2/pixelflow/annotators/filled_box.py +118 -0
- pixelflow-0.1.2/pixelflow/annotators/fps_counter.py +43 -0
- pixelflow-0.1.2/pixelflow/annotators/grid_overlay.py +170 -0
- pixelflow-0.1.2/pixelflow/annotators/heatmap.py +11 -0
- pixelflow-0.1.2/pixelflow/annotators/keypoint.py +134 -0
- pixelflow-0.1.2/pixelflow/annotators/keypoint_skeleton.py +165 -0
- pixelflow-0.1.2/pixelflow/annotators/label.py +252 -0
- pixelflow-0.1.2/pixelflow/annotators/mask.py +133 -0
- pixelflow-0.1.2/pixelflow/annotators/motion_dots.py +11 -0
- pixelflow-0.1.2/pixelflow/annotators/motion_trails.py +11 -0
- pixelflow-0.1.2/pixelflow/annotators/oval.py +125 -0
- pixelflow-0.1.2/pixelflow/annotators/pixelate.py +153 -0
- pixelflow-0.1.2/pixelflow/annotators/polygon.py +92 -0
- pixelflow-0.1.2/pixelflow/annotators/scale_bar.py +11 -0
- pixelflow-0.1.2/pixelflow/annotators/utils.py +48 -0
- pixelflow-0.1.2/pixelflow/annotators/zones.py +231 -0
- pixelflow-0.1.2/pixelflow/buffer.py +512 -0
- pixelflow-0.1.2/pixelflow/colors.py +100 -0
- pixelflow-0.1.2/pixelflow/crossings.py +1637 -0
- pixelflow-0.1.2/pixelflow/detections/__init__.py +91 -0
- pixelflow-0.1.2/pixelflow/detections/converters.py +2214 -0
- pixelflow-0.1.2/pixelflow/detections/detections.py +1045 -0
- pixelflow-0.1.2/pixelflow/detections/filters.py +1260 -0
- pixelflow-0.1.2/pixelflow/media.py +427 -0
- pixelflow-0.1.2/pixelflow/slicer.py +906 -0
- pixelflow-0.1.2/pixelflow/smoother.py +627 -0
- pixelflow-0.1.2/pixelflow/strategies.py +481 -0
- pixelflow-0.1.2/pixelflow/timer.py +663 -0
- pixelflow-0.1.2/pixelflow/tracker/__init__.py +19 -0
- pixelflow-0.1.2/pixelflow/tracker/bytetrack.py +837 -0
- pixelflow-0.1.2/pixelflow/tracker/kalman_filter.py +182 -0
- pixelflow-0.1.2/pixelflow/tracker/matching.py +178 -0
- pixelflow-0.1.2/pixelflow/tracker/track.py +239 -0
- pixelflow-0.1.2/pixelflow/transforms/__init__.py +136 -0
- pixelflow-0.1.2/pixelflow/transforms/detections.py +911 -0
- pixelflow-0.1.2/pixelflow/transforms/image.py +468 -0
- pixelflow-0.1.2/pixelflow/transforms/inverse.py +440 -0
- pixelflow-0.1.2/pixelflow/validators.py +139 -0
- pixelflow-0.1.2/pixelflow/zones.py +811 -0
- pixelflow-0.1.2/pixelflow.egg-info/PKG-INFO +374 -0
- pixelflow-0.1.2/pixelflow.egg-info/SOURCES.txt +54 -0
- pixelflow-0.1.2/pixelflow.egg-info/requires.txt +9 -0
- pixelflow-0.1.2/pyproject.toml +67 -0
- pixelflow-0.1.0/PKG-INFO +0 -15
- pixelflow-0.1.0/README.md +0 -8
- pixelflow-0.1.0/pixelflow/__init__.py +0 -2
- pixelflow-0.1.0/pixelflow/core.py +0 -2
- pixelflow-0.1.0/pixelflow.egg-info/PKG-INFO +0 -15
- pixelflow-0.1.0/pixelflow.egg-info/SOURCES.txt +0 -9
- pixelflow-0.1.0/setup.py +0 -19
- {pixelflow-0.1.0 → pixelflow-0.1.2}/pixelflow.egg-info/dependency_links.txt +0 -0
- {pixelflow-0.1.0 → pixelflow-0.1.2}/pixelflow.egg-info/top_level.txt +0 -0
- {pixelflow-0.1.0 → pixelflow-0.1.2}/setup.cfg +0 -0
pixelflow-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pixelflow
|
|
3
|
+
Version: 0.1.2
|
|
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>
|
|
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
|
|
11
|
+
Keywords: computer-vision,visualization,annotation,post-processing,tracking,opencv,yolo,detectron2,ml-results
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: shapely>=2.0.0
|
|
29
|
+
Requires-Dist: numpy>=1.21.0
|
|
30
|
+
Requires-Dist: opencv-python>=4.8.0
|
|
31
|
+
Requires-Dist: scipy>=1.10.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# PixelFlow
|
|
39
|
+
|
|
40
|
+
[](https://badge.fury.io/py/pixelflow)
|
|
41
|
+
[](https://www.python.org/downloads/)
|
|
42
|
+
[](https://opensource.org/licenses/MIT)
|
|
43
|
+
|
|
44
|
+
**The computer vision library that gets out of your way.**
|
|
45
|
+
|
|
46
|
+
PixelFlow provides a unified, intuitive API for object detection, tracking, annotation, and video processing. Write clean, readable pipelines that work with any ML framework.
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import pixelflow as pf
|
|
50
|
+
from ultralytics import YOLO
|
|
51
|
+
|
|
52
|
+
model = YOLO("yolo11n.pt")
|
|
53
|
+
media = pf.Media("traffic.mp4")
|
|
54
|
+
tracker = pf.tracker.ByteTracker()
|
|
55
|
+
zones = pf.Zones()
|
|
56
|
+
zones.add_zone([(100, 400), (500, 400), (500, 600), (100, 600)], zone_id="entrance")
|
|
57
|
+
|
|
58
|
+
for frame in media.frames:
|
|
59
|
+
detections = pf.detections.from_ultralytics(model.predict(frame))
|
|
60
|
+
detections = tracker.update(detections)
|
|
61
|
+
zones.update(detections)
|
|
62
|
+
|
|
63
|
+
frame = pf.annotate.box(frame, detections)
|
|
64
|
+
frame = pf.annotate.label(frame, detections)
|
|
65
|
+
frame = pf.annotate.zones(frame, zones)
|
|
66
|
+
|
|
67
|
+
pf.show_frame("Live", frame)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Installation
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install pixelflow
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Core Concepts
|
|
77
|
+
|
|
78
|
+
### Detections - One Format, Every Framework
|
|
79
|
+
|
|
80
|
+
Convert outputs from any ML framework into a unified format:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import pixelflow as pf
|
|
84
|
+
|
|
85
|
+
# Ultralytics YOLO
|
|
86
|
+
from ultralytics import YOLO
|
|
87
|
+
model = YOLO("yolo11n.pt")
|
|
88
|
+
detections = pf.detections.from_ultralytics(model.predict(image))
|
|
89
|
+
|
|
90
|
+
# Detectron2
|
|
91
|
+
from detectron2.engine import DefaultPredictor
|
|
92
|
+
predictor = DefaultPredictor(cfg)
|
|
93
|
+
detections = pf.detections.from_detectron2(predictor(image), class_names=["person", "car"])
|
|
94
|
+
|
|
95
|
+
# HuggingFace Transformers
|
|
96
|
+
from transformers import pipeline
|
|
97
|
+
detector = pipeline("object-detection")
|
|
98
|
+
detections = pf.detections.from_transformers(detector(image))
|
|
99
|
+
|
|
100
|
+
# Florence-2
|
|
101
|
+
detections = pf.detections.from_florence2(model_output)
|
|
102
|
+
|
|
103
|
+
# SAM (Segment Anything)
|
|
104
|
+
detections = pf.detections.from_sam(masks, scores)
|
|
105
|
+
|
|
106
|
+
# OCR Engines
|
|
107
|
+
detections = pf.detections.from_tesseract(tesseract_output)
|
|
108
|
+
detections = pf.detections.from_paddleocr(paddleocr_output)
|
|
109
|
+
detections = pf.detections.from_easyocr(easyocr_output)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Powerful Filtering
|
|
113
|
+
|
|
114
|
+
Chain filters for complex queries with zero overhead:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# Get high-confidence people in the parking zone, tracked for 5+ seconds
|
|
118
|
+
results = (detections
|
|
119
|
+
.filter_by_confidence(min_confidence=0.7)
|
|
120
|
+
.filter_by_class_id("person")
|
|
121
|
+
.filter_by_zones(["parking_lot"])
|
|
122
|
+
.filter_by_tracking_duration(min_seconds=5.0))
|
|
123
|
+
|
|
124
|
+
# Size-based filtering
|
|
125
|
+
large_objects = detections.filter_by_size(min_area=10000)
|
|
126
|
+
tall_objects = detections.filter_by_dimensions(min_height=200)
|
|
127
|
+
squares = detections.filter_by_aspect_ratio(min_ratio=0.9, max_ratio=1.1)
|
|
128
|
+
|
|
129
|
+
# Spatial filtering
|
|
130
|
+
left_side = detections.filter_by_position(max_x=frame_width // 2)
|
|
131
|
+
|
|
132
|
+
# Remove overlapping detections
|
|
133
|
+
unique = detections.remove_duplicates(iou_threshold=0.5)
|
|
134
|
+
|
|
135
|
+
# OCR-specific filters
|
|
136
|
+
titles = detections.filter_by_text_level("title")
|
|
137
|
+
english_text = detections.filter_by_text_language("en")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Media Handling
|
|
141
|
+
|
|
142
|
+
Unified interface for videos, images, webcams, and streams:
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
import pixelflow as pf
|
|
146
|
+
|
|
147
|
+
# Video file with automatic resizing
|
|
148
|
+
media = pf.Media("video.mp4", width=640)
|
|
149
|
+
print(media.info) # MediaInfo(resolution=1920x1080, fps=30.00, frames=900, duration=30.00s)
|
|
150
|
+
|
|
151
|
+
for frame in media.frames: # Lazy loading, memory efficient
|
|
152
|
+
# Process frame
|
|
153
|
+
pf.show_frame("Preview", frame)
|
|
154
|
+
|
|
155
|
+
# Webcam
|
|
156
|
+
webcam = pf.Media(0)
|
|
157
|
+
|
|
158
|
+
# Network stream
|
|
159
|
+
stream = pf.Media("rtsp://camera.local/stream")
|
|
160
|
+
|
|
161
|
+
# Write processed video
|
|
162
|
+
for frame in pf.Media("input.mp4").frames:
|
|
163
|
+
processed = process(frame)
|
|
164
|
+
pf.write_frame("output.mp4", processed, media.info)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Zone-Based Analytics
|
|
168
|
+
|
|
169
|
+
Define spatial regions and track what enters them:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
import pixelflow as pf
|
|
173
|
+
|
|
174
|
+
zones = pf.Zones()
|
|
175
|
+
|
|
176
|
+
# Define zones with different trigger strategies
|
|
177
|
+
zones.add_zone(
|
|
178
|
+
polygon=[(100, 400), (300, 400), (300, 600), (100, 600)],
|
|
179
|
+
zone_id="entrance",
|
|
180
|
+
name="Main Entrance",
|
|
181
|
+
trigger_strategy="bottom_center" # Trigger when bottom-center of bbox enters
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
zones.add_zone(
|
|
185
|
+
polygon=[(500, 200), (700, 200), (700, 500), (500, 500)],
|
|
186
|
+
zone_id="restricted",
|
|
187
|
+
trigger_strategy="percentage",
|
|
188
|
+
overlap_threshold=0.3 # Trigger when 30% of bbox is inside
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# Update detections with zone info
|
|
192
|
+
zones.update(detections)
|
|
193
|
+
|
|
194
|
+
# Access zone statistics
|
|
195
|
+
print(zones.get_zone_counts()) # {'entrance': 3, 'restricted': 1}
|
|
196
|
+
print(zones.get_zone_stats()) # Detailed stats including total_entered
|
|
197
|
+
|
|
198
|
+
# Filter by zone
|
|
199
|
+
entrance_only = zones.filter_by_zones(detections, ["entrance"])
|
|
200
|
+
not_restricted = zones.filter_by_zones(detections, ["restricted"], exclude=True)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Trigger Strategies:**
|
|
204
|
+
- `center` - Bounding box center point (default)
|
|
205
|
+
- `bottom_center` - Bottom-center point (great for people/vehicles)
|
|
206
|
+
- `percentage` - Percentage of bbox overlap
|
|
207
|
+
- `overlap` - Any intersection
|
|
208
|
+
- Multiple strategies with `mode="any"` or `mode="all"`
|
|
209
|
+
|
|
210
|
+
### Object Tracking
|
|
211
|
+
|
|
212
|
+
Built-in ByteTrack for multi-object tracking:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
import pixelflow as pf
|
|
216
|
+
|
|
217
|
+
tracker = pf.tracker.ByteTracker()
|
|
218
|
+
|
|
219
|
+
for frame in media.frames:
|
|
220
|
+
detections = pf.detections.from_ultralytics(model.predict(frame))
|
|
221
|
+
detections = tracker.update(detections)
|
|
222
|
+
|
|
223
|
+
for det in detections:
|
|
224
|
+
print(f"Track ID: {det.tracker_id}, Class: {det.class_name}")
|
|
225
|
+
print(f"First seen: {det.first_seen_time}, Duration: {det.total_time}s")
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Rich Annotations
|
|
229
|
+
|
|
230
|
+
Beautiful, customizable visualizations:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
import pixelflow as pf
|
|
234
|
+
|
|
235
|
+
# Bounding boxes and labels
|
|
236
|
+
frame = pf.annotate.box(frame, detections, thickness=2)
|
|
237
|
+
frame = pf.annotate.label(frame, detections, font_scale=0.6)
|
|
238
|
+
|
|
239
|
+
# Segmentation masks
|
|
240
|
+
frame = pf.annotate.mask(frame, detections, opacity=0.4)
|
|
241
|
+
|
|
242
|
+
# Keypoints and skeletons (pose estimation)
|
|
243
|
+
frame = pf.annotate.keypoint(frame, detections)
|
|
244
|
+
frame = pf.annotate.keypoint_skeleton(frame, detections)
|
|
245
|
+
|
|
246
|
+
# Zone visualization
|
|
247
|
+
frame = pf.annotate.zones(frame, zones)
|
|
248
|
+
frame = pf.annotate.crossings(frame, crossings)
|
|
249
|
+
|
|
250
|
+
# Privacy protection
|
|
251
|
+
frame = pf.annotate.blur(frame, detections, kernel_size=51)
|
|
252
|
+
frame = pf.annotate.pixelate(frame, detections, pixel_size=15)
|
|
253
|
+
|
|
254
|
+
# Shapes
|
|
255
|
+
frame = pf.annotate.oval(frame, detections)
|
|
256
|
+
frame = pf.annotate.polygon(frame, detections)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Image Transforms
|
|
260
|
+
|
|
261
|
+
Comprehensive image and detection-aware transformations:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
import pixelflow as pf
|
|
265
|
+
|
|
266
|
+
# Image-only transforms
|
|
267
|
+
rotated = pf.transform.rotate(image, 45)
|
|
268
|
+
flipped = pf.transform.flip_horizontal(image)
|
|
269
|
+
cropped = pf.transform.crop(image, [100, 50, 500, 400])
|
|
270
|
+
|
|
271
|
+
# Enhancement
|
|
272
|
+
enhanced = pf.transform.clahe(image)
|
|
273
|
+
gray = pf.transform.to_grayscale(image)
|
|
274
|
+
corrected = pf.transform.gamma_correction(image, gamma=1.2)
|
|
275
|
+
|
|
276
|
+
# Detection-aware transforms (coordinates update automatically)
|
|
277
|
+
rotated_img, rotated_dets = pf.transform.rotate_detections(image, detections, 45)
|
|
278
|
+
flipped_img, flipped_dets = pf.transform.flip_horizontal_detections(image, detections)
|
|
279
|
+
cropped_img, cropped_dets = pf.transform.crop_detections(image, detections, bbox=[100, 50, 500, 400])
|
|
280
|
+
|
|
281
|
+
# Automatic inverse transforms (undo all transforms)
|
|
282
|
+
original_coords = pf.transform.inverse_transforms(transformed_detections)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Sliced Inference for Large Images
|
|
286
|
+
|
|
287
|
+
Detect small objects in high-resolution images:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
import pixelflow as pf
|
|
291
|
+
|
|
292
|
+
slicer = pf.SlicedInference(
|
|
293
|
+
slice_height=640,
|
|
294
|
+
slice_width=640,
|
|
295
|
+
overlap_ratio_h=0.2,
|
|
296
|
+
overlap_ratio_w=0.2
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
def detector(image):
|
|
300
|
+
return pf.detections.from_ultralytics(model.predict(image))
|
|
301
|
+
|
|
302
|
+
# Run on 4K image - automatically slices, detects, and merges
|
|
303
|
+
large_image = cv2.imread("satellite.jpg") # 4000x3000
|
|
304
|
+
detections = slicer.predict(large_image, detector)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Line Crossing Detection
|
|
308
|
+
|
|
309
|
+
Track objects crossing defined lines:
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
import pixelflow as pf
|
|
313
|
+
|
|
314
|
+
crossings = pf.Crossings()
|
|
315
|
+
crossings.add_line(
|
|
316
|
+
start=(100, 300),
|
|
317
|
+
end=(500, 300),
|
|
318
|
+
line_id="entry_line",
|
|
319
|
+
direction="down" # Only count downward crossings
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
for frame in media.frames:
|
|
323
|
+
detections = tracker.update(pf.detections.from_ultralytics(model.predict(frame)))
|
|
324
|
+
crossings.update(detections)
|
|
325
|
+
|
|
326
|
+
print(f"Crossed: {crossings.get_counts()}")
|
|
327
|
+
frame = pf.annotate.crossings(frame, crossings)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Serialization
|
|
331
|
+
|
|
332
|
+
Export and import detection data:
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
# To JSON
|
|
336
|
+
json_str = detections.to_json()
|
|
337
|
+
|
|
338
|
+
# To dictionary (for pandas, etc.)
|
|
339
|
+
data = detections.to_dict()
|
|
340
|
+
df = pd.DataFrame(data)
|
|
341
|
+
|
|
342
|
+
# With metrics
|
|
343
|
+
report = detections.to_json_with_metrics()
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Supported Frameworks
|
|
347
|
+
|
|
348
|
+
| Framework | Converter | Features |
|
|
349
|
+
|-----------|-----------|----------|
|
|
350
|
+
| Ultralytics (YOLO) | `from_ultralytics()` | Boxes, masks, keypoints |
|
|
351
|
+
| Detectron2 | `from_detectron2()` | Boxes, masks, keypoints |
|
|
352
|
+
| HuggingFace Transformers | `from_transformers()` | Boxes, scores |
|
|
353
|
+
| Florence-2 | `from_florence2()` | Boxes, phrases |
|
|
354
|
+
| SAM | `from_sam()` | Masks, scores |
|
|
355
|
+
| Tesseract OCR | `from_tesseract()` | Text, boxes, confidence |
|
|
356
|
+
| PaddleOCR | `from_paddleocr()` | Text, boxes, structure |
|
|
357
|
+
| EasyOCR | `from_easyocr()` | Text, boxes |
|
|
358
|
+
| PP-Structure | `from_ppstructure()` | Tables, formulas, layouts |
|
|
359
|
+
|
|
360
|
+
## Documentation
|
|
361
|
+
|
|
362
|
+
Full documentation available at [https://datamarkin.com/docs/pixelflow/](https://datamarkin.com/docs/pixelflow/)
|
|
363
|
+
|
|
364
|
+
## Contributing
|
|
365
|
+
|
|
366
|
+
Contributions welcome! Please read our contributing guidelines.
|
|
367
|
+
|
|
368
|
+
## License
|
|
369
|
+
|
|
370
|
+
MIT License - see LICENSE file for details.
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
Built with love by [Datamarkin](https://datamarkin.com)
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# PixelFlow
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/pixelflow)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
**The computer vision library that gets out of your way.**
|
|
8
|
+
|
|
9
|
+
PixelFlow provides a unified, intuitive API for object detection, tracking, annotation, and video processing. Write clean, readable pipelines that work with any ML framework.
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import pixelflow as pf
|
|
13
|
+
from ultralytics import YOLO
|
|
14
|
+
|
|
15
|
+
model = YOLO("yolo11n.pt")
|
|
16
|
+
media = pf.Media("traffic.mp4")
|
|
17
|
+
tracker = pf.tracker.ByteTracker()
|
|
18
|
+
zones = pf.Zones()
|
|
19
|
+
zones.add_zone([(100, 400), (500, 400), (500, 600), (100, 600)], zone_id="entrance")
|
|
20
|
+
|
|
21
|
+
for frame in media.frames:
|
|
22
|
+
detections = pf.detections.from_ultralytics(model.predict(frame))
|
|
23
|
+
detections = tracker.update(detections)
|
|
24
|
+
zones.update(detections)
|
|
25
|
+
|
|
26
|
+
frame = pf.annotate.box(frame, detections)
|
|
27
|
+
frame = pf.annotate.label(frame, detections)
|
|
28
|
+
frame = pf.annotate.zones(frame, zones)
|
|
29
|
+
|
|
30
|
+
pf.show_frame("Live", frame)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install pixelflow
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Core Concepts
|
|
40
|
+
|
|
41
|
+
### Detections - One Format, Every Framework
|
|
42
|
+
|
|
43
|
+
Convert outputs from any ML framework into a unified format:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import pixelflow as pf
|
|
47
|
+
|
|
48
|
+
# Ultralytics YOLO
|
|
49
|
+
from ultralytics import YOLO
|
|
50
|
+
model = YOLO("yolo11n.pt")
|
|
51
|
+
detections = pf.detections.from_ultralytics(model.predict(image))
|
|
52
|
+
|
|
53
|
+
# Detectron2
|
|
54
|
+
from detectron2.engine import DefaultPredictor
|
|
55
|
+
predictor = DefaultPredictor(cfg)
|
|
56
|
+
detections = pf.detections.from_detectron2(predictor(image), class_names=["person", "car"])
|
|
57
|
+
|
|
58
|
+
# HuggingFace Transformers
|
|
59
|
+
from transformers import pipeline
|
|
60
|
+
detector = pipeline("object-detection")
|
|
61
|
+
detections = pf.detections.from_transformers(detector(image))
|
|
62
|
+
|
|
63
|
+
# Florence-2
|
|
64
|
+
detections = pf.detections.from_florence2(model_output)
|
|
65
|
+
|
|
66
|
+
# SAM (Segment Anything)
|
|
67
|
+
detections = pf.detections.from_sam(masks, scores)
|
|
68
|
+
|
|
69
|
+
# OCR Engines
|
|
70
|
+
detections = pf.detections.from_tesseract(tesseract_output)
|
|
71
|
+
detections = pf.detections.from_paddleocr(paddleocr_output)
|
|
72
|
+
detections = pf.detections.from_easyocr(easyocr_output)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Powerful Filtering
|
|
76
|
+
|
|
77
|
+
Chain filters for complex queries with zero overhead:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# Get high-confidence people in the parking zone, tracked for 5+ seconds
|
|
81
|
+
results = (detections
|
|
82
|
+
.filter_by_confidence(min_confidence=0.7)
|
|
83
|
+
.filter_by_class_id("person")
|
|
84
|
+
.filter_by_zones(["parking_lot"])
|
|
85
|
+
.filter_by_tracking_duration(min_seconds=5.0))
|
|
86
|
+
|
|
87
|
+
# Size-based filtering
|
|
88
|
+
large_objects = detections.filter_by_size(min_area=10000)
|
|
89
|
+
tall_objects = detections.filter_by_dimensions(min_height=200)
|
|
90
|
+
squares = detections.filter_by_aspect_ratio(min_ratio=0.9, max_ratio=1.1)
|
|
91
|
+
|
|
92
|
+
# Spatial filtering
|
|
93
|
+
left_side = detections.filter_by_position(max_x=frame_width // 2)
|
|
94
|
+
|
|
95
|
+
# Remove overlapping detections
|
|
96
|
+
unique = detections.remove_duplicates(iou_threshold=0.5)
|
|
97
|
+
|
|
98
|
+
# OCR-specific filters
|
|
99
|
+
titles = detections.filter_by_text_level("title")
|
|
100
|
+
english_text = detections.filter_by_text_language("en")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Media Handling
|
|
104
|
+
|
|
105
|
+
Unified interface for videos, images, webcams, and streams:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
import pixelflow as pf
|
|
109
|
+
|
|
110
|
+
# Video file with automatic resizing
|
|
111
|
+
media = pf.Media("video.mp4", width=640)
|
|
112
|
+
print(media.info) # MediaInfo(resolution=1920x1080, fps=30.00, frames=900, duration=30.00s)
|
|
113
|
+
|
|
114
|
+
for frame in media.frames: # Lazy loading, memory efficient
|
|
115
|
+
# Process frame
|
|
116
|
+
pf.show_frame("Preview", frame)
|
|
117
|
+
|
|
118
|
+
# Webcam
|
|
119
|
+
webcam = pf.Media(0)
|
|
120
|
+
|
|
121
|
+
# Network stream
|
|
122
|
+
stream = pf.Media("rtsp://camera.local/stream")
|
|
123
|
+
|
|
124
|
+
# Write processed video
|
|
125
|
+
for frame in pf.Media("input.mp4").frames:
|
|
126
|
+
processed = process(frame)
|
|
127
|
+
pf.write_frame("output.mp4", processed, media.info)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Zone-Based Analytics
|
|
131
|
+
|
|
132
|
+
Define spatial regions and track what enters them:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
import pixelflow as pf
|
|
136
|
+
|
|
137
|
+
zones = pf.Zones()
|
|
138
|
+
|
|
139
|
+
# Define zones with different trigger strategies
|
|
140
|
+
zones.add_zone(
|
|
141
|
+
polygon=[(100, 400), (300, 400), (300, 600), (100, 600)],
|
|
142
|
+
zone_id="entrance",
|
|
143
|
+
name="Main Entrance",
|
|
144
|
+
trigger_strategy="bottom_center" # Trigger when bottom-center of bbox enters
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
zones.add_zone(
|
|
148
|
+
polygon=[(500, 200), (700, 200), (700, 500), (500, 500)],
|
|
149
|
+
zone_id="restricted",
|
|
150
|
+
trigger_strategy="percentage",
|
|
151
|
+
overlap_threshold=0.3 # Trigger when 30% of bbox is inside
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Update detections with zone info
|
|
155
|
+
zones.update(detections)
|
|
156
|
+
|
|
157
|
+
# Access zone statistics
|
|
158
|
+
print(zones.get_zone_counts()) # {'entrance': 3, 'restricted': 1}
|
|
159
|
+
print(zones.get_zone_stats()) # Detailed stats including total_entered
|
|
160
|
+
|
|
161
|
+
# Filter by zone
|
|
162
|
+
entrance_only = zones.filter_by_zones(detections, ["entrance"])
|
|
163
|
+
not_restricted = zones.filter_by_zones(detections, ["restricted"], exclude=True)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Trigger Strategies:**
|
|
167
|
+
- `center` - Bounding box center point (default)
|
|
168
|
+
- `bottom_center` - Bottom-center point (great for people/vehicles)
|
|
169
|
+
- `percentage` - Percentage of bbox overlap
|
|
170
|
+
- `overlap` - Any intersection
|
|
171
|
+
- Multiple strategies with `mode="any"` or `mode="all"`
|
|
172
|
+
|
|
173
|
+
### Object Tracking
|
|
174
|
+
|
|
175
|
+
Built-in ByteTrack for multi-object tracking:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
import pixelflow as pf
|
|
179
|
+
|
|
180
|
+
tracker = pf.tracker.ByteTracker()
|
|
181
|
+
|
|
182
|
+
for frame in media.frames:
|
|
183
|
+
detections = pf.detections.from_ultralytics(model.predict(frame))
|
|
184
|
+
detections = tracker.update(detections)
|
|
185
|
+
|
|
186
|
+
for det in detections:
|
|
187
|
+
print(f"Track ID: {det.tracker_id}, Class: {det.class_name}")
|
|
188
|
+
print(f"First seen: {det.first_seen_time}, Duration: {det.total_time}s")
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Rich Annotations
|
|
192
|
+
|
|
193
|
+
Beautiful, customizable visualizations:
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
import pixelflow as pf
|
|
197
|
+
|
|
198
|
+
# Bounding boxes and labels
|
|
199
|
+
frame = pf.annotate.box(frame, detections, thickness=2)
|
|
200
|
+
frame = pf.annotate.label(frame, detections, font_scale=0.6)
|
|
201
|
+
|
|
202
|
+
# Segmentation masks
|
|
203
|
+
frame = pf.annotate.mask(frame, detections, opacity=0.4)
|
|
204
|
+
|
|
205
|
+
# Keypoints and skeletons (pose estimation)
|
|
206
|
+
frame = pf.annotate.keypoint(frame, detections)
|
|
207
|
+
frame = pf.annotate.keypoint_skeleton(frame, detections)
|
|
208
|
+
|
|
209
|
+
# Zone visualization
|
|
210
|
+
frame = pf.annotate.zones(frame, zones)
|
|
211
|
+
frame = pf.annotate.crossings(frame, crossings)
|
|
212
|
+
|
|
213
|
+
# Privacy protection
|
|
214
|
+
frame = pf.annotate.blur(frame, detections, kernel_size=51)
|
|
215
|
+
frame = pf.annotate.pixelate(frame, detections, pixel_size=15)
|
|
216
|
+
|
|
217
|
+
# Shapes
|
|
218
|
+
frame = pf.annotate.oval(frame, detections)
|
|
219
|
+
frame = pf.annotate.polygon(frame, detections)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Image Transforms
|
|
223
|
+
|
|
224
|
+
Comprehensive image and detection-aware transformations:
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
import pixelflow as pf
|
|
228
|
+
|
|
229
|
+
# Image-only transforms
|
|
230
|
+
rotated = pf.transform.rotate(image, 45)
|
|
231
|
+
flipped = pf.transform.flip_horizontal(image)
|
|
232
|
+
cropped = pf.transform.crop(image, [100, 50, 500, 400])
|
|
233
|
+
|
|
234
|
+
# Enhancement
|
|
235
|
+
enhanced = pf.transform.clahe(image)
|
|
236
|
+
gray = pf.transform.to_grayscale(image)
|
|
237
|
+
corrected = pf.transform.gamma_correction(image, gamma=1.2)
|
|
238
|
+
|
|
239
|
+
# Detection-aware transforms (coordinates update automatically)
|
|
240
|
+
rotated_img, rotated_dets = pf.transform.rotate_detections(image, detections, 45)
|
|
241
|
+
flipped_img, flipped_dets = pf.transform.flip_horizontal_detections(image, detections)
|
|
242
|
+
cropped_img, cropped_dets = pf.transform.crop_detections(image, detections, bbox=[100, 50, 500, 400])
|
|
243
|
+
|
|
244
|
+
# Automatic inverse transforms (undo all transforms)
|
|
245
|
+
original_coords = pf.transform.inverse_transforms(transformed_detections)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Sliced Inference for Large Images
|
|
249
|
+
|
|
250
|
+
Detect small objects in high-resolution images:
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
import pixelflow as pf
|
|
254
|
+
|
|
255
|
+
slicer = pf.SlicedInference(
|
|
256
|
+
slice_height=640,
|
|
257
|
+
slice_width=640,
|
|
258
|
+
overlap_ratio_h=0.2,
|
|
259
|
+
overlap_ratio_w=0.2
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def detector(image):
|
|
263
|
+
return pf.detections.from_ultralytics(model.predict(image))
|
|
264
|
+
|
|
265
|
+
# Run on 4K image - automatically slices, detects, and merges
|
|
266
|
+
large_image = cv2.imread("satellite.jpg") # 4000x3000
|
|
267
|
+
detections = slicer.predict(large_image, detector)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Line Crossing Detection
|
|
271
|
+
|
|
272
|
+
Track objects crossing defined lines:
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
import pixelflow as pf
|
|
276
|
+
|
|
277
|
+
crossings = pf.Crossings()
|
|
278
|
+
crossings.add_line(
|
|
279
|
+
start=(100, 300),
|
|
280
|
+
end=(500, 300),
|
|
281
|
+
line_id="entry_line",
|
|
282
|
+
direction="down" # Only count downward crossings
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
for frame in media.frames:
|
|
286
|
+
detections = tracker.update(pf.detections.from_ultralytics(model.predict(frame)))
|
|
287
|
+
crossings.update(detections)
|
|
288
|
+
|
|
289
|
+
print(f"Crossed: {crossings.get_counts()}")
|
|
290
|
+
frame = pf.annotate.crossings(frame, crossings)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Serialization
|
|
294
|
+
|
|
295
|
+
Export and import detection data:
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
# To JSON
|
|
299
|
+
json_str = detections.to_json()
|
|
300
|
+
|
|
301
|
+
# To dictionary (for pandas, etc.)
|
|
302
|
+
data = detections.to_dict()
|
|
303
|
+
df = pd.DataFrame(data)
|
|
304
|
+
|
|
305
|
+
# With metrics
|
|
306
|
+
report = detections.to_json_with_metrics()
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Supported Frameworks
|
|
310
|
+
|
|
311
|
+
| Framework | Converter | Features |
|
|
312
|
+
|-----------|-----------|----------|
|
|
313
|
+
| Ultralytics (YOLO) | `from_ultralytics()` | Boxes, masks, keypoints |
|
|
314
|
+
| Detectron2 | `from_detectron2()` | Boxes, masks, keypoints |
|
|
315
|
+
| HuggingFace Transformers | `from_transformers()` | Boxes, scores |
|
|
316
|
+
| Florence-2 | `from_florence2()` | Boxes, phrases |
|
|
317
|
+
| SAM | `from_sam()` | Masks, scores |
|
|
318
|
+
| Tesseract OCR | `from_tesseract()` | Text, boxes, confidence |
|
|
319
|
+
| PaddleOCR | `from_paddleocr()` | Text, boxes, structure |
|
|
320
|
+
| EasyOCR | `from_easyocr()` | Text, boxes |
|
|
321
|
+
| PP-Structure | `from_ppstructure()` | Tables, formulas, layouts |
|
|
322
|
+
|
|
323
|
+
## Documentation
|
|
324
|
+
|
|
325
|
+
Full documentation available at [https://datamarkin.com/docs/pixelflow/](https://datamarkin.com/docs/pixelflow/)
|
|
326
|
+
|
|
327
|
+
## Contributing
|
|
328
|
+
|
|
329
|
+
Contributions welcome! Please read our contributing guidelines.
|
|
330
|
+
|
|
331
|
+
## License
|
|
332
|
+
|
|
333
|
+
MIT License - see LICENSE file for details.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
Built with love by [Datamarkin](https://datamarkin.com)
|