Isis 3 Programmer Reference
ForstnerOperator.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "ForstnerOperator.h"
8 #include "Chip.h"
9 #include "FourierTransform.h"
10 #include "tnt/tnt_array2d.h"
11 #include "jama/jama_lu.h"
12 #include <complex>
13 
14 namespace Isis {
24 
25  int nSamp = ft.NextPowerOfTwo(chip.Samples() - 1);
26  int nLine = ft.NextPowerOfTwo(chip.Lines() - 1);
27 
28  TNT::Array2D< std::complex<double> > Guu(nLine, nSamp);
29  TNT::Array2D< std::complex<double> > Guv(nLine, nSamp);
30  TNT::Array2D< std::complex<double> > Gvv(nLine, nSamp);
31 
32  // calculate the diagonal gradients
33  // (if any of the four pixels are special
34  // the gradients are zeroed out)
35  // and perform the fourier transform in the
36  // line direction on the 3 matrices
37  for(int i = 0; i < Guu.dim1(); i++) {
38  std::vector< std::complex<double> > line1(Guu.dim2());
39  std::vector< std::complex<double> > line2(Guv.dim2());
40  std::vector< std::complex<double> > line3(Gvv.dim2());
41 
42  double gu, gv;
43 
44  for(int j = 0; j < Guu.dim2(); j++) {
45  if(i > chip.Lines() - 2 || j > chip.Samples() - 2 ||
46  IsSpecial(chip.GetValue(j + 1, i + 1)) || IsSpecial(chip.GetValue(j + 1, i + 2)) ||
47  IsSpecial(chip.GetValue(j + 2, i + 1)) || IsSpecial(chip.GetValue(j + 2, i + 2))) {
48  gu = 0.0;
49  gv = 0.0;
50  }
51  else {
52  gu = chip.GetValue(j + 1, i + 1) - chip.GetValue(j + 2, i + 2);
53  gv = chip.GetValue(j + 2, i + 1) - chip.GetValue(j + 1, i + 2);
54  }
55 
56  line1[j] = gu * gu;
57  line2[j] = gu * gv;
58  line3[j] = gv * gv;
59  }
60 
61  std::vector< std::complex<double> > transform1 = ft.Transform(line1);
62  std::vector< std::complex<double> > transform2 = ft.Transform(line2);
63  std::vector< std::complex<double> > transform3 = ft.Transform(line3);
64 
65  //copy the transformed data back into the matrices
66  for(int j = 0; j < Guu.dim2(); j++) {
67  Guu[i][j] = transform1[j];
68  Guv[i][j] = transform2[j];
69  Gvv[i][j] = transform3[j];
70  }
71  }
72 
73  // perform the fourier transform in the
74  // sample direction on the 3 matrices
75  for(int j = 0; j < Guu.dim2(); j++) {
76  std::vector< std::complex<double> > samp1(Guu.dim1());
77  std::vector< std::complex<double> > samp2(Guv.dim1());
78  std::vector< std::complex<double> > samp3(Gvv.dim1());
79 
80  for(int i = 0; i < Guu.dim1(); i++) {
81  samp1[i] = Guu[i][j];
82  samp2[i] = Guv[i][j];
83  samp3[i] = Gvv[i][j];
84  }
85 
86  std::vector< std::complex<double> > transform1 = ft.Transform(samp1);
87  std::vector< std::complex<double> > transform2 = ft.Transform(samp2);
88  std::vector< std::complex<double> > transform3 = ft.Transform(samp3);
89 
90  //copy the transformed data back into the matrices
91  for(int i = 0; i < Guu.dim1(); i++) {
92  Guu[i][j] = transform1[i];
93  Guv[i][j] = transform2[i];
94  Gvv[i][j] = transform3[i];
95  }
96  }
97 
98  // First, multiply the three transformed matrices
99  // Then, compute the 2d inverse of the
100  // transformed data starting with the line direction
101  // For convenience, put it back in Guu
102  for(int i = 0; i < Guu.dim1(); i++) {
103  std::vector< std::complex<double> > line(Guu.dim2());
104 
105  for(int j = 0; j < Guu.dim2(); j++) {
106  line[j] = Guu[i][j] * Guv[i][j] * Gvv[i][j];
107  }
108 
109  std::vector< std::complex<double> > transform = ft.Transform(line);
110 
111  //copy the transformed data back into the matrix
112  for(int j = 0; j < Guu.dim2(); j++) {
113  Guu[i][j] = transform[j];
114  }
115  }
116 
117  // After inverting, the matrix will contain N in the upper right
118  // The trace of N determines the roundness of the chip
119  // and the determinant determines the chip's weight
120  // In this case, we will look only at the weight
121  TNT::Array2D<double> N(chip.Lines() - 1, chip.Samples() - 1);
122 
123  // And then the sample direction
124  for(int j = 0; j < N.dim2(); j++) {
125  std::vector< std::complex<double> > samp(Guu.dim1());
126 
127  for(int i = 0; i < Guu.dim1(); i++) {
128  samp[i] = Guu[i][j];
129  }
130 
131  std::vector< std::complex<double> > transform = ft.Transform(samp);
132 
133  //copy the transformed data back into the matrix
134  for(int i = 0; i < N.dim1(); i++) {
135  N[i][j] = real(transform[i]);
136  }
137  }
138 
139  JAMA::LU<double> lu(N);
140 
141  // use LU decomposition to calculate the determinant
142  return abs(lu.det());
143  }
144 }
145 
146 extern "C" Isis::InterestOperator *ForstnerOperatorPlugin(Isis::Pvl &pvl) {
147  return new Isis::ForstnerOperator(pvl);
148 }
Isis::FourierTransform
Fourier Transform class.
Definition: FourierTransform.h:33
Isis::Chip::GetValue
double GetValue(int sample, int line)
Loads a Chip with a value.
Definition: Chip.h:145
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::FourierTransform::Transform
std::vector< std::complex< double > > Transform(std::vector< std::complex< double > > input)
Applies the Fourier transform on the input data and returns the result.
Definition: FourierTransform.cpp:28
Isis::IsSpecial
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:197
Isis::Chip::Lines
int Lines() const
Definition: Chip.h:106
Isis::ForstnerOperator
Forstner interest operator.
Definition: ForstnerOperator.h:35
Isis::Chip
A small chip of data used for pattern matching.
Definition: Chip.h:86
Isis::Chip::Samples
int Samples() const
Definition: Chip.h:99
Isis::FourierTransform::NextPowerOfTwo
int NextPowerOfTwo(int n)
This function returns the next power of two greater than or equal to n.
Definition: FourierTransform.cpp:160
Isis::ForstnerOperator::Interest
virtual double Interest(Chip &chip)
This method returns the amount of interest for the given chip.
Definition: ForstnerOperator.cpp:22
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::InterestOperator
Interest Operator class.
Definition: InterestOperator.h:109