# ========================================================================== # # Copyright NumFOCUS # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0.txt # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # ==========================================================================*/ import itk import tempfile import os dim = 2 PixelType = itk.UC # check the repr string assert "" == repr(itk.Image) # template should work with CType instance and with numbers ImageType = itk.Image[PixelType, dim] # template should return the same class with a class as parameter # or with an object of this class, and should also be the same # with the attribute # create instances of image for the next tests im = ImageType.New() im2 = ImageType.New() readerType = itk.ImageFileReader[ImageType] readerType2 = itk.ImageFileReader[im] readerType3 = itk.ImageFileReader.IUC2 assert readerType == readerType2 == readerType3 # we should be able to get the template and its parameters from the class (tpl, parameters) = itk.template(ImageType) assert tpl == itk.Image assert parameters == (PixelType, dim) # test that `isinstance` works obj = itk.ImageFileReader[ImageType].New() assert isinstance(obj, itk.ImageFileReader.IUC2) assert isinstance(obj, itk.ImageFileReader) # the template must raise a KeyError exception if the template parameter # is unknown try: itk.ImageFileReader["unknown parameter"] raise Exception("no exception sent for unknown parameter") except TypeError as e: print("Exception caught!") print(e) if not "imread" in str(e): raise Exception( "Expected to find extra information about" " `itk.imread()` in exception message." ) pass # TODO: test the rest of the dict interface # TODO: test __eq__, __ne__ and __hash__ # something else ? # now test the New method # without parameter reader = readerType.New() reader2 = readerType.New() # with an attribute parameter reader = readerType.New(FileName="test.png") assert reader.GetFileName() == "test.png" # with a wrong attribute name try: reader = readerType.New(WrongName="test.png") raise Exception("no exception sent for wrong attribute name") except AttributeError: pass # with a wrong attribute type try: reader = readerType.New(FileName=1) raise Exception("no exception sent for wrong attribute type") except: pass # with a wrong file name try: reader = itk.ImageFileReader.New(FileName="wrong filename") raise Exception("no exception sent for wrong file name") except RuntimeError as e: if not "The file doesn't exist." in str(e): raise e pass # pass filter as argument for input # to a filter with SetInput method median = itk.MedianImageFilter[ImageType, ImageType].New(reader) assert reader.GetOutput() == median.GetInput() # filter type determined by the input passed as an arg median_args = itk.MedianImageFilter.New(reader.GetOutput()) assert itk.class_(median) == itk.class_(median_args) # filter type determined by the input passed as a primary method input median_kwarg = itk.MedianImageFilter.New(Input=reader.GetOutput()) assert itk.class_(median) == itk.class_(median_kwarg) # to a filter with a SetImage method calculator = itk.MinimumMaximumImageCalculator[ImageType].New(reader) # not GetImage() method here to verify it's the right image # to a filter with several inputs sub = itk.SubtractImageFilter[ImageType, ImageType, ImageType].New(reader, reader2) assert reader.GetOutput() == sub.GetInput(0) assert reader2.GetOutput() == sub.GetInput(1) # pass image as argument for input # to a filter with SetInput method median = itk.MedianImageFilter[ImageType, ImageType].New(im) assert im == median.GetInput() # to a filter with a SetImage method calculator = itk.MinimumMaximumImageCalculator[ImageType].New(im) # not GetImage() method here to verify it's the right image # to a filter with several inputs sub = itk.SubtractImageFilter[ImageType, ImageType, ImageType].New(im, im2) assert im == sub.GetInput(0) assert im2 == sub.GetInput(1) # pass invalid input try: itk.MedianImageFilter[ImageType, ImageType].New(1) raise Exception("no exception sent for wrong input type") except: pass try: itk.SubtractImageFilter[ImageType, ImageType, ImageType].New(im, "wrong") raise Exception("no exception sent for wrong 2nd input type") except TypeError: pass # pass both input and attribute recons = itk.ReconstructionByDilationImageFilter[ImageType, ImageType].New( reader.GetOutput(), im, FullyConnected=True ) assert reader.GetOutput() == recons.GetInput(0) assert im == recons.GetInput(1) assert recons.GetFullyConnected() # pass input to object which do not take one try: ImageType.New(im) raise Exception("no exception sent for object without input") except AttributeError: pass # pass no attribute to reader and see if it automatically detects input image type. # Since we cannot easily know which type of images are supported in python, we generate # a lot of different types and try to create images using these types, create empty images # that we save, and then try to read them to test the reader. # We ignore the exception raised for creating types of pixels and images and from trying to # write the images on the hard disk the first time. We only care about exception raised from # the reader. def pixel_type_from_IO(pixel, component, dimension): import itk if pixel == "scalar": PixelType = component elif pixel == "rgb": PixelType = itk.RGBPixel[component] elif pixel == "rgba": PixelType = itk.RGBAPixel[component] elif pixel == "offset": PixelType = itk.Offset[dimension] elif pixel == "vector": PixelType = itk.Vector[component, dimension] elif pixel == "point": PixelType = itk.Point[component, dimension] elif pixel == "covariant_vector": PixelType = itk.CovariantVector[component, dimension] elif pixel == "symmetric_second_rank_tensor": PixelType = itk.SymmetricSecondRankTensor[component, dimension] elif pixel == "diffusion_tensor_3D": PixelType = itk.DiffusionTensor3D[component] elif pixel == "complex": PixelType = itk.complex[component] elif pixel == "fixed_array": PixelType = itk.FixedArray[component, dimension] elif pixel == "matrix": PixelType = itk.Matrix[component, dimension, dimension] else: raise RuntimeError(f"Unknown pixel type {pixel}.") return PixelType dimensions = [2, 3] component_type_dic = { "float": itk.F, "double": itk.D, "unsigned_char": itk.UC, "unsigned_short": itk.US, "unsigned_int": itk.UI, "unsigned_long": itk.UL, "unsigned_long_long": itk.ULL, "char": itk.SC, "short": itk.SS, "int": itk.SI, "long": itk.SL, "bool": itk.B, } pixel_types = [ "scalar", "rgb", "rgba", "offset", "vector", "point", "covariant_vector", "symmetric_second_rank_tensor", "diffusion_tensor_3D", "complex", "fixed_array", "matrix", ] dir_name = tempfile.mkdtemp() pixel_type_error = [] image_error = [] other_error = [] writer_error = [] reader_error = [] pixel_fill_error = [] for dim in dimensions: for p in pixel_types: for c, cv in component_type_dic.items(): try: PixelType = pixel_type_from_IO(p, cv, dim) except Exception as ex: pixel_type_error.append(ex) continue try: ImageType = itk.Image[PixelType, dim] im = ImageType.New() except Exception as ex: image_error.append(ex) continue try: zero_value = itk.NumericTraits[PixelType].ZeroValue() except: try: zero_value = PixelType() zero_value.Fill(0) except: try: zero_value = PixelType(0) except Exception as ex: pixel_fill_error.append(ex) try: im.SetRegions(5) im.Allocate() im.FillBuffer(zero_value) filename = os.path.join(dir_name, "_".join([p, c, str(dim)]) + ".nrrd") except Exception as ex: other_error.append(ex) continue try: writer = itk.ImageFileWriter.New(Input=im, FileName=filename) writer.Update() except Exception as ex: writer_error.append(str(ex) + " - " + str([p, c, dim])) continue try: reader = itk.ImageFileReader.New(FileName=filename) reader.Update() print( "Dimension: %i ; Pixel Type: %s ; Component Type: %s - OK" % (dim, p, c) ) except Exception as ex: reader_error.append(ex) continue if reader_error or other_error: print(f"PixelType error: {pixel_type_error}") print(f"Image error: {image_error}") print(f"Other error: {other_error}") print(f"Writer error: {writer_error}") print(f"Pixel Fill error: {pixel_fill_error}") print(f"Reader error: {reader_error}") raise AssertionError() # Try to instantiate a template type that does not exist that is # not an `itk.ImageFileReader` (tested above) since that object # is handled slightly differently. try: itk.Image["unknown parameter"].New() # We should never arrive to this point, so raise an exception if # we do. raise Exception("no exception sent for unknown parameter") except TypeError as e: print("Exception caught!") print(e) pass # Test that ImageFileWriter can be called with filter given as input # with 'Input' keyword. reader = itk.ImageFileReader[itk.Image[itk.F, 3]].New() try: writer = itk.ImageFileWriter.New(Input=reader, FileName=filename) except TypeError: raise Exception("Writer doesn't accept filter with 'Input' keyword") # Test 'ttype' keyword InputImageType = itk.Image[itk.UC, 2] # Check that it works with `ttype` being given a list. cast_filter = itk.CastImageFilter.New(ttype=[InputImageType, InputImageType]) # Check that if the wrong number of template parameters are passed, a `RuntimeError` # is raised. try: itk.CastImageFilter.New(ttype=[InputImageType]) raise Exception("Template CastImageFilter should require 2 template parameters") except RuntimeError: pass # Check that if a tuple is given, it still works. This is especially useful since # the function `itk.template()` which returns the template arguments of an object # returns tuples and its returned value should be usable in this context. template_tuple = itk.template(cast_filter)[ 1 ] # [0] is `` cast_filter = itk.CastImageFilter.New(ttype=template_tuple) # TODO: test auto_progress # but how ? # something else ?