dicube 0.2.2__cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.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.
- dicube/__init__.py +174 -0
- dicube/codecs/__init__.py +152 -0
- dicube/codecs/jph/__init__.py +15 -0
- dicube/codecs/jph/codec.py +161 -0
- dicube/codecs/jph/ojph_complete.cpython-310-aarch64-linux-gnu.so +0 -0
- dicube/codecs/jph/ojph_complete.cpython-311-aarch64-linux-gnu.so +0 -0
- dicube/codecs/jph/ojph_complete.cpython-38-aarch64-linux-gnu.so +0 -0
- dicube/codecs/jph/ojph_complete.cpython-39-aarch64-linux-gnu.so +0 -0
- dicube/codecs/jph/ojph_decode_complete.cpython-310-aarch64-linux-gnu.so +0 -0
- dicube/codecs/jph/ojph_decode_complete.cpython-311-aarch64-linux-gnu.so +0 -0
- dicube/codecs/jph/ojph_decode_complete.cpython-38-aarch64-linux-gnu.so +0 -0
- dicube/codecs/jph/ojph_decode_complete.cpython-39-aarch64-linux-gnu.so +0 -0
- dicube/core/__init__.py +21 -0
- dicube/core/image.py +349 -0
- dicube/core/io.py +408 -0
- dicube/core/pixel_header.py +120 -0
- dicube/dicom/__init__.py +13 -0
- dicube/dicom/dcb_streaming.py +248 -0
- dicube/dicom/dicom_io.py +153 -0
- dicube/dicom/dicom_meta.py +740 -0
- dicube/dicom/dicom_status.py +259 -0
- dicube/dicom/dicom_tags.py +121 -0
- dicube/dicom/merge_utils.py +283 -0
- dicube/dicom/space_from_meta.py +70 -0
- dicube/exceptions.py +189 -0
- dicube/storage/__init__.py +17 -0
- dicube/storage/dcb_file.py +824 -0
- dicube/storage/pixel_utils.py +259 -0
- dicube/utils/__init__.py +6 -0
- dicube/validation.py +380 -0
- dicube-0.2.2.dist-info/METADATA +272 -0
- dicube-0.2.2.dist-info/RECORD +33 -0
- dicube-0.2.2.dist-info/WHEEL +6 -0
dicube/__init__.py
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
"""DiCube: Python library for efficient storage and processing of 3D medical images.
|
2
|
+
|
3
|
+
DiCube provides functionality for working with DICOM image data while preserving
|
4
|
+
complete metadata. It offers efficient storage formats, image processing capabilities,
|
5
|
+
and interoperability with various medical image formats.
|
6
|
+
|
7
|
+
Main functionality:
|
8
|
+
- Load/save 3D medical images with complete DICOM metadata
|
9
|
+
- Efficient binary storage format with multiple compression options
|
10
|
+
- Spatial transformation and orientation handling
|
11
|
+
- Conversion between different medical image formats
|
12
|
+
|
13
|
+
Example:
|
14
|
+
>>> import dicube
|
15
|
+
>>> # Load from DICOM folder
|
16
|
+
>>> image = dicube.load_from_dicom_folder("path/to/dicom_folder")
|
17
|
+
>>> # Save to DCB file
|
18
|
+
>>> dicube.save(image, "output.dcb")
|
19
|
+
>>> # Access the data
|
20
|
+
>>> pixel_data = image.get_fdata()
|
21
|
+
"""
|
22
|
+
|
23
|
+
from .core.image import DicomCubeImage
|
24
|
+
from .core.io import DicomCubeImageIO
|
25
|
+
from .dicom import (
|
26
|
+
CommonTags,
|
27
|
+
DicomMeta,
|
28
|
+
DicomStatus,
|
29
|
+
SortMethod,
|
30
|
+
get_dicom_status,
|
31
|
+
read_dicom_dir,
|
32
|
+
)
|
33
|
+
|
34
|
+
from importlib.metadata import version as _pkg_version, PackageNotFoundError
|
35
|
+
|
36
|
+
try:
|
37
|
+
__version__ = _pkg_version("dicube")
|
38
|
+
except PackageNotFoundError:
|
39
|
+
# editable install / source tree
|
40
|
+
__version__ = "0.1.0+unknown"
|
41
|
+
|
42
|
+
# Default to the number of CPU cores, but cap at 8 threads to avoid excessive resource usage
|
43
|
+
# Fall back to 4 if cpu_count() returns None (which can happen in some environments)
|
44
|
+
_num_threads = 4
|
45
|
+
|
46
|
+
def get_num_threads() -> int:
|
47
|
+
"""Get the global number of threads for parallel processing.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
int: Current number of threads setting.
|
51
|
+
"""
|
52
|
+
global _num_threads
|
53
|
+
return _num_threads
|
54
|
+
|
55
|
+
def set_num_threads(num_threads: int) -> None:
|
56
|
+
"""Set the global number of threads for parallel processing.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
num_threads (int): Number of threads for parallel processing tasks.
|
60
|
+
"""
|
61
|
+
global _num_threads
|
62
|
+
if num_threads < 1:
|
63
|
+
raise ValueError("Number of threads must be at least 1")
|
64
|
+
_num_threads = num_threads
|
65
|
+
|
66
|
+
# Top-level convenience methods
|
67
|
+
def load(file_path: str) -> DicomCubeImage:
|
68
|
+
"""Load a DicomCubeImage from a file.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
file_path (str): Path to the input file.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
DicomCubeImage: The loaded image object.
|
75
|
+
"""
|
76
|
+
return DicomCubeImageIO.load(file_path)
|
77
|
+
|
78
|
+
|
79
|
+
def save(
|
80
|
+
image: DicomCubeImage,
|
81
|
+
file_path: str,
|
82
|
+
file_type: str = "s",
|
83
|
+
) -> None:
|
84
|
+
"""Save a DicomCubeImage to a file.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
image (DicomCubeImage): The image object to save.
|
88
|
+
file_path (str): Output file path.
|
89
|
+
file_type (str): File type, "s" (speed priority), "a" (compression priority),
|
90
|
+
or "l" (lossy compression). Defaults to "s".
|
91
|
+
"""
|
92
|
+
return DicomCubeImageIO.save(image, file_path, file_type)
|
93
|
+
|
94
|
+
|
95
|
+
def load_from_dicom_folder(
|
96
|
+
folder_path: str,
|
97
|
+
sort_method: SortMethod = SortMethod.INSTANCE_NUMBER_ASC,
|
98
|
+
) -> DicomCubeImage:
|
99
|
+
"""Load a DicomCubeImage from a DICOM folder.
|
100
|
+
|
101
|
+
Args:
|
102
|
+
folder_path (str): Path to the DICOM folder.
|
103
|
+
sort_method (SortMethod): Method to sort DICOM files.
|
104
|
+
Defaults to SortMethod.INSTANCE_NUMBER_ASC.
|
105
|
+
**kwargs: Additional parameters.
|
106
|
+
|
107
|
+
Returns:
|
108
|
+
DicomCubeImage: The loaded image object.
|
109
|
+
"""
|
110
|
+
return DicomCubeImageIO.load_from_dicom_folder(folder_path, sort_method)
|
111
|
+
|
112
|
+
|
113
|
+
def load_from_nifti(file_path: str) -> DicomCubeImage:
|
114
|
+
"""Load a DicomCubeImage from a NIfTI file.
|
115
|
+
|
116
|
+
Args:
|
117
|
+
file_path (str): Path to the NIfTI file.
|
118
|
+
**kwargs: Additional parameters.
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
DicomCubeImage: The loaded image object.
|
122
|
+
"""
|
123
|
+
return DicomCubeImageIO.load_from_nifti(file_path)
|
124
|
+
|
125
|
+
|
126
|
+
def save_to_dicom_folder(
|
127
|
+
image: DicomCubeImage,
|
128
|
+
folder_path: str,
|
129
|
+
) -> None:
|
130
|
+
"""Save a DicomCubeImage as a DICOM folder.
|
131
|
+
|
132
|
+
Args:
|
133
|
+
image (DicomCubeImage): The image object to save.
|
134
|
+
folder_path (str): Output directory path.
|
135
|
+
"""
|
136
|
+
return DicomCubeImageIO.save_to_dicom_folder(image, folder_path)
|
137
|
+
|
138
|
+
|
139
|
+
def save_to_nifti(
|
140
|
+
image: DicomCubeImage,
|
141
|
+
file_path: str,
|
142
|
+
) -> None:
|
143
|
+
"""Save a DicomCubeImage as a NIfTI file.
|
144
|
+
|
145
|
+
Args:
|
146
|
+
image (DicomCubeImage): The image object to save.
|
147
|
+
file_path (str): Output file path.
|
148
|
+
|
149
|
+
Raises:
|
150
|
+
ImportError: When nibabel is not installed.
|
151
|
+
"""
|
152
|
+
return DicomCubeImageIO.save_to_nifti(image, file_path)
|
153
|
+
|
154
|
+
|
155
|
+
__all__ = [
|
156
|
+
"DicomCubeImage",
|
157
|
+
"DicomMeta",
|
158
|
+
"read_dicom_dir",
|
159
|
+
"DicomStatus",
|
160
|
+
"get_dicom_status",
|
161
|
+
"CommonTags",
|
162
|
+
"SortMethod",
|
163
|
+
# Top-level convenience methods
|
164
|
+
"load",
|
165
|
+
"save",
|
166
|
+
"load_from_dicom_folder",
|
167
|
+
"load_from_nifti",
|
168
|
+
"save_to_dicom_folder",
|
169
|
+
"save_to_nifti",
|
170
|
+
"set_num_threads",
|
171
|
+
"get_num_threads",
|
172
|
+
# IO class (for direct use if needed)
|
173
|
+
"DicomCubeImageIO",
|
174
|
+
]
|
@@ -0,0 +1,152 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
"""Image codec sub-package for dicube.
|
4
|
+
|
5
|
+
This package defines the codec registry and base interface for image codecs.
|
6
|
+
Currently supports JPH format with extensible design for future formats.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from typing import Dict, Protocol, runtime_checkable, Optional, Union, Any, Tuple
|
10
|
+
import numpy as np
|
11
|
+
from pathlib import Path
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
"ImageCodec",
|
15
|
+
"get_codec",
|
16
|
+
"list_codecs",
|
17
|
+
"register_codec",
|
18
|
+
"is_codec_available",
|
19
|
+
]
|
20
|
+
|
21
|
+
|
22
|
+
@runtime_checkable
|
23
|
+
class ImageCodec(Protocol):
|
24
|
+
"""Base interface that all image codecs must implement.
|
25
|
+
|
26
|
+
Attributes:
|
27
|
+
id (int): Unique numeric ID for the codec.
|
28
|
+
name (str): Codec name (e.g., "jph").
|
29
|
+
extensions (Tuple[str, ...]): Supported file extensions (e.g., (".j2k",)).
|
30
|
+
"""
|
31
|
+
|
32
|
+
id: int
|
33
|
+
name: str
|
34
|
+
extensions: Tuple[str, ...]
|
35
|
+
|
36
|
+
def encode(
|
37
|
+
self,
|
38
|
+
image: np.ndarray,
|
39
|
+
/,
|
40
|
+
**kwargs: Any
|
41
|
+
) -> bytes:
|
42
|
+
"""Encode numpy array to compressed bytes.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
image (np.ndarray): Input image array.
|
46
|
+
**kwargs: Codec-specific parameters.
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
bytes: Compressed image data.
|
50
|
+
"""
|
51
|
+
...
|
52
|
+
|
53
|
+
def decode(
|
54
|
+
self,
|
55
|
+
data: bytes,
|
56
|
+
/,
|
57
|
+
**kwargs: Any
|
58
|
+
) -> np.ndarray:
|
59
|
+
"""Decode compressed bytes to numpy array.
|
60
|
+
|
61
|
+
Args:
|
62
|
+
data (bytes): Compressed image data.
|
63
|
+
**kwargs: Codec-specific parameters.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
np.ndarray: Decoded image as numpy array.
|
67
|
+
"""
|
68
|
+
...
|
69
|
+
|
70
|
+
def is_available(self) -> bool:
|
71
|
+
"""Check if codec is available and functional.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
bool: True if the codec is available and operational.
|
75
|
+
"""
|
76
|
+
...
|
77
|
+
|
78
|
+
def get_version(self) -> str:
|
79
|
+
"""Get codec version information.
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
str: Version information string.
|
83
|
+
"""
|
84
|
+
...
|
85
|
+
|
86
|
+
|
87
|
+
# ---------------------------------------------------------------------------
|
88
|
+
# Registry implementation ---------------------------------------------------
|
89
|
+
# ---------------------------------------------------------------------------
|
90
|
+
|
91
|
+
_codec_registry: Dict[str, ImageCodec] = {}
|
92
|
+
|
93
|
+
|
94
|
+
def register_codec(codec: ImageCodec) -> None:
|
95
|
+
"""Register a codec in the global registry.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
codec (ImageCodec): The codec instance to register.
|
99
|
+
"""
|
100
|
+
_codec_registry[codec.name.lower()] = codec
|
101
|
+
|
102
|
+
|
103
|
+
def get_codec(name: str) -> ImageCodec:
|
104
|
+
"""Get codec by name (case-insensitive).
|
105
|
+
|
106
|
+
Args:
|
107
|
+
name (str): Codec name (e.g., "jph").
|
108
|
+
|
109
|
+
Returns:
|
110
|
+
ImageCodec: Codec instance.
|
111
|
+
|
112
|
+
Raises:
|
113
|
+
ValueError: If codec not found.
|
114
|
+
"""
|
115
|
+
try:
|
116
|
+
return _codec_registry[name.lower()]
|
117
|
+
except KeyError as err:
|
118
|
+
available = list(_codec_registry.keys())
|
119
|
+
raise ValueError(f"Unknown codec '{name}'. Available: {available}") from err
|
120
|
+
|
121
|
+
|
122
|
+
def list_codecs() -> list[str]:
|
123
|
+
"""List all registered codec names.
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
list[str]: List of registered codec names.
|
127
|
+
"""
|
128
|
+
return list(_codec_registry.keys())
|
129
|
+
|
130
|
+
|
131
|
+
def is_codec_available(name: str) -> bool:
|
132
|
+
"""Check if a codec is available.
|
133
|
+
|
134
|
+
Args:
|
135
|
+
name (str): Codec name (e.g., "jph").
|
136
|
+
|
137
|
+
Returns:
|
138
|
+
bool: True if codec is available and functional, False otherwise.
|
139
|
+
"""
|
140
|
+
try:
|
141
|
+
codec = get_codec(name)
|
142
|
+
return codec.is_available()
|
143
|
+
except ValueError:
|
144
|
+
return False
|
145
|
+
|
146
|
+
|
147
|
+
# Import and register concrete implementations
|
148
|
+
try:
|
149
|
+
from .jph.codec import JphCodec
|
150
|
+
register_codec(JphCodec())
|
151
|
+
except ImportError:
|
152
|
+
pass # JPH codec not available
|
@@ -0,0 +1,15 @@
|
|
1
|
+
"""JPEG 2000 (HTJ2K) codec module for DiCube.
|
2
|
+
|
3
|
+
This module provides JPEG 2000 High Throughput (HTJ2K) compression functionality
|
4
|
+
through the OpenJPH library. It implements the ImageCodec interface for seamless
|
5
|
+
integration with DiCube's storage system.
|
6
|
+
|
7
|
+
Classes:
|
8
|
+
JphCodec: Implementation of the JPEG 2000 codec using OpenJPH.
|
9
|
+
"""
|
10
|
+
|
11
|
+
from .codec import JphCodec
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
"JphCodec",
|
15
|
+
]
|
@@ -0,0 +1,161 @@
|
|
1
|
+
"""JPH codec adapter implementing ImageCodec interface."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
import numpy as np
|
6
|
+
from pathlib import Path
|
7
|
+
from typing import Union, Any, Tuple
|
8
|
+
|
9
|
+
from .ojph_complete import encode_image
|
10
|
+
from .ojph_decode_complete import decode_image
|
11
|
+
|
12
|
+
|
13
|
+
class JphCodec:
|
14
|
+
"""JPEG 2000 codec (OpenJPH) implementing ImageCodec interface.
|
15
|
+
|
16
|
+
Attributes:
|
17
|
+
id (int): Unique numeric ID for the codec.
|
18
|
+
name (str): Codec name ("jph").
|
19
|
+
extensions (Tuple[str, ...]): Supported file extensions (.j2k, .j2c, .jp2).
|
20
|
+
"""
|
21
|
+
|
22
|
+
id: int = 2
|
23
|
+
name: str = "jph"
|
24
|
+
extensions: Tuple[str, ...] = (".j2k", ".j2c", ".jp2")
|
25
|
+
|
26
|
+
def encode(
|
27
|
+
self,
|
28
|
+
image: np.ndarray,
|
29
|
+
/,
|
30
|
+
reversible: bool = True,
|
31
|
+
num_decompositions: int = 5,
|
32
|
+
block_size: tuple = (64, 64),
|
33
|
+
precinct_size: tuple = None,
|
34
|
+
progression_order: str = "RPCL",
|
35
|
+
color_transform: bool = False,
|
36
|
+
profile: str = None,
|
37
|
+
**kwargs: Any
|
38
|
+
) -> bytes:
|
39
|
+
"""Encode numpy array to JPEG 2000 bytes.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
image (np.ndarray): Input image array.
|
43
|
+
reversible (bool): Whether to use reversible transform. Defaults to True.
|
44
|
+
num_decompositions (int): Number of wavelet decompositions. Defaults to 5.
|
45
|
+
block_size (tuple): Code block size as (width, height). Defaults to (64, 64).
|
46
|
+
precinct_size (tuple, optional): Precinct size for each level as (width, height).
|
47
|
+
Defaults to None.
|
48
|
+
progression_order (str): Progression order, one of LRCP, RLCP, RPCL, PCRL, CPRL.
|
49
|
+
Defaults to "RPCL".
|
50
|
+
color_transform (bool): Whether to use color transform. Defaults to False.
|
51
|
+
profile (str, optional): Profile to use, one of None, IMF, BROADCAST.
|
52
|
+
Defaults to None.
|
53
|
+
**kwargs: Additional parameters (ignored for compatibility).
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
bytes: Compressed JPEG 2000 data.
|
57
|
+
|
58
|
+
Raises:
|
59
|
+
ValueError: If the image dimensions or block size are invalid.
|
60
|
+
"""
|
61
|
+
# Parameter validation
|
62
|
+
if len(image.shape) not in (2, 3):
|
63
|
+
raise ValueError("Image must be 2D or 3D array")
|
64
|
+
|
65
|
+
# Validate code block size
|
66
|
+
if not all(
|
67
|
+
size > 0 and size <= 64 and (size & (size - 1)) == 0 for size in block_size
|
68
|
+
):
|
69
|
+
raise ValueError(
|
70
|
+
"Code block dimensions must be powers of 2 and not larger than 64"
|
71
|
+
)
|
72
|
+
|
73
|
+
# Ensure data is contiguous
|
74
|
+
if not image.flags["C_CONTIGUOUS"]:
|
75
|
+
image = np.ascontiguousarray(image)
|
76
|
+
|
77
|
+
# Call C++ implementation
|
78
|
+
return encode_image(
|
79
|
+
image,
|
80
|
+
reversible=reversible,
|
81
|
+
num_decompositions=num_decompositions,
|
82
|
+
block_size=block_size,
|
83
|
+
precinct_size=precinct_size if precinct_size is not None else (0, 0),
|
84
|
+
progression_order=progression_order,
|
85
|
+
color_transform=color_transform,
|
86
|
+
profile="" if profile is None else profile,
|
87
|
+
)
|
88
|
+
|
89
|
+
def encode_lossless(
|
90
|
+
self,
|
91
|
+
image: np.ndarray,
|
92
|
+
/,
|
93
|
+
**kwargs: Any
|
94
|
+
) -> bytes:
|
95
|
+
"""Encode numpy array to lossless JPEG 2000 bytes.
|
96
|
+
|
97
|
+
This is a convenience method that calls encode() with reversible=True.
|
98
|
+
|
99
|
+
Args:
|
100
|
+
image (np.ndarray): Input image array.
|
101
|
+
**kwargs: Additional parameters passed to encode().
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
bytes: Compressed JPEG 2000 data.
|
105
|
+
"""
|
106
|
+
return self.encode(image, reversible=True, **kwargs)
|
107
|
+
|
108
|
+
def decode(
|
109
|
+
self,
|
110
|
+
data: bytes,
|
111
|
+
/,
|
112
|
+
level: int = 0,
|
113
|
+
resilient: bool = False,
|
114
|
+
**kwargs: Any
|
115
|
+
) -> np.ndarray:
|
116
|
+
"""Decode JPEG 2000 bytes to numpy array.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
data (bytes): Compressed JPEG 2000 data.
|
120
|
+
level (int): Resolution level to decode at (0 = full resolution).
|
121
|
+
Defaults to 0.
|
122
|
+
resilient (bool): Whether to enable resilient decoding. Defaults to False.
|
123
|
+
**kwargs: Additional parameters (ignored for compatibility).
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
np.ndarray: Decoded image as numpy array.
|
127
|
+
"""
|
128
|
+
# Use C++ implementation
|
129
|
+
return decode_image(data, level=level, resilient=resilient)
|
130
|
+
|
131
|
+
|
132
|
+
def is_available(self) -> bool:
|
133
|
+
"""Check if JPEG 2000 codec is available and functional.
|
134
|
+
|
135
|
+
Returns:
|
136
|
+
bool: True if the codec is available and operational.
|
137
|
+
"""
|
138
|
+
try:
|
139
|
+
# Test with a small image
|
140
|
+
test_image = np.ones((10, 10), dtype=np.uint8)
|
141
|
+
encoded = self.encode(test_image)
|
142
|
+
decoded = self.decode(encoded)
|
143
|
+
return decoded.shape == test_image.shape
|
144
|
+
except Exception:
|
145
|
+
return False
|
146
|
+
|
147
|
+
def get_version(self) -> str:
|
148
|
+
"""Get JPEG 2000 codec version.
|
149
|
+
|
150
|
+
Returns:
|
151
|
+
str: Version information string.
|
152
|
+
"""
|
153
|
+
return "OpenJPH" # TODO: Get actual version from OpenJPH
|
154
|
+
|
155
|
+
def __repr__(self) -> str:
|
156
|
+
"""Get string representation of the codec.
|
157
|
+
|
158
|
+
Returns:
|
159
|
+
str: String representation.
|
160
|
+
"""
|
161
|
+
return f"<{self.__class__.__name__} id={self.id} name='{self.name}' version='{self.get_version()}'>"
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
dicube/core/__init__.py
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
"""Core module for DiCube library.
|
2
|
+
|
3
|
+
This module provides the main interfaces and core functionality for working with
|
4
|
+
medical images in the DiCube format, including image representation, metadata handling,
|
5
|
+
and file I/O operations.
|
6
|
+
|
7
|
+
Classes:
|
8
|
+
DicomCubeImage: Main class for representing DICOM image data with metadata.
|
9
|
+
PixelDataHeader: Header class for storing pixel data information.
|
10
|
+
DicomCubeImageIO: Static I/O utility class for file operations.
|
11
|
+
"""
|
12
|
+
|
13
|
+
from .image import DicomCubeImage
|
14
|
+
from .pixel_header import PixelDataHeader
|
15
|
+
from .io import DicomCubeImageIO
|
16
|
+
|
17
|
+
__all__ = [
|
18
|
+
"DicomCubeImage",
|
19
|
+
"PixelDataHeader",
|
20
|
+
"DicomCubeImageIO",
|
21
|
+
]
|