OTB  10.0.0
Orfeo Toolbox
otbBandMathImageFilter.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 otbBandMathImageFilter_hxx
23 #define otbBandMathImageFilter_hxx
24 #include "otbBandMathImageFilter.h"
25 
26 #include "itkImageRegionIterator.h"
27 #include "itkNumericTraits.h"
28 #include "itkProgressReporter.h"
29 #include "otbMacro.h"
30 
31 
32 #include <iostream>
33 #include <string>
34 
35 namespace otb
36 {
37 
39 template <class TImage>
41 {
42  this->DynamicMultiThreadingOff();
43  // This number will be incremented each time an image
44  // is added over the one minimumrequired
45  this->SetNumberOfRequiredInputs(1);
46  this->InPlaceOff();
48 
49  m_UnderflowCount = 0;
50  m_OverflowCount = 0;
51  m_ThreadUnderflow.SetSize(1);
52  m_ThreadOverflow.SetSize(1);
53 }
54 
56 template <class TImage>
58 {
59 }
60 
61 template <class TImage>
62 void BandMathImageFilter<TImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
63 {
64  Superclass::PrintSelf(os, indent);
65 
66  os << indent << "Expression: " << m_Expression << std::endl;
67  os << indent << "Computed values follow:" << std::endl;
68  os << indent << "UnderflowCount: " << m_UnderflowCount << std::endl;
69  os << indent << "OverflowCount: " << m_OverflowCount << std::endl;
70  os << indent << "itk::NumericTraits<PixelType>::NonpositiveMin() : " << itk::NumericTraits<PixelType>::NonpositiveMin() << std::endl;
71  os << indent << "itk::NumericTraits<PixelType>::max() : " << itk::NumericTraits<PixelType>::max() << std::endl;
72 }
73 
74 template <class TImage>
76 {
77  this->SetInput(idx, const_cast<TImage*>(image));
78  DataObjectPointerArraySizeType nbInput = this->GetNumberOfInputs();
79  m_VVarName.resize(nbInput + 4);
80  std::ostringstream varName;
81  varName << "b" << nbInput;
82  m_VVarName[idx] = varName.str();
83 
84  m_VVarName[idx + 1] = "idxX";
85  m_VVarName[idx + 2] = "idxY";
86  m_VVarName[idx + 3] = "idxPhyX";
87  m_VVarName[idx + 4] = "idxPhyY";
88 }
89 
90 template <class TImage>
91 void BandMathImageFilter<TImage>::SetNthInput(DataObjectPointerArraySizeType idx, const ImageType* image, const std::string& varName)
92 {
93  this->SetInput(idx, const_cast<TImage*>(image));
94  m_VVarName.resize(this->GetNumberOfInputs() + 4);
95  m_VVarName[idx] = varName;
96 
97  m_VVarName[idx + 1] = "idxX";
98  m_VVarName[idx + 2] = "idxY";
99  m_VVarName[idx + 3] = "idxPhyX";
100  m_VVarName[idx + 4] = "idxPhyY";
101 }
102 
103 template <class TImage>
105 {
106  m_VVarName[idx] = varName;
107 }
108 
109 template <typename TImage>
111 {
112  return const_cast<TImage*>(this->GetInput(idx));
113 }
114 
115 template <typename TImage>
116 void BandMathImageFilter<TImage>::SetExpression(const std::string& expression)
117 {
118  if (m_Expression != expression)
119  m_Expression = expression;
120  this->Modified();
121 }
122 
123 template <typename TImage>
125 {
126  return m_Expression;
127 }
128 
129 template <typename TImage>
131 {
132  return m_VVarName.at(idx);
133 }
134 
135 template <typename TImage>
137 {
138  typename std::vector<ParserType::Pointer>::iterator itParser;
139  unsigned int nbThreads = this->GetNumberOfWorkUnits();
140  unsigned int nbInputImages = this->GetNumberOfInputs();
141  unsigned int nbAccessIndex = 4; // to give access to image and physical index
142  unsigned int i, j;
143  unsigned int inputSize[2];
144  std::vector<std::string> tmpIdxVarNames;
145 
146  tmpIdxVarNames.resize(nbAccessIndex);
147 
148  tmpIdxVarNames.resize(nbAccessIndex);
149  tmpIdxVarNames[0] = "idxX";
150  tmpIdxVarNames[1] = "idxY";
151  tmpIdxVarNames[2] = "idxPhyX";
152  tmpIdxVarNames[3] = "idxPhyY";
153 
154  // Check if input image dimensions matches
155  inputSize[0] = this->GetNthInput(0)->GetLargestPossibleRegion().GetSize(0);
156  inputSize[1] = this->GetNthInput(0)->GetLargestPossibleRegion().GetSize(1);
157 
158  for (unsigned int p = 1; p < nbInputImages; p++)
159  {
160  if ((inputSize[0] != this->GetNthInput(p)->GetLargestPossibleRegion().GetSize(0)) ||
161  (inputSize[1] != this->GetNthInput(p)->GetLargestPossibleRegion().GetSize(1)))
162  {
163  itkExceptionMacro(<< "Input images must have the same dimensions." << std::endl
164  << "band #1 is [" << inputSize[0] << ";" << inputSize[1] << "]" << std::endl
165  << "band #" << p + 1 << " is [" << this->GetNthInput(p)->GetLargestPossibleRegion().GetSize(0) << ";"
166  << this->GetNthInput(p)->GetLargestPossibleRegion().GetSize(1) << "]");
167  }
168  }
169 
170  // Store images specs
171  m_Spacing = this->GetNthInput(0)->GetSignedSpacing();
172  m_Origin = this->GetNthInput(0)->GetOrigin();
173 
174  // Allocate and initialize the thread temporaries
175  m_ThreadUnderflow.SetSize(nbThreads);
176  m_ThreadUnderflow.Fill(0);
177  m_ThreadOverflow.SetSize(nbThreads);
178  m_ThreadOverflow.Fill(0);
179  m_VParser.resize(nbThreads);
180  m_AImage.resize(nbThreads);
181  m_NbVar = nbInputImages + nbAccessIndex;
182  m_VVarName.resize(m_NbVar);
183 
184  for (itParser = m_VParser.begin(); itParser < m_VParser.end(); itParser++)
185  {
186  *itParser = ParserType::New();
187  }
188 
189  for (i = 0; i < nbThreads; ++i)
190  {
191  m_AImage[i].resize(m_NbVar);
192  m_VParser[i]->SetExpr(m_Expression);
193 
194  for (j = 0; j < nbInputImages; ++j)
195  {
196  m_VParser[i]->DefineVar(m_VVarName[j], &(m_AImage[i][j]));
197  }
198 
199  for (j = nbInputImages; j < nbInputImages + nbAccessIndex; ++j)
200  {
201  m_VVarName[j] = tmpIdxVarNames[j - nbInputImages];
202  m_VParser[i]->DefineVar(m_VVarName[j], &(m_AImage[i][j]));
203  }
204  }
205 }
206 
207 template <typename TImage>
209 {
210  unsigned int nbThreads = this->GetNumberOfWorkUnits();
211  unsigned int i;
212 
213  m_UnderflowCount = 0;
214  m_OverflowCount = 0;
215 
216  // Accumulate counts for each thread
217  for (i = 0; i < nbThreads; ++i)
218  {
219  m_UnderflowCount += m_ThreadUnderflow[i];
220  m_OverflowCount += m_ThreadOverflow[i];
221  }
222 
223  if ((m_UnderflowCount != 0) || (m_OverflowCount != 0))
224  otbWarningMacro(<< std::endl
225  << "The Following Parsed Expression : " << this->GetExpression() << std::endl
226  << "Generated " << m_UnderflowCount << " Underflow(s) "
227  << "And " << m_OverflowCount << " Overflow(s) " << std::endl
228  << "The Parsed Expression, The Inputs And The Output "
229  << "Type May Be Incompatible !");
230 }
231 
232 template <typename TImage>
233 void BandMathImageFilter<TImage>::ThreadedGenerateData(const ImageRegionType& outputRegionForThread, itk::ThreadIdType threadId)
234 {
235  double value;
236  unsigned int j;
237  unsigned int nbInputImages = this->GetNumberOfInputs();
238 
239  typedef itk::ImageRegionConstIterator<TImage> ImageRegionConstIteratorType;
240 
241  assert(nbInputImages);
242  std::vector<ImageRegionConstIteratorType> Vit(nbInputImages);
243 
244  for (j = 0; j < nbInputImages; ++j)
245  {
246  Vit[j] = ImageRegionConstIteratorType(this->GetNthInput(j), outputRegionForThread);
247  }
248 
249  itk::ImageRegionIterator<TImage> ot(this->GetOutput(), outputRegionForThread);
250 
251  // support progress methods/callbacks
252  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
253 
254  std::vector<double>& threadImage = m_AImage[threadId];
255  ParserType::Pointer const& threadParser = m_VParser[threadId];
256  long& threadUnderflow = m_ThreadUnderflow[threadId];
257  long& threadOverflow = m_ThreadOverflow[threadId];
258  ImageRegionConstIteratorType& firstImageRegion = Vit.front(); // alias for better perfs
259  while (!firstImageRegion.IsAtEnd())
260  {
261  for (j = 0; j < nbInputImages; ++j)
262  {
263  threadImage[j] = static_cast<double>(Vit[j].Get());
264  }
265 
266  // Image Indexes
267  for (j = 0; j < 2; ++j)
268  {
269  threadImage[nbInputImages + j] = static_cast<double>(firstImageRegion.GetIndex()[j]);
270  }
271  for (j = 0; j < 2; ++j)
272  {
273  threadImage[nbInputImages + 2 + j] =
274  static_cast<double>(m_Origin[j]) + static_cast<double>(firstImageRegion.GetIndex()[j]) * static_cast<double>(m_Spacing[j]);
275  }
276 
277  try
278  {
279 
280  value = threadParser->Eval();
281  }
282  catch (itk::ExceptionObject& err)
283  {
284  itkExceptionMacro(<< err);
285  }
286 
287  // Case value is equal to -inf or inferior to the minimum value
288  // allowed by the pixelType cast
289  if (value < double(itk::NumericTraits<PixelType>::NonpositiveMin()))
290  {
291  ot.Set(itk::NumericTraits<PixelType>::NonpositiveMin());
292  threadUnderflow++;
293  }
294  // Case value is equal to inf or superior to the maximum value
295  // allowed by the pixelType cast
296  else if (value > double(itk::NumericTraits<PixelType>::max()))
297  {
298  ot.Set(itk::NumericTraits<PixelType>::max());
299  threadOverflow++;
300  }
301  else
302  {
303  ot.Set(static_cast<PixelType>(value));
304  }
305 
306  for (j = 0; j < nbInputImages; ++j)
307  {
308  ++Vit[j];
309  }
310 
311  ++ot;
312 
313  progress.CompletedPixel();
314  }
315 }
316 
317 } // end namespace otb
318 
319 #endif
void SetExpression(const std::string &expression)
ImageType::RegionType ImageRegionType
void SetNthInput(DataObjectPointerArraySizeType idx, const ImageType *image)
void PrintSelf(std::ostream &os, itk::Indent indent) const override
std::string GetNthInputName(DataObjectPointerArraySizeType idx) const
void SetNthInputName(DataObjectPointerArraySizeType idx, const std::string &expression)
ImageType::PixelType PixelType
ImageType * GetNthInput(DataObjectPointerArraySizeType idx)
void ThreadedGenerateData(const ImageRegionType &outputRegionForThread, itk::ThreadIdType threadId) override
itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType
itk::SmartPointer< Self > Pointer
Definition: otbParser.h:51
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
#define otbWarningMacro(x)
Definition: otbMacro.h:117