2424#include " itkDiscreteGaussianImageFilter.h"
2525#include " itkLinearInterpolateImageFunction.h"
2626#include " itkResampleImageFilter.h"
27+ #include " itkVectorIndexSelectionCastImageFilter.h"
28+ #include " itkComposeImageFilter.h"
2729
2830#include " downsampleSigma.h"
2931
32+ // Scalar image processing
33+ template <typename TImage>
34+ int
35+ DownsampleScalarImage (itk::wasm::Pipeline & pipeline, const TImage * inputImage)
36+ {
37+ using ImageType = TImage;
38+ constexpr unsigned int ImageDimension = ImageType::ImageDimension;
39+
40+ pipeline.get_option (" input" )->required ()->type_name (" INPUT_IMAGE" );
41+
42+ std::vector<unsigned int > shrinkFactors{ 2 , 2 };
43+ pipeline.add_option (" -s,--shrink-factors" , shrinkFactors, " Shrink factors" )->required ()->type_size (ImageDimension);
44+
45+ std::vector<unsigned int > cropRadius;
46+ pipeline.add_option (" -r,--crop-radius" , cropRadius, " Optional crop radius in pixel units." )
47+ ->type_size (ImageDimension);
48+
49+ using OutputImageType = itk::wasm::OutputImage<ImageType>;
50+ OutputImageType downsampledImage;
51+ pipeline.add_option (" downsampled" , downsampledImage, " Output downsampled image" )
52+ ->required ()
53+ ->type_name (" OUTPUT_IMAGE" );
54+
55+ ITK_WASM_PARSE (pipeline);
56+
57+ auto sigmaValues = downsampleSigma (shrinkFactors);
58+
59+ using GaussianFilterType = itk::DiscreteGaussianImageFilter<ImageType, ImageType>;
60+ auto gaussianFilter = GaussianFilterType::New ();
61+ gaussianFilter->SetInput (inputImage);
62+ typename GaussianFilterType::ArrayType sigmaArray;
63+ for (unsigned int i = 0 ; i < ImageDimension; ++i)
64+ {
65+ sigmaArray[i] = sigmaValues[i];
66+ }
67+ gaussianFilter->SetSigmaArray (sigmaArray);
68+ gaussianFilter->SetUseImageSpacingOff ();
69+
70+ const auto inputOrigin = inputImage->GetOrigin ();
71+ const auto inputSpacing = inputImage->GetSpacing ();
72+ const auto inputSize = inputImage->GetLargestPossibleRegion ().GetSize ();
73+
74+ typename ImageType::PointType outputOrigin;
75+ typename ImageType::SpacingType outputSpacing;
76+ typename ImageType::SizeType outputSize;
77+ for (unsigned int i = 0 ; i < ImageDimension; ++i)
78+ {
79+ const double cropRadiusValue = cropRadius.size () ? cropRadius[i] : 0.0 ;
80+
81+ outputOrigin[i] = inputOrigin[i] + cropRadiusValue * inputSpacing[i];
82+ outputSpacing[i] = inputSpacing[i] * shrinkFactors[i];
83+ outputSize[i] = std::max<itk::SizeValueType>(0 , (inputSize[i] - 2 * cropRadiusValue) / shrinkFactors[i]);
84+ }
85+
86+ using InterpolatorType = itk::LinearInterpolateImageFunction<ImageType, double >;
87+ auto interpolator = InterpolatorType::New ();
88+
89+ using ResampleFilterType = itk::ResampleImageFilter<ImageType, ImageType>;
90+ auto shrinkFilter = ResampleFilterType::New ();
91+ shrinkFilter->SetInput (gaussianFilter->GetOutput ());
92+ shrinkFilter->SetInterpolator (interpolator);
93+ shrinkFilter->SetOutputOrigin (outputOrigin);
94+ shrinkFilter->SetOutputSpacing (outputSpacing);
95+ shrinkFilter->SetOutputDirection (inputImage->GetDirection ());
96+ shrinkFilter->SetSize (outputSize);
97+ shrinkFilter->SetOutputStartIndex (inputImage->GetLargestPossibleRegion ().GetIndex ());
98+
99+ ITK_WASM_CATCH_EXCEPTION (pipeline, shrinkFilter->UpdateLargestPossibleRegion ());
100+
101+ typename ImageType::ConstPointer result = shrinkFilter->GetOutput ();
102+ downsampledImage.Set (result);
103+
104+ return EXIT_SUCCESS;
105+ }
106+
30107template <typename TImage>
31108class PipelineFunctor
32109{
@@ -39,44 +116,64 @@ class PipelineFunctor
39116
40117 using InputImageType = itk::wasm::InputImage<ImageType>;
41118 InputImageType inputImage;
119+ pipeline.add_option (" input" , inputImage, " Input image" )->type_name (" INPUT_IMAGE" );
120+
121+ ITK_WASM_PRE_PARSE (pipeline);
122+
123+ typename ImageType::ConstPointer image = inputImage.Get ();
124+ return DownsampleScalarImage<ImageType>(pipeline, image);
125+ }
126+ };
127+
128+ // Specialization for VectorImage types
129+ template <typename TPixel, unsigned int VDimension>
130+ class PipelineFunctor <itk::VectorImage<TPixel, VDimension>>
131+ {
132+ public:
133+ int
134+ operator ()(itk::wasm::Pipeline & pipeline)
135+ {
136+ constexpr unsigned int Dimension = VDimension;
137+ using PixelType = TPixel;
138+ using VectorImageType = itk::VectorImage<PixelType, Dimension>;
139+ using ScalarImageType = itk::Image<PixelType, Dimension>;
140+
141+ using InputImageType = itk::wasm::InputImage<VectorImageType>;
142+ InputImageType inputImage;
42143 pipeline.add_option (" input" , inputImage, " Input image" )->required ()->type_name (" INPUT_IMAGE" );
43144
44145 std::vector<unsigned int > shrinkFactors{ 2 , 2 };
45- pipeline.add_option (" -s,--shrink-factors" , shrinkFactors, " Shrink factors" )->required ()->type_size (ImageDimension );
146+ pipeline.add_option (" -s,--shrink-factors" , shrinkFactors, " Shrink factors" )->required ()->type_size (Dimension );
46147
47148 std::vector<unsigned int > cropRadius;
48149 pipeline.add_option (" -r,--crop-radius" , cropRadius, " Optional crop radius in pixel units." )
49- ->type_size (ImageDimension );
150+ ->type_size (Dimension );
50151
51- using OutputImageType = itk::wasm::OutputImage<ImageType >;
152+ using OutputImageType = itk::wasm::OutputImage<VectorImageType >;
52153 OutputImageType downsampledImage;
53154 pipeline.add_option (" downsampled" , downsampledImage, " Output downsampled image" )
54155 ->required ()
55156 ->type_name (" OUTPUT_IMAGE" );
56157
57158 ITK_WASM_PARSE (pipeline);
58159
59- auto sigmaValues = downsampleSigma (shrinkFactors);
160+ // Get number of components
161+ const unsigned int numberOfComponents = inputImage.Get ()->GetNumberOfComponentsPerPixel ();
60162
61- using GaussianFilterType = itk::DiscreteGaussianImageFilter<ImageType, ImageType>;
62- auto gaussianFilter = GaussianFilterType::New ();
63- gaussianFilter->SetInput (inputImage.Get ());
64- typename GaussianFilterType::ArrayType sigmaArray;
65- for (unsigned int i = 0 ; i < ImageDimension; ++i)
66- {
67- sigmaArray[i] = sigmaValues[i];
68- }
69- gaussianFilter->SetSigmaArray (sigmaArray);
70- gaussianFilter->SetUseImageSpacingOff ();
163+ // Extract, process, and compose each component
164+ using ExtractFilterType = itk::VectorIndexSelectionCastImageFilter<VectorImageType, ScalarImageType>;
165+ using ComposeFilterType = itk::ComposeImageFilter<ScalarImageType>;
166+
167+ auto sigmaValues = downsampleSigma (shrinkFactors);
71168
72169 const auto inputOrigin = inputImage.Get ()->GetOrigin ();
73170 const auto inputSpacing = inputImage.Get ()->GetSpacing ();
74171 const auto inputSize = inputImage.Get ()->GetLargestPossibleRegion ().GetSize ();
75172
76- typename ImageType ::PointType outputOrigin;
77- typename ImageType ::SpacingType outputSpacing;
78- typename ImageType ::SizeType outputSize;
79- for (unsigned int i = 0 ; i < ImageDimension ; ++i)
173+ typename VectorImageType ::PointType outputOrigin;
174+ typename VectorImageType ::SpacingType outputSpacing;
175+ typename VectorImageType ::SizeType outputSize;
176+ for (unsigned int i = 0 ; i < Dimension ; ++i)
80177 {
81178 const double cropRadiusValue = cropRadius.size () ? cropRadius[i] : 0.0 ;
82179
@@ -85,23 +182,51 @@ class PipelineFunctor
85182 outputSize[i] = std::max<itk::SizeValueType>(0 , (inputSize[i] - 2 * cropRadiusValue) / shrinkFactors[i]);
86183 }
87184
88- using InterpolatorType = itk::LinearInterpolateImageFunction<ImageType, double >;
89- auto interpolator = InterpolatorType::New ();
185+ auto composeFilter = ComposeFilterType::New ();
186+
187+ auto extractFilter = ExtractFilterType::New ();
188+ extractFilter->SetInput (inputImage.Get ());
189+
190+ using GaussianFilterType = itk::DiscreteGaussianImageFilter<ScalarImageType, ScalarImageType>;
191+ auto gaussianFilter = GaussianFilterType::New ();
192+
193+ for (unsigned int component = 0 ; component < numberOfComponents; ++component)
194+ {
195+ // Extract component
196+ extractFilter->SetIndex (component);
197+
198+ // Smooth component
199+ gaussianFilter->SetInput (extractFilter->GetOutput ());
200+ typename GaussianFilterType::ArrayType sigmaArray;
201+ for (unsigned int i = 0 ; i < Dimension; ++i)
202+ {
203+ sigmaArray[i] = sigmaValues[i];
204+ }
205+ gaussianFilter->SetSigmaArray (sigmaArray);
206+ gaussianFilter->SetUseImageSpacingOff ();
90207
91- using ResampleFilterType = itk::ResampleImageFilter<ImageType, ImageType>;
92- auto shrinkFilter = ResampleFilterType::New ();
93- shrinkFilter->SetInput (gaussianFilter->GetOutput ());
94- shrinkFilter->SetInterpolator (interpolator);
95- shrinkFilter->SetOutputOrigin (outputOrigin);
96- shrinkFilter->SetOutputSpacing (outputSpacing);
97- shrinkFilter->SetOutputDirection (inputImage.Get ()->GetDirection ());
98- shrinkFilter->SetSize (outputSize);
99- shrinkFilter->SetOutputStartIndex (inputImage.Get ()->GetLargestPossibleRegion ().GetIndex ());
208+ // Resample component
209+ using InterpolatorType = itk::LinearInterpolateImageFunction<ScalarImageType, double >;
210+ auto interpolator = InterpolatorType::New ();
211+
212+ using ResampleFilterType = itk::ResampleImageFilter<ScalarImageType, ScalarImageType>;
213+ auto shrinkFilter = ResampleFilterType::New ();
214+ shrinkFilter->SetInput (gaussianFilter->GetOutput ());
215+ shrinkFilter->SetInterpolator (interpolator);
216+ shrinkFilter->SetOutputOrigin (outputOrigin);
217+ shrinkFilter->SetOutputSpacing (outputSpacing);
218+ shrinkFilter->SetOutputDirection (inputImage.Get ()->GetDirection ());
219+ shrinkFilter->SetSize (outputSize);
220+ shrinkFilter->SetOutputStartIndex (inputImage.Get ()->GetLargestPossibleRegion ().GetIndex ());
221+ shrinkFilter->UpdateLargestPossibleRegion ();
222+
223+ // Add to compose filter
224+ composeFilter->SetInput (component, shrinkFilter->GetOutput ());
225+ }
100226
101- ITK_WASM_CATCH_EXCEPTION (pipeline, shrinkFilter ->UpdateLargestPossibleRegion ());
227+ ITK_WASM_CATCH_EXCEPTION (pipeline, composeFilter ->UpdateLargestPossibleRegion ());
102228
103- typename ImageType::ConstPointer result = shrinkFilter->GetOutput ();
104- downsampledImage.Set (result);
229+ downsampledImage.Set (composeFilter->GetOutput ());
105230
106231 return EXIT_SUCCESS;
107232 }
@@ -123,5 +248,11 @@ main(int argc, char * argv[])
123248 uint64_t ,
124249 int64_t ,
125250 float ,
126- double >::Dimensions<2U , 3U , 4U , 5U >(" input" , pipeline);
251+ double ,
252+ itk::VariableLengthVector<uint8_t >,
253+ itk::VariableLengthVector<uint16_t >,
254+ itk::VariableLengthVector<int16_t >,
255+ itk::VariableLengthVector<float >,
256+ itk::VariableLengthVector<double >
257+ >::Dimensions<2U , 3U , 4U , 5U >(" input" , pipeline);
127258}
0 commit comments