[Insight-developers] Progress reporting revisited

Miller, James V (Research) millerjv at crd . ge . com
Fri, 23 May 2003 08:52:00 -0400


There is another common design pattern to the filters in your list
that are not reporting progress correctly. At least 4 of them are 
implemented by calling other ITK filters.  For progress to work
properly in these cases, the filters need to "watch" the progress
of their subfilters and "propagate" that progress up another level.

There are some filtes that have added this pattern of progress delegation.
But it has not been consistently applied.  Thanks for the list of filters
with issues.  Keep reporting any that find.

Jim



-----Original Message-----
From: Kurt Augustine [mailto:augustine . kurt at mayo . edu]
Sent: Thursday, May 22, 2003 5:51 PM
To: 'insight-developers at public . kitware . com'
Subject: [Insight-developers] Progress reporting revisited


We have integrated a number of filters in Analyze and incorporated progress
reporting windows that also allow the user to cancel the process if desired.
While the filtering process itself seems to work correctly in all cases, the
same cannot be said for the progress reporting.  This, of course, is not a
new issue but I thought I would give specifics in the hope that they can be
fixed.  The assumption here is that we should be able to handle all progress
reporting the same, regardless of the filter.  Here is what we did:

We instantiate a filter, say ZeroCrossingBasedEdgeDetection and then
instantiate a class we designed called FilterObserver, with the filter as
the only parameter.

typename itk::DanielssonDistanceMapImageFilter<itk::Image<T, 3 >,
itk::Image<T, 3 > >::Pointer myFilter =
itk::DanielssonDistanceMapImageFilter<itk::Image<T, 3 >, itk::Image<T, 3 >
>::New();
FilterObserver watch(myFilter);
   ...
   ...
myFilter->Update();
   ...


Here is FilterObserver:
FilterObserver::FilterObserver(itk::ProcessObject* o)
  {
  m_Process = o;
  itk::SimpleMemberCommand<FilterObserver>::Pointer startFilterCommand;
  itk::SimpleMemberCommand<FilterObserver>::Pointer endFilterCommand;
  itk::SimpleMemberCommand<FilterObserver>::Pointer progressFilterCommand;

  startFilterCommand =    itk::SimpleMemberCommand<FilterObserver>::New();
  endFilterCommand =      itk::SimpleMemberCommand<FilterObserver>::New();
  progressFilterCommand = itk::SimpleMemberCommand<FilterObserver>::New();

  startFilterCommand->SetCallbackFunction(this,
&FilterObserver::StartFilter);
  endFilterCommand->SetCallbackFunction(this, &FilterObserver::EndFilter);
  progressFilterCommand->SetCallbackFunction(this,
&FilterObserver::ShowProgress);
  m_Process->AddObserver(itk::StartEvent(), startFilterCommand);
  m_Process->AddObserver(itk::EndEvent(), endFilterCommand);
  m_Process->AddObserver(itk::ProgressEvent(), progressFilterCommand);
  }

void FilterObserver::ShowProgress()
  {
    if(!someProgressReporterFunction((int)(m_Process->GetProgress()*100)))
    {
	    m_Process->AbortGenerateDataOn(); // clean up and return
	    return;
    }

  }
void FilterObserver::StartFilter()
  {
		someProgressReporterFunction(0);
  }

void FilterObserver::EndFilter()
  {
		someProgressReporterFunction(100);
  }

Where "someProgressReporterFunction(int percent)" can be some function that
reports progress to the user.

Now, this approach works well for some filters, namely:
itkBinaryMinMaxCurvatureFlowImageFilter
itkBinomialBlurImageFilter
itkCurvatureAnisotropicDiffusionImageFilter
itkCurvatureFlowImageFilter
itkDanielssonDistanceMapImageFilter
itkGradientAnisotropicDiffusionImageFilter
itkGradientMagnitudeImageFilter
itkMinMaxCurvatureFlowImageFilter

While others it does not work for:
itkBSplineDecompositionImageFilter
itkDerivativeImageFilter
itkDiscreteGaussianImageFilter
itkGradientMagnitudeRecursiveGaussianImageFilter
itkZeroCrossingBasedEdgeDetectionImageFilter

Some interesting notes that may help in determining problems:  It appears
that only two of the filters from the first list use the ProgressReporter
class and make calls to CompletedPixel().  Most of the rest from the first
list are derived from itkFiniteDiferenceImageFilter, which simply makes
calls to InvokeEvent, specifically this->InvokeEvent(IterationEvent())
followed by this->InvokeEvent(ProgressEvent()).

Three out of the five that do NOT work implement the ProgressReporter class
and are multithreaded.  

So, in general,  it appears that ProgressReporter may have problems with
multithreaded filters (although, one multithreaded case, namely
itkGradientMagnitudeImageFilter appears to work fine).  

Bottom line, ITK filters do not implement progress reporting in a consistent
manner and the chosen report mechanisms do not function at all in some
cases.  As application developers, we obviously need to provide interfaces
that work in a consistent manner.  Therefore, we turn to the filter
developers to help fix the progress reporting bugs (Bill's "code coverage
list" will maybe help identify who).  There certainly may be additional
filters beyond those listed that have the same problem.  We realize this may
seem like a low priority item on some developers' lists but these fixes are
essential to the successful integration of ITK with end-user applications.

Perhaps we can discuss this briefly in the tcon tomorrow.

Thanks (and sorry for the long message) ... Kurt
_______________________________________________
Insight-developers mailing list
Insight-developers at public . kitware . com
http://public . kitware . com/mailman/listinfo/insight-developers