numpyimage 2.4.1__tar.gz → 2.4.3__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.
- {numpyimage-2.4.1 → numpyimage-2.4.3}/PKG-INFO +1 -1
- {numpyimage-2.4.1 → numpyimage-2.4.3}/npimage/core.py +94 -92
- {numpyimage-2.4.1 → numpyimage-2.4.3}/numpyimage.egg-info/PKG-INFO +1 -1
- {numpyimage-2.4.1 → numpyimage-2.4.3}/pyproject.toml +1 -1
- {numpyimage-2.4.1 → numpyimage-2.4.3}/tests/test_heic.py +11 -11
- {numpyimage-2.4.1 → numpyimage-2.4.3}/tests/test_pbm.py +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/LICENSE +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/README.md +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/npimage/__init__.py +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/npimage/align.py +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/npimage/graphics.py +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/npimage/nrrd_utils.py +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/npimage/operations.py +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/npimage/utils.py +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/numpyimage.egg-info/SOURCES.txt +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/numpyimage.egg-info/dependency_links.txt +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/numpyimage.egg-info/requires.txt +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/numpyimage.egg-info/top_level.txt +0 -0
- {numpyimage-2.4.1 → numpyimage-2.4.3}/setup.cfg +0 -0
|
@@ -23,18 +23,6 @@ supported_extensions = [
|
|
|
23
23
|
'nrrd', 'zarr', 'raw', 'vol', 'ng', 'heic'
|
|
24
24
|
]
|
|
25
25
|
|
|
26
|
-
# Flag to track if HEIF opener has been registered
|
|
27
|
-
_heif_opener_registered = False
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def _ensure_heif_opener_registered():
|
|
31
|
-
"""Register the HEIF opener if not already registered."""
|
|
32
|
-
global _heif_opener_registered
|
|
33
|
-
if not _heif_opener_registered:
|
|
34
|
-
from pillow_heif import register_heif_opener
|
|
35
|
-
register_heif_opener()
|
|
36
|
-
_heif_opener_registered = True
|
|
37
|
-
|
|
38
26
|
|
|
39
27
|
def load(filename, dim_order='zyx', **kwargs):
|
|
40
28
|
"""
|
|
@@ -374,6 +362,91 @@ write = save # Function name alias
|
|
|
374
362
|
to_file = save # Function name alias
|
|
375
363
|
|
|
376
364
|
|
|
365
|
+
def load_video(filename, force_rgb=False, progress_bar=True):
|
|
366
|
+
"""
|
|
367
|
+
Load all images in a video file as a numpy array.
|
|
368
|
+
|
|
369
|
+
Parameters
|
|
370
|
+
----------
|
|
371
|
+
filename : str
|
|
372
|
+
Path to the video file
|
|
373
|
+
force_rgb : bool, default False
|
|
374
|
+
If True, always return frames as RGB arrays (shape=(H, W, 3))
|
|
375
|
+
If False, return frames in their native format (e.g., grayscale if possible)
|
|
376
|
+
progress_bar : bool, default True
|
|
377
|
+
If True, display a progress bar
|
|
378
|
+
|
|
379
|
+
Returns
|
|
380
|
+
-------
|
|
381
|
+
data : numpy.ndarray
|
|
382
|
+
The video frames as a numpy array, shape (num_frames, height, width[, channels])
|
|
383
|
+
"""
|
|
384
|
+
try:
|
|
385
|
+
import av
|
|
386
|
+
except ImportError:
|
|
387
|
+
raise ImportError('To use load_video, install PyAV: pip install av')
|
|
388
|
+
from tqdm import tqdm
|
|
389
|
+
container = av.open(filename)
|
|
390
|
+
stream = container.streams.video[0]
|
|
391
|
+
num_frames = stream.frames
|
|
392
|
+
if not num_frames or num_frames == 0:
|
|
393
|
+
# If we don't know the number of frames, we can't preallocate, so
|
|
394
|
+
# it's hard to do better than the following approach (which temporarily
|
|
395
|
+
# uses double the amount of RAM than the preallocated approach uses).
|
|
396
|
+
return np.array(list(lazy_load_video(filename, force_rgb=force_rgb)))
|
|
397
|
+
else:
|
|
398
|
+
# Load first image to get shape and dtype
|
|
399
|
+
frame_iter = container.decode(stream)
|
|
400
|
+
first_frame = next(frame_iter)
|
|
401
|
+
if force_rgb:
|
|
402
|
+
first_img = first_frame.to_ndarray(format='rgb24')
|
|
403
|
+
else:
|
|
404
|
+
first_img = first_frame.to_ndarray()
|
|
405
|
+
# Preallocate memory for the entire array
|
|
406
|
+
data = np.empty((num_frames, *first_img.shape), dtype=first_img.dtype)
|
|
407
|
+
# Then fill it up frame by frame
|
|
408
|
+
data[0] = first_img
|
|
409
|
+
for i, frame in tqdm(enumerate(frame_iter, start=1), total=num_frames,
|
|
410
|
+
desc='Loading video', disable=not progress_bar):
|
|
411
|
+
if force_rgb:
|
|
412
|
+
img = frame.to_ndarray(format='rgb24')
|
|
413
|
+
else:
|
|
414
|
+
img = frame.to_ndarray()
|
|
415
|
+
data[i] = img
|
|
416
|
+
return data
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def lazy_load_video(filename, force_rgb=False):
|
|
420
|
+
"""
|
|
421
|
+
Lazily load video frames as numpy arrays using PyAV.
|
|
422
|
+
|
|
423
|
+
Parameters
|
|
424
|
+
----------
|
|
425
|
+
filename : str
|
|
426
|
+
Path to the video file.
|
|
427
|
+
force_rgb : bool, default False
|
|
428
|
+
If True, always return frames as RGB arrays (shape=(H, W, 3)).
|
|
429
|
+
If False, return frames in their native format (e.g., grayscale if possible).
|
|
430
|
+
|
|
431
|
+
Yields
|
|
432
|
+
------
|
|
433
|
+
frame : np.ndarray
|
|
434
|
+
Video frame as a numpy array, shape (height, width[, colors]).
|
|
435
|
+
"""
|
|
436
|
+
try:
|
|
437
|
+
import av
|
|
438
|
+
except ImportError:
|
|
439
|
+
raise ImportError('To use lazy_load_video, install PyAV: pip install av')
|
|
440
|
+
container = av.open(filename)
|
|
441
|
+
stream = container.streams.video[0]
|
|
442
|
+
for frame in container.decode(stream):
|
|
443
|
+
if force_rgb:
|
|
444
|
+
img = frame.to_ndarray(format='rgb24')
|
|
445
|
+
else:
|
|
446
|
+
img = frame.to_ndarray()
|
|
447
|
+
yield img
|
|
448
|
+
|
|
449
|
+
|
|
377
450
|
def save_video(data, filename, time_axis=0, color_axis=None, overwrite=False,
|
|
378
451
|
dim_order='yx', framerate=30, crf=23, compression_speed='medium'):
|
|
379
452
|
"""
|
|
@@ -582,86 +655,15 @@ def find_channel_axis(data, expected_channel_axis=[0, -1]):
|
|
|
582
655
|
return None
|
|
583
656
|
|
|
584
657
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
Load all images in a video file as a numpy array.
|
|
588
|
-
|
|
589
|
-
Parameters
|
|
590
|
-
----------
|
|
591
|
-
filename : str
|
|
592
|
-
Path to the video file
|
|
593
|
-
force_rgb : bool, default False
|
|
594
|
-
If True, always return frames as RGB arrays (shape=(H, W, 3))
|
|
595
|
-
If False, return frames in their native format (e.g., grayscale if possible)
|
|
596
|
-
progress_bar : bool, default True
|
|
597
|
-
If True, display a progress bar
|
|
598
|
-
|
|
599
|
-
Returns
|
|
600
|
-
-------
|
|
601
|
-
data : numpy.ndarray
|
|
602
|
-
The video frames as a numpy array, shape (num_frames, height, width[, channels])
|
|
603
|
-
"""
|
|
604
|
-
try:
|
|
605
|
-
import av
|
|
606
|
-
except ImportError:
|
|
607
|
-
raise ImportError('To use load_video, install PyAV: pip install av')
|
|
608
|
-
from tqdm import tqdm
|
|
609
|
-
container = av.open(filename)
|
|
610
|
-
stream = container.streams.video[0]
|
|
611
|
-
num_frames = stream.frames
|
|
612
|
-
if not num_frames or num_frames == 0:
|
|
613
|
-
# If we don't know the number of frames, we can't preallocate, so
|
|
614
|
-
# it's hard to do better than the following approach (which temporarily
|
|
615
|
-
# uses double the amount of RAM than the preallocated approach uses).
|
|
616
|
-
return np.array(list(lazy_load_video(filename, force_rgb=force_rgb)))
|
|
617
|
-
else:
|
|
618
|
-
# Load first image to get shape and dtype
|
|
619
|
-
frame_iter = container.decode(stream)
|
|
620
|
-
first_frame = next(frame_iter)
|
|
621
|
-
if force_rgb:
|
|
622
|
-
first_img = first_frame.to_ndarray(format='rgb24')
|
|
623
|
-
else:
|
|
624
|
-
first_img = first_frame.to_ndarray()
|
|
625
|
-
# Preallocate memory for the entire array
|
|
626
|
-
data = np.empty((num_frames, *first_img.shape), dtype=first_img.dtype)
|
|
627
|
-
# Then fill it up frame by frame
|
|
628
|
-
data[0] = first_img
|
|
629
|
-
for i, frame in tqdm(enumerate(frame_iter, start=1), total=num_frames,
|
|
630
|
-
desc='Loading video', disable=not progress_bar):
|
|
631
|
-
if force_rgb:
|
|
632
|
-
img = frame.to_ndarray(format='rgb24')
|
|
633
|
-
else:
|
|
634
|
-
img = frame.to_ndarray()
|
|
635
|
-
data[i] = img
|
|
636
|
-
return data
|
|
658
|
+
# Flag to track if HEIF opener has been registered
|
|
659
|
+
_heif_opener_registered = False
|
|
637
660
|
|
|
638
661
|
|
|
639
|
-
def
|
|
640
|
-
"""
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
Path to the video file.
|
|
647
|
-
force_rgb : bool, default False
|
|
648
|
-
If True, always return frames as RGB arrays (shape=(H, W, 3)).
|
|
649
|
-
If False, return frames in their native format (e.g., grayscale if possible).
|
|
662
|
+
def _ensure_heif_opener_registered():
|
|
663
|
+
"""Register the HEIF opener if not already registered."""
|
|
664
|
+
global _heif_opener_registered
|
|
665
|
+
if not _heif_opener_registered:
|
|
666
|
+
from pillow_heif import register_heif_opener
|
|
667
|
+
register_heif_opener()
|
|
668
|
+
_heif_opener_registered = True
|
|
650
669
|
|
|
651
|
-
Yields
|
|
652
|
-
------
|
|
653
|
-
frame : np.ndarray
|
|
654
|
-
Video frame as a numpy array, shape (height, width[, colors]).
|
|
655
|
-
"""
|
|
656
|
-
try:
|
|
657
|
-
import av
|
|
658
|
-
except ImportError:
|
|
659
|
-
raise ImportError('To use lazy_load_video, install PyAV: pip install av')
|
|
660
|
-
container = av.open(filename)
|
|
661
|
-
stream = container.streams.video[0]
|
|
662
|
-
for frame in container.decode(stream):
|
|
663
|
-
if force_rgb:
|
|
664
|
-
img = frame.to_ndarray(format='rgb24')
|
|
665
|
-
else:
|
|
666
|
-
img = frame.to_ndarray()
|
|
667
|
-
yield img
|
|
@@ -10,29 +10,29 @@ def test_heic_load_save():
|
|
|
10
10
|
"""Test loading and saving HEIC images."""
|
|
11
11
|
# Create a simple test image
|
|
12
12
|
test_data = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
15
15
|
# Test saving as HEIC
|
|
16
16
|
heic_filename = os.path.join(tmpdir, "test_image.heic")
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
try:
|
|
19
19
|
# Save the test data as HEIC
|
|
20
20
|
npimage.save(test_data, heic_filename)
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
# Verify the file was created
|
|
23
23
|
assert os.path.exists(heic_filename), "HEIC file was not created"
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
# Load the HEIC file back
|
|
26
26
|
loaded_data = npimage.load(heic_filename)
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
# Check that the loaded data has the same shape
|
|
29
29
|
assert loaded_data.shape == test_data.shape, f"Shape mismatch: expected {test_data.shape}, got {loaded_data.shape}"
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
# Check that the data type is correct
|
|
32
32
|
assert loaded_data.dtype == np.uint8, f"Data type mismatch: expected uint8, got {loaded_data.dtype}"
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
print("Test passed: HEIC load/save functionality works correctly.")
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
except Exception as e:
|
|
37
37
|
print(f"Test failed with error: {e}")
|
|
38
38
|
raise
|
|
@@ -42,12 +42,12 @@ def test_heic_extension_support():
|
|
|
42
42
|
"""Test that HEIC extension is properly recognized."""
|
|
43
43
|
# Test that HEIC is in the supported extensions
|
|
44
44
|
assert 'heic' in npimage.core.supported_extensions, "HEIC extension not in supported extensions"
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
# Test that the extension is properly parsed
|
|
47
47
|
filename = "test_image.heic"
|
|
48
48
|
extension = filename.split('.')[-1].lower()
|
|
49
49
|
assert extension == 'heic', f"Extension parsing failed: expected 'heic', got '{extension}'"
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
print("Test passed: HEIC extension is properly supported.")
|
|
52
52
|
|
|
53
53
|
|
|
@@ -58,4 +58,4 @@ if __name__ == '__main__':
|
|
|
58
58
|
print("All HEIC tests passed!")
|
|
59
59
|
except Exception as e:
|
|
60
60
|
print(f"HEIC tests failed: {e}")
|
|
61
|
-
raise
|
|
61
|
+
raise
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|