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