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
#ifndef __itkShrinkAverageFilter_h
#define __itkShrinkAverageFilter_h
#include "itkImageToImageFilter.h"
namespace itk
{
/** \class ShrinkAverageFilter
* \brief Reduce the size of an image by an integer factor in each
* dimension and calculate the average value.
*
* ShrinkAverageFilter reduces the size of an image by an integer factor
* in each dimension. In contrast to itkShrinkImageFilter, this filter
* calculates the average pixel value from each corresponding input
* pixel. The algorithm implemented is a simple subsample.
*
* This is basicaly a copy of itkShrinkImageFilter, with modyfications
* in ThreadedGenerateData() method, where the output pixel values are
* calculated.
*
* \author Carsten Kendziorra, Henning Meyer, Marc Dewey. Charite Berlin, Germany.
*/
template< class TInputImage, class TOutputImage >
class ITK_EXPORT ShrinkAverageFilter:
public ImageToImageFilter< TInputImage, TOutputImage >
{
public:
/** Standard class typedefs. */
typedef ShrinkAverageFilter Self;
typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass;
typedef SmartPointer< Self > Pointer;
typedef SmartPointer< const Self > ConstPointer;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(ShrinkAverageFilter, ImageToImageFilter);
/** Typedef to images */
typedef TOutputImage OutputImageType;
typedef TInputImage InputImageType;
typedef typename OutputImageType::Pointer OutputImagePointer;
typedef typename InputImageType::Pointer InputImagePointer;
typedef typename InputImageType::ConstPointer InputImageConstPointer;
typedef typename TOutputImage::IndexType OutputIndexType;
typedef typename TInputImage::IndexType InputIndexType;
typedef typename TOutputImage::OffsetType OutputOffsetType;
typedef typename TInputImage::PixelType InputImagePixelType;
typedef typename TOutputImage::PixelType OutputImagePixelType;
/** Typedef to describe the output image region type. */
typedef typename TInputImage::RegionType InputImageRegionType;
/** Typedef to describe the output image region type. */
typedef typename TOutputImage::RegionType OutputImageRegionType;
/** ImageDimension enumeration. */
itkStaticConstMacro(ImageDimension, unsigned int,
TInputImage::ImageDimension);
itkStaticConstMacro(OutputImageDimension, unsigned int,
TOutputImage::ImageDimension);
typedef FixedArray< unsigned int, ImageDimension > ShrinkFactorsType;
/** Set the shrink factors. Values are clamped to
* a minimum value of 1. Default is 1 for all dimensions. */
itkSetMacro(ShrinkFactors, ShrinkFactorsType);
void SetShrinkFactors(unsigned int factor);
void SetShrinkFactor(unsigned int i, unsigned int factor)
{
m_ShrinkFactors[i] = factor;
}
/** Get the shrink factors. */
itkGetConstReferenceMacro(ShrinkFactors, ShrinkFactorsType);
/** ShrinkAverageFilter produces an image which is a different
* resolution and with a different pixel spacing than its input
* image. As such, ShrinkAverageFilter needs to provide an
* implementation for GenerateOutputInformation() in order to inform
* the pipeline execution model. The original documentation of this
* method is below.
* \sa ProcessObject::GenerateOutputInformaton() */
virtual void GenerateOutputInformation();
/** ShrinkAverageFilter needs a larger input requested region than the output
* requested region. As such, ShrinkAverageFilter needs to provide an
* implementation for GenerateInputRequestedRegion() in order to inform the
* pipeline execution model.
* \sa ProcessObject::GenerateInputRequestedRegion() */
virtual void GenerateInputRequestedRegion();
#ifdef ITK_USE_CONCEPT_CHECKING
/** Begin concept checking */
itkConceptMacro( InputConvertibleToOutputCheck,
( Concept::Convertible< typename TInputImage::PixelType, typename TOutputImage::PixelType > ) );
itkConceptMacro( SameDimensionCheck,
( Concept::SameDimension< ImageDimension, OutputImageDimension > ) );
/** End concept checking */
#endif
protected:
ShrinkAverageFilter();
~ShrinkAverageFilter() {}
void PrintSelf(std::ostream & os, Indent indent) const;
/** ShrinkAverageFilter can be implemented as a multithreaded filter.
* Therefore, this implementation provides a ThreadedGenerateData() routine
* which is called for each processing thread. The output image data is
* allocated automatically by the superclass prior to calling
* ThreadedGenerateData(). ThreadedGenerateData can only write to the
* portion of the output image specified by the parameter
* "outputRegionForThread"
*
* \sa ImageToImageFilter::ThreadedGenerateData(),
* ImageToImageFilter::GenerateData() */
void ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread,
ThreadIdType threadId);
private:
ShrinkAverageFilter(const Self &); //purposely not implemented
void operator=(const Self &); //purposely not implemented
ShrinkFactorsType m_ShrinkFactors;
};
} // end namespace itk
#ifndef ITK_MANUAL_INSTANTIATION
#include "itkShrinkAverageFilter.txx"
#endif
#endif
#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
_______________________________________________
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