[Insight-users] Problems with image corruption : Reusing filt ers

Miller, James V (Research) millerjv at crd . ge . com
Thu, 18 Dec 2003 09:08:16 -0500


Radhika, 

To followup on Luis' message.  In your original code, you had a series of
statements

	extracter2D->SetExtractionRegion( desiredRegion );
	extracter2D->SetInput(readervolume->GetOutput());
	extracter2D->Update();
      ImageType2D::Pointer gs = extracter2D->GetOutput();

	thresholder->SetInput(extracter2D->GetOutput());
	connectedcomponent2D->SetInput(thresholder->GetOutput());
	relabelcomponent2D->SetInput(connectedcomponent2D->GetOutput());
	relabelcomponent2D->Update();
	ImageType2D::Pointer binimg = relabelcomponent2D->GetOutput();
//Contains labeled components

	extracter2D->SetInput(readermask->GetOutput());
	extracter2D->Update();
	ImageType2D::Pointer mask = extracter2D->GetOutput();
	
     
binimg is the output of the relabeller.  However, when you change the input
to
extracter2D, that (implictly) changed what thresholder operated on, which
(implicitly)
changed that the relabeller operated on, which (implictly) changed binimg.
If an Update()
is called on the pipeline, all the above filters would re-execute since they
have new
input (the input to extracter2D). Calling Write() on a writer, causes
Update() to be called
on the pipeline which caused your apparent "corruption".

As Luis said, the easiest thing to do is not to reuse an instance of a
filter with a 
different input until you are completely done with the output first
execution of the 
filter (for instance, you have already written the output to disk). 

You can use ITK in more of a procedural manner, but it requires an extra set
of 
function calls.  For instance, 

	extracter2D->SetExtractionRegion( desiredRegion );
	extracter2D->SetInput(readervolume->GetOutput());
	extracter2D->Update();
      ImageType2D::Pointer gs = extracter2D->GetOutput();
	gs->DisconnectPipeline();

The DisconnectPipeline() call disassociates the data object pointed to by gs
from the
extracter2D.  This means gs does not have a source.  It is simply an image
that is not
connected to a pipeline.  If you called gs->Update() after calling
DisconnectPipeline(), 
nothing would happen (even if you modified a parameter of extracter2D,
nothing would
happen to gs since it is no longer connected to extracter2D).  If you called

extracter2D->Update() after calling DisconnectPipeline(), then extracter2D
would 
re-execute, creating a new output.  But gs would be distinct from this
output.

So to run in procedural manner, you can use a style like

    filter->SetInput( someDataObject );
    filter->Update();
    anotherDataObject = filter->GetOutput();
    anotherDataObject->DisconnectPipeline();

    filter2->SetInput( anotherDataObject );
    filter2->Update();
    yetAnotherDataObject = filter2->GetOutput();
    yetAnotherDataObject->DisconnectPipeline();

Note that what you lose in running procedurally, is the ability to change a
setting 
on a filter and have the entire pipeline re-execute.  Once you start
disconnecting 
the pipeline you cannot use the pipeline mechanism to pull information
through.

In real applications, we typically end up using a combination of the styles.
For instance, 
if you are writing an application like Photoshop, you may take a data
centric view. 
Here, your application keeps a handle to a data object.  When the user
selects a
filtering operation, you pass that dataobject to a "mini-pipeline" to
implement
that task.  After the pipeline finishes, you grab the output of the
mini-pipeline, 
disconnect it from the pipeline, and destroy the mini-pipeline.  When the
user selects
another filtering operation, you pass the new data object to a another
mini-pipeline
to implement that task, run that pipeline, disconnect its output, and throw
away the
pipeline.

When the user runs an operation with a mini-pipeline, you may provide a
"preview" mode
which shows the results of the mini-pipeline and allows the user to edit the
parameters
of the mini-pipeline.  Once the user is happy with the results, you grab the
output
of the mini-pipeline, disconnect it, and destroy the mini-pipeline.

Jim





-----Original Message-----
From: Luis Ibanez [mailto:luis . ibanez at kitware . com]
Sent: Wednesday, December 17, 2003 11:18 PM
To: Radhika Sivaramakrishna
Cc: insight-users at itk . org
Subject: Re: [Insight-users] Problems with image corruption : Reusing
filters



Hi Radhika,

  - Code reuse is a good thing
  - Variable names reuse is a bad, very bad thing

  - Filter reconection is a dangerous practice

Nothing good can result from saving a couple of bytes
in one extra pointer in your program.

When you reused "extracter2D" you were probably
thinking in terms of procedural programming.  e.g.
invoking functions for performing processing on data.

The data flow pipeline is a different paradigm.
It is like connecting circuits: When you need a
second switch, you don't take it out from somewhere
else in the circuit... you just add a new one  :-)

When you connect the filter with

         a->SetInput( b->GetOutput() )

Those connections are intended to be used in a
permanent way by running data through the filters
multiple times.

If you need a second extract filter, you should
(as you discovered by yourself) create a new extract
filter object and connect it in the pipeline in the
new appropriate place.

It is a "pipeline": you put the tubes, the elbows,
the tees, the valves,... as many as you need, and
once you install them, you don't take them out.
Especially not just before letting water run through
the pipe.


Think "plumber" and you will be ITK-enlightened.



Regards,


    Luis


--------------------------------
Radhika Sivaramakrishna wrote:

> Hi Luis,
> Thanks for your suggestion. I will try this also, but I am not sure if
this
> is the problem though it is a good suggestion. After I sent off that piece
> of code to you, I decided to do some more experimenting. In the code I
sent
> you I reused extracter2D (ExtractImageFilter Pointer) twice once to
extract
> a slice from the greyscale image, and then a second time to extract a
slice
> off the mask image. I decided to use two different pointers (one
> extracter2Dimage and another extracter2Dmask) and lo and behold, things
> started working and things were written out correctly. I dont understand
why
> this should happen? Could you explain?
> 
> Radhika
> 
> 
> ----- Original Message ----- 
> From: "Luis Ibanez" <luis . ibanez at kitware . com>
> To: "Radhika Sivaramakrishna" <radshashi at earthlink . net>
> Cc: <insight-users at itk . org>
> Sent: Wednesday, December 17, 2003 11:19 AM
> Subject: Re: [Insight-users] Problems with image corruption : Shouldn't
use
> LargestPossibleRegion for Iterators.
> 
> 
> 
>>Hi Radhika,
>>
>>It seems that the error is related to the use of
>>"GetLargestPossibleRegion()" in order to define
>>the iterators in line 230 of your code:
>>
>>
>>
>>>    ImageType2D::RegionType region = binimg->GetLargestPossibleRegion();
>>>    ConstIteratorType maskit (mask, region);
>>>    ConstIteratorType binimgit( binimg, region );
>>>    IteratorType newmaskit(newmask,region);
>>>
>>>   maskit.GoToBegin();
>>>   binimgit.GoToBegin();
>>>   newmaskit.GoToBegin();
>>>   while( ! maskit.IsAtEnd() && ! binimgit.IsAtEnd() && !
> 
> newmaskit.IsAtEnd())
> 
>>>     {
>>>newmaskit.Set(binimgit.Get());
>>>       if( maskit.Get() == 0 )   // if mask pixel is off
>>>         {
>>>newmaskit.Set(0);
>>>         }
>>>       ++maskit;
>>>++binimgit;
>>>++newmaskit;
>>>     }
>>
>>In general you shouldn't use "LargestPossibleRegion"
>>since there is no guarranty that all this data is
>>going to be in memory.  The safe region to use is the
>>"Buffered" region.
>>
>>Just to make sure that this is the problem, please
>>insert the line:
>>
>>            binimg->Print( std::cout )
>>
>>in line 229, run the program and look at the printed
>>values of the image regions. There will be: Requested,
>>Buffered and LargestPossible region.
>>
>>My guess is that the largest possible region is
>>larger than the buffered region and your iterators
>>are stepping out of the image buffers, therefore
>>corrupting the memory.
>>
>>BTW the process that you are attempting with the
>>iterators is done by the MaskImageFilter
>>http://www . itk . org/Insight/Doxygen/html/classitk_1_1MaskImageFilter . html
>>
>>You may simply replace this while loop with a
>>MaskImageFilter.
>>
>>
>>
>>Please let us know what you find.
>>
>>
>>Thanks
>>
>>
>>   Luis
>>
>>
>>
>>------------------------------------
>>Radhika Sivaramakrishna wrote:
>>
>>>Hi Luis,
>>>I am having some problems with my program. I have enclosed a portion of
>>>my code here where the problem is. I am not able to figure it out.
>>>Basically, "binimg" in my code is the output of the relabel filter. At
>>>that point when I write it out, it is correct. However, further down the
>>>line, when I try to write out the output of the relabel filter, it is
>>>corrupted. In fact, all are corrupted and they all have the same values
>>>which is that of the result of the mask filter. Even "gs" the output of
>>>the extractimagefilter is wrong at the point where I am writing it out.
>>>Could you help me figure out the problem? Maybe there is something wrong
>>>in the way I am setting the region of iteration for each or is there a
>>>problem in reusing the extractimagefilter for first extracting a
>>>greyscale slice and then using the same thing to extract a mask?
>>>
>>>Thanks
>>>Radhika
>>>
>>
>>
>>
> 
> 
> 



_______________________________________________
Insight-users mailing list
Insight-users at itk . org
http://www . itk . org/mailman/listinfo/insight-users