本文继续带大家了解itk,虽然数据翻转通常就是用来看一看(其实在DICOM浏览器中的图像翻转并不是这个思路,关键词:camera),但还是要深入了解下itk在翻转中的实现方法,我猜是矩阵变换。
itkFlipImageFilter (翻转)
实现代码:
itk::FixedArray<bool,2>flipAxes;
flipAxes[0]=false;
flipAxes[1]=true;
typedef itk::FlipImageFilter<ImageType>FlipImageFilterType;
FlipImageFilterType::PointerflipFilter=FlipImageFilterType::New();
flipFilter->SetInput(input_data);
//flipFilter->SetFlipAboutOrigin(bool);
/*
true:以图像原点翻转
false:以图像中心翻转
*/
flipFilter->SetFlipAxes(flipAxes);
/*
itkFixedArray:沿着哪个坐标轴翻转
*/
flipFilter->Updata();
1.构建输出数据的信息:这是到目前为止最长的一个GenerateOutputInformation,因为比起输入图像来,输出图像的信息有了一些改变。
template <class TImage>
void
FlipImageFilter<TImage>
::GenerateOutputInformation()
{
// call the superclass's implementation of this method 大赞超类!
Superclass::GenerateOutputInformation();
// get pointers to the input and output 获得输入和输出的指针
InputImagePointer inputPtr =
const_cast< TImage * >( this->GetInput() );
OutputImagePointer outputPtr = this->GetOutput();
if( !inputPtr || !outputPtr ) //防爆安全代码
{
return;
}
//获得输入数据的各种信息
const typename TImage::DirectionType& inputDirection = inputPtr->GetDirection();
const typename TImage::SizeType& inputSize =
inputPtr->GetLargestPossibleRegion().GetSize();
const typename TImage::IndexType& inputStartIndex =
inputPtr->GetLargestPossibleRegion().GetIndex();
typename TImage::PointType outputOrigin;
typename TImage::IndexType newIndex = inputStartIndex;
unsigned int j;
//看到没?翻转矩阵~!!哈哈,我猜就是。
typename TImage::DirectionType flipMatrix;
flipMatrix.SetIdentity();
// Need the coordinate of the pixel that will become the first pixel
// and need a matrix to model the flip
for ( j = 0; j < ImageDimension; j++ )
{
if ( m_FlipAxes[j] )
{
// If flipping the axis, then we need to know the last pixel in
// that dimension
//由于是翻转,直接倒着数像素
newIndex[j] += (inputSize[j] - 1);
// What we really want is the index padded out past this point
// by the amount the start index is from [0,0,0] (because the
// output regions have the same index layout as the input
// regions)
newIndex[j] += inputStartIndex[j];
// Only flip the directions if we are NOT flipping about the
// origin (when flipping about the origin, the pixels are
// ordered in the same direction as the input directions. when
// NOT flipping about the origin, the pixels traverse space in
// the opposite direction. when flipping about the origin,
// increasing indices traverse space in the same direction as
// the original data.).
if (!m_FlipAboutOrigin)
{
flipMatrix[j][j] = -1.0;
}
}
}
inputPtr->TransformIndexToPhysicalPoint( newIndex, outputOrigin );
// Finally, flip about the origin if needed
if (m_FlipAboutOrigin)//默认true
{
for ( j = 0; j < ImageDimension; j++ )
{
if ( m_FlipAxes[j] )
{
outputOrigin[j] *= -1;//输出的原点
}
}
}
outputPtr->SetDirection( inputDirection * flipMatrix );
outputPtr->SetOrigin( outputOrigin );
}
2.构建输入请求区域:这个也是itk工具包架构的亮点,可以在输入图像中设置一块计算区域。(实际上是通过指向目标区域的索引和面积来实现的)
template <class TImage>
void
FlipImageFilter<TImage>
::GenerateInputRequestedRegion()
{
//...只贴关键部分
IndexType inputRequestedIndex;
unsigned int j;
for ( j = 0; j < ImageDimension; j++ )
{
if ( m_FlipAxes[j] )
{ //重点在这里!!
inputRequestedIndex[j] =
2 * outputLargestPossibleIndex[j]
+ static_cast<IndexValueType>( outputLargestPossibleSize[j] )
- static_cast<IndexValueType>( outputRequestedSize[j] )
- outputRequestedIndex[j];
}
else
{
inputRequestedIndex[j] = outputRequestedIndex[j];
}
}
typename TImage::RegionType inputRequestedRegion;
inputRequestedRegion.SetSize( outputRequestedSize );
inputRequestedRegion.SetIndex( inputRequestedIndex );
inputPtr->SetRequestedRegion( inputRequestedRegion );
}
3.计算
template <class TImage>
void
FlipImageFilter<TImage>
::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
int threadId)
{
unsigned long i;
unsigned int j;
// Get the input and output pointers
InputImageConstPointer inputPtr = this->GetInput();
OutputImagePointer outputPtr = this->GetOutput();
// Setup output region iterator
typedef ImageRegionIteratorWithIndex<TImage> OutputIterator;
OutputIterator outIt(outputPtr, outputRegionForThread);
typename TImage::IndexType outputIndex;
typename TImage::IndexType inputIndex;
// support progress methods/callbacks
ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
const typename TImage::SizeType & outputLargestPossibleSize =
outputPtr->GetLargestPossibleRegion().GetSize();
const typename TImage::IndexType& outputLargestPossibleIndex =
outputPtr->GetLargestPossibleRegion().GetIndex();
IndexValueType offset[ImageDimension];//定义一个偏移量
for ( j = 0; j < ImageDimension; j++ )
{
if ( m_FlipAxes[j] )//体现出定义m_FlipAxes的优势了
{
offset[j] = 2 * outputLargestPossibleIndex[j]
+ static_cast<IndexValueType>( outputLargestPossibleSize[j] ) - 1;
}
}
// walk the output region, and sample the input image
for ( i = 0; !outIt.IsAtEnd(); ++outIt, i++ )
{
// determine the index of the output pixel 确定输出像素的索引
outputIndex = outIt.GetIndex();
//确定与此输出像素相关联的输入像素位置。
//这里体现出这个翻转算法的设计思路:将输出像素的索引与输入像素的索引对应起来!
// determine the input pixel location associated with this output pixel
for ( j = 0; j < ImageDimension; j++ )
{
if ( m_FlipAxes[j] )
{
inputIndex[j] = - 1 * outputIndex[j] + offset[j];
}
else
{
inputIndex[j] = outputIndex[ j ];
}
}
// copy the input pixel to the output
outIt.Set( inputPtr->GetPixel(inputIndex) );
progress.CompletedPixel();
}
}
生命中,总会有为之奋斗的一些东西,或者,人。活着,从来都不是为了自己。
参考文献:
1.https://itk.org/Wiki/ITK/Examples/Images/FlipImageFilter