[Insight-developers] BinaryMedianImageFilter

Luis Ibanez luisedoibanez at yahoo . com
Sun, 21 Jul 2002 17:56:40 -0700 (PDT)


--0-979044662-1027299400=:23166
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline


Hi Bill,

Thanks for pointing this out.

The handling of boundaries wasn´t following the
correct use of the Neighborhood iterator.

It looked like a bad copy/paste of code...

I have fixed it in my local checkout but won´t 
be able to check this in until thursday.
(when I should be back in town).

In the meantime, the fixed version is attached
to this email.

 Thanks

   Luis

PS. Please feel free to check this in if you will.


--- Bill Lorensen <wlorens1@nycap.rr.com> wrote:
> Luis,
> The subject filter has an Array Bounds Read purify
> error. I think the logic for handling boundary faces
> is flawed.
> 
> I put a cout in the boundary face loop and printed
> **inner_it. Some of its values are strange.
> 
> Hope all is well,
> 
> Bill
> 
> _______________________________________________
> Insight-developers mailing list
> Insight-developers@public.kitware.com
>
http://public.kitware.com/mailman/listinfo/insight-developers


__________________________________________________
Do You Yahoo!?
Yahoo! Health - Feel better, live better
http://health.yahoo.com
--0-979044662-1027299400=:23166
Content-Type: text/plain; name="itkBinaryMedianImageFilter.txx"
Content-Description: itkBinaryMedianImageFilter.txx
Content-Disposition: inline; filename="itkBinaryMedianImageFilter.txx"

/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: itkBinaryMedianImageFilter.txx,v $
  Language:  C++
  Date:      $Date: 2002/07/19 19:32:45 $
  Version:   $Revision: 1.5 $

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef _itkBinaryMedianImageFilter_txx
#define _itkBinaryMedianImageFilter_txx
#include "itkBinaryMedianImageFilter.h"

#include "itkConstNeighborhoodIterator.h"
#include "itkConstSmartNeighborhoodIterator.h"
#include "itkNeighborhoodInnerProduct.h"
#include "itkImageRegionIterator.h"
#include "itkNeighborhoodAlgorithm.h"
#include "itkZeroFluxNeumannBoundaryCondition.h"
#include "itkOffset.h"

#include <vector>
#include <algorithm>

namespace itk
{

template <class TInputImage, class TOutputImage>
BinaryMedianImageFilter<TInputImage, TOutputImage>
::BinaryMedianImageFilter()
{
  m_Radius.Fill(1);
  m_ForegroundValue = NumericTraits<InputPixelType>::max();
  m_BackgroundValue = NumericTraits<InputPixelType>::Zero;
}

template <class TInputImage, class TOutputImage>
void 
BinaryMedianImageFilter<TInputImage, TOutputImage>
::GenerateInputRequestedRegion() throw (InvalidRequestedRegionError)
{
  // call the superclass' implementation of this method
  Superclass::GenerateInputRequestedRegion();
  
  // get pointers to the input and output
  InputImagePointer inputPtr = 
      const_cast< TInputImage * >( this->GetInput() );
  OutputImagePointer outputPtr = this->GetOutput();
  
  if ( !inputPtr || !outputPtr )
    {
    return;
    }

  // get a copy of the input requested region (should equal the output
  // requested region)
  typename TInputImage::RegionType inputRequestedRegion;
  inputRequestedRegion = inputPtr->GetRequestedRegion();

  // pad the input requested region by the operator radius
  inputRequestedRegion.PadByRadius( m_Radius );

  // crop the input requested region at the input's largest possible region
  if ( inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()) )
    {
    inputPtr->SetRequestedRegion( inputRequestedRegion );
    return;
    }
  else
    {
    // Couldn't crop the region (requested region is outside the largest
    // possible region).  Throw an exception.

    // store what we tried to request (prior to trying to crop)
    inputPtr->SetRequestedRegion( inputRequestedRegion );
    
    // build an exception
    InvalidRequestedRegionError e(__FILE__, __LINE__);
    OStringStream msg;
    msg << (char *)this->GetNameOfClass()
        << "::GenerateInputRequestedRegion()";
    e.SetLocation(msg.str().c_str());
    e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
    e.SetDataObject(inputPtr);
    throw e;
    }
}


template< class TInputImage, class TOutputImage>
void
BinaryMedianImageFilter< TInputImage, TOutputImage>
::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
                       int threadId)
{
  
  ZeroFluxNeumannBoundaryCondition<InputImageType> nbc;

  ConstNeighborhoodIterator<InputImageType> nit;
  ConstSmartNeighborhoodIterator<InputImageType> bit;
  ImageRegionIterator<OutputImageType> it;
  ConstNeighborhoodIterator<InputImageType>::ConstIterator inner_it;
  ConstNeighborhoodIterator<InputImageType>::ConstIterator innerEnd_it;
  
  // Allocate output
  typename OutputImageType::Pointer output = this->GetOutput();
  typename  InputImageType::ConstPointer input  = this->GetInput();
  
  // Find the data-set boundary "faces"
  typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator<InputImageType>::FaceListType faceList;
  NeighborhoodAlgorithm::ImageBoundaryFacesCalculator<InputImageType> bC;
  faceList = bC(input, outputRegionForThread, m_Radius);

  typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator<InputImageType>::FaceListType::iterator fit;
  fit = faceList.begin();

  // support progress methods/callbacks
  unsigned long ii = 0;
  unsigned long updateVisits = 0;
  unsigned long totalPixels = 0;
  if ( threadId == 0 )
    {
    totalPixels = outputRegionForThread.GetNumberOfPixels();
    updateVisits = totalPixels / 10;
    if( updateVisits < 1 ) updateVisits = 1;
    }

  // Process non-boundary face
  nit = ConstNeighborhoodIterator<InputImageType>(m_Radius, input, *fit);
  it  = ImageRegionIterator<OutputImageType>(output, *fit);

  nit.GoToBegin();
  it.GoToBegin();

  // All of our neighborhoods have an odd number of pixels, so there is
  // always a median index (if there where an even number of pixels
  // in the neighborhood we have to average the middle two values).
  unsigned int medianPosition = nit.Size() / 2;

  while( ! nit.IsAtEnd() )
    {
    if ( threadId == 0 && !(++ii % updateVisits ) )
      {
      this->UpdateProgress((float)ii / (float)totalPixels);
      }

    // count the pixels in the neighborhood
    unsigned int count = 0;
    innerEnd_it = nit.End();
    for (inner_it = nit.Begin(); inner_it != innerEnd_it; ++inner_it)
      {
      if( **inner_it == m_ForegroundValue )
        {
        count++;
        }
      }

    if( count > medianPosition )
      {
      it.Set( static_cast<OutputPixelType>( m_ForegroundValue ) );
      }
    else 
      {
      it.Set( static_cast<OutputPixelType>( m_BackgroundValue ) );
      }

    ++nit;
    ++it;
    }
  
  // Process each of the boundary faces.  These are N-d regions which border
  // the edge of the buffer.
  for (++fit; fit != faceList.end(); ++fit)
    { 
    bit = ConstSmartNeighborhoodIterator<InputImageType>(m_Radius, input, *fit);
    it  = ImageRegionIterator<OutputImageType>(output, *fit);
    bit.OverrideBoundaryCondition(&nbc);
    bit.GoToBegin();
    
    unsigned int neighborhoodSize = bit.Size();

    while ( ! bit.IsAtEnd() )
      {
      if ( threadId == 0 && !(++ii % updateVisits ) )
        {
        this->UpdateProgress((float)ii / (float)totalPixels);
        }

       // count the pixels in the neighborhood
      unsigned int count = 0;
      for (unsigned int i = 0; i < neighborhoodSize; ++i)
        {
        InputPixelType value = bit.GetPixel(i);
        if( value == m_ForegroundValue )
          {
          count++;
          }
        }

      if( count > medianPosition )
        {
        it.Set( static_cast<OutputPixelType>( m_ForegroundValue ) );
        }
      else 
        {
        it.Set( static_cast<OutputPixelType>( m_BackgroundValue ) );
        }
       
      ++bit;
      ++it;
      }
    }
}

/**
 * Standard "PrintSelf" method
 */
template <class TInputImage, class TOutput>
void
BinaryMedianImageFilter<TInputImage, TOutput>
::PrintSelf(
std::ostream& os, 
Indent indent) const
{
  Superclass::PrintSelf( os, indent );
  os << indent << "Radius: " << m_Radius << std::endl;
  os << indent << "Foreground value : " << m_ForegroundValue << std::endl;
  os << indent << "Background value : " << m_BackgroundValue << std::endl;

}

} // end namespace itk

#endif

--0-979044662-1027299400=:23166--