pycerr 2.2.0__tar.gz → 2.2.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.
Files changed (486) hide show
  1. {pycerr-2.2.0 → pycerr-2.2.2}/CHANGELOG.md +46 -0
  2. {pycerr-2.2.0/pycerr.egg-info → pycerr-2.2.2}/PKG-INFO +5 -4
  3. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/_version.py +3 -3
  4. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/contour/rasterseg.py +74 -70
  5. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/structure.py +3 -2
  6. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/gray_level_cooccurence.py +2 -2
  7. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/neighbor_gray_tone.py +3 -7
  8. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/README_pycerr_gui.md +5 -2
  9. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/__init__.py +2 -1
  10. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/common.py +14 -2
  11. {pycerr-2.2.0 → pycerr-2.2.2/pycerr.egg-info}/PKG-INFO +5 -4
  12. {pycerr-2.2.0 → pycerr-2.2.2}/pycerr.egg-info/SOURCES.txt +1 -0
  13. {pycerr-2.2.0 → pycerr-2.2.2}/pycerr.egg-info/requires.txt +5 -3
  14. {pycerr-2.2.0 → pycerr-2.2.2}/pycerr.egg-info/scm_file_list.json +1 -0
  15. pycerr-2.2.2/pycerr.egg-info/scm_version.json +8 -0
  16. {pycerr-2.2.0 → pycerr-2.2.2}/pyproject.toml +16 -6
  17. pycerr-2.2.2/tests/test_poly_fill.py +115 -0
  18. pycerr-2.2.0/pycerr.egg-info/scm_version.json +0 -8
  19. {pycerr-2.2.0 → pycerr-2.2.2}/.github/workflows/_version_tmp.py +0 -0
  20. {pycerr-2.2.0 → pycerr-2.2.2}/.github/workflows/publish.yml +0 -0
  21. {pycerr-2.2.0 → pycerr-2.2.2}/.github/workflows/python-package.yml +0 -0
  22. {pycerr-2.2.0 → pycerr-2.2.2}/.gitignore +0 -0
  23. {pycerr-2.2.0 → pycerr-2.2.2}/.readthedocs.yaml +0 -0
  24. {pycerr-2.2.0 → pycerr-2.2.2}/CLAUDE.md +0 -0
  25. {pycerr-2.2.0 → pycerr-2.2.2}/LICENSE +0 -0
  26. {pycerr-2.2.0 → pycerr-2.2.2}/MANIFEST.in +0 -0
  27. {pycerr-2.2.0 → pycerr-2.2.2}/README.md +0 -0
  28. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/__init__.py +0 -0
  29. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/__init__.py +0 -0
  30. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/install_utils.py +0 -0
  31. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/post/CT_LungOAR_incrMRRN.py +0 -0
  32. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/post/MR_BrainMets_SMITplus.py +0 -0
  33. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/post/MR_Rectum_GTV_SMIT.py +0 -0
  34. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/prep/CT_LungOAR_incrMRRN.py +0 -0
  35. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/prep/MR_BrainMets_SMITplus.py +0 -0
  36. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/prep/MR_Rectum_GTV_SMIT.py +0 -0
  37. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/ai_models/run_utils.py +0 -0
  38. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/contour/__init__.py +0 -0
  39. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/contour/contour_processing.py +0 -0
  40. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/contour/structure_consensus.py +0 -0
  41. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/__init__.py +0 -0
  42. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/beams.py +0 -0
  43. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/dcm_cerr_name_map.json +0 -0
  44. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/deform.py +0 -0
  45. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/dose.py +0 -0
  46. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/header.py +0 -0
  47. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/imrt.py +0 -0
  48. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/scan.py +0 -0
  49. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/scan_info.py +0 -0
  50. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dataclasses/uromt.py +0 -0
  51. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/__init__.py +0 -0
  52. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/convolutional_filter_settings/LoG_filter.json +0 -0
  53. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/convolutional_filter_settings/Rot_inv_laws_energy_filter.json +0 -0
  54. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/convolutional_filter_settings/gabor_filter.json +0 -0
  55. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/convolutional_filter_settings/mean_filter.json +0 -0
  56. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/README_LICENSE.txt +0 -0
  57. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00000.dcm +0 -0
  58. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00001.dcm +0 -0
  59. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00002.dcm +0 -0
  60. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00003.dcm +0 -0
  61. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00004.dcm +0 -0
  62. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00005.dcm +0 -0
  63. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00006.dcm +0 -0
  64. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00007.dcm +0 -0
  65. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00008.dcm +0 -0
  66. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00009.dcm +0 -0
  67. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00010.dcm +0 -0
  68. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00011.dcm +0 -0
  69. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00012.dcm +0 -0
  70. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00013.dcm +0 -0
  71. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00014.dcm +0 -0
  72. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00015.dcm +0 -0
  73. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00016.dcm +0 -0
  74. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00017.dcm +0 -0
  75. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00018.dcm +0 -0
  76. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00019.dcm +0 -0
  77. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00020.dcm +0 -0
  78. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00021.dcm +0 -0
  79. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00022.dcm +0 -0
  80. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00023.dcm +0 -0
  81. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00024.dcm +0 -0
  82. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00025.dcm +0 -0
  83. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00026.dcm +0 -0
  84. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00027.dcm +0 -0
  85. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00028.dcm +0 -0
  86. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00029.dcm +0 -0
  87. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00030.dcm +0 -0
  88. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00031.dcm +0 -0
  89. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00032.dcm +0 -0
  90. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00033.dcm +0 -0
  91. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00034.dcm +0 -0
  92. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00035.dcm +0 -0
  93. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00036.dcm +0 -0
  94. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00037.dcm +0 -0
  95. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00038.dcm +0 -0
  96. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00039.dcm +0 -0
  97. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00040.dcm +0 -0
  98. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00041.dcm +0 -0
  99. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00042.dcm +0 -0
  100. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00043.dcm +0 -0
  101. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00044.dcm +0 -0
  102. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00045.dcm +0 -0
  103. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00046.dcm +0 -0
  104. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00047.dcm +0 -0
  105. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00048.dcm +0 -0
  106. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00049.dcm +0 -0
  107. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00050.dcm +0 -0
  108. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00051.dcm +0 -0
  109. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00052.dcm +0 -0
  110. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00053.dcm +0 -0
  111. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00054.dcm +0 -0
  112. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00055.dcm +0 -0
  113. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00056.dcm +0 -0
  114. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00057.dcm +0 -0
  115. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00058.dcm +0 -0
  116. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_IMG_00059.dcm +0 -0
  117. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_1/DCM_RS_00060.dcm +0 -0
  118. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00000.dcm +0 -0
  119. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00001.dcm +0 -0
  120. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00002.dcm +0 -0
  121. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00003.dcm +0 -0
  122. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00004.dcm +0 -0
  123. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00005.dcm +0 -0
  124. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00006.dcm +0 -0
  125. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00007.dcm +0 -0
  126. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00008.dcm +0 -0
  127. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00009.dcm +0 -0
  128. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00010.dcm +0 -0
  129. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00011.dcm +0 -0
  130. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00012.dcm +0 -0
  131. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00013.dcm +0 -0
  132. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00014.dcm +0 -0
  133. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00015.dcm +0 -0
  134. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00016.dcm +0 -0
  135. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00017.dcm +0 -0
  136. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00018.dcm +0 -0
  137. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00019.dcm +0 -0
  138. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00020.dcm +0 -0
  139. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00021.dcm +0 -0
  140. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00022.dcm +0 -0
  141. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00023.dcm +0 -0
  142. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00024.dcm +0 -0
  143. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00025.dcm +0 -0
  144. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00026.dcm +0 -0
  145. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00027.dcm +0 -0
  146. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00028.dcm +0 -0
  147. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00029.dcm +0 -0
  148. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00030.dcm +0 -0
  149. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00031.dcm +0 -0
  150. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00032.dcm +0 -0
  151. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00033.dcm +0 -0
  152. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00034.dcm +0 -0
  153. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00035.dcm +0 -0
  154. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00036.dcm +0 -0
  155. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00037.dcm +0 -0
  156. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00038.dcm +0 -0
  157. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00039.dcm +0 -0
  158. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_IMG_00040.dcm +0 -0
  159. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_2/DCM_RS_00041.dcm +0 -0
  160. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00000.dcm +0 -0
  161. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00001.dcm +0 -0
  162. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00002.dcm +0 -0
  163. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00003.dcm +0 -0
  164. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00004.dcm +0 -0
  165. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00005.dcm +0 -0
  166. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00006.dcm +0 -0
  167. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00007.dcm +0 -0
  168. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00008.dcm +0 -0
  169. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00009.dcm +0 -0
  170. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00010.dcm +0 -0
  171. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00011.dcm +0 -0
  172. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00012.dcm +0 -0
  173. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00013.dcm +0 -0
  174. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00014.dcm +0 -0
  175. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00015.dcm +0 -0
  176. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00016.dcm +0 -0
  177. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00017.dcm +0 -0
  178. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00018.dcm +0 -0
  179. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00019.dcm +0 -0
  180. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00020.dcm +0 -0
  181. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00021.dcm +0 -0
  182. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00022.dcm +0 -0
  183. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00023.dcm +0 -0
  184. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00024.dcm +0 -0
  185. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00025.dcm +0 -0
  186. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00026.dcm +0 -0
  187. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00027.dcm +0 -0
  188. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00028.dcm +0 -0
  189. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00029.dcm +0 -0
  190. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00030.dcm +0 -0
  191. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00031.dcm +0 -0
  192. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00032.dcm +0 -0
  193. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00033.dcm +0 -0
  194. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00034.dcm +0 -0
  195. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00035.dcm +0 -0
  196. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00036.dcm +0 -0
  197. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00037.dcm +0 -0
  198. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00038.dcm +0 -0
  199. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00039.dcm +0 -0
  200. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00040.dcm +0 -0
  201. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00041.dcm +0 -0
  202. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00042.dcm +0 -0
  203. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00043.dcm +0 -0
  204. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00044.dcm +0 -0
  205. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_IMG_00045.dcm +0 -0
  206. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_3/DCM_RS_00046.dcm +0 -0
  207. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00000.dcm +0 -0
  208. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00001.dcm +0 -0
  209. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00002.dcm +0 -0
  210. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00003.dcm +0 -0
  211. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00004.dcm +0 -0
  212. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00005.dcm +0 -0
  213. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00006.dcm +0 -0
  214. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00007.dcm +0 -0
  215. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00008.dcm +0 -0
  216. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00009.dcm +0 -0
  217. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00010.dcm +0 -0
  218. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00011.dcm +0 -0
  219. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00012.dcm +0 -0
  220. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00013.dcm +0 -0
  221. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00014.dcm +0 -0
  222. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00015.dcm +0 -0
  223. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00016.dcm +0 -0
  224. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00017.dcm +0 -0
  225. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00018.dcm +0 -0
  226. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00019.dcm +0 -0
  227. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00020.dcm +0 -0
  228. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00021.dcm +0 -0
  229. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00022.dcm +0 -0
  230. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00023.dcm +0 -0
  231. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00024.dcm +0 -0
  232. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00025.dcm +0 -0
  233. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00026.dcm +0 -0
  234. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00027.dcm +0 -0
  235. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00028.dcm +0 -0
  236. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00029.dcm +0 -0
  237. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00030.dcm +0 -0
  238. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00031.dcm +0 -0
  239. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00032.dcm +0 -0
  240. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00033.dcm +0 -0
  241. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00034.dcm +0 -0
  242. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00035.dcm +0 -0
  243. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00036.dcm +0 -0
  244. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00037.dcm +0 -0
  245. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00038.dcm +0 -0
  246. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00039.dcm +0 -0
  247. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00040.dcm +0 -0
  248. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00041.dcm +0 -0
  249. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00042.dcm +0 -0
  250. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00043.dcm +0 -0
  251. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00044.dcm +0 -0
  252. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00045.dcm +0 -0
  253. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00046.dcm +0 -0
  254. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00047.dcm +0 -0
  255. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00048.dcm +0 -0
  256. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00049.dcm +0 -0
  257. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00050.dcm +0 -0
  258. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00051.dcm +0 -0
  259. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00052.dcm +0 -0
  260. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00053.dcm +0 -0
  261. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00054.dcm +0 -0
  262. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_IMG_00055.dcm +0 -0
  263. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_phantom_dicom/pat_4/DCM_RS_00056.dcm +0 -0
  264. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi1/ibsi1_id_a1.json +0 -0
  265. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi1/ibsi1_id_a2.json +0 -0
  266. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi1/ibsi1_id_b1.json +0 -0
  267. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi1/ibsi1_id_b2.json +0 -0
  268. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi1/ibsi1_id_c1.json +0 -0
  269. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi1/ibsi1_id_c2.json +0 -0
  270. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_1a1.json +0 -0
  271. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_1a2.json +0 -0
  272. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_1a3.json +0 -0
  273. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_1a4.json +0 -0
  274. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_1b1.json +0 -0
  275. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_1b2.json +0 -0
  276. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_2a.json +0 -0
  277. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_2b.json +0 -0
  278. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_2c.json +0 -0
  279. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3a1.json +0 -0
  280. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3a2.json +0 -0
  281. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3a3.json +0 -0
  282. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3b1.json +0 -0
  283. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3b2.json +0 -0
  284. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3b3.json +0 -0
  285. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3c1.json +0 -0
  286. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3c2.json +0 -0
  287. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_3c3.json +0 -0
  288. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_4a1.json +0 -0
  289. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_4a2.json +0 -0
  290. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_4b1.json +0 -0
  291. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_4b2.json +0 -0
  292. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_5a1.json +0 -0
  293. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_5a2.json +0 -0
  294. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_6a1.json +0 -0
  295. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_1/ibsi_phase2_1_id_6a2.json +0 -0
  296. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_1a.json +0 -0
  297. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_1b.json +0 -0
  298. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_2a.json +0 -0
  299. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_2b.json +0 -0
  300. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_3a.json +0 -0
  301. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_3b.json +0 -0
  302. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_4a.json +0 -0
  303. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_4b.json +0 -0
  304. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_5a.json +0 -0
  305. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_5b.json +0 -0
  306. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_6a.json +0 -0
  307. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/ibsi_settings/ibsi2_phase_2/ibsi_phase2_2_id_6b.json +0 -0
  308. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/radiomics_settings/original_settings.json +0 -0
  309. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/sample_ct/dosimetric_model_test_data/dose.nii +0 -0
  310. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/sample_ct/dosimetric_model_test_data/mask_(testStr1 U testStr3).nii +0 -0
  311. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/sample_ct/dosimetric_model_test_data/mask_testStr1.nii +0 -0
  312. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/sample_ct/dosimetric_model_test_data/mask_testStr2.nii +0 -0
  313. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/sample_ct/dosimetric_model_test_data/mask_testStr3.nii +0 -0
  314. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/datasets/sample_ct/dosimetric_model_test_data/scan.nii +0 -0
  315. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dcm_export/__init__.py +0 -0
  316. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dcm_export/iod_helper.py +0 -0
  317. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dcm_export/reg_iod.py +0 -0
  318. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dcm_export/rtdose_iod.py +0 -0
  319. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dcm_export/rtplan_iod.py +0 -0
  320. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dcm_export/rtstruct_iod.py +0 -0
  321. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dcm_export/scan_iod.py +0 -0
  322. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/dvh.py +0 -0
  323. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/gamma.py +0 -0
  324. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/README_IMRTP.md +0 -0
  325. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/__init__.py +0 -0
  326. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/QIBData/aahn_18b.dat +0 -0
  327. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/QIBData/aahn_6b.dat +0 -0
  328. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/QIBData/qib_tables.npz +0 -0
  329. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/__init__.py +0 -0
  330. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/influence.py +0 -0
  331. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/montecarlo.py +0 -0
  332. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/qib.py +0 -0
  333. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/qib_data.py +0 -0
  334. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/raytrace.py +0 -0
  335. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/recalc.py +0 -0
  336. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/dosecalc/rtplan.py +0 -0
  337. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/imrtp.py +0 -0
  338. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/imrtp_gui.py +0 -0
  339. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/imrtp_problem.py +0 -0
  340. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/lattice.py +0 -0
  341. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/portpy_bridge.py +0 -0
  342. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/imrtp/pyradplan_bridge.py +0 -0
  343. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/mri_metrics/__init__.py +0 -0
  344. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/mri_metrics/dce_mri.py +0 -0
  345. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/multiViewHelper.py +0 -0
  346. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/plan_container.py +0 -0
  347. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/__init__.py +0 -0
  348. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/first_order.py +0 -0
  349. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/ibsi1.py +0 -0
  350. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/neighbor_gray_level_dependence.py +0 -0
  351. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/preprocess.py +0 -0
  352. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/run_length.py +0 -0
  353. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/shape.py +0 -0
  354. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/size_zone.py +0 -0
  355. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/texture_filters.py +0 -0
  356. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/texture_utils.py +0 -0
  357. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/radiomics/vector_elasticity.py +0 -0
  358. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/registration/__init__.py +0 -0
  359. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/registration/ants_reg.py +0 -0
  360. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/registration/register.py +0 -0
  361. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/registration/settings/plastimatch_ct_ct_intra_pt_affine.txt +0 -0
  362. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/registration/settings/plastimatch_ct_ct_intra_pt_bsplines.txt +0 -0
  363. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/registration/settings/plastimatch_ct_ct_intra_pt_w_masks_affine.txt +0 -0
  364. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/registration/settings/plastimatch_ct_ct_intra_pt_w_masks_bsplines.txt +0 -0
  365. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/__init__.py +0 -0
  366. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/dosimetric_models.py +0 -0
  367. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Bronchial stenosis (cox).json +0 -0
  368. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Bronchial stenosis (logistic).json +0 -0
  369. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Bronchial toxicity (Grade 3+).json +0 -0
  370. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Bronchial toxicity (Grade 5).json +0 -0
  371. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Esophagitis (Huang).json +0 -0
  372. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Esophagitis (Jackson_cox).json +0 -0
  373. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Esophagitis (Jackson_logistic).json +0 -0
  374. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Esophagitis (Wijsman).json +0 -0
  375. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Pneumonitis (Appelt).json +0 -0
  376. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Rectal bleeding (grade 2+).json +0 -0
  377. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/model_parameters/Xerostomia (grade 2+).json +0 -0
  378. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/roe/roe_gui.py +0 -0
  379. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/scripts/bench_uromt_overlay.py +0 -0
  380. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/scripts/demo_imrtp_gui.py +0 -0
  381. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/scripts/structure_consensus_example.py +0 -0
  382. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/scripts/uromt_matlab_compare.py +0 -0
  383. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/segmentation/models.py +0 -0
  384. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/MATLAB_COMPARISON.md +0 -0
  385. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/__init__.py +0 -0
  386. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/analyze.py +0 -0
  387. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/config.py +0 -0
  388. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/data.py +0 -0
  389. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/export.py +0 -0
  390. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/gpu.py +0 -0
  391. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/gpu_kernels.py +0 -0
  392. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/kernels.py +0 -0
  393. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/numerics.py +0 -0
  394. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/settings/dce_concentration_settings.json +0 -0
  395. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/settings/uromt_model_settings.json +0 -0
  396. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/solver.py +0 -0
  397. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/uromt/viz.py +0 -0
  398. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/utils/__init__.py +0 -0
  399. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/utils/ai_pipeline.py +0 -0
  400. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/utils/custom_colormaps.py +0 -0
  401. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/utils/image_proc.py +0 -0
  402. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/utils/interp.py +0 -0
  403. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/utils/mask.py +0 -0
  404. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/utils/statistics.py +0 -0
  405. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/utils/uid.py +0 -0
  406. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/API_pycerr_gui.md +0 -0
  407. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/__init__.py +0 -0
  408. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/cerr_colormaps.py +0 -0
  409. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/CERR_logo.icns +0 -0
  410. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/CERR_logo.ico +0 -0
  411. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/CERR_logo.png +0 -0
  412. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/__main__.py +0 -0
  413. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/app.py +0 -0
  414. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/colorbars.py +0 -0
  415. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/dialogs.py +0 -0
  416. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/main_window.py +0 -0
  417. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/pyCERR_logo_HQ.png +0 -0
  418. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/slice_view.py +0 -0
  419. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/uromt_gui.py +0 -0
  420. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_gui/volume3d.py +0 -0
  421. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_napari.py +0 -0
  422. {pycerr-2.2.0 → pycerr-2.2.2}/cerr/viewer/pycerr_nbviewer.py +0 -0
  423. {pycerr-2.2.0 → pycerr-2.2.2}/docs/Makefile +0 -0
  424. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.contour.rst +0 -0
  425. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.dataclasses.rst +0 -0
  426. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.datasets.rst +0 -0
  427. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.dcm_export.rst +0 -0
  428. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.imrtp.dosecalc.rst +0 -0
  429. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.imrtp.rst +0 -0
  430. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.mri_metrics.rst +0 -0
  431. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.radiomics.rst +0 -0
  432. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.registration.rst +0 -0
  433. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.roe.rst +0 -0
  434. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.rst +0 -0
  435. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.utils.rst +0 -0
  436. {pycerr-2.2.0 → pycerr-2.2.2}/docs/cerr.viewer.rst +0 -0
  437. {pycerr-2.2.0 → pycerr-2.2.2}/docs/conf.py +0 -0
  438. {pycerr-2.2.0 → pycerr-2.2.2}/docs/index.rst +0 -0
  439. {pycerr-2.2.0 → pycerr-2.2.2}/docs/make.bat +0 -0
  440. {pycerr-2.2.0 → pycerr-2.2.2}/docs/modules.rst +0 -0
  441. {pycerr-2.2.0 → pycerr-2.2.2}/docs/requirements.txt +0 -0
  442. {pycerr-2.2.0 → pycerr-2.2.2}/docs/setup.rst +0 -0
  443. {pycerr-2.2.0 → pycerr-2.2.2}/docs/tests.rst +0 -0
  444. {pycerr-2.2.0 → pycerr-2.2.2}/notebooks/urOMT_demo.ipynb +0 -0
  445. {pycerr-2.2.0 → pycerr-2.2.2}/notebooks/urOMT_fast_settings.json +0 -0
  446. {pycerr-2.2.0 → pycerr-2.2.2}/pycerr.egg-info/dependency_links.txt +0 -0
  447. {pycerr-2.2.0 → pycerr-2.2.2}/pycerr.egg-info/not-zip-safe +0 -0
  448. {pycerr-2.2.0 → pycerr-2.2.2}/pycerr.egg-info/top_level.txt +0 -0
  449. {pycerr-2.2.0 → pycerr-2.2.2}/requirements.txt +0 -0
  450. {pycerr-2.2.0 → pycerr-2.2.2}/setup.cfg +0 -0
  451. {pycerr-2.2.0 → pycerr-2.2.2}/setup.py +0 -0
  452. {pycerr-2.2.0 → pycerr-2.2.2}/tests/README.md +0 -0
  453. {pycerr-2.2.0 → pycerr-2.2.2}/tests/__init__.py +0 -0
  454. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_ants_registration.py +0 -0
  455. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_dcm_export_reg.py +0 -0
  456. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_dcm_export_rtstruct.py +0 -0
  457. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_dcm_reg_import.py +0 -0
  458. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_dicom_import_robustness.py +0 -0
  459. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_dicom_load.py +0 -0
  460. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_dvh.py +0 -0
  461. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_gamma.py +0 -0
  462. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_gui_disprange_3d.py +0 -0
  463. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_gui_dvf_overlay.py +0 -0
  464. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_gui_fast_alpha.py +0 -0
  465. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_gui_fused_dose.py +0 -0
  466. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_gui_isodose_levels.py +0 -0
  467. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_gui_plane_labels.py +0 -0
  468. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_gui_upsample.py +0 -0
  469. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_h5_roundtrip.py +0 -0
  470. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_ibsi1_features.py +0 -0
  471. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_ibsi2_features.py +0 -0
  472. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_ibsi2_filters.py +0 -0
  473. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_imrtp.py +0 -0
  474. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_lattice.py +0 -0
  475. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_module_imports.py +0 -0
  476. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_nii_export_import.py +0 -0
  477. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_portpy_bridge.py +0 -0
  478. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_portpy_bridge_phase2.py +0 -0
  479. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_portpy_bridge_phase3.py +0 -0
  480. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_portpy_bridge_phase4.py +0 -0
  481. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_pyradplan_bridge.py +0 -0
  482. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_rasterization.py +0 -0
  483. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_roe_models.py +0 -0
  484. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_structure_json.py +0 -0
  485. {pycerr-2.2.0 → pycerr-2.2.2}/tests/test_uromt.py +0 -0
  486. {pycerr-2.2.0 → pycerr-2.2.2}/tools/sync-branches.sh +0 -0
@@ -7,6 +7,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.2.2] - 2026-09-28
11
+
12
+ ### Fixed
13
+
14
+ - **GLCM sum entropy dropped the p(x+y) = 2 term.** The emptiness check on the
15
+ indices of grey-level sum 2 used `np.any`, and the only cell with that sum
16
+ sits at index 0, so the term p(1,1)·log₂p(1,1) was left out whenever the
17
+ lowest grey level neighboured itself. Sum entropy was underestimated for
18
+ such structures. The same check in the difference-entropy loop is fixed too.
19
+ - **NGTDM contrast skipped grey-level shifts.** The contrast double sum
20
+ skipped shift *k* whenever grey level *k* was empty, which dropped valid
21
+ pairs for any structure with empty grey levels (typically homogeneous
22
+ organs with fixed bin number).
23
+ - **NGTDM level probabilities now follow IBSI.** `p` counted every voxel in
24
+ the structure but was normalised by the number of voxels with a valid
25
+ neighbourhood (N<sub>v,c</sub>), so it could sum to more than 1 in 2D/2.5D.
26
+ It now counts only voxels with at least one neighbour. All NGTDM features
27
+ can change slightly for 2D/2.5D calculations. With both NGTDM fixes, contrast
28
+ matches the IBSI 1 consensus values for configurations A, B and C.
29
+
30
+ ### Changed
31
+
32
+ - **`polyFill` is vectorized**, 3-23x faster on typical contours, with
33
+ pixel-identical output (checked against the previous implementation in
34
+ `tests/test_poly_fill.py`). Contours extending past the image edge are now
35
+ clipped; previously they raised `IndexError` past the far edge and wrapped
36
+ around at negative indices.
37
+ - **`importStructureMask` pads a uint8 mask** instead of an int64 copy,
38
+ cutting its memory use 8x. Output is unchanged.
39
+
40
+ ## [2.2.1] - 2026-09-26
41
+
42
+ ### Changed
43
+
44
+ - **The Qt desktop viewer's dependencies are now an optional extra.** `PyQt5`,
45
+ `pyvista` and `pyvistaqt` moved out of the base install into
46
+ `pip install "pycerr[viewer]"`. PyQt5 publishes no aarch64 Linux wheel, so
47
+ `pip install pycerr` on arm64 Linux (Apple Silicon Docker images, ARM
48
+ servers) tried to build it from source and failed for want of `qmake`.
49
+ Everything that does not draw a Qt window is unaffected: the Python API,
50
+ batch/headless processing in containers, and the Jupyter viewer
51
+ (`cerr.viewer.pycerr_nbviewer`), which uses `ipywidgets` + matplotlib and
52
+ keeps `ipywidgets` as a base dependency. Launching the desktop viewer without
53
+ the extra now raises an ImportError naming the install command instead of
54
+ `No module named 'PySide2'`.
55
+
10
56
  ## [2.2.0] - 2026-09-17
11
57
 
12
58
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycerr
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: A Computational Environment for Radiological Research
5
5
  Author-email: "Aditya P. Apte" <aptea@mskcc.org>, Aditi Iyer <iyera@mskcc.org>, Eve LoCastro <locastre@mskcc.org>, "Joseph O. Deasy" <deasyj@mskcc.org>
6
6
  Project-URL: Homepage, https://github.com/cerr/pyCERR
@@ -30,9 +30,10 @@ Requires-Dist: ipywidgets
30
30
  Requires-Dist: surface-distance-based-measures
31
31
  Requires-Dist: itk-strain
32
32
  Requires-Dist: numba
33
- Requires-Dist: PyQt5
34
- Requires-Dist: pyvista
35
- Requires-Dist: pyvistaqt
33
+ Provides-Extra: viewer
34
+ Requires-Dist: PyQt5; extra == "viewer"
35
+ Requires-Dist: pyvista; extra == "viewer"
36
+ Requires-Dist: pyvistaqt; extra == "viewer"
36
37
  Provides-Extra: napari
37
38
  Requires-Dist: napari[all]; extra == "napari"
38
39
  Requires-Dist: napari-animation; extra == "napari"
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.2.0'
22
- __version_tuple__ = version_tuple = (2, 2, 0)
21
+ __version__ = version = '2.2.2'
22
+ __version_tuple__ = version_tuple = (2, 2, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g1496840a3'
24
+ __commit_id__ = commit_id = 'gf85644a5a'
@@ -29,77 +29,81 @@ def polyFill(rowV, colV, xSize, ySize):
29
29
  np.ndarray: Boolean mask of shape ``(xSize, ySize)`` where filled
30
30
  pixels are 1 and background pixels are 0.
31
31
  """
32
- # Initialize the result matrix with zeros
32
+ # Vectorized scanline fill: O(edge crossings) rather than a Python loop over
33
+ # scanlines x edges. Scanlines run along the column (y) axis. Semantics:
34
+ # an edge covers scanlines ceil(top)..bottom but toggles only where y != bottom;
35
+ # a flat edge on an integer scanline draws ceil(min row)..floor(max row); an
36
+ # integer bottom vertex draws its own pixel; toggles within 1e-6 of an integer
37
+ # snap to it; sorted toggles pair up as ceil(t0)..floor(t1). An odd crossing
38
+ # count on a scanline raises IndexError. Pixels outside the image are clipped.
33
39
  result = np.zeros((xSize, ySize))
34
-
35
- # Some contours have more than one segment. Treat them as separate polygons on the same image.
36
- # They shouldn't overlap, but if they do, the value of the resultant mask will be 1.0.
37
- pointCount = len(rowV)
38
- edgeList = np.zeros((pointCount, 4))
39
-
40
- # Iterate over each point in the contour
41
- for point in range(pointCount):
42
- if point == pointCount - 1:
43
- p1x, p1y = rowV[point], colV[point]
44
- p2x, p2y = rowV[0], colV[0]
45
- else:
46
- p1x, p1y = rowV[point], colV[point]
47
- p2x, p2y = rowV[point + 1], colV[point + 1]
48
-
49
- # Ensure that the edge is ordered from top to bottom (y-wise)
50
- if p1y <= p2y:
51
- edgeList[point, :] = [p1x, p1y, p2x, p2y]
52
- else:
53
- edgeList[point, :] = [p2x, p2y, p1x, p1y]
54
-
55
- # Get the relevant y-range to loop over
56
- minY = int(np.ceil(np.min(edgeList[:, 1])))
57
- maxY = int(np.floor(np.max(edgeList[:, 3])))
58
-
59
- # Loop over the relevant lines in the image.
60
- for y in range(minY, maxY + 1):
61
- # Get the active edges that cover the current y value
62
- indV = (edgeList[:, 1] <= y) & (edgeList[:, 3] >= y)
63
- activeEdges = edgeList[indV, :]
64
-
65
- # Create lists to store pixels to draw and intersections
66
- drawlist = np.empty(0,dtype=int)
67
- togglelist = np.empty(0,dtype=float)
68
-
69
- # Iterate over the active edges
70
- edgeCount = activeEdges.shape[0]
71
- for edge in range(edgeCount):
72
- p1x, p1y, p2x, p2y = activeEdges[edge, :]
73
-
74
- # Check if it's a flat line
75
- if p1y == p2y:
76
- if p1x > p2x:
77
- drawlist = np.append(drawlist, np.arange(int(np.ceil(p2x)), int(np.floor(p1x)) + 1))
78
- else:
79
- drawlist = np.append(drawlist, np.arange(int(np.ceil(p1x)), int(np.floor(p2x)) + 1))
80
- elif p2y == y and p2x == round(p2x):
81
- drawlist = np.append(drawlist,int(p2x))
82
- elif p2y != y:
83
- invslope = float(p2x - p1x) / float(p2y - p1y)
84
- togglelist = np.append(togglelist, p1x + (invslope * (y - p1y)))
85
-
86
- # Snap to center if less than tolerance
87
- snap_tol = 1e-6
88
- togglelistRound = np.round(togglelist)
89
- ind_snap = np.abs(togglelistRound - togglelist) < snap_tol
90
- togglelist[ind_snap] = togglelistRound[ind_snap]
91
-
92
- # Sort the toggle points in order
93
- togglelist.sort()
94
-
95
- # Iterate over pairs in the toggle list and draw the pixels accordingly
96
- for i in range(0, len(togglelist), 2):
97
- x1, x2 = int(np.ceil(togglelist[i])), int(np.floor(togglelist[i + 1]))
98
- result[x1:x2 + 1, y] = 1
99
-
100
- # Turn on the pixels in the drawlist
101
- result[drawlist, y] = 1
102
-
40
+ rowV = np.asarray(rowV, dtype=float)
41
+ colV = np.asarray(colV, dtype=float)
42
+ if len(rowV) == 0:
43
+ return result
44
+
45
+ # Edges ordered top to bottom (y-wise); the polygon is closed
46
+ nxt = np.roll(np.arange(len(rowV)), -1)
47
+ p1x, p1y, p2x, p2y = rowV, colV, rowV[nxt], colV[nxt]
48
+ swap = ~(p1y <= p2y)
49
+ ax = np.where(swap, p2x, p1x)
50
+ ay = np.where(swap, p2y, p1y)
51
+ bx = np.where(swap, p1x, p2x)
52
+ by = np.where(swap, p1y, p2y)
53
+ if int(np.floor(np.max(by))) < int(np.ceil(np.min(ay))):
54
+ return result
55
+
56
+ # Flat edges lying on an integer scanline
57
+ flat = ay == by
58
+ for e in np.nonzero(flat & (ay == np.round(ay)) & (ay >= 0) & (ay < ySize))[0]:
59
+ lo, hi = (bx[e], ax[e]) if ax[e] > bx[e] else (ax[e], bx[e])
60
+ result[max(int(np.ceil(lo)), 0):int(np.floor(hi)) + 1, int(ay[e])] = 1
61
+
62
+ # Bottom vertices on integer grid points
63
+ ax, ay, bx, by = ax[~flat], ay[~flat], bx[~flat], by[~flat]
64
+ vertex = (by == np.round(by)) & (bx == np.round(bx)) & (bx >= 0) & (bx < xSize) & (by >= 0) & (by < ySize)
65
+ result[bx[vertex].astype(int), by[vertex].astype(int)] = 1
66
+
67
+ # Toggle points of each edge on every scanline it crosses
68
+ y0 = np.ceil(ay).astype(np.int64)
69
+ y1 = np.floor(by).astype(np.int64)
70
+ y1 = np.where(by == np.round(by), y1 - 1, y1) # no toggle on the bottom scanline
71
+ k = np.maximum(y1 - y0 + 1, 0)
72
+ total = int(k.sum())
73
+ if total == 0:
74
+ return result
75
+ e = np.repeat(np.arange(len(k)), k)
76
+ y = y0[e] + (np.arange(total) - np.repeat(np.cumsum(k) - k, k))
77
+ invslope = (bx[e] - ax[e]) / (by[e] - ay[e])
78
+ t = ax[e] + invslope * (y.astype(float) - ay[e])
79
+
80
+ # Snap to center if less than tolerance
81
+ t_round = np.round(t)
82
+ snap = np.abs(t_round - t) < 1e-6
83
+ t[snap] = t_round[snap]
84
+
85
+ # Sort toggles within each scanline and pair them up
86
+ order = np.lexsort((t, y))
87
+ t, y = t[order], y[order]
88
+ if np.any(np.unique(y, return_counts=True)[1] % 2):
89
+ raise IndexError("odd number of polygon crossings on a scanline")
90
+ x1 = np.ceil(t[0::2]).astype(np.int64)
91
+ x2 = np.floor(t[1::2]).astype(np.int64)
92
+ cols = y[0::2]
93
+ # Clip runs to the image
94
+ x1 = np.maximum(x1, 0)
95
+ x2 = np.minimum(x2, xSize - 1)
96
+ keep = (x1 <= x2) & (cols >= 0) & (cols < ySize)
97
+ x1, x2, cols = x1[keep], x2[keep], cols[keep]
98
+ if len(x1) == 0:
99
+ return result
100
+
101
+ # Draw all runs at once with a difference array along rows
102
+ r0, r1, c0, c1 = int(x1.min()), int(x2.max()), int(cols.min()), int(cols.max())
103
+ runs = np.zeros((r1 - r0 + 2, c1 - c0 + 1), dtype=np.int32)
104
+ np.add.at(runs, (x1 - r0, cols - c0), 1)
105
+ np.add.at(runs, (x2 + 1 - r0, cols - c0), -1)
106
+ result[r0:r1 + 1, c0:c1 + 1][np.cumsum(runs, axis=0)[:-1] > 0] = 1
103
107
  return result
104
108
 
105
109
  # Example usage:
@@ -956,8 +956,9 @@ def importStructureMask(mask3M, assocScanNum, structName, planC, structNum=None)
956
956
  """
957
957
 
958
958
  # Pad mask to account for boundary edges
959
- paddedMask3M = mask3M.astype(int)
960
- paddedMask3M = np.pad(paddedMask3M, ((1,1),(1,1),(0,0)), 'constant', constant_values = 0)
959
+ # uint8 rather than int64 keeps the copy small; only voxels == 1 are contoured below
960
+ paddedMask3M = np.pad(np.asarray(mask3M == 1, dtype=np.uint8), ((1, 1), (1, 1), (0, 0)),
961
+ 'constant', constant_values=0)
961
962
  dt = datetime.now()
962
963
  if isinstance(structNum,(int, float, np.integer, np.floating)):
963
964
  struct_meta = planC.structure[structNum]
@@ -178,7 +178,7 @@ def cooccurToScalarFeatures(cooccurM):
178
178
  px[n, col] = np.sum(cooccurM[indPxC[n], col])
179
179
  pXminusY[n, col] = np.sum(cooccurM[indCtrstC[n], col])
180
180
 
181
- if np.any(indCtrstC[n]):
181
+ if len(indCtrstC[n]) > 0:
182
182
  pXminusYlogPXminusY[n, col] = pXminusY[n, col] * np.log2(pXminusY[n, col] + np.finfo(float).eps)
183
183
  else:
184
184
  pXminusYlogPXminusY[n, col] = 0
@@ -273,7 +273,7 @@ def cooccurToScalarFeatures(cooccurM):
273
273
  pXplusY[n - 1, off] = np.sum(cooccurM[indPxPlusYc[n - 1], off], axis=0)
274
274
 
275
275
  # Calculate p(x+y) log2(p(x+y))
276
- if np.any(indPxPlusYc[n - 1]):
276
+ if len(indPxPlusYc[n - 1]) > 0:
277
277
  pXplusYlogPXplusY[n - 1, off] = pXplusY[n - 1, off] * np.log2(pXplusY[n - 1, off] + np.finfo(float).eps)
278
278
  else:
279
279
  pXplusYlogPXplusY[n - 1, off] = 0 #np.zeros(numCooccurs)
@@ -100,12 +100,10 @@ def calcNGTDM(scan_array, patch_size, numGrLevels):
100
100
  ind_lev_v = (vox_val_v == lev) & vox_mask_v.astype(bool)
101
101
  vals_v = q_m[ind_lev_v]
102
102
  s[lev - 1, :] += vals_v.sum().astype(s.dtype)
103
+ p[lev - 1] += ind_lev_v.sum()
103
104
 
104
- # Calculate level probabilities (p)
105
- numVoxels = np.sum(scan_array > 0)
106
- for iLev in range(1, numGrLevels + 1):
107
- scanLev3M = scan_array == iLev
108
- p[iLev - 1] = np.sum(scanLev3M) / Nvc
105
+ # Level probabilities (p) over voxels with a valid neighbourhood (IBSI n_i / N_v,c)
106
+ p = p / Nvc
109
107
 
110
108
  return s, p, Nvc
111
109
 
@@ -127,8 +125,6 @@ def ngtdmToScalarFeatures(s, p, Nvc):
127
125
  term1 = 0
128
126
  term2 = 0
129
127
  for lev in range(1, numLevels + 1):
130
- if p[lev-1] == 0:
131
- continue
132
128
  term1 += np.sum(p * np.roll(p, lev) * (indV - np.roll(indV, lev))**2)
133
129
  term2 += s[lev - 1, 0]
134
130
  featuresS['contrast'] = 1 / (Ng * (Ng - 1)) * term1 * term2 / Nvc
@@ -8,10 +8,13 @@ A CERR-style (MATLAB CERR) slice viewer built on **pyCERR**, in a single file: `
8
8
  ## Setup (Windows, your paths)
9
9
 
10
10
  ```bat
11
- pip install PyQt5 matplotlib scipy
12
- pip install pyvista pyvistaqt :: optional, GPU-accelerated 3D view
11
+ pip install "pycerr[viewer]" :: Qt binding + pyvista/pyvistaqt 3D view
13
12
  ```
14
13
 
14
+ The base `pip install pycerr` is deliberately Qt-free, so it installs on
15
+ platforms without a PyQt5 wheel (arm64 Linux) and in headless containers; the
16
+ `viewer` extra adds what this desktop GUI needs.
17
+
15
18
  pyCERR itself: either `pip install pyCERR`, **or** use your local checkout — the script
16
19
  already points at it via:
17
20
 
@@ -57,7 +57,8 @@ Features (mirroring the classic CERR slice viewer):
57
57
  view (updates as you scroll) and the full field pyramid in the 3D view
58
58
 
59
59
  Requirements:
60
- pip install pyCERR PyQt5 matplotlib scipy
60
+ pip install "pycerr[viewer]" -- Qt binding + pyvista/pyvistaqt 3D view
61
+ (the base pycerr install is Qt-free)
61
62
  -- or add your local pyCERR checkout to sys.path (see PYCERR_PATH below).
62
63
 
63
64
  Run:
@@ -18,8 +18,20 @@ try:
18
18
  from PyQt5 import QtCore, QtGui, QtWidgets
19
19
  from PyQt5.QtCore import Qt
20
20
  except ImportError: # pragma: no cover - PySide fallback
21
- from PySide2 import QtCore, QtGui, QtWidgets # type: ignore
22
- from PySide2.QtCore import Qt # type: ignore
21
+ try:
22
+ from PySide2 import QtCore, QtGui, QtWidgets # type: ignore
23
+ from PySide2.QtCore import Qt # type: ignore
24
+ except ImportError as exc: # no Qt binding at all
25
+ # The Qt binding is an optional dependency (see pyproject's `viewer`
26
+ # extra), so say how to get it rather than surfacing a bare
27
+ # "No module named 'PySide2'".
28
+ raise ImportError(
29
+ "The pyCERR desktop viewer needs a Qt binding, which is not part of "
30
+ "the base install. Install it with:\n"
31
+ ' pip install "pycerr[viewer]"\n'
32
+ "For notebooks use the Qt-free viewer instead: "
33
+ "from cerr.viewer.pycerr_nbviewer import showNB"
34
+ ) from exc
23
35
 
24
36
  import logging
25
37
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycerr
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: A Computational Environment for Radiological Research
5
5
  Author-email: "Aditya P. Apte" <aptea@mskcc.org>, Aditi Iyer <iyera@mskcc.org>, Eve LoCastro <locastre@mskcc.org>, "Joseph O. Deasy" <deasyj@mskcc.org>
6
6
  Project-URL: Homepage, https://github.com/cerr/pyCERR
@@ -30,9 +30,10 @@ Requires-Dist: ipywidgets
30
30
  Requires-Dist: surface-distance-based-measures
31
31
  Requires-Dist: itk-strain
32
32
  Requires-Dist: numba
33
- Requires-Dist: PyQt5
34
- Requires-Dist: pyvista
35
- Requires-Dist: pyvistaqt
33
+ Provides-Extra: viewer
34
+ Requires-Dist: PyQt5; extra == "viewer"
35
+ Requires-Dist: pyvista; extra == "viewer"
36
+ Requires-Dist: pyvistaqt; extra == "viewer"
36
37
  Provides-Extra: napari
37
38
  Requires-Dist: napari[all]; extra == "napari"
38
39
  Requires-Dist: napari-animation; extra == "napari"
@@ -470,6 +470,7 @@ tests/test_imrtp.py
470
470
  tests/test_lattice.py
471
471
  tests/test_module_imports.py
472
472
  tests/test_nii_export_import.py
473
+ tests/test_poly_fill.py
473
474
  tests/test_portpy_bridge.py
474
475
  tests/test_portpy_bridge_phase2.py
475
476
  tests/test_portpy_bridge_phase3.py
@@ -17,9 +17,6 @@ ipywidgets
17
17
  surface-distance-based-measures
18
18
  itk-strain
19
19
  numba
20
- PyQt5
21
- pyvista
22
- pyvistaqt
23
20
 
24
21
  [ants]
25
22
  antspyx
@@ -37,3 +34,8 @@ nvidia-curand
37
34
  [napari]
38
35
  napari[all]
39
36
  napari-animation
37
+
38
+ [viewer]
39
+ PyQt5
40
+ pyvista
41
+ pyvistaqt
@@ -1164,6 +1164,7 @@
1164
1164
  "tests/test_lattice.py",
1165
1165
  "tests/test_module_imports.py",
1166
1166
  "tests/test_nii_export_import.py",
1167
+ "tests/test_poly_fill.py",
1167
1168
  "tests/test_portpy_bridge.py",
1168
1169
  "tests/test_portpy_bridge_phase2.py",
1169
1170
  "tests/test_portpy_bridge_phase3.py",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.2.2",
3
+ "distance": 0,
4
+ "node": "gf85644a5ac131d6d64abcc0b4153e55632377685",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-09-28"
8
+ }
@@ -48,12 +48,6 @@ dependencies = [
48
48
  # that dominate its Gauss-Newton CG matvec. ~90x on the derivative operator
49
49
  # versus the vectorized numpy form.
50
50
  'numba',
51
- # Desktop Qt viewer (cerr.viewer.pycerr_gui): PyQt5 is the Qt binding;
52
- # pyvista/pyvistaqt drive the GPU-accelerated 3D view (vtk is pulled in
53
- # transitively by pyvista).
54
- 'PyQt5',
55
- 'pyvista',
56
- 'pyvistaqt'
57
51
  ]
58
52
 
59
53
  [project.urls]
@@ -61,6 +55,22 @@ dependencies = [
61
55
  "Bug Tracker" = "https://github.com/cerr/pyCERR/issues"
62
56
 
63
57
  [project.optional-dependencies]
58
+ # Desktop Qt viewer (cerr.viewer.pycerr_gui) plus the ROE and IMRTP GUIs: PyQt5
59
+ # is the Qt binding; pyvista/pyvistaqt drive the GPU-accelerated 3D view (vtk
60
+ # comes in transitively via pyvista).
61
+ #
62
+ # Kept out of the base install because PyQt5 publishes no aarch64 Linux wheel:
63
+ # on arm64 Linux (Apple Silicon Docker, ARM servers) `pip install pycerr` tried
64
+ # to build it from source and failed for want of qmake. Everything that does
65
+ # not draw a Qt window -- headless servers and containers, batch processing,
66
+ # and the Jupyter viewer (cerr.viewer.pycerr_nbviewer, which needs only
67
+ # ipywidgets + matplotlib) -- works without it:
68
+ # pip install "pycerr[viewer]"
69
+ viewer = [
70
+ "PyQt5",
71
+ "pyvista",
72
+ "pyvistaqt",
73
+ ]
64
74
  napari = [
65
75
  "napari[all]",
66
76
  "napari-animation"
@@ -0,0 +1,115 @@
1
+ """
2
+ Checks that the vectorized rasterseg.polyFill reproduces the original
3
+ scanline implementation pixel for pixel.
4
+ """
5
+
6
+ import numpy as np
7
+ import pytest
8
+ from cerr.contour.rasterseg import polyFill
9
+
10
+
11
+ def reference_poly_fill(rowV, colV, xSize, ySize):
12
+ """Original loop-based polyFill (pyCERR <= 2.2.1), kept as the reference."""
13
+ result = np.zeros((xSize, ySize))
14
+ pointCount = len(rowV)
15
+ edgeList = np.zeros((pointCount, 4))
16
+ for point in range(pointCount):
17
+ p1x, p1y = rowV[point], colV[point]
18
+ p2x, p2y = rowV[(point + 1) % pointCount], colV[(point + 1) % pointCount]
19
+ if p1y <= p2y:
20
+ edgeList[point, :] = [p1x, p1y, p2x, p2y]
21
+ else:
22
+ edgeList[point, :] = [p2x, p2y, p1x, p1y]
23
+ minY = int(np.ceil(np.min(edgeList[:, 1])))
24
+ maxY = int(np.floor(np.max(edgeList[:, 3])))
25
+ for y in range(minY, maxY + 1):
26
+ indV = (edgeList[:, 1] <= y) & (edgeList[:, 3] >= y)
27
+ activeEdges = edgeList[indV, :]
28
+ drawlist = np.empty(0, dtype=int)
29
+ togglelist = np.empty(0, dtype=float)
30
+ for edge in range(activeEdges.shape[0]):
31
+ p1x, p1y, p2x, p2y = activeEdges[edge, :]
32
+ if p1y == p2y:
33
+ if p1x > p2x:
34
+ drawlist = np.append(drawlist, np.arange(int(np.ceil(p2x)), int(np.floor(p1x)) + 1))
35
+ else:
36
+ drawlist = np.append(drawlist, np.arange(int(np.ceil(p1x)), int(np.floor(p2x)) + 1))
37
+ elif p2y == y and p2x == round(p2x):
38
+ drawlist = np.append(drawlist, int(p2x))
39
+ elif p2y != y:
40
+ invslope = float(p2x - p1x) / float(p2y - p1y)
41
+ togglelist = np.append(togglelist, p1x + (invslope * (y - p1y)))
42
+ togglelistRound = np.round(togglelist)
43
+ ind_snap = np.abs(togglelistRound - togglelist) < 1e-6
44
+ togglelist[ind_snap] = togglelistRound[ind_snap]
45
+ togglelist.sort()
46
+ for i in range(0, len(togglelist), 2):
47
+ x1, x2 = int(np.ceil(togglelist[i])), int(np.floor(togglelist[i + 1]))
48
+ result[x1:x2 + 1, y] = 1
49
+ result[drawlist, y] = 1
50
+ return result
51
+
52
+
53
+ def star_polygon(rng, center, rMax, nPts, integer=False):
54
+ ang = np.sort(rng.uniform(0, 2 * np.pi, nPts))
55
+ rad = rng.uniform(0.3 * rMax, rMax, nPts)
56
+ rowV = center[0] + rad * np.cos(ang)
57
+ colV = center[1] + rad * np.sin(ang)
58
+ if integer:
59
+ rowV, colV = np.round(rowV), np.round(colV)
60
+ return rowV, colV
61
+
62
+
63
+ def assert_same(rowV, colV, xSize, ySize):
64
+ rowV, colV = np.asarray(rowV, dtype=float), np.asarray(colV, dtype=float)
65
+ inside = rowV.min() >= 0 and colV.min() >= 0 and rowV.max() < xSize - 1 and colV.max() < ySize - 1
66
+ if inside:
67
+ expected = reference_poly_fill(rowV, colV, xSize, ySize)
68
+ else:
69
+ # The reference raises past the far edge and wraps negative indices;
70
+ # polyFill clips. Compare against the reference on a padded canvas.
71
+ pad = int(np.ceil(max(-rowV.min(), -colV.min(), rowV.max() - xSize,
72
+ colV.max() - ySize, 0))) + 2
73
+ expected = reference_poly_fill(rowV + pad, colV + pad, xSize + 2 * pad,
74
+ ySize + 2 * pad)[pad:pad + xSize, pad:pad + ySize]
75
+ np.testing.assert_array_equal(polyFill(rowV, colV, xSize, ySize), expected)
76
+
77
+
78
+ @pytest.mark.parametrize("integer", [False, True])
79
+ def test_random_polygons(integer):
80
+ rng = np.random.default_rng(0 if integer else 1)
81
+ for _ in range(300):
82
+ nPts = int(rng.integers(3, 60))
83
+ rowV, colV = star_polygon(rng, (64, 64), rng.uniform(2, 60), nPts, integer)
84
+ assert_same(rowV, colV, 128, 128)
85
+
86
+
87
+ def test_axis_aligned_and_degenerate():
88
+ # square with flat edges on integer scanlines
89
+ assert_same([10, 10, 20, 20], [10, 30, 30, 10], 64, 64)
90
+ # half-integer square
91
+ assert_same([10.5, 10.5, 20.5, 20.5], [10.5, 30.5, 30.5, 10.5], 64, 64)
92
+ # triangle with integer vertices
93
+ assert_same([10, 20, 30, 20], [5, 10, 5, 1], 50, 50)
94
+ # sub-pixel polygon
95
+ assert_same([5.2, 5.4, 5.3], [5.1, 5.2, 5.4], 16, 16)
96
+ # single point and a line
97
+ assert_same([5.0], [5.0], 16, 16)
98
+ assert_same([2.0, 12.0], [3.0, 3.0], 16, 16)
99
+
100
+
101
+ def test_polygon_extending_past_image():
102
+ rng = np.random.default_rng(2)
103
+ for _ in range(100):
104
+ rowV, colV = star_polygon(rng, (rng.uniform(40, 60), rng.uniform(40, 60)), 30, 25)
105
+ assert_same(rowV, colV, 64, 64)
106
+ # crossing the top/left border (negative indices)
107
+ rowV, colV = star_polygon(rng, (rng.uniform(0, 10), rng.uniform(15, 50)), 12, 25)
108
+ assert_same(rowV, colV, 64, 64)
109
+
110
+
111
+ def test_multi_segment_contour():
112
+ # two disjoint polygons concatenated into one vertex list
113
+ rowV = np.r_[10.3, 10.3, 20.7, 20.7, 30.2, 40.8, 35.5]
114
+ colV = np.r_[10.2, 20.6, 20.6, 10.2, 30.1, 30.9, 45.4]
115
+ assert_same(rowV, colV, 64, 64)
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "2.2.0",
3
- "distance": 0,
4
- "node": "g1496840a36511ad614704e99556a973f04f2d509",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-09-17"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes