[Insight-developers] new shrink filter with average value

Carsten Kendziorra carsten.kendziorra at charite.de
Thu Jun 20 04:23:05 EDT 2013


Sorry, forgot the files.

Here they are!

On 06/20/2013 09:20 AM, Carsten Kendziorra wrote:
> Hello,
>
> we've produced a shrink filter, that calculates the output pixel value
> as the average of all corresponding input pixels.
>
> This is basically a copy of the itkShrinkImageFilter (ITK 4.2.0), with
> modifications in the ThreadedGenerateData() method, where the output
> pixel values are calculated.
>
> Author: Carsten Kendziorra, Henning Meyer, Marc Dewey. Charite Berlin,
> Germany.
>
> Maybe you want to include it in ITK.
>
> Cheers,
> Carsten
> _______________________________________________
> Powered by www.kitware.com
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Kitware offers ITK Training Courses, for more information visit:
> http://kitware.com/products/protraining.php
>
> Please keep messages on-topic and check the ITK FAQ at:
> http://www.itk.org/Wiki/ITK_FAQ
>
> Follow this link to subscribe/unsubscribe:
> http://www.itk.org/mailman/listinfo/insight-developers

-------------- next part --------------
A non-text attachment was scrubbed...
Name: itkShrinkAverageFilter.h
Type: text/x-chdr
Size: 5427 bytes
Desc: not available
URL: <http://www.itk.org/pipermail/insight-developers/attachments/20130620/eab9b2e0/attachment.h>
-------------- next part --------------
#ifndef __itkShrinkAverageFilter_txx
#define __itkShrinkAverageFilter_txx

#include "itkShrinkAverageFilter.h"
#include <itkImageRegionIterator.h>
#include <itkImageRegionConstIterator.h>
#include <itkContinuousIndex.h>
#include <itkObjectFactory.h>
#include <itkProgressReporter.h>
#include <itkVariableLengthVector.h>
#include <boost/type_traits.hpp>
#include <boost/mpl/if.hpp>

namespace itk
{
	/**
	 * 
	 */
	template< class TInputImage, class TOutputImage >
	ShrinkAverageFilter< TInputImage, TOutputImage >
	::ShrinkAverageFilter()
	{
		for ( unsigned int j = 0; j < ImageDimension; j++ )
		{
			m_ShrinkFactors[j] = 1;
		}
	}
	
	/**
	 * 
	 */
	template< class TInputImage, class TOutputImage >
	void
	ShrinkAverageFilter< TInputImage, TOutputImage >
	::PrintSelf(std::ostream & os, Indent indent) const
	{
		Superclass::PrintSelf(os, indent);
		
		os << indent << "Shrink Factor: ";
		for ( unsigned int j = 0; j < ImageDimension; j++ )
		{
			os << m_ShrinkFactors[j] << " ";
		}
		os << std::endl;
	}
	
	/**
	 * 
	 */
	template< class TInputImage, class TOutputImage >
	void
	ShrinkAverageFilter< TInputImage, TOutputImage >
	::SetShrinkFactors(unsigned int factor)
	{
		unsigned int j;
		
		for ( j = 0; j < ImageDimension; j++ )
		{
			if ( factor != m_ShrinkFactors[j] ) { break; }
		}
		if ( j < ImageDimension )
		{
			this->Modified();
			for ( j = 0; j < ImageDimension; j++ )
			{
				m_ShrinkFactors[j] = factor;
				if ( m_ShrinkFactors[j] < 1 )
				{
					m_ShrinkFactors[j] = 1;
				}
			}
		}
	}
	
	/**
	 * 
	 */
	template< class TInputImage, class TOutputImage >
	void
	ShrinkAverageFilter< TInputImage, TOutputImage >
	::ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread,
						   ThreadIdType threadId)
	{
		// Get the input and output pointers
		InputImageConstPointer inputPtr = this->GetInput();
		OutputImagePointer     outputPtr = this->GetOutput();

		typename OutputImageType::SizeType outputSize = outputRegionForThread.GetSize();
		typename OutputImageType::IndexType outputIndex = outputRegionForThread.GetIndex();
		
		InputImageRegionType inputRegion = inputPtr->GetLargestPossibleRegion();
		typename InputImageType::SizeType inputSize;
		typename InputImageType::IndexType inputIndex;

		for ( unsigned int dim = 0; dim < TInputImage::ImageDimension; dim++ )
		{
			inputSize[dim] = outputSize[dim] * m_ShrinkFactors[dim];
			inputIndex[dim] = outputIndex[dim] * m_ShrinkFactors[dim];
		}
		inputRegion.SetSize(inputSize);
		inputRegion.SetIndex(inputIndex);
		
		// number of all pixel/voxel of the output image
		unsigned int outputPixelNumber = 1;
		for ( unsigned int dim = 0; dim < TInputImage::ImageDimension; dim++ )
		{
			outputPixelNumber *= outputSize[dim];
		}
		
		// set pixel type depending on input image
		typedef typename boost::mpl::if_< boost::is_integral<InputImagePixelType>, long int, double >::type ValType;

		// sum of all pixel values of the corresponding input values for each output pixel
		typedef itk::VariableLengthVector<ValType> VectorValSumType;
		VectorValSumType valSum;
		valSum.SetSize(outputPixelNumber);
		valSum.Fill(0);
		
		// iterator for input image
		typedef ImageRegionConstIterator< TInputImage > InputImageIterator;
		InputImageIterator inIt(inputPtr, inputRegion);
		
		unsigned outIdx = 0;
		typedef itk::VariableLengthVector<unsigned> VectorUnsignedType;
		VectorUnsignedType outIdxA;
		outIdxA.SetSize(OutputImageType::ImageDimension);
		outIdxA.Fill(0);

		InputIndexType indexInsideOutputBlock;

		VectorUnsignedType outBlockSizePerDimension;
		outBlockSizePerDimension.SetSize(OutputImageType::ImageDimension);
		unsigned osize = 1;
		for(unsigned dim = 0; dim < OutputImageType::ImageDimension; dim++) {
			outBlockSizePerDimension[dim] = osize;
			osize *= outputSize[dim];
			indexInsideOutputBlock[dim] = 0;
		}

		// walk the input image and sum all values for each corresponding output pixel
		while ( !inIt.IsAtEnd() )
		{
			valSum[outIdx] += inIt.Get();
			++inIt;
			unsigned dim = 0;
			bool nextdim = false;
			do {
				indexInsideOutputBlock[dim]++;
				nextdim = false;
				if (indexInsideOutputBlock[dim] == m_ShrinkFactors[dim])
				{
					indexInsideOutputBlock[dim] = 0;
					outIdx += outBlockSizePerDimension[dim];
					outIdxA[dim]++;
					if ( outIdxA[dim] == outputSize[dim] )
					{
						outIdxA[dim] = 0;
						outIdx -= outBlockSizePerDimension[dim+1];
						nextdim = true;
					}
				}
				dim++;
			} while (nextdim);
		}
		
		// Define/declare an iterator that will walk the output region for this
		// thread.
		typedef ImageRegionIterator< TOutputImage > OutputIterator;
		OutputIterator outIt(outputPtr, outputRegionForThread);
		
		// Number of input pixel per output pixel
		int VoxelShrinkNumber = 1;
		for ( unsigned int dim = 0; dim < TInputImage::ImageDimension; dim++ )
		{
			VoxelShrinkNumber *= m_ShrinkFactors[dim];
		}
		
		outIdx = 0;
		
		// walk the output pixel and set new value
		while ( !outIt.IsAtEnd() )
		{
			outIt.Set( valSum[outIdx] / VoxelShrinkNumber );
			++outIdx;
			++outIt;
		}

	}
	
	/**
	 * 
	 */
	template< class TInputImage, class TOutputImage >
	void
	ShrinkAverageFilter< TInputImage, TOutputImage >
	::GenerateInputRequestedRegion()
	{
		// Call the superclass' implementation of this method
		Superclass::GenerateInputRequestedRegion();
		
		// Get pointers to the input and output
		InputImagePointer  inputPtr = const_cast< TInputImage * >( this->GetInput() );
		OutputImagePointer outputPtr = this->GetOutput();
		
		if ( !inputPtr || !outputPtr )
		{
			return;
		}
		
		// Compute the input requested region (size and start index)
		// Use the image transformations to insure an input requested region
		// that will provide the proper range
		unsigned int i;
		const typename TOutputImage::SizeType & outputRequestedRegionSize =
		outputPtr->GetRequestedRegion().GetSize();
		const typename TOutputImage::IndexType & outputRequestedRegionStartIndex =
		outputPtr->GetRequestedRegion().GetIndex();
		
		// Convert the factor for convenient multiplication
		typename TOutputImage::SizeType factorSize;
		for ( i = 0; i < TInputImage::ImageDimension; i++ )
		{
			factorSize[i] = m_ShrinkFactors[i];
		}
		
		OutputIndexType  outputIndex;
		InputIndexType   inputIndex, inputRequestedRegionIndex;
		OutputOffsetType offsetIndex;
		
		typename TInputImage::SizeType inputRequestedRegionSize;
		typename TOutputImage::PointType tempPoint;
		
		// Use this index to compute the offset everywhere in this class
		outputIndex = outputPtr->GetLargestPossibleRegion().GetIndex();
		
		// We wish to perform the following mapping of outputIndex to
		// inputIndex on all points in our region
		outputPtr->TransformIndexToPhysicalPoint(outputIndex, tempPoint);
		inputPtr->TransformPhysicalPointToIndex(tempPoint, inputIndex);
		
		// Given that the size is scaled by a constant factor eq:
		// inputIndex = outputIndex * factorSize
		// is equivalent up to a fixed offset which we now compute
		OffsetValueType zeroOffset = 0;
		for ( i = 0; i < TInputImage::ImageDimension; i++ )
		{
			offsetIndex[i] = inputIndex[i] - outputIndex[i] * m_ShrinkFactors[i];
			// It is plausible that due to small amounts of loss of numerical
			// precision that the offset it negaive, this would cause sampling
			// out of out region, this is insurance against that possibility
			offsetIndex[i] = vnl_math_max(zeroOffset, offsetIndex[i]);
		}
		
		inputRequestedRegionIndex = outputRequestedRegionStartIndex * factorSize + offsetIndex;
		
		// Originally this was
		//  for ( i=0; i < TInputImage::ImageDimension; ++i )
		//  {
			//  inputRequestedRegionSize[i] = (outputRequestedRegionSize[i] - 1 ) *
		// factorSize[i] + 1;
		//  }
		// but with centered pixels we may sample edge to edge
		
		inputRequestedRegionSize = outputRequestedRegionSize * factorSize;
		
		typename TInputImage::RegionType inputRequestedRegion;
		inputRequestedRegion.SetIndex(inputRequestedRegionIndex);
		inputRequestedRegion.SetSize(inputRequestedRegionSize);
		inputRequestedRegion.Crop( inputPtr->GetLargestPossibleRegion() );
		
		inputPtr->SetRequestedRegion(inputRequestedRegion);
	}
	
	/**
	 * 
	 */
	template< class TInputImage, class TOutputImage >
	void
	ShrinkAverageFilter< TInputImage, TOutputImage >
	::GenerateOutputInformation()
	{
		// Call the superclass' implementation of this method
		Superclass::GenerateOutputInformation();
		
		// Get pointers to the input and output
		InputImageConstPointer inputPtr  = this->GetInput();
		OutputImagePointer     outputPtr = this->GetOutput();
		
		if ( !inputPtr || !outputPtr )
		{
			return;
		}
		
		// Compute the output spacing, the output image size, and the
		// output image start index
		unsigned int i;
		const typename TInputImage::SpacingType &
		inputSpacing = inputPtr->GetSpacing();
		const typename TInputImage::SizeType &   inputSize =
		inputPtr->GetLargestPossibleRegion().GetSize();
		const typename TInputImage::IndexType &  inputStartIndex =
		inputPtr->GetLargestPossibleRegion().GetIndex();
		
		typename TOutputImage::SpacingType outputSpacing;
		typename TOutputImage::SizeType outputSize;
		typename TOutputImage::IndexType outputStartIndex;
		
		for ( i = 0; i < TOutputImage::ImageDimension; i++ )
		{
			outputSpacing[i] = inputSpacing[i] * (double)m_ShrinkFactors[i];
			
			// Round down so that all output pixels fit input input region
			outputSize[i] = static_cast<SizeValueType>(
				vcl_floor( (double)inputSize[i] / (double)m_ShrinkFactors[i] ) );
			
			if ( outputSize[i] < 1 )
			{
				outputSize[i] = 1;
			}
			
			// Because of the later origin shift this starting index is not
			// critical
			outputStartIndex[i] = static_cast<IndexValueType>(
				vcl_ceil( (double)inputStartIndex[i] / (double)m_ShrinkFactors[i] ) );
		}
		
		outputPtr->SetSpacing(outputSpacing);
		
		// Compute origin offset
		// The physical center's of the input and output should be the same
		ContinuousIndex< double, TOutputImage::ImageDimension > inputCenterIndex;
		ContinuousIndex< double, TOutputImage::ImageDimension > outputCenterIndex;
		for ( i = 0; i < TOutputImage::ImageDimension; i++ )
		{
			inputCenterIndex[i] = inputStartIndex[i] + ( inputSize[i] - 1 ) / 2.0;
			outputCenterIndex[i] = outputStartIndex[i] + ( outputSize[i] - 1 ) / 2.0;
		}
		
		typename TOutputImage::PointType inputCenterPoint;
		typename TOutputImage::PointType outputCenterPoint;
		inputPtr->TransformContinuousIndexToPhysicalPoint(inputCenterIndex, inputCenterPoint);
		outputPtr->TransformContinuousIndexToPhysicalPoint(outputCenterIndex, outputCenterPoint);
		
		typename TOutputImage::PointType outputOrigin = outputPtr->GetOrigin();
		outputOrigin = outputOrigin + ( inputCenterPoint - outputCenterPoint );
		outputPtr->SetOrigin(outputOrigin);
		
		// Set region
		typename TOutputImage::RegionType outputLargestPossibleRegion;
		outputLargestPossibleRegion.SetSize(outputSize);
		outputLargestPossibleRegion.SetIndex(outputStartIndex);
		
		outputPtr->SetLargestPossibleRegion(outputLargestPossibleRegion);
	}
} // end namespace itk

#endif


More information about the Insight-developers mailing list