MITK-IGT
IGT Extension of MITK
Loading...
Searching...
No Matches
mitkToFCompositeFilter.cpp
Go to the documentation of this file.
1/*============================================================================
2
3The Medical Imaging Interaction Toolkit (MITK)
4
5Copyright (c) German Cancer Research Center (DKFZ)
6All rights reserved.
7
8Use of this source code is governed by a 3-clause BSD license that can be
9found in the LICENSE file.
10
11============================================================================*/
12
14#include <mitkInstantiateAccessFunctions.h>
15#include "mitkImageReadAccessor.h"
16
17#include <itkImage.h>
18
19#include <opencv2/imgproc/imgproc_c.h>
20
21mitk::ToFCompositeFilter::ToFCompositeFilter() : m_SegmentationMask(nullptr), m_ImageWidth(0), m_ImageHeight(0), m_ImageSize(0),
22m_IplDistanceImage(nullptr), m_IplOutputImage(nullptr), m_ItkInputImage(nullptr), m_ApplyTemporalMedianFilter(false), m_ApplyAverageFilter(false),
23 m_ApplyMedianFilter(false), m_ApplyThresholdFilter(false), m_ApplyMaskSegmentation(false), m_ApplyBilateralFilter(false), m_DataBuffer(nullptr),
24m_DataBufferCurrentIndex(0), m_DataBufferMaxSize(0), m_TemporalMedianFilterNumOfFrames(10), m_ThresholdFilterMin(1),
25m_ThresholdFilterMax(7000), m_BilateralFilterDomainSigma(2), m_BilateralFilterRangeSigma(60), m_BilateralFilterKernelRadius(0)
26{
27}
28
30{
31 cvReleaseImage(&(this->m_IplDistanceImage));
32 cvReleaseImage(&(this->m_IplOutputImage));
33 if (m_DataBuffer!=nullptr)
34 {
35 delete [] m_DataBuffer;
36 }
37}
38
39void mitk::ToFCompositeFilter::SetInput( const InputImageType* distanceImage )
40{
41 this->SetInput(0, distanceImage);
42}
43
44void mitk::ToFCompositeFilter::SetInput( unsigned int idx, const InputImageType* distanceImage )
45{
46 if ((distanceImage == nullptr) && (idx == this->GetNumberOfInputs() - 1)) // if the last input is set to nullptr, reduce the number of inputs by one
47 {
48 this->SetNumberOfIndexedInputs(this->GetNumberOfInputs() - 1);
49 }
50 else
51 {
52 if (idx==0) //create IPL image holding distance data
53 {
54 if (!distanceImage->IsEmpty())
55 {
56 this->m_ImageWidth = distanceImage->GetDimension(0);
57 this->m_ImageHeight = distanceImage->GetDimension(1);
58 this->m_ImageSize = this->m_ImageWidth * this->m_ImageHeight * sizeof(float);
59
60 if (this->m_IplDistanceImage != nullptr)
61 {
62 cvReleaseImage(&(this->m_IplDistanceImage));
63 }
64 ImageReadAccessor distImgAcc(distanceImage, distanceImage->GetSliceData(0,0,0));
65 float* distanceFloatData = (float*) distImgAcc.GetData();
66 this->m_IplDistanceImage = cvCreateImage(cvSize(this->m_ImageWidth, this->m_ImageHeight), IPL_DEPTH_32F, 1);
67 memcpy(this->m_IplDistanceImage->imageData, (void*)distanceFloatData, this->m_ImageSize);
68
69 if (this->m_IplOutputImage != nullptr)
70 {
71 cvReleaseImage(&(this->m_IplOutputImage));
72 }
73 this->m_IplOutputImage = cvCreateImage(cvSize(this->m_ImageWidth, this->m_ImageHeight), IPL_DEPTH_32F, 1);
74
75 CreateItkImage(this->m_ItkInputImage);
76 }
77 }
78 this->ProcessObject::SetNthInput(idx, const_cast<InputImageType*>(distanceImage)); // Process object is not const-correct so the const_cast is required here
79 }
80
81 this->CreateOutputsForAllInputs();
82}
83
85{
86 return this->GetInput(0);
87}
88
89 mitk::Image* mitk::ToFCompositeFilter::GetInput( unsigned int idx )
90{
91 if (this->GetNumberOfInputs() < 1)
92 return nullptr; //TODO: geeignete exception werfen
93 return static_cast< mitk::Image*>(this->ProcessObject::GetInput(idx));
94}
95
97{
98 // copy input 1...n to output 1...n
99 for (unsigned int idx=0; idx<this->GetNumberOfOutputs(); idx++)
100 {
101 mitk::Image::Pointer outputImage = this->GetOutput(idx);
102 mitk::Image::Pointer inputImage = this->GetInput(idx);
103 if (outputImage.IsNotNull()&&inputImage.IsNotNull())
104 {
105 ImageReadAccessor inputAcc(inputImage, inputImage->GetSliceData());
106 outputImage->CopyInformation(inputImage);
107 outputImage->Initialize(inputImage->GetPixelType(),inputImage->GetDimension(),inputImage->GetDimensions());
108 outputImage->SetSlice(inputAcc.GetData());
109 }
110 }
111 //mitk::Image::Pointer outputDistanceImage = this->GetOutput();
112 ImageReadAccessor outputAcc(this->GetOutput(), this->GetOutput()->GetSliceData(0, 0, 0) );
113 float* outputDistanceFloatData = (float*) outputAcc.GetData();
114
115 //mitk::Image::Pointer inputDistanceImage = this->GetInput();
116 ImageReadAccessor inputAcc(this->GetInput(), this->GetInput()->GetSliceData(0, 0, 0) );
117
118 // copy initial distance image to ipl image
119 float* distanceFloatData = (float*)inputAcc.GetData();
120 memcpy(this->m_IplDistanceImage->imageData, (void*)distanceFloatData, this->m_ImageSize);
121 if (m_ApplyThresholdFilter||m_ApplyMaskSegmentation)
122 {
123 ProcessSegmentation(this->m_IplDistanceImage);
124 }
125 if (this->m_ApplyTemporalMedianFilter||this->m_ApplyAverageFilter)
126 {
127 ProcessStreamedQuickSelectMedianImageFilter(this->m_IplDistanceImage);
128 }
129 if (this->m_ApplyMedianFilter)
130 {
131 ProcessCVMedianFilter(this->m_IplDistanceImage, this->m_IplOutputImage);
132 memcpy( this->m_IplDistanceImage->imageData, this->m_IplOutputImage->imageData, this->m_ImageSize );
133 }
134 if (this->m_ApplyBilateralFilter)
135 {
136 float* itkFloatData = this->m_ItkInputImage->GetBufferPointer();
137 memcpy(itkFloatData, this->m_IplDistanceImage->imageData, this->m_ImageSize );
138 ItkImageType2D::Pointer itkOutputImage = ProcessItkBilateralFilter(this->m_ItkInputImage);
139 memcpy( this->m_IplDistanceImage->imageData, itkOutputImage->GetBufferPointer(), this->m_ImageSize );
140
141 //ProcessCVBilateralFilter(this->m_IplDistanceImage, this->m_OutputIplImage, domainSigma, rangeSigma, kernelRadius);
142 //memcpy( distanceFloatData, this->m_OutputIplImage->imageData, distanceImageSize );
143 }
144 memcpy( outputDistanceFloatData, this->m_IplDistanceImage->imageData, this->m_ImageSize );
145}
146
148{
149 this->SetNumberOfIndexedOutputs(this->GetNumberOfInputs()); // create outputs for all inputs
150 for (unsigned int idx = 0; idx < this->GetNumberOfIndexedInputs(); ++idx)
151 {
152 if (this->GetOutput(idx) == nullptr)
153 {
154 DataObjectPointer newOutput = this->MakeOutput(idx);
155 this->SetNthOutput(idx, newOutput);
156 }
157 }
158 this->Modified();
159}
160
162{
163 mitk::Image::ConstPointer input = this->GetInput();
164 mitk::Image::Pointer output = this->GetOutput();
165
166 if (output->IsInitialized())
167 return;
168
169 itkDebugMacro(<<"GenerateOutputInformation()");
170
171 output->Initialize(input->GetPixelType(), *input->GetTimeGeometry());
172 output->SetPropertyList(input->GetPropertyList()->Clone());
173}
174
176{
177 char* segmentationMask;
178 if (m_SegmentationMask.IsNotNull())
179 {
180 ImageReadAccessor segMaskAcc(m_SegmentationMask, m_SegmentationMask->GetSliceData(0,0,0));
181 segmentationMask = (char*)segMaskAcc.GetData();
182 }
183 else
184 {
185 segmentationMask = nullptr;
186 }
187 float *f = (float*)inputIplImage->imageData;
188 for(int i=0; i<this->m_ImageWidth*this->m_ImageHeight; i++)
189 {
190 if (this->m_ApplyThresholdFilter)
191 {
192 if (f[i]<=m_ThresholdFilterMin)
193 {
194 f[i] = 0.0;
195 }
196 else if (f[i]>=m_ThresholdFilterMax)
197 {
198 f[i] = 0.0;
199 }
200 }
201 if (this->m_ApplyMaskSegmentation)
202 {
203 if (segmentationMask)
204 {
205 if (segmentationMask[i]==0)
206 {
207 f[i] = 0.0;
208 }
209 }
210 }
211 }
212}
213
214ItkImageType2D::Pointer mitk::ToFCompositeFilter::ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage)
215{
216 ItkImageType2D::Pointer outputItkImage;
217 BilateralFilterType::Pointer bilateralFilter = BilateralFilterType::New();
218 bilateralFilter->SetInput(inputItkImage);
219 bilateralFilter->SetDomainSigma(m_BilateralFilterDomainSigma);
220 bilateralFilter->SetRangeSigma(m_BilateralFilterRangeSigma);
221 //bilateralFilter->SetRadius(m_BilateralFilterKernelRadius);
222 outputItkImage = bilateralFilter->GetOutput();
223 outputItkImage->Update();
224 return outputItkImage;
225}
226
227void mitk::ToFCompositeFilter::ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage)
228{
229 int diameter = m_BilateralFilterKernelRadius;
230 double sigmaColor = m_BilateralFilterRangeSigma;
231 double sigmaSpace = m_BilateralFilterDomainSigma;
232 cvSmooth(inputIplImage, outputIplImage, CV_BILATERAL, diameter, 0, sigmaColor, sigmaSpace);
233}
234
235void mitk::ToFCompositeFilter::ProcessCVMedianFilter(IplImage* inputIplImage, IplImage* outputIplImage, int radius)
236{
237 cvSmooth(inputIplImage, outputIplImage, CV_MEDIAN, radius, 0, 0, 0);
238}
239
241{
242 float* data = (float*)inputIplImage->imageData;
243
244 int imageSize = inputIplImage->width * inputIplImage->height;
245 float* tmpArray;
246
247 if (this->m_TemporalMedianFilterNumOfFrames == 0)
248 {
249 return;
250 }
251
252 if (m_TemporalMedianFilterNumOfFrames != this->m_DataBufferMaxSize) // reset
253 {
254 //delete current buffer
255 for( int i=0; i<this->m_DataBufferMaxSize; i++ ) {
256 delete[] this->m_DataBuffer[i];
257 }
258 if (this->m_DataBuffer != nullptr)
259 {
260 delete[] this->m_DataBuffer;
261 }
262
263 this->m_DataBufferMaxSize = m_TemporalMedianFilterNumOfFrames;
264
265 // create new buffer with current size
266 this->m_DataBuffer = new float*[this->m_DataBufferMaxSize];
267 for(int i=0; i<this->m_DataBufferMaxSize; i++)
268 {
269 this->m_DataBuffer[i] = nullptr;
270 }
271 this->m_DataBufferCurrentIndex = 0;
272 }
273
274 int currentBufferSize = this->m_DataBufferMaxSize;
275 tmpArray = new float[this->m_DataBufferMaxSize];
276
277 // copy data to buffer
278 if (this->m_DataBuffer[this->m_DataBufferCurrentIndex] == nullptr)
279 {
280 this->m_DataBuffer[this->m_DataBufferCurrentIndex] = new float[imageSize];
281 currentBufferSize = this->m_DataBufferCurrentIndex + 1;
282 }
283
284 for(int j=0; j<imageSize; j++)
285 {
286 this->m_DataBuffer[this->m_DataBufferCurrentIndex][j] = data[j];
287 }
288
289 float tmpValue = 0.0f;
290 for(int i=0; i<imageSize; i++)
291 {
292 if (m_ApplyAverageFilter)
293 {
294 tmpValue = 0.0f;
295 for(int j=0; j<currentBufferSize; j++)
296 {
297 tmpValue+=this->m_DataBuffer[j][i];
298 }
299 data[i] = tmpValue/currentBufferSize;
300 }
301 else if (m_ApplyTemporalMedianFilter)
302 {
303 for(int j=0; j<currentBufferSize; j++)
304 {
305 tmpArray[j] = this->m_DataBuffer[j][i];
306 }
307 data[i] = quick_select(tmpArray, currentBufferSize);
308 }
309 }
310
311 this->m_DataBufferCurrentIndex = (this->m_DataBufferCurrentIndex + 1) % this->m_DataBufferMaxSize;
312
313 delete[] tmpArray;
314}
315
316#define ELEM_SWAP(a,b) { float t=(a);(a)=(b);(b)=t; }
318{
319 int low = 0;
320 int high = n-1;
321 int median = (low + high)/2;
322 int middle = 0;
323 int ll = 0;
324 int hh = 0;
325 for (;;) {
326 if (high <= low) /* One element only */
327 return arr[median] ;
328 if (high == low + 1) { /* Two elements only */
329 if (arr[low] > arr[high])
330 ELEM_SWAP(arr[low], arr[high]) ;
331 return arr[median] ;
332 }
333 /* Find median of low, middle and high items; swap into position low */
334 middle = (low + high) / 2;
335 if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ;
336 if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ;
337 if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
338 /* Swap low item (now in position middle) into position (low+1) */
339 ELEM_SWAP(arr[middle], arr[low+1]) ;
340 /* Nibble from each end towards middle, swapping items when stuck */
341 ll = low + 1;
342 hh = high;
343 for (;;) {
344 do ll++; while (arr[low] > arr[ll]) ;
345 do hh--; while (arr[hh] > arr[low]) ;
346 if (hh < ll)
347 break;
348 ELEM_SWAP(arr[ll], arr[hh]) ;
349 }
350 /* Swap middle item (in position low) back into correct position */
351 ELEM_SWAP(arr[low], arr[hh]) ;
352 /* Re-set active partition */
353 if (hh <= median)
354 low = ll;
355 if (hh >= median)
356 high = hh - 1;
357 }
358}
359#undef ELEM_SWAP
360
362{
363 this->m_TemporalMedianFilterNumOfFrames = tmporalMedianFilterNumOfFrames;
364}
365
367{
368 if (min > max)
369 {
370 min = max;
371 }
372 this->m_ThresholdFilterMin = min;
373 this->m_ThresholdFilterMax = max;
374}
375
376void mitk::ToFCompositeFilter::SetBilateralFilterParameter(double domainSigma, double rangeSigma, int kernelRadius = 0)
377{
378 this->m_BilateralFilterDomainSigma = domainSigma;
379 this->m_BilateralFilterRangeSigma = rangeSigma;
380 this->m_BilateralFilterKernelRadius = kernelRadius;
381}
382
383void mitk::ToFCompositeFilter::CreateItkImage(ItkImageType2D::Pointer &itkInputImage)
384{
385 itkInputImage = ItkImageType2D::New();
386 ItkImageType2D::IndexType startIndex;
387 startIndex[0] = 0; // first index on X
388 startIndex[1] = 0; // first index on Y
389 ItkImageType2D::SizeType size;
390 size[0] = this->m_ImageWidth; // size along X
391 size[1] = this->m_ImageHeight; // size along Y
392 ItkImageType2D::RegionType region;
393 region.SetSize( size );
394 region.SetIndex( startIndex );
395 itkInputImage->SetRegions( region );
396 itkInputImage->Allocate();
397
398}
void SetThresholdFilterParameter(int min, int max)
Sets the parameters (lower, upper threshold) of the threshold filter.
void ProcessSegmentation(IplImage *inputIplImage)
Applies a mask and/or threshold segmentation to the input image. All pixels with values outside the m...
void ProcessCVBilateralFilter(IplImage *inputIplImage, IplImage *outputIplImage)
Applies the OpenCV bilateral filter to the input image.
void ProcessStreamedQuickSelectMedianImageFilter(IplImage *inputIplImage)
Performs temporal median filter on an image given the number of frames to be considered.
void SetBilateralFilterParameter(double domainSigma, double rangeSigma, int kernelRadius)
Sets the parameters (domain sigma, range sigma, kernel radius) of the bilateral filter.
void ProcessCVMedianFilter(IplImage *inputIplImage, IplImage *outputIplImage, int radius=3)
Applies the OpenCV median filter to the input image.
void SetInput(const InputImageType *distanceImage) override
sets the input of this filter
ItkImageType2D::Pointer ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage)
Applies the ITK bilateral filter to the input image.
Image * GetInput()
returns the input of this filter
ToFCompositeFilter()
standard constructor
void GenerateData() override
method generating the output of this filter. Called in the updated process of the pipeline....
~ToFCompositeFilter() override
standard destructor
void CreateOutputsForAllInputs()
Create an output for each input.
void SetTemporalMedianFilterParameter(int tmporalMedianFilterNumOfFrames)
Sets the parameter of the temporal median filter.
float quick_select(float arr[], int n)
Quickselect algorithm This Quickselect routine is based on the algorithm described in "Numerical reci...
void CreateItkImage(ItkImageType2D::Pointer &itkInputImage)
Initialize and allocate a 2D ITK image of dimension m_ImageWidth*m_ImageHeight.
#define ELEM_SWAP(a, b)