[ITK] About pipeline recursion
Nicolas Gallego
nicgallego at gmail.com
Fri Jun 20 10:11:44 EDT 2014
Hi Bradley,
Great! That works on this toy example, I will use this technique on my
filter.
For the record I post the code that works.
Could you suggest a documentation entry or somewhere in the code where I
can learn about the architectural mechanism preventing circular execution?
And strategies to trade off like this one?
Thank you very much
Nicolás Gallego-Ortiz
Université catholique de Louvain, Belgium
2014-06-20 15:19 GMT+02:00 Bradley Lowekamp <blowekamp at mail.nih.gov>:
> Hello,
>
> There is some code in the pipeline architecture to prevent circular
> execution. I believe it has been used for more complex circular pipelines.
> But your case is a bit simplified and has a problem.
>
> For your particular case the input image IS same as the output image. This
> does not surprise me that it breaks things and causes odd behavior.
>
> I am not sure if the below pipeline is close to what you are trying to do
> in the end or not. But I'll suggest the following:
>
> 1) After getting the output, call tmpImage->DisconnectPipeline().
> This will explicitly sever the pipeline, and allow you to manual place the
> output as a input.
>
> 2) Turn on InPlace for the AddImageFilter.
> This will copy the buffer of input1 to the output and remove the need to
> allocate a new output.
>
> Hope that helps,
> Brad
>
> On Jun 20, 2014, at 4:35 AM, Nicolas Gallego <nicgallego at gmail.com> wrote:
>
> Good morning,
>
> I have been coding a filter that implements an iterative procedure on
> images. I have tried the straight forward implementation of updating a
> temporal image on the recursion loop but results are wrong. The correct
> result is obtained when I explicitly unroll the pipeline although it
> becomes harder to code for more complex pipelines, and I am concerned about
> the scalability on the number of recursions.
>
> Could you give me some ideas to work this point out. Is there a way to
> implement a straight forward way in itk? Here the code that illustrates the
> point on recursively adding images:
>
> ----- code 1 -------------
> std::cout << "Recursion on image pointer" << std::endl;
>
> ImageType::Pointer image1 = ImageType::New();
>
> image1->SetRegions( region );
>
> image1->Allocate();
>
> image1->FillBuffer( 1 );
>
> AdderType::Pointer adder = AdderType::New();
>
> adder->SetInput1( image1 );
>
> adder->SetInput2( image1 );
>
> adder->Update();
>
> ImageType::Pointer tmpImage = adder->GetOutput();
>
> std::cout << "start: " << image1->GetPixel( index ) << std::endl;
>
> const unsigned short N = 10;
>
> for ( unsigned short k = 0; k < N; k++ ) {
>
> adder->Update();
>
> tmpImage = adder->GetOutput();
>
> std::cout << k << " " << tmpImage->GetPixel( index ) << std::endl;
>
> adder->SetInput1( tmpImage );
>
> adder->SetInput2( image1 );
>
> }
>
> std::cout << std::endl;
>
> --- end of 1 --------------
>
> Code 1 produces the following output:
> -----------------------------------------------
> Recursion on image pointer
> start: 1
> 0 2
> 1 3
> 2 3
> 3 3
> 4 4
> 5 4
> 6 4
> 7 5
> 8 5
> 9 5
> ---------------------------------------------
>
> The explicit pipeline unroll is illustrated in code 2
>
> --- code 2 -----------------------------------------------
> std::cout << "Pipeline explicit unroll recursion" << std::endl;
>
> std::vector< AdderType::Pointer > adders( N );
>
> adders[0] = AdderType::New();
>
> adders[0]->SetInput1( image1 );
>
> adders[0]->SetInput2( image1 );
>
> std::cout << "start: " << image1->GetPixel( index ) << std::endl;
>
> // connections
>
> for ( unsigned short k = 1; k < N; k++ ) {
>
> adders[k] = AdderType::New();
>
> adders[k]->SetInput1( adders[k-1]->GetOutput() );
>
> adders[k]->SetInput2( image1 );
>
> }
>
> // execution
>
> adders[N-1]->Update();
>
> for ( unsigned short k = 0; k < N; k++ ) {
>
> std::cout << k << " " << adders[k]->GetOutput()->GetPixel( index ) << std::endl;
>
> }
>
>
> --- end of code 2 --------------------------------------
>
> Pipeline explicit unroll recursion
> start: 1
> 0 2
> 1 3
> 2 4
> 3 5
> 4 6
> 5 7
> 6 8
> 7 9
> 8 10
> 9 11
> ------------------------------------
>
> Find attached complete code file, thank you for your help
>
> ------
> Nicolás Gallego-Ortiz
> Université catholique de Louvain, Belgium
> <recursionTest.cxx>_______________________________________________
> Community mailing list
> Community at itk.org
> http://public.kitware.com/mailman/listinfo/community
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/community/attachments/20140620/3cd8a26e/attachment-0002.html>
-------------- next part --------------
#include <itkImage.h>
#include <itkAddImageFilter.h>
int main()
{
typedef unsigned short PixelType;
const unsigned int Dimension = 3;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::AddImageFilter< ImageType, ImageType, ImageType > AdderType;
ImageType::RegionType region;
ImageType::IndexType index;
index.Fill(0);
ImageType::SizeType size;
size.Fill(1);
region.SetIndex( index );
region.SetSize( size );
std::cout << "Recursion on image pointer" << std::endl;
ImageType::Pointer image1 = ImageType::New();
image1->SetRegions( region );
image1->Allocate();
image1->FillBuffer( 1 );
AdderType::Pointer adder = AdderType::New();
adder->SetInput1( image1 );
adder->SetInput2( image1 );
adder->Update();
ImageType::Pointer tmpImage = adder->GetOutput();
std::cout << "start: " << image1->GetPixel( index ) << std::endl;
const unsigned short N = 10;
for ( unsigned short k = 0; k < N; k++ ) {
adder->Update();
tmpImage = adder->GetOutput();
tmpImage->DisconnectPipeline(); // allows reuse it as input
adder->SetInPlace( true ); // prevents allocating output again
std::cout << k << " " << tmpImage->GetPixel( index ) << std::endl;
adder->SetInput1( tmpImage );
adder->SetInput2( image1 );
}
std::cout << std::endl;
std::cout << "Pipeline explicit unroll recursion" << std::endl;
std::vector< AdderType::Pointer > adders( N );
adders[0] = AdderType::New();
adders[0]->SetInput1( image1 );
adders[0]->SetInput2( image1 );
std::cout << "start: " << image1->GetPixel( index ) << std::endl;
// connections
for ( unsigned short k = 1; k < N; k++ ) {
adders[k] = AdderType::New();
adders[k]->SetInput1( adders[k-1]->GetOutput() );
adders[k]->SetInput2( image1 );
}
// execution
adders[N-1]->Update();
for ( unsigned short k = 0; k < N; k++ ) {
std::cout << k << " " << adders[k]->GetOutput()->GetPixel( index ) << std::endl;
}
return 0;
}
More information about the Community
mailing list