def test_4d_mh_loader_with_more_than_4_dimensions_fails(tmpdir): src = RESOURCE_PATH / "image10x11x12x13.mhd" dest = Path(tmpdir) / src.name shutil.copy(str(src), str(dest)) with open(str(dest)) as f: modified_header = f.read().replace("NDims = 4", "NDims = 5") with open(str(dest), "w") as f: f.write(modified_header) with pytest.raises(NotImplementedError): load_sitk_image(dest)
def test_load_sitk_image_with_corrupt_additional_meta_data_fails( tmpdir, test_img: str, key: str, value: str): src = RESOURCE_PATH / "image10x11x12x13.mhd" dest = Path(tmpdir) / src.name shutil.copy(str(src), str(dest)) with open(str(dest)) as f: lines = f.readlines() lines.insert(-1, f"{key} = {value}\n") with open(str(dest), "w") as f: f.writelines(lines) with pytest.raises(ValidationError): load_sitk_image(dest)
def test_writing_4d_mhd_produces_same_results(tmpdir, image: Path): def assert_img_properties(img: SimpleITK.Image): assert img.GetDimension() == 4 assert img.GetWidth() == 10 assert img.GetHeight() == 11 assert img.GetDepth() == 12 assert img.GetSize()[-1] == 13 img_ref = load_sitk_image(image) assert_img_properties(img_ref) copypath = Path(tmpdir / "temp4d.mhd") SimpleITK.WriteImage(img_ref, str(copypath), True) img = load_sitk_image(copypath) assert_img_properties(img) assert_sitk_img_equivalence(img, img_ref)
def test_load_sitk_image_with_additional_meta_data(tmpdir, test_img: str): src = RESOURCE_PATH / test_img sitk_image = load_sitk_image(src) for key in sitk_image.GetMetaDataKeys(): assert key in ADDITIONAL_HEADERS assert ADDITIONAL_HEADERS[key].match(sitk_image.GetMetaData(key)) assert "Bogus" not in sitk_image.GetMetaDataKeys()
def test_convert_itk_to_internal(image: Path): def assert_img_properties(img: SimpleITK.Image, internal_image: SimpleITKImage): color_space = { 1: ColorSpace.GRAY, 3: ColorSpace.RGB, 4: ColorSpace.RGBA, } assert internal_image.color_space == color_space.get( img.GetNumberOfComponentsPerPixel()) if img.GetDimension() == 4: assert internal_image.timepoints == img.GetSize()[-1] else: assert internal_image.timepoints is None if img.GetDepth(): assert internal_image.depth == img.GetDepth() assert internal_image.voxel_depth_mm == img.GetSpacing()[2] else: assert internal_image.depth is None assert internal_image.voxel_depth_mm is None assert internal_image.width == img.GetWidth() assert internal_image.height == img.GetHeight() assert internal_image.voxel_width_mm == approx(img.GetSpacing()[0]) assert internal_image.voxel_height_mm == approx(img.GetSpacing()[1]) img_ref = load_sitk_image(image) internal_image = SimpleITKImage( name=image.name, image=img_ref, consumed_files=set(), spacing_valid=True, ) assert_img_properties(img_ref, internal_image)
def get_sitk_image(self): """ Return the image that belongs to this model as an SimpleITK image. Requires that exactly one MHD/RAW file pair is associated with the model. Otherwise it wil raise a MultipleObjectsReturned or ObjectDoesNotExist exception. Returns ------- A SimpleITK image """ # self.files should contain 1 .mhd file try: mhd_file = self.files.get(image_type=ImageFile.IMAGE_TYPE_MHD, file__endswith=".mha") files = [mhd_file] except ObjectDoesNotExist: # Fallback to files that are still stored as mhd/(z)raw mhd_file = self.files.get(image_type=ImageFile.IMAGE_TYPE_MHD, file__endswith=".mhd") raw_file = self.files.get(image_type=ImageFile.IMAGE_TYPE_MHD, file__endswith="raw") files = [mhd_file, raw_file] file_size = 0 for file in files: if not file.file.storage.exists(name=file.file.name): raise FileNotFoundError(f"No file found for {file.file}") # Add up file sizes of mhd and raw file to get total file size file_size += file.file.size # Check file size to guard for out of memory error if file_size > settings.MAX_SITK_FILE_SIZE: raise OSError( f"File exceeds maximum file size. (Size: {file_size}, Max: {settings.MAX_SITK_FILE_SIZE})" ) with TemporaryDirectory() as tempdirname: for file in files: with file.file.open("rb") as infile, open( Path(tempdirname) / Path(file.file.name).name, "wb") as outfile: buffer = True while buffer: buffer = infile.read(1024) outfile.write(buffer) try: hdr_path = Path(tempdirname) / Path(mhd_file.file.name).name sitk_image = load_sitk_image(mhd_file=hdr_path) except RuntimeError as e: logging.error( f"Failed to load SimpleITK image with error: {e}") raise return sitk_image
def test_4d_mh_loader_with_invalid_data_type_fails(tmpdir): sources = [ RESOURCE_PATH / "image10x11x12x13.mhd", RESOURCE_PATH / "image10x11x12x13.zraw", ] targets = [] for src in sources: dest = Path(tmpdir) / src.name targets.append(dest) shutil.copy(str(src), str(dest)) tmp_header_file = targets[0] with open(str(tmp_header_file)) as f: modified_header = f.read().replace("MET_UCHAR", "MET_OTHER") with open(str(tmp_header_file), "w") as f: f.write(modified_header) with pytest.raises(RuntimeError, match="Unknown PixelType"): load_sitk_image(tmp_header_file)
def test_load_sitk_image_with_various_window_formats( test_img: str, center: Union[float, List[float]], width: Union[float, List[float]], ): src = MHD_WINDOW_DIR / test_img sitk_image = load_sitk_image(src) assert center == sitk_image.GetMetaData("WindowCenter") assert width == sitk_image.GetMetaData("WindowWidth")
def test_4d_mh_loader_with_uncompressed_data(tmpdir): sources = [ RESOURCE_PATH / "image10x11x12x13.mhd", RESOURCE_PATH / "image10x11x12x13.zraw", ] targets = [] for src in sources: dest = Path(tmpdir) / src.name targets.append(dest) shutil.copy(str(src), str(dest)) tmp_header_file, tmp_data_file = targets with open(str(tmp_header_file)) as f: modified_header = f.read().replace("CompressedData = True", "CompressedData = False") with open(str(tmp_header_file), "w") as f: f.write(modified_header) with open(str(tmp_data_file), "rb") as f: data = zlib.decompress(f.read()) with open(str(tmp_data_file), "wb") as f: f.write(data) load_sitk_image(tmp_header_file)
def get_sitk_image(self): """ Return the image that belongs to this model as an SimpleITK image. Requires that exactly one MHD/RAW file pair is associated with the model. Otherwise it wil raise a MultipleObjectsReturned or ObjectDoesNotExist exception. Returns ------- A SimpleITK image """ files = [i for i in self.get_metaimage_files() if i is not None] file_size = 0 for file in files: if not file.file.storage.exists(name=file.file.name): raise FileNotFoundError(f"No file found for {file.file}") # Add up file sizes of mhd and raw file to get total file size file_size += file.file.size # Check file size to guard for out of memory error if file_size > settings.MAX_SITK_FILE_SIZE: raise OSError( f"File exceeds maximum file size. (Size: {file_size}, Max: {settings.MAX_SITK_FILE_SIZE})" ) with TemporaryDirectory() as tempdirname: for file in files: with file.file.open("rb") as infile, open( Path(tempdirname) / Path(file.file.name).name, "wb" ) as outfile: buffer = True while buffer: buffer = infile.read(1024) outfile.write(buffer) try: hdr_path = Path(tempdirname) / Path(files[0].file.name).name sitk_image = load_sitk_image(mhd_file=hdr_path) except RuntimeError as e: logging.error( f"Failed to load SimpleITK image with error: {e}" ) raise return sitk_image
def test_load_sitk_image_with_faulty_window_formats(test_img: str, error_msg: str): src = MHD_WINDOW_DIR / "errors" / test_img with pytest.raises(ValidationError, match=error_msg): load_sitk_image(src)
def test_4d_mh_loader_without_datafile_fails(tmpdir): src = RESOURCE_PATH / "image10x11x12x13.mhd" dest = Path(tmpdir) / src.name shutil.copy(str(src), str(dest)) with pytest.raises(RuntimeError, match="File cannot be read"): load_sitk_image(dest)