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.
- datamint/apihandler/annotation_api_handler.py +241 -153
- datamint/apihandler/dto/annotation_dto.py +1 -1
- datamint/apihandler/root_api_handler.py +4 -2
- datamint/client_cmd_tools/datamint_upload.py +101 -42
- datamint/dataset/base_dataset.py +2 -2
- {datamint-1.5.5.dist-info → datamint-1.6.2.dist-info}/METADATA +2 -1
- {datamint-1.5.5.dist-info → datamint-1.6.2.dist-info}/RECORD +9 -11
- datamint/utils/dicom_utils.py +0 -707
- datamint/utils/io_utils.py +0 -187
- {datamint-1.5.5.dist-info → datamint-1.6.2.dist-info}/WHEEL +0 -0
- {datamint-1.5.5.dist-info → datamint-1.6.2.dist-info}/entry_points.txt +0 -0
datamint/utils/io_utils.py
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|