datamint 1.5.5__py3-none-any.whl → 1.6.2__py3-none-any.whl

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.

Potentially problematic release.


This version of datamint might be problematic. Click here for more details.

@@ -1,187 +0,0 @@
1
- import numpy as np
2
- import nibabel as nib
3
- from PIL import Image
4
- from .dicom_utils import load_image_normalized, is_dicom
5
- import pydicom
6
- import os
7
- from typing import Any
8
- import logging
9
- from PIL import ImageFile
10
- import cv2
11
-
12
- ImageFile.LOAD_TRUNCATED_IMAGES = True
13
-
14
- _LOGGER = logging.getLogger(__name__)
15
-
16
- IMAGE_EXTS = ('.png', '.jpg', '.jpeg')
17
- NII_EXTS = ('.nii', '.nii.gz')
18
- VIDEO_EXTS = ('.mp4', '.avi', '.mov', '.mkv')
19
-
20
-
21
- def read_video(file_path: str, index: int = None) -> np.ndarray:
22
- cap = cv2.VideoCapture(file_path)
23
- if not cap.isOpened():
24
- raise ValueError(f"Failed to open video file: {file_path}")
25
- try:
26
- if index is None:
27
- frames = []
28
- while True:
29
- ret, frame = cap.read()
30
- if not ret:
31
- break
32
- # Convert BGR to RGB and transpose to (C, H, W) format
33
- frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
34
- frame = frame.transpose(2, 0, 1)
35
- frames.append(frame)
36
- imgs = np.array(frames) # shape: (#frames, C, H, W)
37
- else:
38
- while index > 0:
39
- cap.grab()
40
- index -= 1
41
- ret, frame = cap.read()
42
- if not ret:
43
- raise ValueError(f"Failed to read frame {index} from video file: {file_path}")
44
- # Convert BGR to RGB and transpose to (C, H, W) format
45
- frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
46
- imgs = frame.transpose(2, 0, 1)
47
- finally:
48
- cap.release()
49
-
50
- if imgs is None or len(imgs) == 0:
51
- raise ValueError(f"No frames found in video file: {file_path}")
52
-
53
- return imgs
54
-
55
-
56
- def read_nifti(file_path: str, mimetype: str | None = None) -> np.ndarray:
57
- """
58
- Read a NIfTI file and return the image data in standardized format.
59
-
60
- Args:
61
- file_path: Path to the NIfTI file (.nii or .nii.gz)
62
- mimetype: Optional MIME type of the file. If provided, it can help in determining how to read the file.
63
-
64
- Returns:
65
- np.ndarray: Image data with shape (#frames, C, H, W)
66
- """
67
- from nibabel.filebasedimages import ImageFileError
68
- try:
69
- imgs = nib.load(file_path).get_fdata() # shape: (W, H, #frame) or (W, H)
70
- except ImageFileError as e:
71
- if mimetype is None:
72
- raise e
73
- # has_ext = os.path.splitext(file_path)[1] != ''
74
- if mimetype == 'application/gzip':
75
- with gzip.open(file_path, 'rb') as f:
76
- imgs = nib.Nifti1Image.from_stream(f).get_fdata()
77
- elif mimetype in ('image/x.nifti', 'application/x-nifti'):
78
- with open(file_path, 'rb') as f:
79
- imgs = nib.Nifti1Image.from_stream(f).get_fdata()
80
- else:
81
- raise e
82
- if imgs.ndim == 2:
83
- imgs = imgs.transpose(1, 0)
84
- imgs = imgs[np.newaxis, np.newaxis]
85
- elif imgs.ndim == 3:
86
- imgs = imgs.transpose(2, 1, 0)
87
- imgs = imgs[:, np.newaxis]
88
- else:
89
- raise ValueError(f"Unsupported number of dimensions in '{file_path}': {imgs.ndim}")
90
-
91
- return imgs
92
-
93
-
94
- def read_image(file_path: str) -> np.ndarray:
95
- with Image.open(file_path) as pilimg:
96
- imgs = np.array(pilimg)
97
- if imgs.ndim == 2: # (H, W)
98
- imgs = imgs[np.newaxis, np.newaxis]
99
- elif imgs.ndim == 3: # (H, W, C)
100
- imgs = imgs.transpose(2, 0, 1)[np.newaxis] # (H, W, C) -> (1, C, H, W)
101
-
102
- return imgs
103
-
104
-
105
- def read_array_normalized(file_path: str,
106
- index: int | None = None,
107
- return_metainfo: bool = False,
108
- use_magic=False) -> np.ndarray | tuple[np.ndarray, Any]:
109
- """
110
- Read an array from a file.
111
-
112
- Args:
113
- file_path: The path to the file.
114
- index: If specified, read only the frame at this index (0-based).
115
- If None, read all frames.
116
- Supported file formats are NIfTI (.nii, .nii.gz), PNG (.png), JPEG (.jpg, .jpeg) and npy (.npy).
117
-
118
- Returns:
119
- The array read from the file in shape (#frames, C, H, W), if `index=None`,
120
- or (C, H, W) if `index` is specified.
121
- """
122
- if not os.path.exists(file_path):
123
- raise FileNotFoundError(f"File not found: {file_path}")
124
-
125
- metainfo = None
126
-
127
- try:
128
- if is_dicom(file_path):
129
- ds = pydicom.dcmread(file_path)
130
- if index is not None:
131
- imgs = load_image_normalized(ds, index=index)[0]
132
- else:
133
- imgs = load_image_normalized(ds)
134
- # Free up memory
135
- if hasattr(ds, '_pixel_array'):
136
- ds._pixel_array = None
137
- if hasattr(ds, 'PixelData'):
138
- ds.PixelData = None
139
- metainfo = ds
140
- else:
141
- if use_magic:
142
- import magic # it is important to import here because magic has an OS lib dependency.
143
- mime_type = magic.from_file(file_path, mime=True)
144
- else:
145
- mime_type = ""
146
-
147
- if mime_type.startswith('video/') or file_path.endswith(VIDEO_EXTS):
148
- imgs = read_video(file_path, index)
149
- else:
150
- if mime_type in ('image/x.nifti', 'application/x-nifti') or mime_type == 'application/gzip' or file_path.endswith(NII_EXTS):
151
- imgs = read_nifti(file_path, mimetype=mime_type)
152
- # For NIfTI files, try to load associated JSON metadata
153
- if return_metainfo:
154
- json_path = file_path.replace('.nii.gz', '.json').replace('.nii', '.json')
155
- if os.path.exists(json_path):
156
- try:
157
- import json
158
- with open(json_path, 'r') as f:
159
- metainfo = json.load(f)
160
- _LOGGER.debug(f"Loaded JSON metadata from {json_path}")
161
- except Exception as e:
162
- _LOGGER.warning(f"Failed to load JSON metadata from {json_path}: {e}")
163
- metainfo = None
164
- elif mime_type.startswith('image/') or file_path.endswith(IMAGE_EXTS):
165
- imgs = read_image(file_path)
166
- elif file_path.endswith('.npy') or mime_type == 'application/x-numpy-data':
167
- imgs = np.load(file_path)
168
- if imgs.ndim != 4:
169
- raise ValueError(f"Unsupported number of dimensions in '{file_path}': {imgs.ndim}")
170
- else:
171
- raise ValueError(f"Unsupported file format '{mime_type}' of '{file_path}'")
172
-
173
- if index is not None:
174
- if len(imgs) > 1:
175
- _LOGGER.warning(f"It is inefficient to load all frames from '{file_path}' to access a single frame." +
176
- " Consider converting the file to a format that supports random access (DICOM), or" +
177
- " convert to png/jpeg files or" +
178
- " manually handle all frames at once instead of loading a specific frame.")
179
- imgs = imgs[index]
180
-
181
- if return_metainfo:
182
- return imgs, metainfo
183
- return imgs
184
-
185
- except Exception as e:
186
- _LOGGER.error(f"Failed to read array from '{file_path}': {e}")
187
- raise e