GCC Code Coverage Report


Directory: ./
File: libs/filter/image/filters.hxx
Date: 2024-04-24 14:25:45
Exec Total Coverage
Lines: 0 27 0.0%
Branches: 0 36 0.0%

Line Branch Exec Source
1 /************************************************************************
2 *
3 * Copyright (C) 2018-2023 IRCAD France
4 * Copyright (C) 2018-2021 IHU Strasbourg
5 *
6 * This file is part of Sight.
7 *
8 * Sight is free software: you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Sight is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with Sight. If not, see <https://www.gnu.org/licenses/>.
20 *
21 ***********************************************************************/
22
23 #pragma once
24
25 #include "filter/image/filters.hpp"
26
27 #include <io/itk/itk.hpp>
28
29 #include <itkBinaryBallStructuringElement.h>
30 #include <itkBinaryFillholeImageFilter.h>
31 #include <itkBinaryThresholdImageFilter.h>
32 #include <itkConnectedComponentImageFilter.h>
33 #include <itkExtractImageFilter.h>
34 #include <itkFloodFilledImageFunctionConditionalConstIterator.h>
35 #include <itkGrayscaleMorphologicalClosingImageFilter.h>
36 #include <itkMedianImageFilter.h>
37 #include <itkRelabelComponentImageFilter.h>
38
39 namespace sight::filter::image
40 {
41
42 //------------------------------------------------------------------------------
43
44 template<typename IMAGEINPTR, typename IMAGELABELPTR>
45 void bug_work_around_labeling(
46 IMAGEINPTR _image_in,
47 IMAGELABELPTR _labeled,
48 typename IMAGEINPTR::ObjectType::PixelType _background
49 )
50 {
51 itk::ImageRegionIterator<typename IMAGEINPTR::ObjectType> i_it(_image_in, _image_in->GetLargestPossibleRegion());
52 itk::ImageRegionIterator<typename IMAGELABELPTR::ObjectType> l_it(_labeled, _labeled->GetLargestPossibleRegion());
53
54 while(!i_it.IsAtEnd())
55 {
56 if(i_it.Get() == _background)
57 {
58 l_it.Set(itk::NumericTraits<typename IMAGELABELPTR::ObjectType::PixelType>::Zero);
59 }
60
61 ++i_it;
62 ++l_it;
63 }
64 }
65
66 //------------------------------------------------------------------------------
67
68 template<typename IMAGE_TYPE, unsigned int DIM>
69 typename itk::Image<std::uint8_t, DIM>::Pointer threshold(
70 typename itk::Image<IMAGE_TYPE, DIM>::Pointer _image,
71 IMAGE_TYPE _lower_threshold,
72 IMAGE_TYPE _upper_threshold
73 )
74 {
75 // ITK threshold
76 typedef itk::BinaryThresholdImageFilter<itk::Image<IMAGE_TYPE, DIM>,
77 itk::Image<std::uint8_t, DIM> > BinaryThresholdImageFilter;
78 typename BinaryThresholdImageFilter::Pointer threshold_filter = BinaryThresholdImageFilter::New();
79 threshold_filter->SetInput(_image);
80 threshold_filter->SetInsideValue(std::numeric_limits<std::uint8_t>::max());
81 threshold_filter->SetOutsideValue(std::numeric_limits<std::uint8_t>::min());
82 threshold_filter->SetLowerThreshold(_lower_threshold);
83 threshold_filter->SetUpperThreshold(_upper_threshold);
84 threshold_filter->Update();
85
86 return threshold_filter->GetOutput();
87 }
88
89 //------------------------------------------------------------------------------
90
91 template<typename IMAGE_TYPE, unsigned int DIM>
92 typename itk::Image<IMAGE_TYPE, DIM>::Pointer median(
93 typename itk::Image<IMAGE_TYPE, DIM>::Pointer _image,
94 std::size_t _x,
95 std::size_t _y,
96 std::size_t _z
97 )
98 {
99 // ITK median filter
100 typedef itk::Image<IMAGE_TYPE, DIM> image_t;
101 typedef itk::MedianImageFilter<image_t, image_t> MedianImageFilter;
102 typename MedianImageFilter::Pointer median_filter = MedianImageFilter::New();
103
104 typename MedianImageFilter::radius_t radius;
105 radius[0] = _x;
106 radius[1] = _y;
107 radius[2] = _z;
108
109 median_filter->SetInput(_image);
110 median_filter->SetRadius(radius);
111 median_filter->Update();
112
113 return median_filter->GetOutput();
114 }
115
116 //------------------------------------------------------------------------------
117
118 template<typename IMAGE_TYPE, unsigned int DIM>
119 typename itk::Image<std::uint8_t, DIM>::Pointer labeling(
120 typename itk::Image<IMAGE_TYPE, DIM>::Pointer _image,
121 unsigned int _num_labels
122 )
123 {
124 // ITK median filter
125 typedef itk::Image<IMAGE_TYPE, DIM> image_t;
126 typedef itk::Image<std::uint8_t, 3> label_image_t;
127
128 // ITK labeling
129 // Connected component filter
130 typedef itk::ConnectedComponentImageFilter<image_t, label_image_t> ConnectedComponentFilter;
131 typename ConnectedComponentFilter::Pointer filter_cc = ConnectedComponentFilter::New();
132 filter_cc->SetInput(_image);
133 filter_cc->SetBackgroundValue(0); // ignored by ITK !!! fixed by (*)
134 filter_cc->SetFullyConnected(true);
135 filter_cc->Update();
136
137 typename label_image_t::Pointer labeled_img = filter_cc->GetOutput();
138 bug_work_around_labeling(_image, labeled_img, 0); // (*)
139
140 // Relabels connected component filter
141 typedef itk::RelabelComponentImageFilter<label_image_t, label_image_t> RelabelFilter;
142 typename RelabelFilter::Pointer relabel_filter = RelabelFilter::New();
143 relabel_filter->SetInPlace(true); // can be set inplace because it is an internal filter
144 relabel_filter->SetInput(labeled_img);
145 relabel_filter->Update();
146
147 // Output
148 typename label_image_t::Pointer img_out = relabel_filter->GetOutput();
149 typename itk::ImageRegionIterator<label_image_t> itk_it_out(img_out, img_out->GetBufferedRegion());
150
151 for(itk_it_out.GoToBegin() ; !itk_it_out.IsAtEnd() ; ++itk_it_out)
152 {
153 bool is_pixel = itk_it_out.Get() != itk::NumericTraits<IMAGE_TYPE>::Zero;
154
155 is_pixel = is_pixel && itk_it_out.Get() <= static_cast<IMAGE_TYPE>(_num_labels);
156
157 if(!is_pixel)
158 {
159 itk_it_out.Set(decltype(itk_it_out) ::PixelType(itk::NumericTraits<IMAGE_TYPE>::Zero));
160 }
161 }
162
163 return img_out;
164 }
165
166 //------------------------------------------------------------------------------
167
168 template<typename IMAGE_TYPE, unsigned int DIM>
169 typename itk::Image<IMAGE_TYPE, DIM>::Pointer closing(
170 typename itk::Image<IMAGE_TYPE, DIM>::Pointer _image,
171 std::size_t _x,
172 std::size_t _y,
173 std::size_t _z
174 )
175 {
176 // ITK median filter
177 typedef itk::Image<IMAGE_TYPE, DIM> image_t;
178 typedef itk::BinaryBallStructuringElement<IMAGE_TYPE, 3> structuring_element_t;
179 typedef itk::GrayscaleMorphologicalClosingImageFilter<image_t, image_t,
180 structuring_element_t> ITKFilterType;
181 typename image_t::Pointer itk_output_image;
182 typename ITKFilterType::Pointer filter = ITKFilterType::New();
183
184 typename ITKFilterType::Pointer::ObjectType::KernelType structuring_element;
185 typename ITKFilterType::Pointer::ObjectType::KernelType::size_t size;
186 size[0] = _x;
187 size[1] = _y;
188 size[2] = _z;
189
190 structuring_element.SetRadius(size);
191 structuring_element.CreateStructuringElement();
192 filter->SetKernel(structuring_element);
193 filter->SetInput(_image);
194 filter->Update();
195 itk_output_image = filter->GetOutput();
196
197 return itk_output_image;
198 }
199
200 //------------------------------------------------------------------------------
201
202 template<typename IMAGE_TYPE, unsigned int DIM>
203 typename itk::Image<IMAGE_TYPE, DIM>::Pointer fill_hole_2d(
204 typename itk::Image<IMAGE_TYPE, DIM>::Pointer _image,
205 unsigned int _direction,
206 IMAGE_TYPE _foreground
207 )
208 {
209 typedef itk::Image<IMAGE_TYPE, DIM> Image3D;
210 typedef itk::Image<IMAGE_TYPE, 2> Image2D;
211 std::uint64_t nb_planes = _image->GetBufferedRegion().GetSize(_direction);
212
213 for(std::uint64_t plane = 0 ; plane < nb_planes ; ++plane)
214 {
215 itk::ImageRegion<3> region_to_extract = _image->GetBufferedRegion();
216
217 typedef typename itk::ExtractImageFilter<Image3D, Image2D> ExtractFilter;
218 typename ExtractFilter::Pointer extractor = ExtractFilter::New();
219
220 // extracts plane along other "direction"
221 region_to_extract.SetSize(_direction, 0);
222 region_to_extract.SetIndex(_direction, static_cast<std::int64_t>(plane));
223 extractor->InPlaceOff();
224 extractor->set_input(_image);
225 extractor->SetExtractionRegion(region_to_extract);
226 extractor->SetDirectionCollapseToIdentity();
227 extractor->Update();
228
229 typename Image2D::Pointer image_2d = extractor->GetOutput();
230
231 typedef typename itk::BinaryFillholeImageFilter<Image2D> FillHoleFilter;
232 typename FillHoleFilter::Pointer fill_hole = FillHoleFilter::New();
233
234 fill_hole->set_input(image_2d);
235 fill_hole->SetForegroundValue(_foreground);
236 fill_hole->SetFullyConnected(true);
237 fill_hole->Update();
238
239 itk::ImageRegionConstIterator<Image2D> img_2d_it(fill_hole->GetOutput(),
240 fill_hole->GetOutput()->GetBufferedRegion());
241
242 // creates a non "empty" region
243 region_to_extract.SetSize(_direction, 1);
244 itk::ImageRegionIterator<Image3D> img_3d_it(_image, region_to_extract);
245 img_3d_it.GoToBegin();
246 img_2d_it.GoToBegin();
247 while(img_3d_it.IsAtEnd() == false)
248 {
249 img_3d_it.Set(img_2d_it.Get());
250 ++img_3d_it;
251 ++img_2d_it;
252 }
253 }
254
255 return _image;
256 }
257
258 } // namespace sight::filter::image.
259