Commit f8b681d
Fix RGB/BGR color channel ordering in .pkg.slp embedded frames (#250)
* Bump SLP format version to 1.4 and add format history
- Increment FORMAT_ID from 1.3 to 1.4
- Document format version history in module docstring:
- 1.0: Initial format
- 1.1: Coordinate system change
- 1.2: Added tracking_score field
- 1.3: Explicit tracking_score handling
- 1.4: Added channel_order for RGB/BGR tracking (this change)
- Remove deprecated embed_video() function (cleanup)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add image plugin system for embedded frame encoding/decoding
Introduce a dedicated plugin system for image encoding/decoding, separate
from the video plugin system. This controls how embedded frames in .pkg.slp
files are encoded and decoded.
Changes:
- Add _default_image_plugin global variable
- Add normalize_image_plugin_name() for validation
- Add set_default_image_plugin() and get_default_image_plugin()
- Only supports "opencv" and "imageio" (no PyAV for images)
- Cleaner separation from video plugins (opencv/FFMPEG/pyav)
Rationale:
- Image encoding/decoding has different requirements than video streaming
- Only OpenCV and imageio support image encode/decode operations
- Avoids special-casing PyAV→imageio mappings everywhere
- Provides clear API for users to control embedded frame encoding
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Thread plugin parameter through embedding API
Add plugin parameter to all embedding functions to allow users to control
which image plugin (opencv or imageio) is used for encoding embedded frames.
Changes:
- Add plugin parameter to process_and_embed_frames()
- Use get_default_image_plugin() if None
- Auto-detect if no default (opencv preferred, then imageio)
- Use plugin to control encoding instead of checking sys.modules
- Thread plugin through call chain:
- embed_frames()
- embed_videos()
- write_labels()
- save_slp()
- Update all docstrings to document plugin parameter
- Update encoding logic to use plugin variable instead of sys.modules check
Benefits:
- Users can explicitly control encoding plugin via save_slp(plugin="opencv")
- Global default via set_default_image_plugin() is respected
- Maintains backwards compatibility (auto-detect if not specified)
- Enables consistent encoding/decoding for color accuracy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Export image plugin functions in public API
Add get_default_image_plugin and set_default_image_plugin to the public
sleap_io API for controlling embedded frame encoding.
Changes:
- Import functions from sleap_io.io.video_reading
- Add to __all__ export list
Usage:
import sleap_io as sio
sio.set_default_image_plugin("opencv") # Use OpenCV for all embedding
sio.save_slp(labels, "file.pkg.slp", embed="all") # Uses OpenCV
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add comprehensive tests for RGB/BGR channel ordering in embedded frames
- Add small_robot_3_frame.mp4 test video fixture (3 frames, 22KB)
- Add test_embed_channel_order_consistency: Parametrized test covering all 4 encoder/decoder plugin combinations (opencv/imageio)
- Add test_embed_channel_order_metadata: Verifies channel_order attribute stored correctly in HDF5
- Add test_embed_backwards_compatibility_channel_order: Ensures legacy files (format < 1.4) default to BGR
- Fix test_format_id_1_3_tracking_score to expect format_id 1.4 (was 1.3)
Tests verify:
✓ Pixel-perfect frame matching across all plugin combinations
✓ Automatic RGB/BGR channel conversion works correctly
✓ HDF5 metadata stores correct channel_order ("RGB" or "BGR")
✓ Backwards compatibility with pre-1.4 files
All 82 tests in test_slp.py pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add image plugin support to ImageVideo with automatic RGB/BGR handling
- Add plugin attribute to ImageVideo class with validator and default factory
- Support both "opencv" and "imageio" plugins for reading images
- Always output RGB regardless of plugin (auto-convert BGR->RGB for OpenCV)
- Respect global _default_image_plugin setting from get_default_image_plugin()
- Auto-detect plugin if none specified (opencv preferred, then imageio)
Updates to ImageVideo._read_frame():
- Use cv2.imread() when plugin="opencv", flip BGR->RGB for color images
- Use iio.imread() when plugin="imageio" (RGB native)
- No metadata storage needed (always assumes RGB output)
Documentation:
- Update VideoBackend.from_filename() docstring to document ImageVideo plugin parameter
- Enhance ImageVideo class docstring with plugin information
Tests:
- Add test_image_video_plugin_consistency: Verify both plugins produce identical RGB output
- Add test_image_video_default_plugin: Test global default plugin setting
- Add test_image_video_explicit_plugin_overrides_default: Test explicit parameter overrides
- Add test_image_video_plugin_with_grayscale: Test plugin works with grayscale images
- All 34 tests in test_video_reading.py pass
Provides consistent API across all video backends (ImageVideo, MediaVideo, HDF5Video).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent b56fad2 commit f8b681d
8 files changed
Lines changed: 550 additions & 138 deletions
File tree
- sleap_io
- io
- tests
- data/videos
- fixtures
- io
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
28 | 29 | | |
| 30 | + | |
29 | 31 | | |
30 | 32 | | |
31 | 33 | | |
| |||
72 | 74 | | |
73 | 75 | | |
74 | 76 | | |
| 77 | + | |
75 | 78 | | |
| 79 | + | |
76 | 80 | | |
77 | 81 | | |
78 | 82 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| 58 | + | |
58 | 59 | | |
59 | 60 | | |
60 | 61 | | |
| |||
79 | 80 | | |
80 | 81 | | |
81 | 82 | | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
82 | 87 | | |
83 | 88 | | |
84 | 89 | | |
85 | 90 | | |
86 | 91 | | |
87 | 92 | | |
88 | 93 | | |
| 94 | + | |
89 | 95 | | |
90 | 96 | | |
91 | 97 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
2 | 10 | | |
3 | 11 | | |
4 | 12 | | |
| |||
290 | 298 | | |
291 | 299 | | |
292 | 300 | | |
293 | | - | |
294 | | - | |
295 | | - | |
296 | | - | |
297 | | - | |
298 | | - | |
299 | | - | |
300 | | - | |
301 | | - | |
302 | | - | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
310 | | - | |
311 | | - | |
312 | | - | |
313 | | - | |
314 | | - | |
315 | | - | |
316 | | - | |
317 | | - | |
318 | | - | |
319 | | - | |
320 | | - | |
321 | | - | |
322 | | - | |
323 | | - | |
324 | | - | |
325 | | - | |
326 | | - | |
327 | | - | |
328 | | - | |
329 | | - | |
330 | | - | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
336 | | - | |
337 | | - | |
338 | | - | |
339 | | - | |
340 | | - | |
341 | | - | |
342 | | - | |
343 | | - | |
344 | | - | |
345 | | - | |
346 | | - | |
347 | | - | |
348 | | - | |
349 | | - | |
350 | | - | |
351 | | - | |
352 | | - | |
353 | | - | |
354 | | - | |
355 | | - | |
356 | | - | |
357 | | - | |
358 | | - | |
359 | | - | |
360 | | - | |
361 | | - | |
362 | | - | |
363 | | - | |
364 | | - | |
365 | | - | |
366 | | - | |
367 | | - | |
368 | | - | |
369 | | - | |
370 | | - | |
371 | | - | |
372 | | - | |
373 | | - | |
374 | | - | |
375 | | - | |
376 | | - | |
377 | | - | |
378 | | - | |
379 | | - | |
380 | | - | |
381 | | - | |
382 | | - | |
383 | | - | |
384 | | - | |
385 | | - | |
386 | | - | |
387 | | - | |
388 | | - | |
389 | | - | |
390 | | - | |
391 | | - | |
392 | | - | |
393 | | - | |
394 | | - | |
395 | | - | |
396 | | - | |
397 | | - | |
398 | | - | |
399 | | - | |
400 | | - | |
401 | | - | |
402 | | - | |
403 | | - | |
404 | | - | |
405 | | - | |
406 | | - | |
407 | | - | |
408 | | - | |
409 | | - | |
410 | | - | |
411 | | - | |
412 | | - | |
413 | | - | |
414 | | - | |
415 | 301 | | |
416 | 302 | | |
417 | 303 | | |
| |||
467 | 353 | | |
468 | 354 | | |
469 | 355 | | |
| 356 | + | |
470 | 357 | | |
471 | 358 | | |
472 | 359 | | |
| |||
484 | 371 | | |
485 | 372 | | |
486 | 373 | | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
487 | 377 | | |
488 | 378 | | |
489 | 379 | | |
490 | 380 | | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
491 | 390 | | |
492 | 391 | | |
493 | 392 | | |
| |||
508 | 407 | | |
509 | 408 | | |
510 | 409 | | |
| 410 | + | |
511 | 411 | | |
512 | 412 | | |
513 | 413 | | |
| |||
516 | 416 | | |
517 | 417 | | |
518 | 418 | | |
| 419 | + | |
519 | 420 | | |
520 | | - | |
| 421 | + | |
521 | 422 | | |
522 | 423 | | |
523 | 424 | | |
524 | | - | |
| 425 | + | |
| 426 | + | |
525 | 427 | | |
526 | 428 | | |
527 | 429 | | |
528 | 430 | | |
529 | 431 | | |
530 | 432 | | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
531 | 438 | | |
532 | 439 | | |
533 | 440 | | |
| |||
570 | 477 | | |
571 | 478 | | |
572 | 479 | | |
| 480 | + | |
573 | 481 | | |
574 | 482 | | |
575 | 483 | | |
| |||
617 | 525 | | |
618 | 526 | | |
619 | 527 | | |
| 528 | + | |
620 | 529 | | |
621 | 530 | | |
622 | 531 | | |
| |||
628 | 537 | | |
629 | 538 | | |
630 | 539 | | |
| 540 | + | |
| 541 | + | |
631 | 542 | | |
632 | 543 | | |
633 | 544 | | |
634 | 545 | | |
635 | 546 | | |
636 | 547 | | |
637 | 548 | | |
638 | | - | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
639 | 554 | | |
640 | 555 | | |
641 | 556 | | |
| |||
647 | 562 | | |
648 | 563 | | |
649 | 564 | | |
| 565 | + | |
650 | 566 | | |
651 | 567 | | |
652 | 568 | | |
| |||
664 | 580 | | |
665 | 581 | | |
666 | 582 | | |
| 583 | + | |
| 584 | + | |
667 | 585 | | |
668 | 586 | | |
669 | 587 | | |
| |||
689 | 607 | | |
690 | 608 | | |
691 | 609 | | |
692 | | - | |
| 610 | + | |
693 | 611 | | |
694 | 612 | | |
695 | 613 | | |
| |||
1054 | 972 | | |
1055 | 973 | | |
1056 | 974 | | |
1057 | | - | |
| 975 | + | |
1058 | 976 | | |
1059 | 977 | | |
1060 | 978 | | |
| |||
2019 | 1937 | | |
2020 | 1938 | | |
2021 | 1939 | | |
| 1940 | + | |
2022 | 1941 | | |
2023 | 1942 | | |
2024 | 1943 | | |
| |||
2043 | 1962 | | |
2044 | 1963 | | |
2045 | 1964 | | |
| 1965 | + | |
| 1966 | + | |
| 1967 | + | |
| 1968 | + | |
2046 | 1969 | | |
2047 | 1970 | | |
2048 | 1971 | | |
| |||
2052 | 1975 | | |
2053 | 1976 | | |
2054 | 1977 | | |
2055 | | - | |
| 1978 | + | |
2056 | 1979 | | |
2057 | 1980 | | |
2058 | 1981 | | |
| |||
0 commit comments