Пример #1
0
def handle_filetype_writing_special_cases(writer, **kwargs):
    '''Handle intermediate steps for writing filetype

    Calls the associated function for each writer type to try
    and handle the output. These may add filters before the
    writer such as casting. It is recommended to set the writer
    input data or input connection before calling this function.

    If no special cases are known for a writer type, nothing
    is done.

    In general, it is recommended to call this on your vtkImageWriter
    class just before calling update to avoid common data typing errors.
    
    Note that this function may insert new filters between the filter connected
    to writer and the writer itself.

    Args:
        writer (vtk.vtkImageWriter):    The file writer
        kwargs (dict):                  Dictionary of args passed to subsequent functions

    Returns:
        None
    '''
    step_map = {
        type(vtkbone.vtkboneAIMWriter()): handle_aim_writing_special_cases,
        type(vtk.vtkTIFFWriter()): handle_tiff_writing_special_cases,
        type(vtk.vtkPNGWriter()): handle_png_writing_special_cases,
        type(vtk.vtkBMPWriter()): handle_bmp_writing_special_cases,
        type(vtk.vtkJPEGWriter()): handle_jpeg_writing_special_cases
    }

    if type(writer) in step_map:
        return step_map[type(writer)](writer, **kwargs)
    return None
Пример #2
0
    def test_write_aim_set_log(self):
        '''Can write aim file with processing log'''
        extension = '.aim'
        filename = os.path.join(self.test_dir, 'file' + extension)
        scalar_type = vtk.VTK_SHORT
        processing_log = 'This is a fake processing log'

        source = self.generate_image(scalar_type)
        writer = vtkbone.vtkboneAIMWriter()
        writer.SetInputConnection(source.GetOutputPort())
        writer.SetFileName(filename)

        handle_filetype_writing_special_cases(writer,
                                              processing_log=processing_log)

        writer.Update()
        self.assertTrue(os.path.isfile(filename))

        reader = vtkbone.vtkboneAIMReader()
        reader.DataOnCellsOff()
        reader.SetFileName(filename)
        reader.Update()

        self.assertEqual(reader.GetOutput().GetScalarType(), vtk.VTK_SHORT)

        # A dummy log is created in this instance. Only check that our log was appended
        self.assertEqual(reader.GetProcessingLog().split(os.linesep)[-1],
                         processing_log)
Пример #3
0
    def test_get_aim(self):
        '''AIM file returns correct reader'''
        extension='.aim'
        expected = type(vtkbone.vtkboneAIMReader())
        writer = vtkbone.vtkboneAIMWriter()

        filename = os.path.join(self.test_dir, 'file'+extension)
        self.generate_image(filename, writer)
        self.assertEqual(type(get_vtk_reader(filename)), expected)
Пример #4
0
    def test_write_aim_unsigned_long(self):
        '''Can write aim file with type unsigned long'''
        extension = '.aim'
        filename = os.path.join(self.test_dir, 'file' + extension)
        scalar_type = vtk.VTK_UNSIGNED_LONG

        source = self.generate_image(scalar_type)
        writer = vtkbone.vtkboneAIMWriter()
        writer.SetInputConnection(source.GetOutputPort())
        writer.SetFileName(filename)

        handle_filetype_writing_special_cases(writer)

        writer.Update()
        self.assertTrue(os.path.isfile(filename))

        reader = vtkbone.vtkboneAIMReader()
        reader.DataOnCellsOff()
        reader.SetFileName(filename)
        reader.Update()

        self.assertEqual(reader.GetOutput().GetScalarType(), vtk.VTK_FLOAT)
Пример #5
0
def aimod(input_aim, output_aim):
    # Python 2/3 compatible input
    from six.moves import input

    # Read file
    print('Reading file: {}.....'.format(input_aim))
    reader = vtkbone.vtkboneAIMReader()
    reader.DataOnCellsOff()
    reader.SetFileName(input_aim)
    reader.Update()
    image = reader.GetOutput()

    spacing = np.array(image.GetSpacing())
    origin = np.array(image.GetOrigin())
    dim = np.array(image.GetDimensions())

    def set(x, index, value):
        x[index] = value

    mapping = [[
        'el_size_mm.x', lambda: spacing[0], lambda x: set(spacing, 0, x), float
    ], [
        'el_size_mm.y', lambda: spacing[1], lambda x: set(spacing, 1, x), float
    ], [
        'el_size_mm.z', lambda: spacing[2], lambda x: set(spacing, 2, x), float
    ], ['pos.x', lambda: origin[0], lambda x: set(origin, 0, x),
        float], [
            'pos.y', lambda: origin[1], lambda x: set(origin, 1, x), float
        ], ['pos.z', lambda: origin[2], lambda x: set(origin, 2, x), float],
               ['dim.x', lambda: dim[0], lambda x: set(dim, 0, x), int],
               ['dim.y', lambda: dim[1], lambda x: set(dim, 1, x), int],
               ['dim.z', lambda: dim[2], lambda x: set(dim, 2, x), int]]

    max_length = 0
    for line in mapping:
        max_length = max(max_length, len(line[0]))
    formatter_float = '{{: <{}}} [{{:0.3f}}] ? '.format(max_length)
    formatter_int = '{{: <{}}} [{{}}] ? '.format(max_length)
    formatter_switch = lambda x: formatter_int if x == int else formatter_float

    for i in range(len(mapping)):
        # Grab this input
        line = mapping[i]
        formatter = formatter_switch(line[3])

        # Prompt user
        result = input(formatter.format(line[0], line[1]()))

        # Enter == continue
        if result == '':
            continue

        # q, quit, no save
        # e, exit, save
        if len(result) > 0:
            if result[0] == 'q':
                print('Quit: not saved.')
                os.sys.exit()
            if result[0] == 'e':
                print('Exit.')
                break

        # Otherwise, set value
        line[2](line[3](result))

    # Set results
    image.SetSpacing(spacing)
    image.SetOrigin(origin)
    image.SetDimensions(dim)

    # Write
    writer = vtkbone.vtkboneAIMWriter()
    writer.SetInputData(image)
    writer.SetFileName(output_aim)
    writer.SetProcessingLog(reader.GetProcessingLog())
    writer.Update()
Пример #6
0
def fileConverter(inputImage, outputImage, AIMProcessingLog):
    print('******************************************************')
    print(f'CONVERTING: {inputImage} to {outputImage}')

    # Extract directory, filename, basename, and extensions from the output image
    outDirectory, outFilename = os.path.split(outputImage)
    outBasename, outExtension = os.path.splitext(outFilename)

    # Check the output file format
    if outExtension.lower() == '.mha':
        outputImageFileName = os.path.join(outDirectory, outBasename + '.mha')
    elif outExtension.lower() == '.aim':
        if not AIMProcessingLog or ('.txt' not in AIMProcessingLog.lower()):
            print()
            print(
                'Error: A valid processing log (header) is needed to write out an AIM file.'
            )
            sys.exit(1)
        outputImageFileName = os.path.join(outDirectory, outBasename + '.aim')
    else:
        print()
        print('Error: output file extension must be MHA or AIM')
        sys.exit(1)

    # Check if the input is a file or directory
    if os.path.isfile(inputImage):
        # NOT DIRECTORY:
        # Extract directory, filename, basename, and extensions from the input image
        inDirectory, inFilename = os.path.split(inputImage)
        inBasename, inExtension = os.path.splitext(inFilename)

        # Setup the correct reader based on the input image extension
        if '.aim' in inExtension.lower():

            # If the input AIM contains a version number, remove it and rename the file
            if ';' in inExtension.lower():
                inputImageNew = inputImage.rsplit(';', 1)[0]
                os.rename(inputImage, inputImageNew)
                inputImage = inputImageNew

            # Get the processing log file extension
            procLogDir, procLogFilename = os.path.split(
                AIMProcessingLog.lower())
            procLogBasename, procLogExtension = os.path.splitext(
                procLogFilename)

            # Check to make sure the processing log file extension is valid
            # If the provided file name is not valid, create a new file based on the requested output file name
            if not AIMProcessingLog or (procLogExtension != '.txt'):
                AIMProcessingLog = os.path.join(outDirectory,
                                                outBasename + '.txt')
                print(
                    'Warning: No AIM processing log file name provided or invalid file extension provided. Using default file name: '
                    + AIMProcessingLog)
            else:
                print('WRITING PROCESSING LOG: ' + AIMProcessingLog)

            # Read in the AIM
            imageReader = vtkbone.vtkboneAIMReader()
            imageReader.SetFileName(inputImage)
            imageReader.DataOnCellsOff()
            imageReader.Update()
            inputHeader = imageReader.GetProcessingLog()

            # Write out the processing log as a txt file
            f = open(AIMProcessingLog, 'w')
            f.write(inputHeader)

            # Determine scalar type to use
            #   VTK_CHAR <-> D1char
            #   VTK_SHORT <-> D1short
            #   If it is of type BIT, CHAR, SIGNED CHAR, or UNSIGNED CHAR it is possible
            #   to store in a CHAR.
            inputScalarType = imageReader.GetOutput().GetScalarType()

            if (inputScalarType == vtk.VTK_BIT
                    or inputScalarType == vtk.VTK_CHAR
                    or inputScalarType == vtk.VTK_SIGNED_CHAR
                    or inputScalarType == vtk.VTK_UNSIGNED_CHAR):

                # Make sure the image will fit in the range
                #   It is possible that the chars are defined in such a way that either
                #   signed or unsigned chars don't fit inside the char. We can be safe
                #   buy checking if the image range will fit inside the VTK_CHAR
                scalarRange = imageReader.GetOutput().GetScalarRange()
                if scalarRange[0] >= vtk.VTK_SHORT_MIN and scalarRange[
                        1] <= vtk.VTK_SHORT_MAX:
                    outputScalarType = vtk.VTK_CHAR
                else:
                    outputScalarType = vtk.VTK_SHORT
            else:
                outputScalarType = vtk.VTK_SHORT

            # Cast
            caster = vtk.vtkImageCast()
            caster.SetOutputScalarType(outputScalarType)
            caster.SetInputConnection(imageReader.GetOutputPort())
            caster.ReleaseDataFlagOff()
            caster.Update()

            # Get VTK and SITK images
            vtk_image = caster.GetOutput()
            sitk_image = vtk2sitk(vtk_image)

        else:
            sitk_image = sitk.ReadImage(inputImage)

    # Check if the input is a directory
    elif os.path.isdir(inputImage):
        # DIRECTORY:
        print()
        print('Error: Please provide a valid file, not a directory!')
        sys.exit(1)

    # Setup the correct writer based on the output image extension
    if outExtension.lower() == '.mha':
        print('WRITING IMAGE: ' + str(outputImage))
        sitk.WriteImage(sitk_image, str(outputImageFileName))

    elif outExtension.lower() == '.aim':
        print('WRITING IMAGE: ' + str(outputImage))

        # Handle the special case of MHA to AIM to avoid crashing due to SITK to VTK conversion
        # Need to cast grayscale images to VTK_SHORT type and binary images to VTK_CHAR type to display properly on the OpenVMS system
        # Scan the AIM log file to determine if the image is segmented or grayscale
        segFile = searchAIMLog(AIMProcessingLog)

        if segFile and inExtension.lower() == '.mha':
            img = vtk.vtkMetaImageReader()
            img.SetFileName(inputImage)
            img.Update()

            caster = vtk.vtkImageCast()
            caster.SetInputData(img.GetOutput())
            caster.SetOutputScalarType(vtk.VTK_CHAR)
            caster.ReleaseDataFlagOff()
            caster.Update()

            vtk_image = caster.GetOutput()

        elif not segFile and inExtension.lower() == '.mha':
            img = vtk.vtkMetaImageReader()
            img.SetFileName(inputImage)
            img.Update()

            caster = vtk.vtkImageCast()
            caster.SetInputData(img.GetOutput())
            caster.SetOutputScalarType(vtk.VTK_SHORT)
            caster.ReleaseDataFlagOff()
            caster.Update()

            vtk_image = caster.GetOutput()

        # Open the processing log for reading
        f = open(AIMProcessingLog, 'r')
        header = f.read()

        writer = vtkbone.vtkboneAIMWriter()
        writer.SetInputData(vtk_image)
        writer.SetFileName(str(outputImageFileName))

        # Do not create a new processing log as this will add extra values that
        # will cause problems when processing the new AIM in IPL
        writer.NewProcessingLogOff()
        writer.SetProcessingLog(header)

        writer.Update()

    print('DONE')
    print('******************************************************')
    print()
Пример #7
0
    def extrudeFromPoints(self):

        pts = self.pickerstyle.getPoints("in1_pipeline")

        if (pts.GetNumberOfPoints() < 3):
            qtw.QMessageBox.warning(
                self, "Warning",
                "At least 3 points must be defined on image 1 to create extrusion."
            )
            return

        if (not self.in1_pipe.getIsValidForExtrusion()):
            qtw.QMessageBox.warning(
                self, "Warning",
                "Extrusion may not work properly when input file is not of type AIM."
            )

        # Spline
        spline = vtk.vtkParametricSpline()
        spline.SetPoints(pts)
        spline.ClosedOn()

        parametricFunction = vtk.vtkParametricFunctionSource()
        parametricFunction.SetParametricFunction(spline)
        parametricFunction.Update()

        # Extrude
        extrusionFactor = 100.0  # mm above and below surface
        # A large number will cause the extrusion to fill the extent of the input image

        positiveExtruder = vtk.vtkLinearExtrusionFilter()
        positiveExtruder.SetInputConnection(parametricFunction.GetOutputPort())
        positiveExtruder.SetExtrusionTypeToNormalExtrusion()
        positiveExtruder.SetVector(0, 0, 1)
        positiveExtruder.CappingOn()
        positiveExtruder.SetScaleFactor(extrusionFactor)

        posTriFilter = vtk.vtkTriangleFilter()
        posTriFilter.SetInputConnection(positiveExtruder.GetOutputPort())

        negativeExtruder = vtk.vtkLinearExtrusionFilter()
        negativeExtruder.SetInputConnection(parametricFunction.GetOutputPort())
        negativeExtruder.SetExtrusionTypeToNormalExtrusion()
        negativeExtruder.SetVector(0, 0, -1)
        negativeExtruder.CappingOn()
        negativeExtruder.SetScaleFactor(extrusionFactor)

        negTriFilter = vtk.vtkTriangleFilter()
        negTriFilter.SetInputConnection(negativeExtruder.GetOutputPort())

        # Combine data
        combiner = vtk.vtkAppendPolyData()
        combiner.AddInputConnection(posTriFilter.GetOutputPort())
        combiner.AddInputConnection(negTriFilter.GetOutputPort())

        cleaner = vtk.vtkCleanPolyData()
        cleaner.SetInputConnection(combiner.GetOutputPort())
        cleaner.Update()

        el_size_mm = self.in1_pipe.getElementSize()
        dim = self.in1_pipe.getDimensions()
        extent = self.in1_pipe.getExtent()
        origin = self.in1_pipe.getOrigin()
        foregroundValue = 127
        backgroundValue = 0

        # Stencil
        whiteImage = vtk.vtkImageData()
        whiteImage.SetSpacing(el_size_mm)
        whiteImage.SetDimensions(dim)
        whiteImage.SetExtent(extent)
        whiteImage.SetOrigin(origin)
        whiteImage.AllocateScalars(vtk.VTK_CHAR, 1)
        whiteImage.GetPointData().GetScalars().Fill(foregroundValue)

        # Use our extruded polydata to stencil the solid image
        poly2sten = vtk.vtkPolyDataToImageStencil()
        poly2sten.SetTolerance(0)
        #poly2sten.SetInputConnection(clipper.GetOutputPort())
        poly2sten.SetInputConnection(cleaner.GetOutputPort())
        poly2sten.SetOutputOrigin(origin)
        poly2sten.SetOutputSpacing(el_size_mm)
        poly2sten.SetOutputWholeExtent(whiteImage.GetExtent())

        stencil = vtk.vtkImageStencil()
        stencil.SetInputData(whiteImage)
        stencil.SetStencilConnection(poly2sten.GetOutputPort())
        #stencil.ReverseStencilOff()
        stencil.SetBackgroundValue(backgroundValue)
        stencil.Update()

        # Write image
        filename, _ = qtw.QFileDialog.getSaveFileName(
            self, "Select the file to save to…", qtc.QDir.homePath(),
            "AIM File (*.aim)")

        if (filename):
            writer = vtkbone.vtkboneAIMWriter()
            writer.SetInputConnection(stencil.GetOutputPort())
            writer.SetFileName(filename)
            writer.SetProcessingLog(
                '!-------------------------------------------------------------------------------\n'
                + 'Written by blQtViewer.')
            writer.Update()
            self.statusBar().showMessage("File " + filename + " written.",
                                         4000)
Пример #8
0
def stl2aim(input_file, output_file, transform_file, el_size_mm, visualize, overwrite, func):

  if os.path.isfile(output_file) and not overwrite:
    result = input('File \"{}\" already exists. Overwrite? [y/n]: '.format(output_file))
    if result.lower() not in ['y', 'yes']:
      print('Not overwriting. Exiting...')
      os.sys.exit()

  model = vtk.vtkSTLReader()
  model.SetFileName(input_file)
  model.Update()
  
  model = applyTransform(transform_file, model)
  
  if (visualize):
    mat4x4 = visualize_actors( model.GetOutputPort(), None )
  else:
    mat4x4 = vtk.vtkMatrix4x4()
  
  transform = vtk.vtkTransform()
  transform.SetMatrix(mat4x4)

  transformFilter = vtk.vtkTransformFilter()
  transformFilter.SetInputConnection( model.GetOutputPort() )
  transformFilter.SetTransform( transform )
  transformFilter.Update()
  
  bounds = transformFilter.GetOutput().GetBounds()
  dim = [1,1,1]
  for i in range(3):
    dim[i] = (math.ceil((bounds[i*2+1]-bounds[i*2]) / el_size_mm[i]))
  origin = [1,1,1]
  origin[0] = bounds[0] + el_size_mm[0] / 2
  origin[1] = bounds[2] + el_size_mm[1] / 2
  origin[2] = bounds[4] + el_size_mm[2] / 2
  
  whiteImage = vtk.vtkImageData()
  whiteImage.SetSpacing(el_size_mm)
  whiteImage.SetDimensions(dim)
  whiteImage.SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1)
  whiteImage.SetOrigin(origin)
  whiteImage.AllocateScalars(vtk.VTK_CHAR,1)
  for i in range(whiteImage.GetNumberOfPoints()):
    whiteImage.GetPointData().GetScalars().SetTuple1(i, 127)

  pol2stenc = vtk.vtkPolyDataToImageStencil()
  pol2stenc.SetInputData( transformFilter.GetOutput() )
  pol2stenc.SetOutputOrigin( origin )
  pol2stenc.SetOutputSpacing( el_size_mm )
  pol2stenc.SetOutputWholeExtent( whiteImage.GetExtent() )
  pol2stenc.Update()
  
  imgstenc = vtk.vtkImageStencil()
  imgstenc.SetInputData(whiteImage)
  imgstenc.SetStencilConnection( pol2stenc.GetOutputPort() )
  imgstenc.ReverseStencilOff()
  imgstenc.SetBackgroundValue(0)
  imgstenc.Update()
  
  writer = vtkbone.vtkboneAIMWriter()
  writer.SetInputData( imgstenc.GetOutput() )
  writer.SetFileName(output_file)
  writer.SetProcessingLog('!-------------------------------------------------------------------------------\n'+'Written by blRapidPrototype.')
  writer.Update()

  message("Writing file " + output_file)
Пример #9
0
 def test_get_aim(self):
     '''AIM filetype returns None'''
     expected = type(vtkbone.vtkboneAIMWriter())
     self.assertEqual(type(get_vtk_writer('test25a.AiM')), expected)