OTB  10.0.0
Orfeo Toolbox
otbApplyGainFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2024 Centre National d'Etudes Spatiales (CNES)
3  *
4  * This file is part of Orfeo Toolbox
5  *
6  * https://www.orfeo-toolbox.org/
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef otbApplyGainFilter_hxx
22 #define otbApplyGainFilter_hxx
23 
24 #include "otbApplyGainFilter.h"
25 #include "itkImageRegionIterator.h"
26 #include "itkImageRegionConstIteratorWithIndex.h"
27 #include "itkContinuousIndex.h"
28 
29 #include <limits>
30 
31 namespace otb
32 {
33 template <class TInputImage, class TLut, class TOutputImage>
35 {
36  this->SetNumberOfRequiredInputs(2);
37  m_Min = std::numeric_limits<InputPixelType>::quiet_NaN();
38  m_Max = std::numeric_limits<InputPixelType>::quiet_NaN();
39  m_NoData = std::numeric_limits<InputPixelType>::quiet_NaN();
40  m_NoDataFlag = false;
41  m_ThumbSizeFromSpacing = true;
42  m_Step = -1;
43  this->DynamicMultiThreadingOn();
44 }
45 
46 template <class TInputImage, class TLut, class TOutputImage>
48 {
49  // Process object is not const-correct so the const casting is required.
50  this->SetNthInput(0, const_cast<InputImageType*>(input));
51 }
52 
53 template <class TInputImage, class TLut, class TOutputImage>
55 {
56  return static_cast<const InputImageType*>(this->itk::ProcessObject::GetInput(0));
57 }
58 
59 template <class TInputImage, class TLut, class TOutputImage>
61 {
62  // Process object is not const-correct so the const casting is required.
63  this->SetNthInput(1, const_cast<LutType*>(lut));
64 }
65 
66 template <class TInputImage, class TLut, class TOutputImage>
68 {
69  return static_cast<const LutType*>(this->itk::ProcessObject::GetInput(1));
70 }
71 
72 template <class TInputImage, class TLut, class TOutputImage>
74 {
75  typename InputImageType::Pointer input(const_cast<InputImageType*>(GetInputImage()));
76  typename LutType::Pointer lut(const_cast<LutType*>(GetInputLut()));
77  typename OutputImageType::Pointer output(this->GetOutput());
78 
79  lut->SetRequestedRegion(lut->GetLargestPossibleRegion());
80  input->SetRequestedRegion(output->GetRequestedRegion());
81  if (input->GetRequestedRegion().GetNumberOfPixels() == 0)
82  {
83  input->SetRequestedRegionToLargestPossibleRegion();
84  }
85 }
86 
87 template <class TInputImage, class TLut, class TOutputImage>
89 {
90  typename LutType::ConstPointer lut(GetInputLut());
91  typename InputImageType::ConstPointer input(GetInputImage());
92  if (m_ThumbSizeFromSpacing)
93  {
94  m_ThumbSize[0] = std::round(lut->GetSignedSpacing()[0] / input->GetSignedSpacing()[0]);
95  m_ThumbSize[1] = std::round(lut->GetSignedSpacing()[1] / input->GetSignedSpacing()[1]);
96  }
97  m_Step = static_cast<double>(m_Max - m_Min) / static_cast<double>(lut->GetVectorLength() - 1);
98 }
99 
100 template <class TInputImage, class TLut, class TOutputImage>
102 {
103  assert(m_Step > 0);
104 
105  typename InputImageType::ConstPointer input(GetInputImage());
106  typename LutType::ConstPointer lut(GetInputLut());
107  typename OutputImageType::Pointer output(this->GetOutput());
108  typename InputImageType::RegionType inputRegionForThread(outputRegionForThread);
109 
110 
111  itk::ImageRegionConstIteratorWithIndex<InputImageType> it(input, inputRegionForThread);
112  itk::ImageRegionIterator<OutputImageType> oit(output, outputRegionForThread);
113 
114  unsigned int pixelLutValue(0);
115  double gain(0.0), newValue(0);
116  InputPixelType currentPixel(0);
117 
118  for (it.GoToBegin(), oit.GoToBegin(); !oit.IsAtEnd() || !it.IsAtEnd(); ++oit, ++it)
119  {
120  currentPixel = it.Get();
121  newValue = static_cast<double>(currentPixel);
122  if (!((currentPixel == m_NoData && m_NoDataFlag) || currentPixel > m_Max || currentPixel < m_Min))
123  {
124  pixelLutValue = static_cast<unsigned int>(std::round((currentPixel - m_Min) / m_Step));
125  gain = InterpolateGain(lut, pixelLutValue, it.GetIndex());
126  newValue *= gain;
127  }
128  oit.Set(static_cast<OutputPixelType>(newValue));
129  }
130  assert(oit.IsAtEnd() && it.IsAtEnd());
131 }
132 
133 template <class TInputImage, class TLut, class TOutputImage>
134 double ApplyGainFilter<TInputImage, TLut, TOutputImage>::InterpolateGain(typename LutType::ConstPointer gridLut, unsigned int pixelLutValue,
135  typename InputImageType::IndexType index)
136 {
137  typename InputImageType::PointType pixelPoint;
138  typename itk::ContinuousIndex<double, 2> pixelIndex;
139  typename InputImageType::ConstPointer input(GetInputImage());
140  typename LutType::ConstPointer lut(GetInputLut());
141  input->TransformIndexToPhysicalPoint(index, pixelPoint);
142  lut->TransformPhysicalPointToContinuousIndex(pixelPoint, pixelIndex);
143  std::vector<typename LutType::IndexType> neighbors(4);
144  neighbors[0][0] = std::floor(pixelIndex[0]);
145  neighbors[0][1] = std::floor(pixelIndex[1]);
146  neighbors[1][0] = neighbors[0][0] + 1;
147  neighbors[1][1] = neighbors[0][1];
148  neighbors[2][0] = neighbors[0][0];
149  neighbors[2][1] = neighbors[0][1] + 1;
150  neighbors[3][0] = neighbors[0][0] + 1;
151  neighbors[3][1] = neighbors[0][1] + 1;
152  float gain(0.f), w(0.f), wtm(0.f);
153  typename LutType::IndexType maxIndex;
154  maxIndex[0] = lut->GetLargestPossibleRegion().GetSize()[0];
155  maxIndex[1] = lut->GetLargestPossibleRegion().GetSize()[1];
156  for (auto i : neighbors)
157  {
158  if (i[0] < 0 || i[1] < 0 || i[0] >= maxIndex[0] || i[1] >= maxIndex[1])
159  continue;
160  if (gridLut->GetPixel(i)[pixelLutValue] == -1)
161  continue;
162  wtm = (1 - std::abs(pixelIndex[0] - i[0])) * (1 - std::abs(pixelIndex[1] - i[1]));
163  gain += gridLut->GetPixel(i)[pixelLutValue] * wtm;
164  w += wtm;
165  }
166  if (w == 0)
167  {
168  w = 1;
169  gain = 1;
170  }
171 
172  return gain / w;
173 }
174 
178 template <class TInputImage, class TLut, class TOutputImage>
179 void ApplyGainFilter<TInputImage, TLut, TOutputImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
180 {
181  Superclass::PrintSelf(os, indent);
182  os << indent << "Is no data activated : " << m_NoDataFlag << std::endl;
183  os << indent << "No Data : " << m_NoData << std::endl;
184  os << indent << "Minimum : " << m_Min << std::endl;
185  os << indent << "Maximum : " << m_Max << std::endl;
186  os << indent << "Step : " << m_Step << std::endl;
187  os << indent << "Look up table size : " << m_LutSize << std::endl;
188  os << indent << "Is ThumbSize from sapcing is activated : " << m_NoDataFlag << std::endl;
189  os << indent << "Thumbnail size : " << m_ThumbSize << std::endl;
190 }
192 
193 
194 } // End namespace otb
195 
196 #endif
const LutType * GetInputLut() const
void GenerateInputRequestedRegion() override
const InputImageType * GetInputImage() const
void SetInputLut(const LutType *lut)
double InterpolateGain(typename LutType::ConstPointer gridLut, unsigned int pixelValue, typename InputImageType::IndexType index)
InputImageType::InternalPixelType InputPixelType
OutputImageType::RegionType OutputImageRegionType
void DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread) override
void SetInputImage(const InputImageType *input)
void BeforeThreadedGenerateData() override
void PrintSelf(std::ostream &os, itk::Indent indent) const override
OutputImageType::InternalPixelType OutputPixelType
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.