OTB  10.0.0
Orfeo Toolbox
otbMultiChannelsPolarimetricSynthesisFilter.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 otbMultiChannelsPolarimetricSynthesisFilter_hxx
22 #define otbMultiChannelsPolarimetricSynthesisFilter_hxx
23 
24 #include <complex>
25 
27 #include "itkImageRegionIterator.h"
28 #include "otbMath.h"
29 
30 namespace otb
31 {
32 
36 template <class TInputImage, class TOutputImage, class TFunction>
38  : m_PsiI(0.0), m_KhiI(0.0), m_PsiR(0.0), m_KhiR(0.0), m_Gain(1.0), m_Mode(0), m_EmissionH(false), m_EmissionV(false)
39 {
40  this->SetNumberOfRequiredInputs(1);
41  this->InPlaceOff();
43  this->DynamicMultiThreadingOn();
44 }
46 
50 template <class TInputImage, class TOutputImage, class TFunction>
52 {
53  // do not call the superclass' implementation of this method since
54  // this filter allows the input the output to be of different dimensions
55 
56  // get pointers to the input and output
57  typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
58  typename Superclass::InputImageConstPointer inputPtr = this->GetInput();
59 
60  if (!outputPtr || !inputPtr)
61  {
62  return;
63  }
64 
65  // Set the output image largest possible region. Use a RegionCopier
66  // so that the input and output images can be different dimensions.
67  OutputImageRegionType outputLargestPossibleRegion;
68  this->CallCopyInputRegionToOutputRegion(outputLargestPossibleRegion, inputPtr->GetLargestPossibleRegion());
69  outputPtr->SetLargestPossibleRegion(outputLargestPossibleRegion);
70 
71  // Set the output spacing and origin
72  const itk::ImageBase<Superclass::InputImageDimension>* phyData;
73 
74  phyData = dynamic_cast<const itk::ImageBase<Superclass::InputImageDimension>*>(this->GetInput());
75 
76  if (phyData)
77  {
78  // Copy what we can from the image from spacing and origin of the input
79  // This logic needs to be augmented with logic that select which
80  // dimensions to copy
81  unsigned int i, j;
82  const typename InputImageType::SpacingType& inputSpacing = inputPtr->GetSignedSpacing();
83  const typename InputImageType::PointType& inputOrigin = inputPtr->GetOrigin();
84  const typename InputImageType::DirectionType& inputDirection = inputPtr->GetDirection();
85 
86  typename OutputImageType::SpacingType outputSpacing;
87  typename OutputImageType::PointType outputOrigin;
88  typename OutputImageType::DirectionType outputDirection;
89 
90  // copy the input to the output and fill the rest of the
91  // output with zeros.
92  for (i = 0; i < Superclass::InputImageDimension; ++i)
93  {
94  outputSpacing[i] = inputSpacing[i];
95  outputOrigin[i] = inputOrigin[i];
96  for (j = 0; j < Superclass::OutputImageDimension; ++j)
97  {
98  if (j < Superclass::InputImageDimension)
99  {
100  outputDirection[j][i] = inputDirection[j][i];
101  }
102  else
103  {
104  outputDirection[j][i] = 0.0;
105  }
106  }
107  }
108  for (; i < Superclass::OutputImageDimension; ++i)
109  {
110  outputSpacing[i] = 1.0;
111  outputOrigin[i] = 0.0;
112  for (j = 0; j < Superclass::OutputImageDimension; ++j)
113  {
114  if (j == i)
115  {
116  outputDirection[j][i] = 1.0;
117  }
118  else
119  {
120  outputDirection[j][i] = 0.0;
121  }
122  }
123  }
124 
125  // set the spacing and origin
126  outputPtr->SetSignedSpacing(outputSpacing);
127  outputPtr->SetOrigin(outputOrigin);
128  outputPtr->SetDirection(outputDirection);
129  }
130  else
131  {
132  // pointer could not be cast back down
133  itkExceptionMacro(<< "otb::MultiChannelsPolarimetricSynthesisFilter::GenerateOutputInformation "
134  << "cannot cast input to " << typeid(itk::ImageBase<Superclass::InputImageDimension>*).name());
135  }
136 }
137 
141 template <class TInputImage, class TOutputImage, class TFunction>
143 {
144 
145  InputImagePointer inputPtr = this->GetInput();
146  OutputImagePointer outputPtr = this->GetOutput(0);
147 
148  // Define the portion of the input to walk for this thread, using
149  // the CallCopyOutputRegionToInputRegion method allows for the input
150  // and output images to be different dimensions
151  InputImageRegionType inputRegionForThread;
152  this->CallCopyOutputRegionToInputRegion(inputRegionForThread, outputRegionForThread);
153 
154  // Define the iterators
155  itk::ImageRegionConstIterator<TInputImage> inputIt(inputPtr, inputRegionForThread);
156  itk::ImageRegionIterator<TOutputImage> outputIt(outputPtr, outputRegionForThread);
157 
158  inputIt.GoToBegin();
159  outputIt.GoToBegin();
160 
161  ArchitectureType val = m_ArchitectureType->GetArchitectureType();
162 
163  // Computation with 4 channels
164  switch (val)
165  {
166  case HH_HV_VH_VV:
167  while (!inputIt.IsAtEnd())
168  {
169  outputIt.Set(m_Gain * GetFunctor()(inputIt.Get()[0], inputIt.Get()[1], inputIt.Get()[2], inputIt.Get()[3]));
170  ++inputIt;
171  ++outputIt;
172  }
173  break;
174 
175  // With 3 channels : HH HV VV or HH VH VV
176  case HH_HV_VV:
177  while (!inputIt.IsAtEnd())
178  {
179  outputIt.Set(m_Gain * GetFunctor()(inputIt.Get()[0], inputIt.Get()[1], inputIt.Get()[1], inputIt.Get()[2]));
180  ++inputIt;
181  ++outputIt;
182  }
183  break;
184 
185  // Only HH and HV are present
186  case HH_HV:
187  while (!inputIt.IsAtEnd())
188  {
189  outputIt.Set(m_Gain * GetFunctor()(inputIt.Get()[0], inputIt.Get()[1], 0, 0));
190  ++inputIt;
191  ++outputIt;
192  }
193  break;
194 
195  // Only VH and VV are present
196  case VH_VV:
197  while (!inputIt.IsAtEnd())
198  {
199  outputIt.Set(m_Gain * GetFunctor()(0, 0, inputIt.Get()[2], inputIt.Get()[3]));
200  ++inputIt;
201  ++outputIt;
202  }
203  break;
204 
205  default:
206  itkExceptionMacro("Unknown architecture : Polarimetric synthesis is impossible !");
207  return;
208  }
209 }
210 
214 template <class TInputImage, class TOutputImage, class TFunction>
216 {
217  ComplexArrayType AEi, AEr;
218 
220  double DTOR = CONST_PI_180;
221  double real, imag;
222 
223  real = std::cos(DTOR * m_PsiI) * std::cos(DTOR * m_KhiI);
224  imag = -std::sin(DTOR * m_PsiI) * std::sin(DTOR * m_KhiI);
225  ComplexType Ei0(real, imag);
226 
227  real = std::sin(DTOR * m_PsiI) * std::cos(DTOR * m_KhiI);
228  imag = std::cos(DTOR * m_PsiI) * std::sin(DTOR * m_KhiI);
229  ComplexType Ei1(real, imag);
230 
231  real = std::cos(DTOR * m_PsiR) * std::cos(DTOR * m_KhiR);
232  imag = -std::sin(DTOR * m_PsiR) * std::sin(DTOR * m_KhiR);
233  ComplexType Er0(real, imag);
234 
235  real = std::sin(DTOR * m_PsiR) * std::cos(DTOR * m_KhiR);
236  imag = std::cos(DTOR * m_PsiR) * std::sin(DTOR * m_KhiR);
237  ComplexType Er1(real, imag);
238 
239  AEi[0] = Ei0;
240  AEi[1] = Ei1;
241  AEr[0] = Er0;
242  AEr[1] = Er1;
243 
244  this->SetEi(AEi);
245  this->SetEr(AEr);
246 }
247 
251 template <class TInputImage, class TOutputImage, class TFunction>
253 {
254 
255  ArchitectureType val = m_ArchitectureType->GetArchitectureType();
256 
257  switch (val)
258  {
259 
260  case HH_HV_VH_VV:
261  break;
262  case HH_HV_VV:
263  break;
264  case HH_VH_VV:
265  break;
266  // Only HH and HV are present
267  case HH_HV:
268 
269  // Forcing KhiI=0 PsiI=0
270  this->SetKhiI(0);
271  this->SetPsiI(0);
272  break;
273 
274  // Only VH and VV are present
275  case VH_VV:
276 
277  // Forcing KhiI=0 PsiI=90
278  this->SetKhiI(0);
279  this->SetPsiI(90);
280  break;
281 
282  default:
283  itkExceptionMacro("Unknown architecture : Polarimetric synthesis is impossible !!");
284  return;
285  }
286 
287  if (GetMode() == 1)
288  ForceCoPolar();
289  else if (GetMode() == 2)
290  ForceCrossPolar();
291 }
292 
296 template <class TInputImage, class TOutputImage, class TFunction>
298 {
299 
300  int NumberOfImages = this->GetInput()->GetNumberOfComponentsPerPixel();
301 
302  // First Part. Determine the kind of architecture of the input picture
303  m_ArchitectureType->DetermineArchitecture(NumberOfImages, GetEmissionH(), GetEmissionV());
304 
305  // Second Part. Verify and force the inputs
306  VerifyAndForceInputs();
307 
308  // Third Part. Estimation of the incident field Ei and the reflected field Er
309  ComputeElectromagneticFields();
310 }
311 
315 template <class TInputImage, class TOutputImage, class TFunction>
317 {
318  SetPsiR(m_PsiI);
319  SetKhiR(m_KhiI);
320 }
322 
326 template <class TInputImage, class TOutputImage, class TFunction>
328 {
329  SetPsiR(m_PsiI + 90);
330  SetKhiR(-m_KhiI);
331  SetMode(2);
332 }
334 
338 template <class TInputImage, class TOutputImage, class TFunction>
340 {
341  this->Superclass::PrintSelf(os, indent);
342  os << indent << "PsiI: " << m_PsiI << std::endl;
343  os << indent << "KhiI: " << m_KhiI << std::endl;
344  os << indent << "PsiR: " << m_PsiR << std::endl;
345  os << indent << "KhiR: " << m_KhiR << std::endl;
347 
348  os << indent << "Ei0 im: " << m_Ei[0].imag() << std::endl;
349  os << indent << "Ei0 re: " << m_Ei[0].real() << std::endl;
350  os << indent << "Ei1 im: " << m_Ei[1].imag() << std::endl;
351  os << indent << "Ei1 re: " << m_Ei[1].real() << std::endl;
352 
353  os << indent << "Er0 im: " << m_Er[0].imag() << std::endl;
354  os << indent << "Er0 re: " << m_Er[0].real() << std::endl;
355  os << indent << "Er1 im: " << m_Er[1].imag() << std::endl;
356  os << indent << "Er1 re: " << m_Er[1].real() << std::endl;
357 }
358 
359 } // end namespace otb
360 
361 #endif
void PrintSelf(std::ostream &os, itk::Indent indent) const override
void DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread) override
static Pointer New()
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
constexpr double CONST_PI_180
Definition: otbMath.h:56
ArchitectureType
This enumeration describes the different architectures we can find in polarimetry....