/*========================================================================= Kenneth Johnson Open Source Software Practice Confidence Connected modified from Example Code ConfidenceConnected.cxx =========================================================================*/ // The following example illustrates the use of the // \doxygen{ConfidenceConnectedImageFilter}. The criterion used by the // ConfidenceConnectedImageFilter is based on simple statistics of the // current region. First, the algorithm computes the mean and standard // deviation of intensity values for all the pixels currently included in the // region. A user-provided factor is used to multiply the standard deviation // and define a range around the mean. Neighbor pixels whose intensity values // fall inside the range are accepted and included in the region. When no // more neighbor pixels are found that satisfy the criterion, the algorithm // is considered to have finished its first iteration. At that point, the // mean and standard deviation of the intensity levels are recomputed using // all the pixels currently included in the region. This mean and standard // deviation defines a new intensity range that is used to visit current // region neighbors and evaluate whether their intensity falls inside the // range. This iterative process is repeated until no more pixels are added // or the maximum number of iterations is reached. The following equation // illustrates the inclusion criterion used by this filter, // // I(\mathbf{X}) \in [ m - f \sigma , m + f \sigma ] // // where $m$ and $\sigma$ are the mean and standard deviation of the region // intensities, $f$ is a factor defined by the user, $I()$ is the image and // $\mathbf{X}$ is the position of the particular neighbor pixel being // considered for inclusion in the region. #include "itkConfidenceConnectedImageFilter.h" #include "itkImage.h" #include "itkCastImageFilter.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" int main( int argc, char *argv[] ) { if( argc < 6 ) { std::cerr << "Missing Parameters " << std::endl; std::cerr << "Usage: " << argv[0]; std::cerr << " inputImage outputImage seedX seedY seedZ" << std::endl; return 1; } // We now define the image type using a pixel type and a particular // dimension. typedef unsigned short InternalPixelType; // changed from sample code const unsigned int Dimension = 3; // changed from sample code typedef itk::Image< InternalPixelType, Dimension > InternalImageType; typedef unsigned short OutputPixelType; // changed from sample code typedef itk::Image< OutputPixelType, Dimension > OutputImageType; // We instantiate reader and writer types typedef itk::ImageFileReader< InternalImageType > ReaderType; typedef itk::ImageFileWriter< OutputImageType > WriterType; ReaderType::Pointer reader = ReaderType::New(); WriterType::Pointer writer = WriterType::New(); reader->SetFileName( argv[1] ); writer->SetFileName( argv[2] ); // We now declare the type of the region growing filter. In this case it is // the ConfidenceConnectedImageFilter. typedef itk::ConfidenceConnectedImageFilter ConnectedFilterType; // Then, we construct one filter of this class using the \code{New()} // method. ConnectedFilterType::Pointer confidenceConnected = ConnectedFilterType::New(); // Now it is time to create a simple, linear pipeline. A file reader is // added at the beginning of the pipeline and a cast filter and writer are // added at the end. The cast filter is required here to convert // \code{float} pixel types to integer types since only a few image file // formats support \code{float} types. confidenceConnected->SetInput( reader->GetOutput() ); writer->SetInput( confidenceConnected->GetOutput() ); // The ConfidenceConnectedImageFilter requires defining two parameters. // First, the factor $f$ that the defines how large the range of // intensities will be. Small values of the multiplier will restrict the // inclusion of pixels to those having very similar intensities to those // in the current region. Larger values of the multiplier will relax the // accepting condition and will result in more generous growth of the // region. Values that are too large will cause the region to grow into // neighboring regions that may actually belong to separate anatomical // structures. // // \index{itk::ConfidenceConnectedImageFilter!SetMultiplier()} confidenceConnected->SetMultiplier( 2.5 ); // The number of iterations is specified based on the homogeneity of the // intensities of the anatomical structure to be segmented. Highly // homogeneous regions may only require a couple of iterations. Regions // with ramp effects, like MRI images with inhomogeneous fields, may // require more iterations. In practice, it seems to be more important to // carefully select the multiplier factor than the number of iterations. // However, keep in mind that there is no reason to assume that this // algorithm should converge to a stable region. It is possible that by // letting the algorithm run for more iterations the region will end up // engulfing the entire image. // // \index{itk::ConfidenceConnectedImageFilter!SetNumberOfIterations()} confidenceConnected->SetNumberOfIterations( 5 ); // The output of this filter is a binary image with zero-value pixels // everywhere except on the extracted region. The intensity value to be // set inside the region is selected with the method // \code{SetReplaceValue()} // // \index{itk::ConfidenceConnectedImageFilter!SetReplaceValue()} confidenceConnected->SetReplaceValue( 255 ); // The initialization of the algorithm requires the user to provide a seed // point. It is convenient to select this point to be placed in a // \emph{typical} region of the anatomical structure to be segmented. A // small neighborhood around the seed point will be used to compute the // initial mean and standard deviation for the inclusion criterion. The // seed is passed in the form of a \doxygen{Index} to the \code{SetSeed()} // method. // // \index{itk::ConfidenceConnectedImageFilter!SetSeed()} // \index{itk::ConfidenceConnectedImageFilter!SetInitialNeighborhoodRadius()} InternalImageType::IndexType index; index[0] = atoi( argv[3] ); index[1] = atoi( argv[4] ); index[2] = atoi( argv[5] ); // add another index for the additional dimension confidenceConnected->SetSeed( index ); // The size of the initial neighborhood around the seed is defined with the // method \code{SetInitialNeighborhoodRadius()}. The neighborhood will be // defined as an $N$-dimensional rectangular region with $2r+1$ pixels on // the side, where $r$ is the value passed as initial neighborhood radius. confidenceConnected->SetInitialNeighborhoodRadius( 2 ); // The invocation of the \code{Update()} method on the writer triggers the // execution of the pipeline. It is recommended to place update calls in a // \code{try/catch} block in case errors occur and exceptions are thrown. try { writer->Update(); } catch( itk::ExceptionObject & excep ) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } // Let's now run this example using as input the image // \code{BrainProtonDensitySlice.png} provided in the directory // \code{Examples/Data}. We can easily segment the major anatomical // structures by providing seeds in the appropriate locations. For example // // \begin{center} // \begin{tabular}{|l|c|c|} // \hline // Structure & Seed Index & Output Image \\ \hline // White matter & $(60,116)$ & Second from left in Figure \ref{fig:ConfidenceConnectedOutput} \\ \hline // Ventricle & $(81,112)$ & Third from left in Figure \ref{fig:ConfidenceConnectedOutput} \\ \hline // Gray matter & $(107,69)$ & Fourth from left in Figure \ref{fig:ConfidenceConnectedOutput} \\ \hline // \end{tabular} // \end{center} // // \begin{figure} \center // \includegraphics[width=0.24\textwidth]{BrainProtonDensitySlice.eps} // \includegraphics[width=0.24\textwidth]{ConfidenceConnectedOutput1.eps} // \includegraphics[width=0.24\textwidth]{ConfidenceConnectedOutput2.eps} // \includegraphics[width=0.24\textwidth]{ConfidenceConnectedOutput3.eps} // \itkcaption[ConfidenceConnected segmentation results]{Segmentation results // for the ConfidenceConnected filter for various seed points.} // \label{fig:ConfidenceConnectedOutput} // \end{figure} // // Note that the gray matter is not being completely segmented. This // illustrates the vulnerability of the region growing methods when the // anatomical structures to be segmented do not have a homogeneous // statistical distribution over the image space. You may want to // experiment with different numbers of iterations to verify how the // accepted region will extend. return 0; }