numpyimage 2.4.1__tar.gz → 2.4.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numpyimage
3
- Version: 2.4.1
3
+ Version: 2.4.2
4
4
  Summary: Load, save, & manipulate image files as numpy arrays
5
5
  Author-email: Jasper Phelps <jasper.s.phelps@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -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
- def load_video(filename, force_rgb=False, progress_bar=True):
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 lazy_load_video(filename, force_rgb=False):
640
- """
641
- Lazily load video frames as numpy arrays using PyAV.
642
-
643
- Parameters
644
- ----------
645
- filename : str
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numpyimage
3
- Version: 2.4.1
3
+ Version: 2.4.2
4
4
  Summary: Load, save, & manipulate image files as numpy arrays
5
5
  Author-email: Jasper Phelps <jasper.s.phelps@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
4
4
 
5
5
  [project]
6
6
  name = 'numpyimage'
7
- version = '2.4.1'
7
+ version = '2.4.2'
8
8
  description = 'Load, save, & manipulate image files as numpy arrays'
9
9
  readme.file = 'README.md'
10
10
  readme.content-type = 'text/markdown'
@@ -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