libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNMatrixComplex.cpp
Go to the documentation of this file.
1 /* Copyright 2013-2014 INSA Lyon
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNMatrixComplex.cpp
19  * \author Yann LEYDIER
20  */
21 
25 #include <CRNProtocols.h>
26 #include <CRNi18n.h>
27 
28 using namespace crn;
29 
31 static void doFFT(std::complex<double> *sig, int n, bool direct)
32 {
33  // dimensions
34  double logsize = log2(n);
35  if (logsize != ceil(logsize))
36  throw ExceptionDimension(_("FFT: signal size is not a power of 2."));
37  int m = int(logsize);
38 
39  // bit reversal
40  int i2 = n >> 1;
41  int j = 0;
42  for (int i = 0; i < n-1 ; i++)
43  {
44  if (i < j)
45  swap(sig[i], sig[j]);
46  int k = i2;
47  while (k <= j)
48  {
49  j -= k;
50  k >>= 1;
51  }
52  j += k;
53  }
54 
55  // compute the FFT
56  std::complex<double> c(-1.0, 0.0);
57  int l2 = 1;
58  for (int l = 0; l < m; l++)
59  {
60  int l1 = l2;
61  l2 <<= 1;
62  std::complex<double> u(1.0, 0.0);
63  for (j = 0; j < l1; j++)
64  {
65  for (int i = j; i < n; i += l2)
66  {
67  int i1 = i + l1;
68  std::complex<double> t1 = u * sig[i1];
69  sig[i1] = sig[i] - t1;
70  sig[i] += t1;
71  }
72 
73  u = u * c;
74  }
75 
76  double ima = sqrt((1.0 - c.real()) / 2.0);
77  if (direct)
78  ima = -ima;
79  c = std::complex<double>(sqrt((1.0 + c.real()) / 2.0), ima);
80  }
81 
82  // scaling for forward transform
83  if (direct)
84  {
85  for (int i = 0; i < n; i++)
86  sig[i] /= n;
87  }
88 }
89 
98 void crn::FFT(std::vector<std::complex<double> > &sig, bool direct)
99 {
100  doFFT(sig.data(), int(sig.size()), direct);
101 }
102 
107 void MatrixComplex::GrowToPowerOf2(bool make_square, const std::complex<double> &fill_value)
108 {
109  // find power of 2 row size
110  size_t newr = rows;
111  double logr = log2(int(newr));
112  while (logr != ceil(logr))
113  {
114  newr += 1;
115  logr = log2(int(newr));
116  }
117  // find power of 2 col size
118  size_t newc = cols;
119  double logc = log2(int(newc));
120  while (logc != ceil(logc))
121  {
122  newc += 1;
123  logc = log2(int(newc));
124  }
125  // make a square matrix?
126  if (make_square)
127  {
128  newc = newr = Max(newr, newc);
129  }
130  // copy the data
131  datatype newdata(newr * newc, fill_value);
132  for (size_t r = 0; r < rows; ++r)
133  std::copy(data.begin() + r * cols, data.begin() + (r + 1) * cols, newdata.begin() + r * newc);
134 
135  std::swap(rows, newr);
136  std::swap(cols, newc);
137  data.swap(newdata);
138 }
139 
142 {
143  MatrixDouble m(rows, cols);
144  for (size_t r = 0; r < rows; ++r)
145  for (size_t c = 0; c < cols; ++c)
146  m[r][c] = std::abs(At(r, c));
147  return m;
148 }
149 
150 /* Inplace fast Fourier transform
151  *
152  * \warning Sizes must be power of 2
153  *
154  * \throws ExceptionDimension signal does not have a power of 2 size
155  * \param[in] direct direct=true, inverse=false
156  */
157 void MatrixComplex::FFT(bool direct)
158 {
159  if ((rows == 1) || (cols == 1))
160  { // line vector
161  crn::FFT(data, direct);
162  }
163  else
164  { // 2D transform
165  // lines
166  for (size_t r = 0; r < rows; ++r)
167  doFFT(data.data() + r * cols, int(cols), direct);
168  // columns
169  Transpose();
170  try
171  {
172  for (size_t r = 0; r < rows; ++r)
173  doFFT(data.data() + r * cols, int(cols), direct);
174  Transpose();
175  }
176  catch (...)
177  { // transpose back to ensure exception safety
178  Transpose();
179  throw;
180  }
181  }
182 }
183 
190 std::pair<Point2DInt, double> MatrixComplex::CrossCorrelation(const MatrixComplex &other, const std::complex<double> &fill1, const std::complex<double> &fill2)
191 {
192  // find nearest power of 2 dimensions
193  size_t w = crn::Max(GetCols(), other.GetCols());
194  size_t h = crn::Max(GetRows(), other.GetRows());
195  double logs = log2(int(w));
196  while (logs != ceil(logs))
197  {
198  w += 1;
199  logs = log2(int(w));
200  }
201  if (w < 2) w = 2;
202  logs = log2(int(h));
203  while (logs != ceil(logs))
204  {
205  h += 1;
206  logs = log2(int(h));
207  }
208  if (h < 2) h = 2;
209  // compute cross correlation
210  MatrixComplex c1(h, w, fill1);
211  for (size_t r = 0; r < GetRows(); ++r)
212  for (size_t c = 0; c < GetCols(); ++c)
213  c1[r][c] = At(r, c);
214  c1.FFT(true);
215  UMatrixComplex c2(std::make_unique<MatrixComplex>(h, w, fill2));
216  for (size_t r = 0; r < other.GetRows(); ++r)
217  for (size_t c = 0; c < other.GetCols(); ++c)
218  (*c2)[r][c] = other[r][c];
219  c2->FFT(true);
220  for (size_t r = 0; r < h; ++r)
221  for (size_t c = 0; c < w; ++c)
222  c1[r][c] *= std::conj((*c2)[r][c]);
223  c2 = nullptr; // free memory
224  c1.FFT(true);
225  // find best match
226  Point2DInt p;
227  double maxc = 0;
228  for (size_t r = 0; r < h; ++r)
229  for (size_t c = 0; c < w; ++c)
230  {
231  double corr = std::norm(c1[r][c]);
232  if (corr > maxc)
233  {
234  p.X = int(c);
235  p.Y = int(r);
236  maxc = corr;
237  }
238  }
239  int hw = (int)w/2;
240  int hh = (int)h/2;
241  if (p.X >= hw)
242  p.X = (p.X % hw) - hw;
243  if (p.Y >= hh)
244  p.Y = (p.Y % hh) - hh;
245  return std::make_pair(p, maxc);
246 }
247 
249  Cloner::Register<MatrixComplex>();
250 CRN_END_CLASS_CONSTRUCTOR(MatrixComplex)
size_t GetRows() const noexcept
Returns the number of rows.
Definition: CRNMatrix.h:157
size_t GetCols() const noexcept
Returns the number of columns.
Definition: CRNMatrix.h:163
void FFT(std::vector< std::complex< double > > &sig, bool direct)
Fast Fourier transform.
virtual Matrix & Transpose()
Inplace transposition.
Definition: CRNMatrix.h:472
MatrixDouble MakeModule() const
Returns a matrix containing the modules of the inner values.
#define _(String)
Definition: CRNi18n.h:51
const T & Max(const T &a, const T &b)
Returns the max of two values.
Definition: CRNMath.h:47
#define CRN_END_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Definition: CRNObject.h:198
value_type X
Definition: CRNPoint2D.h:63
A dimension error.
Definition: CRNException.h:119
double matrix class
std::vector< std::complex< double > > datatype
Definition: CRNMatrix.h:692
std::pair< Point2DInt, double > CrossCorrelation(const MatrixComplex &other, const std::complex< double > &fill1=std::complex< double >(0, 0), const std::complex< double > &fill2=std::complex< double >(0, 0))
Cross correlation.
const std::complex< double > & At(size_t pos) const noexcept
Definition: CRNMatrix.h:165
value_type Y
Definition: CRNPoint2D.h:63
void GrowToPowerOf2(bool make_square, const std::complex< double > &fill_value=std::complex< double >(0, 0))
Grows the matrix to power of 2 sizes (for FFT)
Complex matrix class.
void FFT(bool direct)
Inplace fast Fourier transform.
A 2D point class.
Definition: CRNPoint2DInt.h:39
#define CRN_BEGIN_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Definition: CRNObject.h:185