dicube 0.1.4__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.
Files changed (194) hide show
  1. dicube-0.1.4/.cursor/rules/error-handling.mdc +39 -0
  2. dicube-0.1.4/.cursor/rules/file-formats.mdc +26 -0
  3. dicube-0.1.4/.cursor/rules/key-classes.mdc +52 -0
  4. dicube-0.1.4/.cursor/rules/project-structure.mdc +33 -0
  5. dicube-0.1.4/.cursor/rules/python-style.mdc +46 -0
  6. dicube-0.1.4/.github/actions/setup-python-env/action.yml +39 -0
  7. dicube-0.1.4/.github/workflows/build-wheels.yml +101 -0
  8. dicube-0.1.4/.github/workflows/release.yml +86 -0
  9. dicube-0.1.4/.github/workflows/test.yml +43 -0
  10. dicube-0.1.4/.gitignore +65 -0
  11. dicube-0.1.4/.gitmodules +6 -0
  12. dicube-0.1.4/CMakeLists.txt +141 -0
  13. dicube-0.1.4/PKG-INFO +271 -0
  14. dicube-0.1.4/README.md +226 -0
  15. dicube-0.1.4/build_scripts/build_local.py +191 -0
  16. dicube-0.1.4/build_scripts/check_wheels.py +237 -0
  17. dicube-0.1.4/dicube/__init__.py +140 -0
  18. dicube-0.1.4/dicube/codecs/__init__.py +152 -0
  19. dicube-0.1.4/dicube/codecs/jph/__init__.py +15 -0
  20. dicube-0.1.4/dicube/codecs/jph/codec.py +161 -0
  21. dicube-0.1.4/dicube/codecs/jph/decode_complete.cpp +191 -0
  22. dicube-0.1.4/dicube/codecs/jph/encode_complete.cpp +220 -0
  23. dicube-0.1.4/dicube/core/__init__.py +21 -0
  24. dicube-0.1.4/dicube/core/image.py +349 -0
  25. dicube-0.1.4/dicube/core/io.py +354 -0
  26. dicube-0.1.4/dicube/core/pixel_header.py +117 -0
  27. dicube-0.1.4/dicube/dicom/__init__.py +13 -0
  28. dicube-0.1.4/dicube/dicom/dcb_streaming.py +250 -0
  29. dicube-0.1.4/dicube/dicom/dicom_io.py +153 -0
  30. dicube-0.1.4/dicube/dicom/dicom_meta.py +740 -0
  31. dicube-0.1.4/dicube/dicom/dicom_status.py +259 -0
  32. dicube-0.1.4/dicube/dicom/dicom_tags.py +121 -0
  33. dicube-0.1.4/dicube/dicom/merge_utils.py +283 -0
  34. dicube-0.1.4/dicube/dicom/space_from_meta.py +70 -0
  35. dicube-0.1.4/dicube/exceptions.py +189 -0
  36. dicube-0.1.4/dicube/storage/__init__.py +17 -0
  37. dicube-0.1.4/dicube/storage/dcb_file.py +805 -0
  38. dicube-0.1.4/dicube/storage/pixel_utils.py +141 -0
  39. dicube-0.1.4/dicube/utils/__init__.py +6 -0
  40. dicube-0.1.4/dicube/validation.py +380 -0
  41. dicube-0.1.4/example/example.ipynb +442 -0
  42. dicube-0.1.4/pyproject.toml +114 -0
  43. dicube-0.1.4/source/OpenJPH/.devcontainer/Dockerfile +42 -0
  44. dicube-0.1.4/source/OpenJPH/.devcontainer/devcontainer.json +29 -0
  45. dicube-0.1.4/source/OpenJPH/.github/FUNDING.yml +13 -0
  46. dicube-0.1.4/source/OpenJPH/.github/workflows/ccp-workflow.yml +348 -0
  47. dicube-0.1.4/source/OpenJPH/.github/workflows/codeql.yml +82 -0
  48. dicube-0.1.4/source/OpenJPH/.github/workflows/emcc.yml +47 -0
  49. dicube-0.1.4/source/OpenJPH/.gitignore +7 -0
  50. dicube-0.1.4/source/OpenJPH/CMakeLists.txt +232 -0
  51. dicube-0.1.4/source/OpenJPH/Dockerfile +32 -0
  52. dicube-0.1.4/source/OpenJPH/LICENSE +27 -0
  53. dicube-0.1.4/source/OpenJPH/README.md +24 -0
  54. dicube-0.1.4/source/OpenJPH/_config.yml +1 -0
  55. dicube-0.1.4/source/OpenJPH/docs/.gitignore +2 -0
  56. dicube-0.1.4/source/OpenJPH/docs/Doxyfile +2494 -0
  57. dicube-0.1.4/source/OpenJPH/docs/OpenJPH_docs.css +6 -0
  58. dicube-0.1.4/source/OpenJPH/docs/compiling.md +116 -0
  59. dicube-0.1.4/source/OpenJPH/docs/docker.md +16 -0
  60. dicube-0.1.4/source/OpenJPH/docs/doxygen_style.md +47 -0
  61. dicube-0.1.4/source/OpenJPH/docs/status.md +9 -0
  62. dicube-0.1.4/source/OpenJPH/docs/usage_examples.md +19 -0
  63. dicube-0.1.4/source/OpenJPH/docs/web_demos.md +5 -0
  64. dicube-0.1.4/source/OpenJPH/ojph_version.cmake +29 -0
  65. dicube-0.1.4/source/OpenJPH/src/apps/CMakeLists.txt +29 -0
  66. dicube-0.1.4/source/OpenJPH/src/apps/common/ojph_img_io.h +819 -0
  67. dicube-0.1.4/source/OpenJPH/src/apps/common/ojph_sockets.h +236 -0
  68. dicube-0.1.4/source/OpenJPH/src/apps/common/ojph_threads.h +155 -0
  69. dicube-0.1.4/source/OpenJPH/src/apps/ojph_compress/CMakeLists.txt +58 -0
  70. dicube-0.1.4/source/OpenJPH/src/apps/ojph_compress/ojph_compress.cpp +1178 -0
  71. dicube-0.1.4/source/OpenJPH/src/apps/ojph_expand/CMakeLists.txt +58 -0
  72. dicube-0.1.4/source/OpenJPH/src/apps/ojph_expand/ojph_expand.cpp +438 -0
  73. dicube-0.1.4/source/OpenJPH/src/apps/ojph_stream_expand/CMakeLists.txt +26 -0
  74. dicube-0.1.4/source/OpenJPH/src/apps/ojph_stream_expand/ojph_stream_expand.cpp +373 -0
  75. dicube-0.1.4/source/OpenJPH/src/apps/ojph_stream_expand/stream_expand_support.cpp +464 -0
  76. dicube-0.1.4/source/OpenJPH/src/apps/ojph_stream_expand/stream_expand_support.h +554 -0
  77. dicube-0.1.4/source/OpenJPH/src/apps/ojph_stream_expand/threaded_frame_processors.cpp +64 -0
  78. dicube-0.1.4/source/OpenJPH/src/apps/ojph_stream_expand/threaded_frame_processors.h +107 -0
  79. dicube-0.1.4/source/OpenJPH/src/apps/others/ojph_img_io.cpp +2125 -0
  80. dicube-0.1.4/source/OpenJPH/src/apps/others/ojph_img_io_avx2.cpp +358 -0
  81. dicube-0.1.4/source/OpenJPH/src/apps/others/ojph_img_io_sse41.cpp +513 -0
  82. dicube-0.1.4/source/OpenJPH/src/apps/others/ojph_sockets.cpp +202 -0
  83. dicube-0.1.4/source/OpenJPH/src/apps/others/ojph_threads.cpp +108 -0
  84. dicube-0.1.4/source/OpenJPH/src/core/CMakeLists.txt +154 -0
  85. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_bitbuffer_read.h +226 -0
  86. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_bitbuffer_write.h +147 -0
  87. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codeblock.cpp +264 -0
  88. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codeblock.h +130 -0
  89. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codeblock_fun.cpp +286 -0
  90. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codeblock_fun.h +123 -0
  91. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream.cpp +208 -0
  92. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream_avx.cpp +58 -0
  93. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream_avx2.cpp +278 -0
  94. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream_gen.cpp +171 -0
  95. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream_local.cpp +1232 -0
  96. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream_local.h +177 -0
  97. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream_sse.cpp +58 -0
  98. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream_sse2.cpp +295 -0
  99. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_codestream_wasm.cpp +289 -0
  100. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_params.cpp +2498 -0
  101. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_params_local.h +1049 -0
  102. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_precinct.cpp +559 -0
  103. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_precinct.h +82 -0
  104. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_resolution.cpp +1049 -0
  105. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_resolution.h +133 -0
  106. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_subband.cpp +382 -0
  107. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_subband.h +124 -0
  108. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_tile.cpp +897 -0
  109. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_tile.h +112 -0
  110. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_tile_comp.cpp +200 -0
  111. dicube-0.1.4/source/OpenJPH/src/core/codestream/ojph_tile_comp.h +104 -0
  112. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_common.cpp +345 -0
  113. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_common.h +49 -0
  114. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_decoder.h +83 -0
  115. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_decoder32.cpp +1616 -0
  116. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_decoder64.cpp +1663 -0
  117. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_decoder_avx2.cpp +2044 -0
  118. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_decoder_ssse3.cpp +2070 -0
  119. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_decoder_wasm.cpp +2118 -0
  120. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_encoder.cpp +1523 -0
  121. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_encoder.h +88 -0
  122. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_encoder_avx2.cpp +1229 -0
  123. dicube-0.1.4/source/OpenJPH/src/core/coding/ojph_block_encoder_avx512.cpp +1218 -0
  124. dicube-0.1.4/source/OpenJPH/src/core/coding/table0.h +444 -0
  125. dicube-0.1.4/source/OpenJPH/src/core/coding/table1.h +358 -0
  126. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_arch.h +317 -0
  127. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_arg.h +272 -0
  128. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_base.h +72 -0
  129. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_codestream.h +370 -0
  130. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_defs.h +83 -0
  131. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_file.h +294 -0
  132. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_mem.h +241 -0
  133. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_message.h +291 -0
  134. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_params.h +306 -0
  135. dicube-0.1.4/source/OpenJPH/src/core/common/ojph_version.h +38 -0
  136. dicube-0.1.4/source/OpenJPH/src/core/others/ojph_arch.cpp +250 -0
  137. dicube-0.1.4/source/OpenJPH/src/core/others/ojph_file.cpp +336 -0
  138. dicube-0.1.4/source/OpenJPH/src/core/others/ojph_mem.cpp +120 -0
  139. dicube-0.1.4/source/OpenJPH/src/core/others/ojph_message.cpp +181 -0
  140. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_colour.cpp +558 -0
  141. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_colour.h +109 -0
  142. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_colour_avx.cpp +103 -0
  143. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_colour_avx2.cpp +623 -0
  144. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_colour_local.h +320 -0
  145. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_colour_sse.cpp +102 -0
  146. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_colour_sse2.cpp +662 -0
  147. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_colour_wasm.cpp +678 -0
  148. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform.cpp +844 -0
  149. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform.h +101 -0
  150. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform_avx.cpp +291 -0
  151. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform_avx2.cpp +1079 -0
  152. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform_avx512.cpp +1429 -0
  153. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform_local.h +318 -0
  154. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform_sse.cpp +287 -0
  155. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform_sse2.cpp +1006 -0
  156. dicube-0.1.4/source/OpenJPH/src/core/transform/ojph_transform_wasm.cpp +1310 -0
  157. dicube-0.1.4/source/OpenJPH/src/openjph-config.cmake.in +5 -0
  158. dicube-0.1.4/source/OpenJPH/src/openjph.pc.in +9 -0
  159. dicube-0.1.4/source/OpenJPH/subprojects/.gitignore +2 -0
  160. dicube-0.1.4/source/OpenJPH/subprojects/js/.gitignore +4 -0
  161. dicube-0.1.4/source/OpenJPH/subprojects/js/CMakeLists.txt +27 -0
  162. dicube-0.1.4/source/OpenJPH/subprojects/js/emscripten-docker.sh +2 -0
  163. dicube-0.1.4/source/OpenJPH/subprojects/js/html/.gitignore +2 -0
  164. dicube-0.1.4/source/OpenJPH/subprojects/js/html/index.html +252 -0
  165. dicube-0.1.4/source/OpenJPH/subprojects/js/html/libopenjph.js +16 -0
  166. dicube-0.1.4/source/OpenJPH/subprojects/js/html/libopenjph.wasm +0 -0
  167. dicube-0.1.4/source/OpenJPH/subprojects/js/html/libopenjph_simd.js +16 -0
  168. dicube-0.1.4/source/OpenJPH/subprojects/js/html/libopenjph_simd.wasm +0 -0
  169. dicube-0.1.4/source/OpenJPH/subprojects/js/html/test.j2c +0 -0
  170. dicube-0.1.4/source/OpenJPH/subprojects/js/src/ojph_wrapper.cpp +248 -0
  171. dicube-0.1.4/source/OpenJPH/subprojects/js/standalone/README.md +52 -0
  172. dicube-0.1.4/source/OpenJPH/subprojects/js/standalone/com_decom.sh +72 -0
  173. dicube-0.1.4/source/OpenJPH/subprojects/js/standalone/com_decom_yuv.sh +77 -0
  174. dicube-0.1.4/source/OpenJPH/target_arch.cmake +68 -0
  175. dicube-0.1.4/source/OpenJPH/tests/CMakeLists.txt +83 -0
  176. dicube-0.1.4/source/OpenJPH/tests/compare_files.cpp +96 -0
  177. dicube-0.1.4/source/OpenJPH/tests/mse_pae.cmake +50 -0
  178. dicube-0.1.4/source/OpenJPH/tests/mse_pae.cpp +706 -0
  179. dicube-0.1.4/source/OpenJPH/tests/test_executables.cpp +1469 -0
  180. dicube-0.1.4/source/OpenJPH/tests/test_helpers/Readme.md +20 -0
  181. dicube-0.1.4/source/OpenJPH/tests/test_helpers/convert_mse_pae_to_tests.cpp +567 -0
  182. dicube-0.1.4/source/OpenJPH/tests/test_helpers/ht_cmdlines.txt +102 -0
  183. dicube-0.1.4/tests/conftest.py +93 -0
  184. dicube-0.1.4/tests/test_codec_integration.py +195 -0
  185. dicube-0.1.4/tests/test_codec_system.py +142 -0
  186. dicube-0.1.4/tests/test_dcb_streaming.py +240 -0
  187. dicube-0.1.4/tests/test_dicom_meta.py +149 -0
  188. dicube-0.1.4/tests/test_dicom_status.py +457 -0
  189. dicube-0.1.4/tests/test_dicom_tags.py +119 -0
  190. dicube-0.1.4/tests/test_exceptions.py +229 -0
  191. dicube-0.1.4/tests/test_image.py +407 -0
  192. dicube-0.1.4/tests/test_image_exceptions.py +217 -0
  193. dicube-0.1.4/tests/test_integration_exceptions.py +301 -0
  194. dicube-0.1.4/tests/test_validation.py +360 -0
@@ -0,0 +1,39 @@
1
+ ---
2
+ description: Guidelines for error handling in DiCube
3
+ ---
4
+ # Error Handling in DiCube
5
+
6
+ DiCube provides a hierarchy of exception classes in [dicube/exceptions.py](mdc:dicube/exceptions.py)
7
+
8
+ ## Key Exceptions
9
+
10
+ ```python
11
+ from dicube.exceptions import (
12
+ DicomCubeError, # Base exception for all DiCube errors
13
+ InvalidCubeFileError, # Invalid file format or corrupted file
14
+ CodecError, # Compression/decompression failures
15
+ MetaDataError, # Missing or invalid metadata
16
+ DataConsistencyError # Inconsistent data structure
17
+ )
18
+ ```
19
+
20
+ ## Best Practices
21
+
22
+ 1. **Use specific exceptions** rather than generic ones
23
+ 2. **Include descriptive error messages** to aid debugging
24
+ 3. **Chain exceptions** when re-raising to preserve context
25
+ 4. **Validate early** to catch errors before processing begins
26
+ 5. **Clean up resources** in finally blocks or context managers
27
+
28
+ ## Example Usage
29
+
30
+ ```python
31
+ try:
32
+ image = dicube.load(\"corrupted.dcbs\")
33
+ except InvalidCubeFileError as e:
34
+ print(f\"Not a valid DiCube file: {e}\")
35
+ except CodecError as e:
36
+ print(f\"Compression/decompression failed: {e}\")
37
+ except MetaDataError as e:
38
+ print(f\"Missing or invalid metadata: {e}\")
39
+ ```
@@ -0,0 +1,26 @@
1
+ ---
2
+ description: Information about DiCube file formats and specifications
3
+ ---
4
+ # DiCube File Formats
5
+
6
+ DiCube defines three file format specifications:
7
+
8
+ ## Currently Implemented
9
+
10
+ ### .dcbs (Speed Format)
11
+ - **Magic**: `DCMCUBES`
12
+ - **Target**: I/O speed suitable for deep learning training with high compression ratio
13
+ - **Codec**: High Throughput JPEG 2000 (HTJ2K)
14
+ - **Implementation**: [storage/dcb_file.py](mdc:dicube/storage/dcb_file.py) and [codecs/jph/](mdc:dicube/codecs/jph/)
15
+
16
+ ## Placeholder Formats (Future Implementation)
17
+
18
+ ### .dcba (Archive Format)
19
+ - **Magic**: `DCMCUBEA`
20
+ - **Target**: 20% better compression ratio than dcbs
21
+ - **Use case**: Long-term storage and archiving
22
+
23
+ ### .dcbl (Lossy Format)
24
+ - **Magic**: `DCMCUBEL`
25
+ - **Target**: 60%+ compression ratio with imperceptible quality loss
26
+ - **Use case**: High-compression scenarios where minor quality trade-offs are acceptable
@@ -0,0 +1,52 @@
1
+ ---
2
+ description: Key classes and interfaces in the DiCube library
3
+ ---
4
+ # Key Classes and Interfaces
5
+
6
+ ## DicomCubeImage
7
+ Main interface for medical image handling, defined in [dicube/core/image.py](mdc:dicube/core/image.py)
8
+
9
+ ```python
10
+ import dicube
11
+
12
+ # Create from DICOM directory
13
+ image = dicube.load_from_dicom_folder(\"path/to/dicom/\")
14
+
15
+ # Save to compressed format
16
+ dicube.save(image, \"output.dcbs\", file_type=\"s\") # HTJ2K (Speed format)
17
+
18
+ # Load from file
19
+ loaded_image = dicube.load(\"output.dcbs\")
20
+
21
+ # Get pixel data
22
+ pixel_data = image.get_fdata() # Returns float array
23
+ raw_data = image.raw_image # Returns original dtype
24
+ ```
25
+
26
+ ## DicomMeta
27
+ DICOM metadata container with efficient shared/non-shared value handling:
28
+ Defined in [dicube/dicom/dicom_meta.py](mdc:dicube/dicom/dicom_meta.py)
29
+
30
+ ```python
31
+ from dicube import DicomMeta, read_dicom_dir
32
+
33
+ # Read DICOM directory
34
+ meta = read_dicom_dir(\"dicom_folder/\")
35
+
36
+ # Access shared values (same across all slices)
37
+ patient_name = meta.get(\"PatientName\") # Returns single value
38
+
39
+ # Access non-shared values (different per slice)
40
+ positions = meta.get(\"ImagePositionPatient\") # Returns list
41
+ ```
42
+
43
+ ## DicomStatus
44
+ DICOM consistency checking provided in [dicube/dicom/dicom_status.py](mdc:dicube/dicom/dicom_status.py)
45
+
46
+ ```python
47
+ from dicube import DicomStatus, get_dicom_status
48
+
49
+ status = get_dicom_status(meta)
50
+ ```
51
+
52
+ Common status values include: `CONSISTENT`, `MISSING_SERIES_UID`, `DUPLICATE_INSTANCE_NUMBERS`, `NON_UNIFORM_SPACING`, etc.
@@ -0,0 +1,33 @@
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+
5
+ # DiCube Project Structure
6
+
7
+ DiCube is a Python library for efficient storage and processing of 3D medical images with complete DICOM metadata preservation.
8
+
9
+ ## Project Organization
10
+
11
+ - **Core modules** in [dicube/core/](mdc:dicube/core/)
12
+ - [image.py](mdc:dicube/core/image.py): DicomCubeImage (main interface)
13
+ - [io.py](mdc:dicube/core/io.py): DicomCubeImageIO (file format I/O)
14
+ - [pixel_header.py](mdc:dicube/core/pixel_header.py): PixelDataHeader (image metadata)
15
+
16
+ - **DICOM handling** in [dicube/dicom/](mdc:dicube/dicom/)
17
+ - [dicom_meta.py](mdc:dicube/dicom/dicom_meta.py): DicomMeta (metadata container)
18
+ - [dicom_status.py](mdc:dicube/dicom/dicom_status.py): DICOM consistency checking
19
+ - [dicom_tags.py](mdc:dicube/dicom/dicom_tags.py): DICOM tag definitions
20
+ - [dicom_io.py](mdc:dicube/dicom/dicom_io.py): DICOM file I/O
21
+ - [merge_utils.py](mdc:dicube/dicom/merge_utils.py): Metadata merging utilities
22
+
23
+ - **Storage formats** in [dicube/storage/](mdc:dicube/storage/)
24
+ - [dcb_file.py](mdc:dicube/storage/dcb_file.py): DCB file format implementations
25
+ - [pixel_utils.py](mdc:dicube/storage/pixel_utils.py): Pixel processing utilities
26
+
27
+ - **Compression codecs** in [dicube/codecs/](mdc:dicube/codecs/)
28
+ - [jph/](mdc:dicube/codecs/jph/): HTJ2K codec implementation
29
+
30
+ - **Entry point**: [dicube/__init__.py](mdc:dicube/__init__.py)
31
+ - **Exceptions**: [dicube/exceptions.py](mdc:dicube/exceptions.py)
32
+
33
+ This library works alongside `spacetransformer` (for 3D spatial transformations) and `medmask` (for medical image segmentation).
@@ -0,0 +1,46 @@
1
+ ---
2
+ globs: *.py
3
+ ---
4
+ # Python Code Style Guide
5
+
6
+ When writing or modifying Python code in this project, follow these guidelines:
7
+
8
+ 1. Use **type annotations** wherever possible for improved code clarity and IDE support.
9
+ 2. Import order should be:
10
+ - Standard library imports
11
+ - Third-party imports
12
+ - Local imports (from dicube)
13
+ 3. Use **Google style docstrings** for all functions, classes, and modules:
14
+
15
+ ```python
16
+ def function_example(param1, param2):
17
+ """Short description of function purpose.
18
+
19
+ Args:
20
+ param1 (type): Description of parameter.
21
+ param2 (type): Description of parameter.
22
+
23
+ Returns:
24
+ type: Description of return value.
25
+
26
+ Raises:
27
+ ExceptionType: When and why this exception is raised.
28
+
29
+ Example:
30
+ >>> result = function_example(1, 2)
31
+ >>> print(result)
32
+ 3
33
+ """
34
+ ```
35
+
36
+ 4. Keep functions **focused** and **single-purpose**.
37
+ 5. For error handling:
38
+ - Use specific exceptions from [dicube/exceptions.py](mdc:dicube/exceptions.py)
39
+ - Validate input parameters early
40
+ - Add clear error messages
41
+ 6. For complex operations, add comments explaining the algorithm or approach.
42
+ 7. Use constants for magic values and define them at the module level.
43
+ 8. Performance matters - use numpy vectorized operations where possible.
44
+ 9. Method naming follows standard Python conventions:
45
+ - Methods that modify state: `set_`, `update_`, etc.
46
+ - Methods that return new objects without modifying state: `get_`, `compute_`, etc.
@@ -0,0 +1,39 @@
1
+ name: 'Setup Python Environment'
2
+ description: 'Setup Python with common dependencies'
3
+ inputs:
4
+ python-version:
5
+ description: 'Python version to use'
6
+ required: true
7
+ default: '3.9'
8
+ install-dev:
9
+ description: 'Install development dependencies'
10
+ required: false
11
+ default: 'false'
12
+
13
+ runs:
14
+ using: 'composite'
15
+ steps:
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v4
18
+ with:
19
+ python-version: ${{ inputs.python-version }}
20
+
21
+ - name: Cache pip
22
+ uses: actions/cache@v3
23
+ with:
24
+ path: ~/.cache/pip
25
+ key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml') }}
26
+ restore-keys: |
27
+ ${{ runner.os }}-pip-${{ inputs.python-version }}-
28
+
29
+ - name: Install base dependencies
30
+ shell: bash
31
+ run: |
32
+ python -m pip install --upgrade pip
33
+ pip install wheel setuptools
34
+
35
+ - name: Install dev dependencies
36
+ if: inputs.install-dev == 'true'
37
+ shell: bash
38
+ run: |
39
+ pip install ruff black mypy pytest pytest-cov
@@ -0,0 +1,101 @@
1
+ name: Build Wheels
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*']
6
+ branches: ['feat/test_build']
7
+ pull_request:
8
+ branches: [main, master]
9
+ workflow_dispatch:
10
+ workflow_call:
11
+
12
+ jobs:
13
+ build_wheels:
14
+ name: Build wheels on ${{ matrix.os }}
15
+ runs-on: ${{ matrix.os }}
16
+ strategy:
17
+ matrix:
18
+ os: [ubuntu-latest, windows-latest, macos-latest]
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ with:
23
+ submodules: recursive
24
+ ref: ${{ github.ref }}
25
+ # Ensure full history to prevent setuptools_scm issues
26
+ fetch-depth: 0
27
+
28
+ # For Windows, we need to manually install pip
29
+ - name: Set up Windows environment
30
+ if: runner.os == 'Windows'
31
+ run: |
32
+ python -m pip install --upgrade pip
33
+
34
+ - name: Build wheels
35
+ # Using explicit command to avoid empty parameter issues on Windows
36
+ run: |
37
+ python -m pip install cibuildwheel==2.16.2
38
+ python -m cibuildwheel
39
+ env:
40
+ CIBW_BUILD: cp38-* cp39-* cp310-* cp311-* cp312-*
41
+ CIBW_SKIP: pp* *-musllinux*
42
+ CIBW_ARCHS_LINUX: auto
43
+ CIBW_ARCHS_MACOS: x86_64 arm64
44
+ CIBW_ARCHS_WINDOWS: auto
45
+
46
+ # 更健壮的依赖安装方式
47
+ CIBW_BEFORE_ALL_LINUX: |
48
+ if command -v yum &>/dev/null; then
49
+ # Try multiple times with increasing timeouts (network issues)
50
+ for i in 1 2 3; do
51
+ echo "Attempt $i: Installing dependencies with yum..."
52
+ yum install -y cmake gcc-c++ && break || sleep 5
53
+ done
54
+ elif command -v apt-get &>/dev/null; then
55
+ echo "Installing dependencies with apt..."
56
+ apt-get update -y && apt-get install -y cmake g++
57
+ elif command -v apk &>/dev/null; then
58
+ echo "Installing dependencies with apk..."
59
+ apk add --no-cache cmake g++
60
+ else
61
+ echo "No supported package manager found!"
62
+ exit 1
63
+ fi
64
+ CIBW_BEFORE_ALL_MACOS: |
65
+ brew install cmake
66
+ CIBW_BEFORE_ALL_WINDOWS: |
67
+ choco install cmake
68
+
69
+ # 简单的测试
70
+ CIBW_TEST_COMMAND: |
71
+ python -c "from dicube.codecs.jph import JphCodec; print('Import test passed successfully')"
72
+
73
+ - uses: actions/upload-artifact@v4
74
+ with:
75
+ name: wheels-${{ matrix.os }}
76
+ path: wheelhouse/*.whl
77
+
78
+ build_sdist:
79
+ name: Build source distribution
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - uses: actions/checkout@v4
83
+ with:
84
+ submodules: recursive
85
+ ref: ${{ github.ref }}
86
+ # Ensure full history to prevent setuptools_scm issues
87
+ fetch-depth: 0
88
+
89
+ - uses: ./.github/actions/setup-python-env
90
+ with:
91
+ python-version: '3.9'
92
+
93
+ - name: Build sdist
94
+ run: |
95
+ pip install build setuptools_scm
96
+ python -m build --sdist
97
+
98
+ - uses: actions/upload-artifact@v4
99
+ with:
100
+ name: sdist
101
+ path: dist/*.tar.gz
@@ -0,0 +1,86 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ tag:
9
+ description: 'Release tag (for manual dispatch)'
10
+ required: false
11
+ default: ''
12
+ type: string
13
+
14
+ jobs:
15
+ # 构建 wheels 和 sdist
16
+ build:
17
+ uses: ./.github/workflows/build-wheels.yml
18
+
19
+ # 发布到 GitHub Release
20
+ github-release:
21
+ runs-on: ubuntu-latest
22
+ needs: build
23
+ if: github.event_name == 'release'
24
+ permissions:
25
+ contents: write
26
+ steps:
27
+ - name: Download all artifacts
28
+ uses: actions/download-artifact@v4
29
+ with:
30
+ path: dist
31
+ merge-multiple: true
32
+
33
+ - name: List release assets
34
+ run: |
35
+ echo "📦 Release assets:"
36
+ ls -la dist/
37
+ echo "Total wheels: $(ls dist/*.whl 2>/dev/null | wc -l)"
38
+ echo "Source dist: $(ls dist/*.tar.gz 2>/dev/null | wc -l)"
39
+
40
+ - name: Upload to GitHub Release
41
+ uses: softprops/action-gh-release@v1
42
+ with:
43
+ files: dist/*
44
+ fail_on_unmatched_files: true
45
+ generate_release_notes: true
46
+
47
+ # 发布到 PyPI
48
+ pypi-release:
49
+ runs-on: ubuntu-latest
50
+ needs: build
51
+ if: github.event_name == 'release'
52
+ environment: pypi
53
+ permissions:
54
+ id-token: write
55
+ steps:
56
+ - name: Download all artifacts
57
+ uses: actions/download-artifact@v4
58
+ with:
59
+ path: dist
60
+ merge-multiple: true
61
+
62
+ - name: Publish to PyPI
63
+ uses: pypa/gh-action-pypi-publish@release/v1
64
+ with:
65
+ packages-dir: dist/
66
+ verbose: true
67
+
68
+ # 发布总结
69
+ release-summary:
70
+ runs-on: ubuntu-latest
71
+ needs: [github-release, pypi-release]
72
+ if: always()
73
+ steps:
74
+ - name: Release Summary
75
+ run: |
76
+ echo "## 🚀 Release Summary" >> $GITHUB_STEP_SUMMARY
77
+ echo "" >> $GITHUB_STEP_SUMMARY
78
+ echo "- GitHub Release: ${{ needs.github-release.result == 'success' && '✅ Success' || '❌ Failed' }}" >> $GITHUB_STEP_SUMMARY
79
+ echo "- PyPI Release: ${{ needs.pypi-release.result == 'success' && '✅ Success' || '❌ Failed' }}" >> $GITHUB_STEP_SUMMARY
80
+ echo "" >> $GITHUB_STEP_SUMMARY
81
+
82
+ if [[ "${{ needs.github-release.result }}" == "success" && "${{ needs.pypi-release.result }}" == "success" ]]; then
83
+ echo "✅ Release completed successfully!" >> $GITHUB_STEP_SUMMARY
84
+ else
85
+ echo "❌ Release encountered issues" >> $GITHUB_STEP_SUMMARY
86
+ fi
@@ -0,0 +1,43 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ branches: [main, master]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ strategy:
13
+ matrix:
14
+ os: [ubuntu-latest]
15
+ python-version: ['3.8', '3.12'] # 只测试最低和最高版本
16
+
17
+ runs-on: ${{ matrix.os }}
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ with:
22
+ submodules: recursive
23
+
24
+ - uses: ./.github/actions/setup-python-env
25
+ with:
26
+ python-version: ${{ matrix.python-version }}
27
+ install-dev: 'true'
28
+
29
+ # 安装和测试
30
+ - name: Install package
31
+ run: |
32
+ pip install -e .[dev]
33
+
34
+ - name: Run tests
35
+ run: |
36
+ pytest tests/ -v --tb=short
37
+
38
+ # 基本导入测试
39
+ python -c "
40
+ import dicube
41
+ from dicube.codecs.jph import JphCodec
42
+ print(f'dicube version: {dicube.__version__} - Import successful')
43
+ "
@@ -0,0 +1,65 @@
1
+ .kiro
2
+ trash
3
+ dicube/_version.py
4
+ *.mska
5
+ *.msk
6
+ *.nii
7
+ *.nii.gz
8
+
9
+ # Byte-compiled / optimized / DLL files
10
+ __pycache__/
11
+ *.py[cod]
12
+ *$py.class
13
+
14
+ # C extensions
15
+ *.so
16
+
17
+ # Distribution / packaging
18
+ .Python
19
+ build/
20
+ dist/
21
+ *.egg-info/
22
+ .eggs/
23
+
24
+ # Installer logs
25
+ pip-log.txt
26
+ pip-delete-this-directory.txt
27
+
28
+ # Unit test / coverage reports
29
+ htmlcov/
30
+ .tox/
31
+ .nox/
32
+ .coverage
33
+ .coverage.*
34
+ .cache
35
+ pytest_cache/
36
+
37
+ # MyPy / Pyright / Pyre type checker
38
+ .mypy_cache/
39
+ .pyre/
40
+ .pytype/
41
+
42
+ # VS Code
43
+ .vscode/
44
+
45
+ # IDEs
46
+ .idea/
47
+
48
+ # Environments
49
+ .env
50
+ .venv
51
+ venv/
52
+ ENV/
53
+
54
+ # Jupyter Notebook checkpoints
55
+ .ipynb_checkpoints/
56
+
57
+ # Mac / Linux
58
+ .DS_Store
59
+ *.swp
60
+
61
+ # Logs
62
+ *.log
63
+
64
+ # uv local cache
65
+ .uv/
@@ -0,0 +1,6 @@
1
+ [submodule "source/OpenJPH"]
2
+ path = source/OpenJPH
3
+ url = https://github.com/aous72/OpenJPH.git
4
+ [submodule "testdata"]
5
+ path = testdata
6
+ url = git@github.com:fastdiag-toolbox/dicube-testdata.git
@@ -0,0 +1,141 @@
1
+ cmake_minimum_required(VERSION 3.15.0)
2
+
3
+ project(dicube-openjph
4
+ VERSION 0.1.0
5
+ DESCRIPTION "DiCube with statically linked OpenJPH"
6
+ LANGUAGES CXX
7
+ )
8
+
9
+ # 设置 C++ 标准
10
+ set(CMAKE_CXX_STANDARD 14)
11
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
12
+
13
+ # 构建类型
14
+ if(NOT CMAKE_BUILD_TYPE)
15
+ set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
16
+ endif()
17
+
18
+ # 设置输出目录
19
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
20
+ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
21
+ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
22
+
23
+ # ================================================================================================
24
+ # 选项配置
25
+ # ================================================================================================
26
+
27
+ option(DICUBE_BUILD_PYTHON_EXTENSIONS "Build Python extensions" ON)
28
+
29
+ # ================================================================================================
30
+ # 编译器设置
31
+ # ================================================================================================
32
+
33
+ if(MSVC)
34
+ # Windows MSVC 设置
35
+ add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
36
+ add_compile_options(/W3 /EHsc)
37
+ # 静态链接 CRT
38
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
39
+ else()
40
+ # GCC/Clang 设置
41
+ add_compile_options(-fexceptions -Wall -Wextra -fPIC)
42
+ if(CMAKE_BUILD_TYPE STREQUAL "Release")
43
+ add_compile_options(-O3 -DNDEBUG)
44
+ endif()
45
+ endif()
46
+
47
+ # ================================================================================================
48
+ # OpenJPH 构建
49
+ # ================================================================================================
50
+
51
+ # 检查 OpenJPH 源码
52
+ set(OPENJPH_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/source/OpenJPH")
53
+ if(NOT EXISTS "${OPENJPH_SOURCE_DIR}/CMakeLists.txt")
54
+ message(FATAL_ERROR
55
+ "OpenJPH source not found. Please run: git submodule update --init --recursive"
56
+ )
57
+ endif()
58
+
59
+ # OpenJPH 构建选项
60
+ set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
61
+ set(OJPH_ENABLE_TIFF_SUPPORT OFF CACHE BOOL "" FORCE)
62
+ set(OJPH_BUILD_TESTS OFF CACHE BOOL "" FORCE)
63
+ set(OJPH_BUILD_EXECUTABLES OFF CACHE BOOL "" FORCE)
64
+ set(OJPH_BUILD_STREAM_EXPAND OFF CACHE BOOL "" FORCE)
65
+ set(OJPH_DISABLE_SIMD OFF CACHE BOOL "" FORCE) # 启用 SIMD 优化
66
+
67
+ # 添加 OpenJPH
68
+ add_subdirectory(${OPENJPH_SOURCE_DIR} openjph EXCLUDE_FROM_ALL)
69
+
70
+ # 设置 OpenJPH 目标和头文件
71
+ set(OPENJPH_TARGET openjph)
72
+ set(OPENJPH_INCLUDE_DIRS
73
+ "${OPENJPH_SOURCE_DIR}/src/core/common"
74
+ "${CMAKE_BINARY_DIR}/openjph/src/core/common" # 生成的配置文件
75
+ )
76
+
77
+ # ================================================================================================
78
+ # Python 扩展构建
79
+ # ================================================================================================
80
+
81
+ if(DICUBE_BUILD_PYTHON_EXTENSIONS)
82
+ # 查找 Python 和 pybind11
83
+ find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
84
+ find_package(pybind11 REQUIRED)
85
+
86
+ # 查找 NumPy
87
+ execute_process(
88
+ COMMAND ${Python_EXECUTABLE} -c "import numpy; print(numpy.get_include())"
89
+ OUTPUT_VARIABLE NUMPY_INCLUDE_DIR
90
+ OUTPUT_STRIP_TRAILING_WHITESPACE
91
+ )
92
+
93
+ if(NOT NUMPY_INCLUDE_DIR)
94
+ message(FATAL_ERROR "NumPy not found")
95
+ endif()
96
+
97
+ # 构建 Python 扩展
98
+ pybind11_add_module(ojph_complete dicube/codecs/jph/encode_complete.cpp)
99
+ pybind11_add_module(ojph_decode_complete dicube/codecs/jph/decode_complete.cpp)
100
+
101
+ # 设置包含目录和链接
102
+ foreach(target ojph_complete ojph_decode_complete)
103
+ target_include_directories(${target} PRIVATE
104
+ ${OPENJPH_INCLUDE_DIRS}
105
+ ${NUMPY_INCLUDE_DIR}
106
+ )
107
+ target_link_libraries(${target} PRIVATE ${OPENJPH_TARGET})
108
+
109
+ # 确保 .pyd/.so 文件直接放在正确的目录,不带 Release 子目录
110
+ if(MSVC)
111
+ # Windows特殊处理,防止产生 Release 子目录
112
+ set_target_properties(${target} PROPERTIES
113
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dicube/codecs/jph
114
+ RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/dicube/codecs/jph
115
+ RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/dicube/codecs/jph
116
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dicube/codecs/jph
117
+ LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/dicube/codecs/jph
118
+ LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/dicube/codecs/jph
119
+ )
120
+ else()
121
+ # Linux/macOS
122
+ set_target_properties(${target} PROPERTIES
123
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dicube/codecs/jph
124
+ )
125
+ endif()
126
+ endforeach()
127
+
128
+ message(STATUS "Python extensions configured (Python ${Python_VERSION})")
129
+ endif()
130
+
131
+ # ================================================================================================
132
+ # 构建摘要
133
+ # ================================================================================================
134
+
135
+ message(STATUS "=== Build Configuration ===")
136
+ message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
137
+ message(STATUS "Python extensions: ${DICUBE_BUILD_PYTHON_EXTENSIONS}")
138
+ if(DICUBE_BUILD_PYTHON_EXTENSIONS)
139
+ message(STATUS "Python: ${Python_VERSION}")
140
+ endif()
141
+ message(STATUS "===========================")