[Insight-developers] Mini-pipelines in filters

Miller, James V (CRD) millerjv@crd.ge.com
Fri, 12 Oct 2001 12:36:47 -0400


This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------_=_NextPart_000_01C1533C.15F893C0
Content-Type: multipart/alternative;
	boundary="----_=_NextPart_001_01C1533C.15F893C0"


------_=_NextPart_001_01C1533C.15F893C0
Content-Type: text/plain;
	charset="iso-8859-1"

I have made changes to the architecture to support running mini-pipelines inside of filters.  The
changes provide an official API to doing these operations. The method SetOutput() will be removed
from the system since it cannot be used safely. Here are a summary of changes:

1.	ProcessObject::MakeOutput(unsigned int idx) - Every subclass of ProcessObject must have a
method that can construct a DataObject of the appropriate type to be used as the idx'th output.  This
method returns a SmartPointer to the constructed DataObject.  This method is used internally to
ProcessObject to keep its output array valid. Most filters have a single output and can use the
default implementations in ImageSource or MeshSource. If a filter has multiple outputs of different
types, then that filter will have to provide a MakeOutput() method.

1.	I added this method to ImageSource and MeshSource.  Other subclasses of ProcessObject like
ImageIO, MultiResolutionRegistration, RegistrationMethod, and Writer need to have this method
defined.  I am not sure what it should do in those cases.

2.	ImageSource::GraftOutput(), MeshSource::GraftOutput() - These methods take an image or mesh
respectively and grab a handle to the bulk data (PixelContainer, etc.) and copies of the region
ivars, spacing etc.  This allows to set up a mini-pipeline to write its output into your filters
output bulk data area and allows you to transfer the bulk data from the end of  a mini-pipeline to
your filters output.  Note the two data objects are distinct, the simply reference the same bulk data
array.  See the usage below. The MeshSource implementation is incomplete. I need to touch base with
Will to see what needs to be copied.

I modified two filters to illustrate how to use these methods.  The first was the
DerivativeImageFilter.  This filter instantiates a single filter internally and delegates the input
and output to that filter.  The critical section of the GenerateData() method now looks like:
 
  filter->SetInput(this->GetInput());
  filter->GraftOutput(this->GetOutput());
  filter->Update();
  this->GraftOutput(filter->GetOutput());

The second filter was the DiscreteGaussianImageFilter.  This filter has a mini-pipeline that is
executed several times in a loop.  The first time through the loop the mini-pipeline input is the
filter's input.  Subsequent times through the loop the input to the mini-pipeline is the output of
the mini-pipeline from the previous iteration.  In this case, we need to use GraftOutput() in
conjunction with DisconnectPipeline(). The critical section of the GenerateData() method for this
filter now looks like:
 
  filter->GraftOutput( output );
  swapPtrA = this->GetInput();
  for (unsigned int i = 0; i < ImageDimension; ++i)
    {
    // Set up the operator for this dimension
    oper->SetDirection(i);
    oper->SetVariance(m_Variance[i]);
    oper->SetMaximumError(m_MaximumError[i]);
    oper->CreateDirectional();
 
    // Set up the filter and run the mini-pipeline
    filter->SetOperator(*oper);
    filter->SetInput(swapPtrA);
    filter->Update();
 
    // Disconnect the output of the mini-pipeline so that it can be
    // used as the input to the mini-pipeline
    swapPtrA = filter->GetOutput();
    swapPtrA->DisconnectPipeline();
    }
  // Graft the last output of the mini-pipeline onto this filters output so
  // the final output has the correct region ivars and a handle to the final
  // bulk data
  this->GraftOutput(swapPtrA);

 
ToDo - 

*	I need to finish MeshSource::GraftOutput().  
*	Need to determine whether MakeOutput() needs to be implemented in ImageIO,
MultiResolutionRegistration, RegistrationMethod, and Writer.
*	Looks like the ImageAdaptors do not provide the necessary API to support these changes.  I'll
look into adding the appropriate methods.
*	Remove SetOutput() whereever it is used .  It looks like the GradientRecursiveGaussian and
some of the VectorNeighborhood operators are using SetOutput().

I added a warning macro to SetOutput() so you can identify at run time that the method is slated to
be removed.
 


Jim Miller 
_____________________________________
Visualization & Computer Vision
GE Corporate Research & Development
Bldg. KW, Room C218B
P.O. Box 8, Schenectady NY 12301

millerjv@crd.ge.com < mailto:millerjv@crd.ge.com <mailto:millerjv@crd.ge.com> >
(518) 387-4005, Dial Comm: 8*833-4005, 
Cell: (518) 505-7065, Fax: (518) 387-6981 


 

------_=_NextPart_001_01C1533C.15F893C0
Content-Type: text/html;
	charset="iso-8859-1"

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">


<META content="MSHTML 5.50.4807.2300" name=GENERATOR></HEAD>
<BODY>
<DIV><SPAN class=930253013-12102001><FONT size=2>I have made changes to the 
architecture to support running mini-pipelines inside of filters.&nbsp; The 
changes provide an official API to doing these operations. The method 
SetOutput() will be removed from the system since it cannot be used safely. Here 
are a summary of changes:</FONT></SPAN></DIV>
<OL>
  <LI><SPAN class=930253013-12102001><FONT 
  size=2>ProcessObject::MakeOutput(unsigned int idx) - Every subclass of 
  ProcessObject must have a method that can construct a DataObject of the 
  appropriate type to be used as the idx'th output.&nbsp; This method returns a 
  SmartPointer to the constructed DataObject.&nbsp; This method is used 
  internally to ProcessObject to keep its output array valid. Most filters have 
  a single output and can use the default implementations in ImageSource or 
  MeshSource. If a filter has multiple outputs of different types, then that 
  filter will have to provide a MakeOutput() method.</FONT></SPAN></LI>
  <OL>
    <LI><SPAN class=930253013-12102001><FONT size=2>I added this method to 
    ImageSource and MeshSource.&nbsp; Other subclasses of ProcessObject like 
    ImageIO, MultiResolutionRegistration, RegistrationMethod, and Writer need to 
    have this method defined.&nbsp; I am not sure what it should do in those 
    cases.</FONT></SPAN></LI></OL>
  <LI><SPAN class=930253013-12102001><FONT size=2>ImageSource::GraftOutput(), 
  MeshSource::GraftOutput() - These methods take an image or mesh respectively 
  and grab a handle to the bulk data (PixelContainer, etc.) and copies of the 
  region ivars, spacing etc.&nbsp; This allows to set up a mini-pipeline to 
  write its output into your filters output bulk data area and allows you to 
  transfer the bulk data from the end of&nbsp; a mini-pipeline to your filters 
  output.&nbsp; Note the two data objects are distinct, the simply reference the 
  same bulk data array.&nbsp; See the usage below. The MeshSource implementation 
  is incomplete. I need to touch base with Will to see what needs to be 
  copied.</FONT></SPAN></LI></OL>
<DIV><SPAN class=930253013-12102001><FONT size=2>I modified two filters to 
illustrate how to use these methods.&nbsp; The first was the 
DerivativeImageFilter.&nbsp; This filter instantiates a single filter internally 
and delegates the input and output to that filter.&nbsp; The critical section of 
the GenerateData() method now looks like:</FONT></SPAN></DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2>&nbsp; 
filter-&gt;SetInput(this-&gt;GetInput());</FONT></SPAN></DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2>&nbsp; 
filter-&gt;GraftOutput(this-&gt;GetOutput());</FONT></SPAN><SPAN 
class=930253013-12102001><FONT size=2><BR>&nbsp; 
filter-&gt;Update();</FONT></SPAN></DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2>&nbsp; 
this-&gt;GraftOutput(filter-&gt;GetOutput());<BR></FONT></SPAN></DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2>The second filter was the 
DiscreteGaussianImageFilter.&nbsp; This filter has a mini-pipeline that&nbsp;is 
executed several times in a loop.&nbsp; The first time through the loop the 
mini-pipeline input is the filter's input.&nbsp; Subsequent times through the 
loop the input to the mini-pipeline is the output of the mini-pipeline from the 
previous iteration.&nbsp; In this case, we need to use GraftOutput() in 
conjunction with DisconnectPipeline(). The critical section of the 
GenerateData() method for this filter now looks like:</FONT></SPAN></DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=930253013-12102001><FONT 
size=2>&nbsp;&nbsp;filter-&gt;GraftOutput( output );<BR>&nbsp; swapPtrA = 
this-&gt;GetInput();<BR>&nbsp; for (unsigned int i = 0; i &lt; ImageDimension; 
++i)<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp; // Set up the operator for 
this dimension<BR>&nbsp;&nbsp;&nbsp; 
oper-&gt;SetDirection(i);<BR>&nbsp;&nbsp;&nbsp; 
oper-&gt;SetVariance(m_Variance[i]);<BR>&nbsp;&nbsp;&nbsp; 
oper-&gt;SetMaximumError(m_MaximumError[i]);<BR>&nbsp;&nbsp;&nbsp; 
oper-&gt;CreateDirectional();</FONT></SPAN></DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2>&nbsp;&nbsp;&nbsp; // Set up 
the filter and run the mini-pipeline<BR>&nbsp;&nbsp;&nbsp; 
filter-&gt;SetOperator(*oper);<BR>&nbsp;&nbsp;&nbsp; 
filter-&gt;SetInput(swapPtrA);<BR>&nbsp;&nbsp;&nbsp; 
filter-&gt;Update();</FONT></SPAN></DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2>&nbsp;&nbsp;&nbsp; // 
Disconnect the output of the mini-pipeline so that it can 
be<BR>&nbsp;&nbsp;&nbsp; // used as the input to the 
mini-pipeline<BR>&nbsp;&nbsp;&nbsp; swapPtrA = 
filter-&gt;GetOutput();<BR>&nbsp;&nbsp;&nbsp; 
swapPtrA-&gt;DisconnectPipeline();</FONT></SPAN><SPAN 
class=930253013-12102001><FONT size=2><BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp; // 
Graft the last output of the mini-pipeline onto this filters output so<BR>&nbsp; 
// the final output has the correct region ivars and a handle to the 
final<BR>&nbsp; // bulk data<BR>&nbsp; 
this-&gt;GraftOutput(swapPtrA);<BR></FONT></SPAN></DIV>
<DIV><SPAN class=930253013-12102001><FONT 
size=2><STRONG></STRONG></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=930253013-12102001><FONT size=2><STRONG>ToDo</STRONG>&nbsp;- 
</FONT></SPAN></DIV>
<UL>
  <LI><SPAN class=930253013-12102001><FONT size=2>I need to finish 
  MeshSource::GraftOutput().&nbsp; </FONT></SPAN></LI>
  <LI><SPAN class=930253013-12102001><FONT size=2>Need to determine whether 
  MakeOutput() needs to be implemented in ImageIO, MultiResolutionRegistration, 
  RegistrationMethod, and Writer.</FONT></SPAN></LI>
  <LI><FONT size=2><SPAN class=930253013-12102001>Looks like the ImageAdaptors 
  do not provide the necessary API to support these changes.&nbsp; I'll look 
  into adding the appropriate methods.</SPAN></FONT></LI>
  <LI><FONT size=2><SPAN class=930253013-12102001></SPAN><SPAN 
  class=930253013-12102001>Remove SetOutput() whereever it is used .&nbsp; It 
  looks like the GradientRecursiveGaussian and some of the VectorNeighborhood 
  operators are using SetOutput().</SPAN></FONT></LI></UL>
<DIV><FONT size=2><SPAN class=930253013-12102001>I added a warning macro to 
SetOutput() so you can identify at run time that the method is slated to be 
removed.</DIV></SPAN></FONT>
<DIV><SPAN class=930253013-12102001><FONT size=2></FONT></SPAN>&nbsp;</DIV><BR>
<P><B><FONT face="Comic Sans MS" color=#000080>Jim Miller</FONT></B> 
<BR><B><I><FONT face=Arial color=#ff0000 
size=2>_____________________________________</FONT></I></B><I></I><BR><I></I><I><FONT 
face=Arial color=#000000 size=1>Visualization &amp; Computer Vision<BR>GE 
Corporate Research &amp; Development<BR>Bldg. KW, Room C218B<BR>P.O. Box 8, 
Schenectady NY 12301<BR><BR></FONT><U><FONT face=Arial color=#0000ff 
size=1>millerjv@crd.ge.com &lt;<A 
href="mailto:millerjv@crd.ge.com">mailto:millerjv@crd.ge.com</A>&gt;</FONT></U></I><BR><I><FONT 
face=Arial color=#000000 size=1>(518) 387-4005, Dial Comm: 8*833-4005, 
</FONT></I><BR><I><FONT face=Arial color=#000000 size=1>Cell: (518) 505-7065, 
Fax: (518) 387-6981</FONT></I> </P><BR>
<DIV>&nbsp;</DIV></BODY></HTML>

------_=_NextPart_001_01C1533C.15F893C0--

------_=_NextPart_000_01C1533C.15F893C0
Content-Type: application/octet-stream;
	name="Miller, James V (CRD).vcf"
Content-Disposition: attachment;
	filename="Miller, James V (CRD).vcf"

BEGIN:VCARD
VERSION:2.1
N:Miller;James
FN:Miller, James V (CRD)
ORG:CRD;ESL
TITLE:Computer Scientist
TEL;WORK;VOICE:*833-4005
TEL;WORK;VOICE:1 518 387-4005
ADR;WORK:;KW-C218B;P.O. Box 8;Schenectady;New York;12301;USA
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:KW-C218B=0D=0AP.O. Box 8=0D=0ASchenectady, New York 12301=0D=0AUSA
EMAIL;PREF;INTERNET:millerjv@crd.ge.com
REV:20010420T140329Z
END:VCARD

------_=_NextPart_000_01C1533C.15F893C0--