OTB  10.0.0
Orfeo Toolbox
otbStreamingInnerProductVectorImageFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1999-2011 Insight Software Consortium
3  * Copyright (C) 2005-2024 Centre National d'Etudes Spatiales (CNES)
4  *
5  * This file is part of Orfeo Toolbox
6  *
7  * https://www.orfeo-toolbox.org/
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #ifndef otbStreamingInnerProductVectorImageFilter_hxx
23 #define otbStreamingInnerProductVectorImageFilter_hxx
25 
26 #include "itkImageRegionIterator.h"
27 #include "itkImageRegionConstIteratorWithIndex.h"
28 #include "itkNumericTraits.h"
29 #include "itkProgressReporter.h"
30 #include "otbMacro.h"
31 
32 namespace otb
33 {
34 
35 template <class TInputImage>
37 {
38  this->DynamicMultiThreadingOff();
39  // first output is a copy of the image, DataObject created by
40  // superclass
41  //
42  // allocate the data objects for the outputs which are
43  // just decorators around pixel types
44 
45  // allocate the data objects for the outputs which are
46  // just decorators around matrix types
47  typename ImageType::Pointer output1 = static_cast<ImageType*>(this->MakeOutput(0).GetPointer());
48  this->itk::ProcessObject::SetNthOutput(0, output1.GetPointer());
49  typename MatrixObjectType::Pointer output2 = static_cast<MatrixObjectType*>(this->MakeOutput(1).GetPointer());
50  this->itk::ProcessObject::SetNthOutput(1, output2.GetPointer());
51 
52  m_CenterData = true;
53 }
54 
55 template <class TInputImage>
57 {
58  switch (output)
59  {
60  case 0:
61  return static_cast<itk::DataObject*>(TInputImage::New().GetPointer());
62  break;
63  case 1:
64  return static_cast<itk::DataObject*>(MatrixObjectType::New().GetPointer());
65  break;
66  default:
67  // might as well make an image
68  return static_cast<itk::DataObject*>(TInputImage::New().GetPointer());
69  break;
70  }
71 }
72 
73 template <class TInputImage>
75 {
76  return static_cast<MatrixObjectType*>(this->itk::ProcessObject::GetOutput(1));
77 }
78 
79 template <class TInputImage>
82 {
83  return static_cast<const MatrixObjectType*>(this->itk::ProcessObject::GetOutput(1));
84 }
85 
86 template <class TInputImage>
88 {
89  Superclass::GenerateOutputInformation();
90  if (this->GetInput())
91  {
92  this->GetOutput()->CopyInformation(this->GetInput());
93  this->GetOutput()->SetLargestPossibleRegion(this->GetInput()->GetLargestPossibleRegion());
94 
95  if (this->GetOutput()->GetRequestedRegion().GetNumberOfPixels() == 0)
96  {
97  this->GetOutput()->SetRequestedRegion(this->GetOutput()->GetLargestPossibleRegion());
98  }
99  }
100 }
101 
102 template <class TInputImage>
104 {
105  // This is commented to prevent the streaming of the whole image for the first stream strip
106  // It shall not cause any problem because the output image of this filter is not intended to be used.
107  // InputImagePointer image = const_cast< TInputImage * >( this->GetInput() );
108  // this->GraftOutput( image );
109  // Nothing that needs to be allocated for the remaining outputs
110 }
111 
112 template <class TInputImage>
114 {
115  TInputImage* inputPtr = const_cast<TInputImage*>(this->GetInput());
116  inputPtr->UpdateOutputInformation();
117 
118  if (this->GetOutput()->GetRequestedRegion().GetNumberOfPixels() == 0)
119  {
120  this->GetOutput()->SetRequestedRegion(this->GetOutput()->GetLargestPossibleRegion());
121  }
122 
123  unsigned int numberOfThreads = this->GetNumberOfWorkUnits();
124  unsigned int numberOfTrainingImages = inputPtr->GetNumberOfComponentsPerPixel();
125  // Set the number of training image
126  MatrixType tempMatrix;
127  tempMatrix.set_size(numberOfTrainingImages, numberOfTrainingImages);
128  tempMatrix.fill(0);
129  m_ThreadInnerProduct = ArrayMatrixType(numberOfThreads, tempMatrix);
130 
131  MatrixType initMatrix;
132  initMatrix.set_size(numberOfTrainingImages, numberOfTrainingImages);
133  initMatrix.fill(0);
134  this->GetInnerProductOutput()->Set(initMatrix);
135 }
136 
137 template <class TInputImage>
139 {
140  // Compute Inner product Matrix
141  TInputImage* inputPtr = const_cast<TInputImage*>(this->GetInput());
142  unsigned int numberOfTrainingImages = inputPtr->GetNumberOfComponentsPerPixel();
143  unsigned int numberOfThreads = this->GetNumberOfWorkUnits();
144  MatrixType innerProduct;
145  innerProduct.set_size(numberOfTrainingImages, numberOfTrainingImages);
146  innerProduct.fill(0);
147 
148  // Concatenate threaded matrix
149  for (unsigned int thread = 0; thread < numberOfThreads; thread++)
150  {
151  innerProduct += m_ThreadInnerProduct[thread];
152  }
153 
154  //---------------------------------------------------------------------
155  // Fill the rest of the inner product matrix and make it symmetric
156  //---------------------------------------------------------------------
157  for (unsigned int band_x = 0; band_x < (numberOfTrainingImages - 1); ++band_x)
158  {
159  for (unsigned int band_y = band_x + 1; band_y < numberOfTrainingImages; ++band_y)
160  {
161  innerProduct[band_x][band_y] = innerProduct[band_y][band_x];
162  } // end band_y loop
163  } // end band_x loop
164 
165  if ((numberOfTrainingImages - 1) != 0)
166  {
167  innerProduct /= (numberOfTrainingImages - 1);
168  }
169  else
170  {
171  innerProduct.fill(0);
172  }
173 
174  // Set the output
175  this->GetInnerProductOutput()->Set(innerProduct);
176 }
177 
178 template <class TInputImage>
179 void PersistentInnerProductVectorImageFilter<TInputImage>::ThreadedGenerateData(const RegionType& outputRegionForThread, itk::ThreadIdType threadId)
180 {
184  InputImagePointer inputPtr = const_cast<TInputImage*>(this->GetInput());
185  // support progress methods/callbacks
186  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
187  unsigned int numberOfTrainingImages = inputPtr->GetNumberOfComponentsPerPixel();
189 
190  itk::ImageRegionConstIterator<TInputImage> it(inputPtr, outputRegionForThread);
191  if (m_CenterData == true)
192  {
193  it.GoToBegin();
194  // do the work
195  while (!it.IsAtEnd())
196  {
197  PixelType vectorValue = it.Get();
198  double mean(0.);
199  for (unsigned int i = 0; i < vectorValue.GetSize(); ++i)
200  {
201  mean += static_cast<double>(vectorValue[i]);
202  }
203  mean /= static_cast<double>(vectorValue.GetSize());
204 
205  // Matrix iteration
206  for (unsigned int band_x = 0; band_x < numberOfTrainingImages; ++band_x)
207  {
208  for (unsigned int band_y = 0; band_y <= band_x; ++band_y)
209  {
210  m_ThreadInnerProduct[threadId][band_x][band_y] +=
211  (static_cast<double>(vectorValue[band_x]) - mean) * (static_cast<double>(vectorValue[band_y]) - mean);
212  } // end: band_y loop
213  } // end: band_x loop
214  ++it;
215  progress.CompletedPixel();
216  } // end: looping through the image
217  }
218  else
219  {
220  it.GoToBegin();
221  // do the work
222  while (!it.IsAtEnd())
223  {
224  PixelType vectorValue = it.Get();
225  // Matrix iteration
226  for (unsigned int band_x = 0; band_x < numberOfTrainingImages; ++band_x)
227  {
228  for (unsigned int band_y = 0; band_y <= band_x; ++band_y)
229  {
230  m_ThreadInnerProduct[threadId][band_x][band_y] += (static_cast<double>(vectorValue[band_x])) * (static_cast<double>(vectorValue[band_y]));
231  } // end: band_y loop
232  } // end: band_x loop
233  ++it;
234  progress.CompletedPixel();
235  } // end: looping through the image
236  }
237 }
238 
239 template <class TImage>
240 void PersistentInnerProductVectorImageFilter<TImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
241 {
242  Superclass::PrintSelf(os, indent);
243  os << indent << "m_CenterData: " << m_CenterData << std::endl;
244  os << indent << "InnerProduct: " << this->GetInnerProductOutput()->Get() << std::endl;
245 }
246 
247 } // end namespace otb
248 #endif
itk::SimpleDataObjectDecorator< MatrixType > MatrixObjectType
itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType
void ThreadedGenerateData(const RegionType &outputRegionForThread, itk::ThreadIdType threadId) override
void PrintSelf(std::ostream &os, itk::Indent indent) const override
DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx) override
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.