Slicer3:Python:pitky

From Slicer Wiki
Revision as of 18:44, 8 November 2010 by Pieper (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Home < Slicer3:Python:pitky

This is part of a NA-MIC Summer Project Week 2009 Project.

Example of an Image Writer

""" A simple example to show how to use weave with ITK.  This lets one
pass numpy arrays to ITK for processing.

based on vtk_example.py from weave distribution.

Author: Steve Pieper
Copyright (c) 2009, Steve Pieper
License: BSD Style.
"""

d = '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/'
packages = ['matplotlib', 'neuroimaging', 'numpy', '', 'scipy']
for p in packages:
  sys.path.append(d+p)

import scipy.weave as weave
import numpy

import sys
import time
import os

# from ITKConfig.cmake - TODO: extract automatically, along with build flags etc (or invoke cmake via distutils?!)
inc_dirs = ['/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/Algorithms', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/BasicFilters', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/Common', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/Numerics', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/IO', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/Numerics/FEM', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/Numerics/Statistics', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/Numerics/NeuralNetworks', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/SpatialObject', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/MetaIO', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/NrrdIO', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/Utilities/NrrdIO', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/DICOMParser', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/Utilities/DICOMParser', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/Utilities/expat', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/expat', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/nifti/niftilib', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/nifti/znzlib', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/itkExtHdrs', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/Utilities', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/vxl/v3p/netlib', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/vxl/vcl', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/vxl/core', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/Utilities/vxl/v3p/netlib', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/Utilities/vxl/vcl', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/Utilities/vxl/core', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/Utilities/gdcm', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Utilities/gdcm/src', '/Users/pieper/slicer3/latest/Slicer3-lib/Insight/Code/Review']

# The ITK library directories.
lib_dirs = ['/Users/pieper/slicer3/latest/Slicer3-lib/Insight-build/bin']


def writer_test():
    """A simple example of how you can use ITK code in weave
       to write a volume to a file.
    """

    fileName = '/tmp/rand.nrrd'
    array = numpy.arange(0,24,dtype='float64').reshape(2,3,4)

    code=r"""
    typedef itk::Image<double,3> ImageType; // TODO: construct from dtype and shape
    ImageType::Pointer image = ImageType::New();
    image->GetPixelContainer()->SetImportPointer( array, Narray[0]*Narray[1]*Narray[2], false );

    ImageType::RegionType region;
    ImageType::IndexType index;
    ImageType::SizeType size;
    index[0] = index[1] = index[2] = 0;
    size[0] = Narray[0]; size[1] = Narray[1]; size[2] = Narray[2];
    region.SetIndex(index);
    region.SetSize(size);
    image->SetLargestPossibleRegion(region);
    image->SetBufferedRegion(region);


    itk::ImageFileWriter< ImageType >::Pointer writer = WriterType::New();
    writer->SetFileName( fileName );
    writer->SetInput( image );
    writer->Update();
    """

    weave.inline(code, ['fileName', 'array'],
                  include_dirs = inc_dirs,
                  library_dirs = lib_dirs,
                  headers=['"itkImage.h"', '"itkImageFileWriter.h"'],
                  libraries=['itkCommon', 'itkIO'])


TODO = """
- apply a filter (volume in and out, where output size may be different from input)
- compile on windows
- interface with cmake?
- how to deploy built libs in cpacked binary
-- how to trigger weave compilation during build process for packaging
"""


if __name__ == "__main__":
    writer_test()

Example of Nonlinear Registration


""" A simple example to show how to use weave with ITK.  This lets one
pass numpy arrays to ITK for processing.

based on pitky.py from steve Pieper

Author: Demian Wassermann
Copyright (c) 2010, Demian Wassermann
License: BSD Style.
"""

import scipy.weave as weave
import numpy as np

# from ITKConfig.cmake - TODO: extract automatically, along with build flags etc (or invoke cmake via distutils?!)
inc_dirs = ['/Users/demian/software/Slicer3-lib/Insight-build', '/Users/demian/software/Slicer3-lib/Insight/Code/Algorithms', '/Users/demian/software/Slicer3-lib/Insight/Code/BasicFilters', '/Users/demian/software/Slicer3-lib/Insight/Code/Common', '/Users/demian/software/Slicer3-lib/Insight/Code/Numerics', '/Users/demian/software/Slicer3-lib/Insight/Code/IO', '/Users/demian/software/Slicer3-lib/Insight/Code/Numerics/FEM', '/Users/demian/software/Slicer3-lib/Insight/Code/Numerics/Statistics', '/Users/demian/software/Slicer3-lib/Insight/Code/Numerics/NeuralNetworks', '/Users/demian/software/Slicer3-lib/Insight/Code/SpatialObject', '/Users/demian/software/Slicer3-lib/Insight/Utilities/MetaIO', '/Users/demian/software/Slicer3-lib/Insight/Utilities/NrrdIO', '/Users/demian/software/Slicer3-lib/Insight-build/Utilities/NrrdIO', '/Users/demian/software/Slicer3-lib/Insight/Utilities/DICOMParser', '/Users/demian/software/Slicer3-lib/Insight-build/Utilities/DICOMParser', '/Users/demian/software/Slicer3-lib/Insight-build/Utilities/expat', '/Users/demian/software/Slicer3-lib/Insight/Utilities/expat', '/Users/demian/software/Slicer3-lib/Insight/Utilities/nifti/niftilib', '/Users/demian/software/Slicer3-lib/Insight/Utilities/nifti/znzlib', '/Users/demian/software/Slicer3-lib/Insight/Utilities/itkExtHdrs', '/Users/demian/software/Slicer3-lib/Insight-build/Utilities', '/Users/demian/software/Slicer3-lib/Insight/Utilities', '/Users/demian/software/Slicer3-lib/Insight/Utilities/vxl/v3p/netlib', '/Users/demian/software/Slicer3-lib/Insight/Utilities/vxl/vcl', '/Users/demian/software/Slicer3-lib/Insight/Utilities/vxl/core', '/Users/demian/software/Slicer3-lib/Insight-build/Utilities/vxl/v3p/netlib', '/Users/demian/software/Slicer3-lib/Insight-build/Utilities/vxl/vcl', '/Users/demian/software/Slicer3-lib/Insight-build/Utilities/vxl/core', '/Users/demian/software/Slicer3-lib/Insight-build/Utilities/gdcm', '/Users/demian/software/Slicer3-lib/Insight/Utilities/gdcm/src', '/Users/demian/software/Slicer3-lib/Insight/Code/Review']

# The ITK library directories.
lib_dirs = ['/Users/demian/software/Slicer3-lib/Insight-build/bin']


def demons_registration( fixed, moving, output, deformation_field, sigmaDef = 1.5, sigmaUp = 0.0, numIterations = 10, maxStepLength = 2.):

    if any( im.dtype != np.dtype('float64') for im in (fixed,moving,output,deformation_field) ):
        raise ValueError('Images must be of dtype float64')

    if any( len(im.shape) != 3 for im in (fixed,moving,output,deformation_field[...,0])): 
        raise ValueError('Images must be 3-dimensional')

    if any( im.shape != fixed.shape for im in (fixed,moving,output,deformation_field[...,0])): 
        raise ValueError('Images must be all of the same size')

    if deformation_field.shape[-1] != 3:
        raise ValueError('deformation field must be a 3-component image')

    sigmaDef = float( sigmaDef)
    sigmaUp = float( sigmaUp )
    numIterations = int( numIterations )
    maxStepLength = float( maxStepLength )

    """A simple example of how you can use ITK code in weave
       to write a volume to a file.
    """

    code=r"""
    #line 45 "demons.py"

    #define Dimension                              (3)
    typedef double                                 PixelType;
    typedef itk::Image< PixelType, Dimension >     ImageType;

    typedef itk::Vector< PixelType, Dimension >    VectorPixelType;
    typedef itk::Image
     < VectorPixelType, Dimension >                DeformationFieldType;

    typedef itk::DiffeomorphicDemonsRegistrationFilter
       < ImageType, ImageType, DeformationFieldType >
                                                   ActualRegistrationFilterType;

    typedef ActualRegistrationFilterType::GradientType GradientType;


    ImageType::Pointer fixedImage = ImageType::New();
    fixedImage->GetPixelContainer()->SetImportPointer( fixed, Nfixed[0]*Nfixed[1]*Nfixed[2], false );


    ImageType::RegionType regionFixed;
    ImageType::IndexType indexFixed;
    ImageType::SizeType sizeFixed;
    indexFixed[0] = indexFixed[1] = indexFixed[2] = 0;

    sizeFixed[0] = Nfixed[0]; sizeFixed[1] = Nfixed[1]; sizeFixed[2] = Nfixed[2];
    regionFixed.SetIndex(indexFixed);
    regionFixed.SetSize(sizeFixed);
    fixedImage->SetLargestPossibleRegion(regionFixed);
    fixedImage->SetBufferedRegion(regionFixed);

    ImageType::Pointer movingImage = ImageType::New();
    movingImage->GetPixelContainer()->SetImportPointer( moving, Nmoving[0]*Nmoving[1]*Nmoving[2], false );

    ImageType::RegionType regionMoving;
    ImageType::IndexType indexMoving;
    ImageType::SizeType sizeMoving;
    indexMoving[0] = indexMoving[1] = indexMoving[2] = 0;

    sizeMoving[0] = Nmoving[0]; sizeMoving[1] = Nmoving[1]; sizeMoving[2] = Nmoving[2];
    regionMoving.SetIndex(indexMoving);
    regionMoving.SetSize(sizeMoving);
    movingImage->SetLargestPossibleRegion(regionMoving);
    movingImage->SetBufferedRegion(regionMoving);


    ImageType::Pointer outputImage = ImageType::New();
    outputImage->GetPixelContainer()->SetImportPointer( output, Noutput[0]*Noutput[1]*Noutput[2], false );

    ImageType::RegionType regionOutput;
    ImageType::IndexType indexOutput;
    ImageType::SizeType sizeOutput;
    indexOutput[0] = indexOutput[1] = indexOutput[2] = 0;

    sizeOutput[0] = Noutput[0]; sizeOutput[1] = Noutput[1]; sizeOutput[2] = Noutput[2];
    regionOutput.SetIndex(indexOutput);
    regionOutput.SetSize(sizeOutput);
    outputImage->SetLargestPossibleRegion(regionOutput);
    outputImage->SetBufferedRegion(regionOutput);

    
// As the GraftOutput didn't work for the deformation field, this paragraph can be ignored.
    DeformationFieldType::Pointer outputDeformationFieldImage = DeformationFieldType::New();
    outputDeformationFieldImage->GetPixelContainer()->SetImportPointer( 
        reinterpret_cast<VectorPixelType*>(deformation_field), 
        Ndeformation_field[0]*Ndeformation_field[1]*Ndeformation_field[2], 
    false );

    ImageType::RegionType regionOutputDeformation;
    ImageType::IndexType indexOutputDeformation;
    ImageType::SizeType sizeOutputDeformation;
    indexOutputDeformation[0] = indexOutputDeformation[1] = indexOutputDeformation[2] = 0;

    sizeOutputDeformation[0] = Ndeformation_field[0]; sizeOutputDeformation[1] = Ndeformation_field[1]; sizeOutputDeformation[2] = Ndeformation_field[2];
    regionOutputDeformation.SetIndex(indexOutputDeformation);
    regionOutputDeformation.SetSize(sizeOutputDeformation);
    outputDeformationFieldImage->SetLargestPossibleRegion(regionOutputDeformation);
    outputDeformationFieldImage->SetBufferedRegion(regionOutputDeformation);

    ActualRegistrationFilterType::Pointer filter
       = ActualRegistrationFilterType::New();

    filter->SetMaximumUpdateStepLength( maxStepLength );
    filter->SetUseGradientType( 
       static_cast<GradientType>(0) );

    filter->GraftOutput( outputDeformationFieldImage );
    filter->UseFirstOrderExpOn();

    if ( sigmaDef > 0.1 )
    {
        filter->SmoothDeformationFieldOn();
        filter->SetStandardDeviations( sigmaDef );
    }
    else
    {
        filter->SmoothDeformationFieldOff();
    }

    if ( sigmaUp > 0.1 )
    {
        filter->SmoothUpdateFieldOn();
        filter->SetUpdateFieldStandardDeviations( sigmaUp );
    }
    else
    {
        filter->SmoothUpdateFieldOff();
    }


    filter->SetFixedImage( fixedImage );
    filter->SetMovingImage( movingImage );
    filter->SetNumberOfIterations( numIterations );

    //This is made for memory efficiency and doesn't work :( 
    filter->GraftOutput( outputDeformationFieldImage );

    filter->UpdateLargestPossibleRegion();

    // warp the result
    typedef itk::WarpImageFilter
     < ImageType, ImageType, DeformationFieldType >  WarperType;
    WarperType::Pointer warper = WarperType::New();
    warper->SetInput( movingImage );
    warper->SetOutputSpacing( fixedImage->GetSpacing() );
    warper->SetOutputOrigin( fixedImage->GetOrigin() );
    warper->SetOutputDirection( fixedImage->GetDirection() );
    warper->SetDeformationField( filter->GetOutput() );
    warper->GraftOutput( outputImage );
    warper->UpdateLargestPossibleRegion();

   // copy resulting deformation field to output

   const size_t numPix = Ndeformation_field[0]*Ndeformation_field[1]*Ndeformation_field[2];
   const size_t bufferSize = sizeof( PixelType )  * 3 * numPix;

   memcpy( reinterpret_cast<void*>(deformation_field), reinterpret_cast<void*>(filter->GetOutput()->GetBufferPointer()), bufferSize);

    """

    weave.inline(code, ['fixed', 'moving','sigmaDef','sigmaUp','numIterations', 'maxStepLength', 'output', 'deformation_field' ],
                  include_dirs = inc_dirs,
                  library_dirs = lib_dirs,
                  headers=['"itkImage.h"', '"itkImageFileWriter.h"','"itkDiffeomorphicDemonsRegistrationFilter.h"'],
                  libraries=['itkCommon', 'itkIO'])



if __name__ == '__main__':
    import nifti

    dtype_ = np.dtype('float64') # 64-bit float or C++ double

    fixed = nifti.NiftiImage('fixed.nii.gz').getDataArray().astype(dtype_)
    moving = nifti.NiftiImage('moving.nii.gz').getDataArray().astype(dtype_)

    output = np.empty( fixed.shape, dtype = dtype_ )
    deformation_field = np.empty( fixed.shape + (3,), dtype = dtype_ )

    demons_registration( fixed, moving, output, deformation_field )