1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 
19 // This example demostrates usage of the itk::BayesianClassifierImageFilter
20 // The input to this example is an itk::VectorImage that represents pixel
21 // memberships to 'n' classes.
22 //
23 // This image is conveniently generated by the BayesianClassifierInitializer.cxx
24 // example.
25 //
26 // The output of the filter is a label map (an image of unsigned char's) with
27 // pixel values indicating the classes they correspond to. Pixels with intensity 0
28 // belong to the 0th class, 1 belong to the 1st class etc. The classification
29 // is done by applying a Maximum decision rule to the posterior image.
30 //
31 // The filter allows you to specify a prior image as well, (although this is not
32 // done in this example). The prior image, if specified will be a itk::VectorImage
33 // with as many components as the number of classes. The posterior image is
34 // then generated by multiplying the prior image with the membership image. If
35 // the prior image is not specified, the posterior image is the same as the
36 // membership image.
37 //
38 // The filter optionally accepts a smoothingIterations argument. See the
39 // itk::BayesianClassifierImageFilter for details on how this affects the
40 // classification. The philosophy is that the filter allows you to iteratively
41 // smooth the posteriors prior to applying the decision rule. It is hoped
42 // that this would yield a better classification. The user will need to plug
43 // in his own smoothing filter. In this case, we specify a
44 // GradientAnisotropicDiffusionImageFilter.
45 //
46 // Example args:
47 //   Memberships.mhd Labelmap.png  3
48 
49 #include "itkImage.h"
50 #include "itkImageFileReader.h"
51 #include "itkBayesianClassifierImageFilter.h"
52 #include "itkImageFileWriter.h"
53 #include "itkGradientAnisotropicDiffusionImageFilter.h"
54 #include "itkRescaleIntensityImageFilter.h"
55 
main(int argc,char * argv[])56 int main(int argc, char* argv[] )
57 {
58 
59   if( argc < 3 )
60     {
61     std::cerr << "Usage: " << std::endl;
62     std::cerr << argv[0] << " inputImageFile outputImageFile [smoothingIterations]" << std::endl;
63     return EXIT_FAILURE;
64     }
65 
66   // input parameters
67   const char * membershipImageFileName  = argv[1];
68   const char * labelMapImageFileName    = argv[2];
69 
70   // setup reader
71   constexpr unsigned int Dimension = 2;
72   using InputPixelType = float;
73   using InputImageType = itk::VectorImage< InputPixelType, Dimension >;
74   using ReaderType = itk::ImageFileReader< InputImageType >;
75 
76   ReaderType::Pointer reader = ReaderType::New();
77   reader->SetFileName( membershipImageFileName );
78 
79   using LabelType = unsigned char;
80   using PriorType = float;
81   using PosteriorType = float;
82 
83 
84   using ClassifierFilterType = itk::BayesianClassifierImageFilter<
85                               InputImageType,LabelType,
86                               PosteriorType,PriorType >;
87 
88   ClassifierFilterType::Pointer filter = ClassifierFilterType::New();
89 
90 
91   filter->SetInput( reader->GetOutput() );
92 
93   if( argv[3] )
94     {
95     filter->SetNumberOfSmoothingIterations( std::stoi( argv[3] ));
96     using ExtractedComponentImageType = ClassifierFilterType::ExtractedComponentImageType;
97     using SmoothingFilterType = itk::GradientAnisotropicDiffusionImageFilter<
98       ExtractedComponentImageType, ExtractedComponentImageType >;
99     SmoothingFilterType::Pointer smoother = SmoothingFilterType::New();
100     smoother->SetNumberOfIterations( 1 );
101     smoother->SetTimeStep( 0.125 );
102     smoother->SetConductanceParameter( 3 );
103     filter->SetSmoothingFilter( smoother );
104     }
105 
106 
107   // SET FILTER'S PRIOR PARAMETERS
108   // do nothing here to default to uniform priors
109   // otherwise set the priors to some user provided values
110 
111   //
112   // Setup writer.. Rescale the label map to the dynamic range of the
113   // datatype and write it
114   //
115   using ClassifierOutputImageType = ClassifierFilterType::OutputImageType;
116   using OutputImageType = itk::Image< unsigned char, Dimension >;
117   using RescalerType = itk::RescaleIntensityImageFilter<
118     ClassifierOutputImageType, OutputImageType >;
119   RescalerType::Pointer rescaler = RescalerType::New();
120   rescaler->SetInput( filter->GetOutput() );
121   rescaler->SetOutputMinimum( 0 );
122   rescaler->SetOutputMaximum( 255 );
123 
124   using WriterType = itk::ImageFileWriter< OutputImageType >;
125 
126   WriterType::Pointer writer = WriterType::New();
127   writer->SetFileName( labelMapImageFileName );
128 
129   //
130   // Write labelmap to file
131   //
132   writer->SetInput( rescaler->GetOutput() );
133 
134   try
135     {
136     writer->Update();
137     }
138   catch( itk::ExceptionObject & excp )
139     {
140     std::cerr << "Exception caught: " << std::endl;
141     std::cerr << excp << std::endl;
142     return EXIT_FAILURE;
143     }
144 
145   // Testing print
146   filter->Print( std::cout );
147   std::cout << "Test passed." << std::endl;
148 
149   return EXIT_SUCCESS;
150 
151 }
152