Openholo  v5.0
Open Source Digital Holographic Library
ophGen.cpp
Go to the documentation of this file.
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install, copy or use the software.
7 //
8 //
9 // License Agreement
10 // For Open Source Digital Holographic Library
11 //
12 // Openholo library is free software;
13 // you can redistribute it and/or modify it under the terms of the BSD 2-Clause license.
14 //
15 // Copyright (C) 2017-2024, Korea Electronics Technology Institute. All rights reserved.
16 // E-mail : contact.openholo@gmail.com
17 // Web : http://www.openholo.org
18 //
19 // Redistribution and use in source and binary forms, with or without modification,
20 // are permitted provided that the following conditions are met:
21 //
22 // 1. Redistribution's of source code must retain the above copyright notice,
23 // this list of conditions and the following disclaimer.
24 //
25 // 2. Redistribution's in binary form must reproduce the above copyright notice,
26 // this list of conditions and the following disclaimer in the documentation
27 // and/or other materials provided with the distribution.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the copyright holder or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 // This software contains opensource software released under GNU Generic Public License,
41 // NVDIA Software License Agreement, or CUDA supplement to Software License Agreement.
42 // Check whether software you use contains licensed software.
43 //
44 //M*/
45 
46 #include "ophGen.h"
47 #include "sys.h"
48 #include "function.h"
49 #include <cuda_runtime_api.h>
50 #include <cufft.h>
51 #include <omp.h>
52 #include <iostream>
53 #include <sstream>
54 #include <algorithm>
55 #include "ImgControl.h"
56 #include "tinyxml2.h"
57 #include "PLYparser.h"
58 
59 extern "C"
60 {
73  void cudaFFT(CUstream_st* stream, int nx, int ny, cufftDoubleComplex* in_filed, cufftDoubleComplex* output_field, int direction, bool bNormailized = false);
74 
89  void cudaCropFringe(CUstream_st* stream, int nx, int ny, cufftDoubleComplex* in_field, cufftDoubleComplex* out_field, int cropx1, int cropx2, int cropy1, int cropy2);
90 
108  void cudaGetFringe(CUstream_st* stream, int pnx, int pny, cufftDoubleComplex* in_field, cufftDoubleComplex* out_field, int sig_locationx, int sig_locationy,
109  Real ssx, Real ssy, Real ppx, Real ppy, Real PI);
110 }
111 
113  : Openholo()
114  , m_vecEncodeSize()
115  , ENCODE_METHOD(0)
116  , SSB_PASSBAND(0)
117  , m_elapsedTime(0.0)
118  , m_lpEncoded(nullptr)
119  , m_lpNormalized(nullptr)
120  , m_nOldChannel(0)
121  , m_precision(PRECISION::DOUBLE)
122  , m_dFieldLength(0.0)
123  , m_nStream(1)
124  , m_mode(0)
125  , AS(nullptr)
126  , normalized(nullptr)
127  , fftTemp(nullptr)
128  , weight(nullptr)
129  , weightC(nullptr)
130  , freqW(nullptr)
131  , realEnc(nullptr)
132  , binary(nullptr)
133  , maskSSB(nullptr)
134  , maskHP(nullptr)
135  , m_bRandomPhase(false)
136 {
137 
138 
139 }
140 
142 {
143 
144 }
145 
147 {
148  // Output Image Size
150  const uint nChannel = context_.waveNum;
151 
152  // Memory Location for Result Image
153  if (complex_H != nullptr) {
154  for (uint i = 0; i < m_nOldChannel; i++) {
155  if (complex_H[i] != nullptr) {
156  delete[] complex_H[i];
157  complex_H[i] = nullptr;
158  }
159  }
160  delete[] complex_H;
161  complex_H = nullptr;
162  }
163 
164  complex_H = new Complex<Real>*[nChannel];
165  for (uint i = 0; i < nChannel; i++) {
166  complex_H[i] = new Complex<Real>[rc.size];
167  memset(complex_H[i], 0, sizeof(Complex<Real>) * rc.size);
168  }
169 
170  if (m_lpEncoded != nullptr) {
171  for (uint i = 0; i < m_nOldChannel; i++) {
172  if (m_lpEncoded[i] != nullptr) {
173  delete[] m_lpEncoded[i];
174  m_lpEncoded[i] = nullptr;
175  }
176  }
177  delete[] m_lpEncoded;
178  m_lpEncoded = nullptr;
179  }
180  m_lpEncoded = new Real*[nChannel];
181  for (uint i = 0; i < nChannel; i++) {
182  m_lpEncoded[i] = new Real[rc.size];
183  memset(m_lpEncoded[i], 0, sizeof(Real) * rc.size);
184  }
185 
186  if (m_lpNormalized != nullptr) {
187  for (uint i = 0; i < m_nOldChannel; i++) {
188  if (m_lpNormalized[i] != nullptr) {
189  delete[] m_lpNormalized[i];
190  m_lpNormalized[i] = nullptr;
191  }
192  }
193  delete[] m_lpNormalized;
194  m_lpNormalized = nullptr;
195  }
196  m_lpNormalized = new uchar*[nChannel];
197  for (uint i = 0; i < nChannel; i++) {
198  m_lpNormalized[i] = new uchar[rc.size];
199  memset(m_lpNormalized[i], 0, sizeof(uchar) * rc.size);
200  }
201 
202  m_nOldChannel = nChannel;
205 }
206 
207 int ophGen::loadPointCloud(const char* pc_file, OphPointCloudData *pc_data_)
208 {
209  int n_points = 0;
210  auto begin = CUR_TIME;
211 
212  PLYparser plyIO;
213  if (!plyIO.loadPLY(pc_file, pc_data_->n_points, &pc_data_->vertices))
214  n_points = -1;
215  else
216  n_points = pc_data_->n_points;
217  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
218  return n_points;
219 }
220 
221 bool ophGen::readConfig(const char* fname)
222 {
223  bool bRet = true;
224  using namespace tinyxml2;
225  tinyxml2::XMLDocument xml_doc;
226  XMLNode *xml_node = nullptr;
227 
228  if (!checkExtension(fname, ".xml"))
229  {
230  LOG("<FAILED> Wrong file ext.\n");
231  return false;
232  }
233  auto ret = xml_doc.LoadFile(fname);
234  if (ret != XML_SUCCESS)
235  {
236  LOG("<FAILED> Loading file (%d)\n", ret);
237  return false;
238  }
239  xml_node = xml_doc.FirstChild();
240 
241  int nWave = 1;
242  char szNodeName[32] = { 0, };
243 
244  sprintf(szNodeName, "SLM_WaveNum");
245  auto next = xml_node->FirstChildElement(szNodeName); // OffsetInDepth
246  if (!next || XML_SUCCESS != next->QueryIntText(&nWave))
247  {
248  LOG("<FAILED> Not found node : \'%s\' (Integer) \n", szNodeName);
249  bRet = false;
250  }
251  context_.waveNum = nWave;
253  context_.wave_length = new Real[nWave];
254 
255  for (int i = 1; i <= nWave; i++) {
256  sprintf(szNodeName, "SLM_WaveLength_%d", i);
257  next = xml_node->FirstChildElement(szNodeName);
258  if (!next || XML_SUCCESS != next->QueryDoubleText(&context_.wave_length[i - 1]))
259  {
260  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
261  bRet = false;
262  }
263  }
264 
265  sprintf(szNodeName, "SLM_PixelNumX");
266  next = xml_node->FirstChildElement(szNodeName);
267  if (!next || XML_SUCCESS != next->QueryIntText(&context_.pixel_number[_X]))
268  {
269  LOG("<FAILED> Not found node : \'%s\' (Integer) \n", szNodeName);
270  bRet = false;
271  }
272 
273  sprintf(szNodeName, "SLM_PixelNumY");
274  next = xml_node->FirstChildElement(szNodeName);
275  if (!next || XML_SUCCESS != next->QueryIntText(&context_.pixel_number[_Y]))
276  {
277  LOG("<FAILED> Not found node : \'%s\' (Integer) \n", szNodeName);
278  bRet = false;
279  }
280 
281  sprintf(szNodeName, "SLM_PixelPitchX");
282  next = xml_node->FirstChildElement("SLM_PixelPitchX");
283  if (!next || XML_SUCCESS != next->QueryDoubleText(&context_.pixel_pitch[_X]))
284  {
285  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
286  bRet = false;
287  }
288 
289  sprintf(szNodeName, "SLM_PixelPitchY");
290  next = xml_node->FirstChildElement("SLM_PixelPitchY");
291  if (!next || XML_SUCCESS != next->QueryDoubleText(&context_.pixel_pitch[_Y]))
292  {
293  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
294  bRet = false;
295  }
296 
297  // option
298  next = xml_node->FirstChildElement("IMG_Rotation");
299  if (!next || XML_SUCCESS != next->QueryBoolText(&imgCfg.rotate))
300  imgCfg.rotate = false;
301  next = xml_node->FirstChildElement("IMG_Merge");
302  if (!next || XML_SUCCESS != next->QueryBoolText(&imgCfg.merge))
303  imgCfg.merge = false;
304  next = xml_node->FirstChildElement("IMG_Flip");
305  if (!next || XML_SUCCESS != next->QueryIntText(&imgCfg.flip))
306  imgCfg.flip = 0;
307  next = xml_node->FirstChildElement("DoublePrecision");
308  if (!next || XML_SUCCESS != next->QueryBoolText(&context_.bUseDP))
309  context_.bUseDP = true;
310  next = xml_node->FirstChildElement("ShiftX");
311  if (!next || XML_SUCCESS != next->QueryDoubleText(&context_.shift[_X]))
312  context_.shift[_X] = 0.0;
313  next = xml_node->FirstChildElement("ShiftY");
314  if (!next || XML_SUCCESS != next->QueryDoubleText(&context_.shift[_Y]))
315  context_.shift[_Y] = 0.0;
316  next = xml_node->FirstChildElement("ShiftZ");
317  if (!next || XML_SUCCESS != next->QueryDoubleText(&context_.shift[_Z]))
318  context_.shift[_Z] = 0.0;
319  next = xml_node->FirstChildElement("FieldLength");
320  if (!next || XML_SUCCESS != next->QueryDoubleText(&m_dFieldLength))
321  m_dFieldLength = 0.0;
322  next = xml_node->FirstChildElement("RandomPhase");
323  if (!next || XML_SUCCESS != next->QueryBoolText(&m_bRandomPhase))
324  m_bRandomPhase = false;
325  next = xml_node->FirstChildElement("NumOfStream");
326  if (!next || XML_SUCCESS != next->QueryIntText(&m_nStream))
327  m_nStream = 1;
328 
331 
334 
336  for (int i = 0; i < nWave; i++)
338 
339  // 2024.04.23. mwnam
340  // set variable for resolution
342 
343  LOG("**************************************************\n");
344  LOG(" Read Config (Common) \n");
345  LOG("1) SLM Number of Waves : %d\n", context_.waveNum);
346  for (uint i = 0; i < context_.waveNum; i++)
347  LOG(" 1-%d) SLM Wave length : %e\n", i + 1, context_.wave_length[i]);
348  LOG("2) SLM Resolution : %d x %d\n", context_.pixel_number[_X], context_.pixel_number[_Y]);
349  LOG("3) SLM Pixel Pitch : %e x %e\n", context_.pixel_pitch[_X], context_.pixel_pitch[_Y]);
350  LOG("4) Image Rotate : %s\n", imgCfg.rotate ? "Y" : "N");
351  LOG("5) Image Flip : %s\n", (imgCfg.flip == FLIP::NONE) ? "NONE" :
352  (imgCfg.flip == FLIP::VERTICAL) ? "VERTICAL" :
353  (imgCfg.flip == FLIP::HORIZONTAL) ? "HORIZONTAL" : "BOTH");
354  LOG("6) Image Merge : %s\n", imgCfg.merge ? "Y" : "N");
355  LOG("**************************************************\n");
356 
357  return bRet;
358 }
359 
360 
361 void ophGen::RS_Diffraction(Point src, Complex<Real> *dst, Real lambda, Real distance, Real amplitude)
362 {
363  OphConfig *pConfig = &context_;
364  const int pnX = pConfig->pixel_number[_X];
365  const int pnY = pConfig->pixel_number[_Y];
366  const Real ppX = pConfig->pixel_pitch[_X];
367  const Real ppY = pConfig->pixel_pitch[_Y];
368  const Real ssX = pConfig->ss[_X] = pnX * ppX;
369  const Real ssY = pConfig->ss[_Y] = pnY * ppY;
370  const int offsetX = pConfig->offset[_X];
371  const int offsetY = pConfig->offset[_Y];
372 
373  const Real tx = lambda / (2 * ppX);
374  const Real ty = lambda / (2 * ppY);
375  const Real sqrtX = sqrt(1 - (tx * tx));
376  const Real sqrtY = sqrt(1 - (ty * ty));
377  const Real x = -ssX / 2;
378  const Real y = -ssY / 2;
379  const Real k = (2 * M_PI) / lambda;
380  Real z = src.pos[_Z] + distance;
381  Real zz = z * z;
382  Real ampZ = amplitude * z;
383 
384  Real _xbound[2] = {
385  src.pos[_X] + abs(tx / sqrtX * z),
386  src.pos[_X] - abs(tx / sqrtX * z)
387  };
388 
389  Real _ybound[2] = {
390  src.pos[_Y] + abs(ty / sqrtY * z),
391  src.pos[_Y] - abs(ty / sqrtY * z)
392  };
393 
394  Real Xbound[2] = {
395  floor((_xbound[_X] - x) / ppX) + 1,
396  floor((_xbound[_Y] - x) / ppX) + 1
397  };
398 
399  Real Ybound[2] = {
400  pnY - floor((_ybound[_Y] - y) / ppY),
401  pnY - floor((_ybound[_X] - y) / ppY)
402  };
403 
404  if (Xbound[_X] > pnX) Xbound[_X] = pnX;
405  if (Xbound[_Y] < 0) Xbound[_Y] = 0;
406  if (Ybound[_X] > pnY) Ybound[_X] = pnY;
407  if (Ybound[_Y] < 0) Ybound[_Y] = 0;
408 
409 
410  for (int yytr = Ybound[_Y]; yytr < Ybound[_X]; ++yytr)
411  {
412  int offset = yytr * pnX;
413  Real yyy = y + ((pnY - yytr + offsetY) * ppY);
414 
415  Real range_x[2] = {
416  src.pos[_X] + abs(tx / sqrtX * sqrt((yyy - src.pos[_Y]) * (yyy - src.pos[_Y]) + zz)),
417  src.pos[_X] - abs(tx / sqrtX * sqrt((yyy - src.pos[_Y]) * (yyy - src.pos[_Y]) + zz))
418  };
419 
420  for (int xxtr = Xbound[_Y]; xxtr < Xbound[_X]; ++xxtr)
421  {
422  Real xxx = x + ((xxtr - 1 + offsetX) * ppX);
423  Real r = sqrt((xxx - src.pos[_X]) * (xxx - src.pos[_X]) + (yyy - src.pos[_Y]) * (yyy - src.pos[_Y]) + zz);
424  Real range_y[2] = {
425  src.pos[_Y] + abs(ty / sqrtY * sqrt((xxx - src.pos[_X]) * (xxx - src.pos[_X]) + zz)),
426  src.pos[_Y] - abs(ty / sqrtY * sqrt((xxx - src.pos[_X]) * (xxx - src.pos[_X]) + zz))
427  };
428 
429  if (((xxx < range_x[_X]) && (xxx > range_x[_Y])) && ((yyy < range_y[_X]) && (yyy > range_y[_Y]))) {
430  Real kr = k * r;
431  Real operand = lambda * r * r;
432  Real res_real = (ampZ * sin(kr)) / operand;
433  Real res_imag = (-ampZ * cos(kr)) / operand;
434 #ifdef _OPENMP
435 #pragma omp atomic
436  dst[offset + xxtr][_RE] += res_real;
437 #endif
438 #ifdef _OPENMP
439 #pragma omp atomic
440  dst[offset + xxtr][_IM] += res_imag;
441 #endif
442  }
443  }
444  }
445 }
446 
447 void ophGen::Fresnel_Diffraction(Point src, Complex<Real> *dst, Real lambda, Real distance, Real amplitude)
448 {
449  OphConfig *pConfig = &context_;
450  const int pnX = pConfig->pixel_number[_X];
451  const int pnY = pConfig->pixel_number[_Y];
452  const Real ppX = pConfig->pixel_pitch[_X];
453  const Real ppY = pConfig->pixel_pitch[_Y];
454  const Real ssX = pConfig->ss[_X] = pnX * ppX;
455  const Real ssY = pConfig->ss[_Y] = pnY * ppY;
456  const int offsetX = pConfig->offset[_X];
457  const int offsetY = pConfig->offset[_Y];
458  const Real k = (2 * M_PI) / lambda;
459 
460  // for performance
461  Real x = -ssX / 2;
462  Real y = -ssY / 2;
463  Real z = src.pos[_Z] + distance;
464  Real zz = z * z;
465  Real operand = lambda * z;
466 
467  Real _xbound[2] = {
468  src.pos[_X] + abs(operand / (2 * ppX)),
469  src.pos[_X] - abs(operand / (2 * ppX))
470  };
471 
472  Real _ybound[2] = {
473  src.pos[_Y] + abs(operand / (2 * ppY)),
474  src.pos[_Y] - abs(operand / (2 * ppY))
475  };
476 
477  Real Xbound[2] = {
478  floor((_xbound[_X] - x) / ppX) + 1,
479  floor((_xbound[_Y] - x) / ppX) + 1
480  };
481 
482  Real Ybound[2] = {
483  pnY - floor((_ybound[_Y] - y) / ppY),
484  pnY - floor((_ybound[_X] - y) / ppY)
485  };
486 
487  if (Xbound[_X] > pnX) Xbound[_X] = pnX;
488  if (Xbound[_Y] < 0) Xbound[_Y] = 0;
489  if (Ybound[_X] > pnY) Ybound[_X] = pnY;
490  if (Ybound[_Y] < 0) Ybound[_Y] = 0;
491 
492  for (int yytr = Ybound[_Y]; yytr < Ybound[_X]; ++yytr)
493  {
494  Real yyy = (y + (pnY - yytr + offsetY) * ppY) - src.pos[_Y];
495  int offset = yytr * pnX;
496  for (int xxtr = Xbound[_Y]; xxtr < Xbound[_X]; ++xxtr)
497  {
498  Real xxx = (x + (xxtr - 1 + offsetX) * ppX) - src.pos[_X];
499  Real p = k * (xxx * xxx + yyy * yyy + 2 * zz) / (2 * z);
500 
501  Real res_real = amplitude * sin(p) / operand;
502  Real res_imag = amplitude * (-cos(p)) / operand;
503 
504 #ifdef _OPENMP
505 #pragma omp atomic
506 #endif
507  dst[offset + xxtr][_RE] += res_real;
508 #ifdef _OPENMP
509 #pragma omp atomic
510 #endif
511  dst[offset + xxtr][_IM] += res_imag;
512  }
513  }
514 }
515 
516 void ophGen::Fresnel_FFT(Complex<Real> *src, Complex<Real> *dst, Real lambda, Real distance)
517 {
518  OphConfig *pConfig = &context_;
519  const ResolutionConfig* rc = &resCfg;
520  const int pnX = pConfig->pixel_number[_X];
521  const int pnY = pConfig->pixel_number[_Y];
522  const Real ppX = pConfig->pixel_pitch[_X];
523  const Real ppY = pConfig->pixel_pitch[_Y];
524  const Real ssX = pConfig->ss[_X] = pnX * ppX;
525  const Real ssY = pConfig->ss[_Y] = pnY * ppY;
526  const Real ssX2 = ssX * 2;
527  const Real ssY2 = ssY * 2;
528  const Real k = (2 * M_PI) / lambda;
529 
530  Complex<Real>* temp = new Complex<Real>[rc->double_size];
531  memset(temp, 0, sizeof(Complex<Real>) * rc->double_size);
532 
533  uint idxIn = 0;
534  for (int i = 0; i < pnY; i++) {
535  for (int j = 0; j < pnX; j++) {
536  temp[(i + rc->half_pnY) * rc->double_pnX+ (j + rc->half_pnX)] = src[idxIn++];
537  }
538  }
539  fft2({ rc->double_pnX, rc->double_pnY}, temp, OPH_FORWARD, OPH_ESTIMATE); // fft spatial domain
540  fft2(temp, temp, rc->double_pnX, rc->double_pnY, OPH_FORWARD, false); //
541 
542  Real* LUT_fx = new Real[rc->double_pnX];
543  Real* LUT_fy = new Real[rc->double_pnY];
544 
545  for (int i = 0; i < rc->double_pnX; i++) {
546  LUT_fx[i] = (i - pnX) / ssX2;
547  LUT_fx[i] *= LUT_fx[i];
548  }
549 
550  for (int i = 0; i < rc->double_pnY; i++) {
551  LUT_fy[i] = (i - pnY) / ssY2;
552  LUT_fy[i] *= LUT_fy[i];
553  }
554 
555  Real sqrtPart;
556  Real lambda_square = lambda * lambda;
557  Real tmp = 2 * M_PI * distance;
558 
559  for (int i = 0; i < rc->double_size; i++) {
560  int j = i % rc->double_pnX;
561  int k = i / rc->double_pnX;
562 
563  sqrtPart = sqrt(1 / lambda_square - LUT_fx[j] - LUT_fy[k]);
564 
565  Complex<Real> prop(0, tmp * sqrtPart);
566  temp[i] = temp[i] * exp(prop);
567  }
568 
569  fft2({ rc->double_pnX, rc->double_pnY}, temp, OPH_BACKWARD, OPH_ESTIMATE);
570  fft2(temp, temp, rc->double_pnX, rc->double_pnY, OPH_BACKWARD, false);
571 
572  uint idxOut = 0;
573  for (int i = 0; i < pnY; i++) {
574  for (int j = 0; j < pnX; j++) {
575  dst[idxOut++] = temp[(i + rc->half_pnY) * rc->double_pnX+ (j + rc->half_pnX)];
576  }
577  }
578  delete[] LUT_fx;
579  delete[] LUT_fy;
580  delete[] temp;
581 }
582 
584 {
585  const int pnX = context_.pixel_number[_X];
586  const int pnY = context_.pixel_number[_Y];
587  const int N = pnX * pnY;
588  const Real ppX = context_.pixel_pitch[_X];
589  const Real ppY = context_.pixel_pitch[_Y];
590  const Real ssX = context_.ss[_X] = pnX * ppX;
591  const Real ssY = context_.ss[_Y] = pnY * ppY;
592 
593  Real dfx = 1 / ssX;
594  Real dfy = 1 / ssY;
595 
596  Real k = context_.k = (2 * M_PI / lambda);
597  Real kk = k * k;
598  Real kd = k * distance;
599  Real fx = -1 / (ppX * 2);
600  Real fy = 1 / (ppY * 2);
601 
602 #ifdef _OPENMP
603 #pragma omp parallel for firstprivate(pnX, dfx, dfy, lambda, kd, kk)
604 #endif
605  for (int i = 0; i < N; i++)
606  {
607  Real x = i % pnX;
608  Real y = i / pnX;
609 
610  Real fxx = fx + dfx * x;
611  Real fyy = fy - dfy - dfy * y;
612 
613  Real fxxx = lambda * fxx;
614  Real fyyy = lambda * fyy;
615 
616  Real sval = sqrt(1 - (fxxx * fxxx) - (fyyy * fyyy));
617  sval = sval * kd;
618  Complex<Real> kernel(0, sval);
619  kernel.exp();
620 
621  bool prop_mask = ((fxx * fxx + fyy * fyy) < kk) ? true : false;
622 
623  Complex<Real> u_frequency;
624  if (prop_mask) {
625  u_frequency = kernel * src[i];
626  dst[i][_RE] += u_frequency[_RE];
627  dst[i][_IM] += u_frequency[_IM];
628  }
629  }
630 }
631 
633 {
634  int N = size[_X] * size[_Y];
635  if (N <= 0) return;
636 
637  Complex<Real>* src1FT = new Complex<Real>[N];
638  Complex<Real>* src2FT = new Complex<Real>[N];
639  Complex<Real>* dstFT = new Complex<Real>[N];
640 
641  fft2(src1, src1FT, size[_X], size[_Y], OPH_FORWARD, (bool)OPH_ESTIMATE);
642  fft2(src2, src2FT, size[_X], size[_Y], OPH_FORWARD, (bool)OPH_ESTIMATE);
643 
644  for (int i = 0; i < N; i++)
645  dstFT[i] = src1FT[i] * src2FT[i];
646 
647  fft2(dstFT, dst, size[_X], size[_Y], OPH_BACKWARD, (bool)OPH_ESTIMATE);
648 
649  delete[] src1FT;
650  delete[] src2FT;
651  delete[] dstFT;
652 }
653 
655 {
656  const int pnX = context_.pixel_number[_X];
657  const int pnY = context_.pixel_number[_Y];
658  const uint nWave = context_.waveNum;
659  const long long int N = pnX * pnY;
660 
661  Real minVal = MAX_DOUBLE, maxVal = MIN_DOUBLE, gap = 0;
662  for (uint ch = 0; ch < nWave; ch++)
663  {
664  Real minTmp = minOfArr(m_lpEncoded[ch], N);
665  Real maxTmp = maxOfArr(m_lpEncoded[ch], N);
666 
667  if (minVal > minTmp)
668  minVal = minTmp;
669  if (maxVal < maxTmp)
670  maxVal = maxTmp;
671  }
672 
673  gap = maxVal - minVal;
674  for (uint ch = 0; ch < nWave; ch++)
675  {
676 #ifdef _OPENMP
677 #pragma omp parallel for firstprivate(minVal, gap, pnX)
678 #endif
679  for (int j = 0; j < pnY; j++) {
680  int start = j * pnX;
681  for (int i = 0; i < pnX; i++) {
682  int idx = start + i;
683  m_lpNormalized[ch][idx] = (((m_lpEncoded[ch][idx] - minVal) / gap) * 255 + 0.5);
684  }
685  }
686  }
687 }
688 
689 bool ophGen::save(const char* fname, uint8_t bitsperpixel, uchar* src, uint px, uint py)
690 {
691  bool bOK = false;
692 
693  if (fname == nullptr) return bOK;
694 
695  uchar* source = src;
696  bool bAlloc = false;
697  const uint nChannel = context_.waveNum;
698 
699  ivec2 p(px, py);
700  if (px == 0 && py == 0)
702 
703 
704  std::string file = fname;
705  std::replace(file.begin(), file.end(), '\\', '/');
706 
707  // split path
708  std::vector<std::string> components;
709  std::stringstream ss(file);
710  std::string item;
711  char token = '/';
712 
713  while (std::getline(ss, item, token)) {
714  components.push_back(item);
715  }
716 
717  std::string dir;
718 
719  for (size_t i = 0; i < components.size() - 1; i++)
720  {
721  dir += components[i];
722  dir += "/";
723  }
724 
725  std::string filename = components[components.size() - 1];
726 
727  // find extension
728  bool hasExt;
729  size_t ext_pos = file.rfind(".");
730  hasExt = (ext_pos == string::npos) ? false : true;
731 
732  if (!hasExt)
733  filename.append(".bmp");
734 
735  std::string fullpath = dir + filename;
736 
737  if (src == nullptr) {
738  if (nChannel == 1) {
739  source = m_lpNormalized[0];
740  saveAsImg(fullpath.c_str(), bitsperpixel, source, p[_X], p[_Y]);
741  }
742  else if (nChannel == 3) {
743  if (imgCfg.merge) {
744  uint nSize = (((p[_X] * bitsperpixel >> 3) + 3) & ~3) * p[_Y];
745  source = new uchar[nSize];
746  bAlloc = true;
747  for (uint i = 0; i < nChannel; i++) {
748  mergeColor(i, p[_X], p[_Y], m_lpNormalized[i], source);
749  }
750 
751  saveAsImg(fullpath.c_str(), bitsperpixel, source, p[_X], p[_Y]);
752  if (bAlloc) delete[] source;
753  }
754  else {
755  for (uint i = 0; i < nChannel; i++) {
756  char path[FILENAME_MAX] = { 0, };
757  sprintf(path, "%s%d_%s", dir.c_str(), i, filename.c_str());
758  source = m_lpNormalized[i];
759  saveAsImg(path, bitsperpixel / nChannel, source, p[_X], p[_Y]);
760  }
761  }
762  }
763  else return false;
764  }
765  else
766  saveAsImg(fullpath.c_str(), bitsperpixel, source, p[_X], p[_Y]);
767 
768  return true;
769 }
770 
771 void* ophGen::load(const char * fname)
772 {
773  if (checkExtension(fname, ".bmp")) {
774  return Openholo::loadAsImg(fname);
775  }
776  else { // when extension is not .bmp
777  return nullptr;
778  }
779 
780  return nullptr;
781 }
782 
783 bool ophGen::loadAsOhc(const char * fname)
784 {
785  if (!Openholo::loadAsOhc(fname)) return false;
786 
787  const uint nChannel = context_.waveNum;
788  const long long int pnXY = context_.pixel_number[_X] * context_.pixel_number[_Y];
789 
790  m_lpEncoded = new Real*[nChannel];
791  m_lpNormalized = new uchar*[nChannel];
792  for (uint ch = 0; ch < nChannel; ch++) {
793  m_lpEncoded[ch] = new Real[pnXY];
794  memset(m_lpEncoded[ch], 0, sizeof(Real) * pnXY);
795  m_lpNormalized[ch] = new uchar[pnXY];
796  memset(m_lpNormalized[ch], 0, sizeof(uchar) * pnXY);
797  }
798  return true;
799 }
800 
802 {
804  int N2 = m_vecEncodeSize[_X] * m_vecEncodeSize[_Y];
805 
806  for (uint ch = 0; ch < context_.waveNum; ch++) {
807  if (complex_H[ch])
808  memset(complex_H[ch], 0., sizeof(Complex<Real>) * N);
809  if (m_lpEncoded[ch])
810  memset(m_lpEncoded[ch], 0., sizeof(Real) * N2);
811  if (m_lpNormalized[ch])
812  memset(m_lpNormalized[ch], 0, sizeof(uchar) * N2);
813  }
814 }
815 
816 void ophGen::encoding(unsigned int ENCODE_FLAG)
817 {
818  auto begin = CUR_TIME;
819 
820  // func pointer
821  void (ophGen::*encodeFunc) (Complex<Real>*, Real*, const int) = nullptr;
822 
823  Complex<Real> *holo = nullptr;
824  Real *encoded = nullptr;
825  const long long int pnXY = context_.pixel_number[_X] * context_.pixel_number[_Y];
827 
828  switch (ENCODE_FLAG)
829  {
830  case ENCODE_PHASE: encodeFunc = &ophGen::Phase; LOG("ENCODE_PHASE\n"); break;
831  case ENCODE_AMPLITUDE: encodeFunc = &ophGen::Amplitude; LOG("ENCODE_AMPLITUDE\n"); break;
832  case ENCODE_REAL: encodeFunc = &ophGen::RealPart; LOG("ENCODE_REAL\n"); break;
833  case ENCODE_IMAGINARY: encodeFunc = &ophGen::ImaginaryPart; LOG("ENCODE_IMAGINARY\n"); break;
834  case ENCODE_SIMPLENI: encodeFunc = &ophGen::SimpleNI; LOG("ENCODE_SIMPLENI\n"); break;
835  case ENCODE_BURCKHARDT: encodeFunc = &ophGen::Burckhardt; LOG("ENCODE_BURCKHARDT\n"); break;
836  case ENCODE_TWOPHASE: encodeFunc = &ophGen::TwoPhase; LOG("ENCODE_TWOPHASE\n"); break;
837  default:
838  LOG("<FAILED> WRONG PARAMETERS.\n");
839  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
840  return;
841  }
842 
843  for (uint ch = 0; ch < context_.waveNum; ch++) {
844  holo = complex_H[ch];
845  encoded = m_lpEncoded[ch];
846  (this->*encodeFunc)(holo, encoded, m_vecEncodeSize[_X] * m_vecEncodeSize[_Y]);
847  }
848  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
849 }
850 
851 //template <typename T>
852 //void ophGen::encoding(unsigned int ENCODE_FLAG, Complex<T>* holo, T* encoded)
853 void ophGen::encoding(unsigned int ENCODE_FLAG, Complex<Real>* holo, Real* encoded)
854 {
855  auto begin = CUR_TIME;
856  // func pointer
857  void (ophGen::*encodeFunc) (Complex<Real>*, Real*, const int) = nullptr;
858 
859  const long long int pnXY = context_.pixel_number[_X] * context_.pixel_number[_Y];
861 
862  switch (ENCODE_FLAG)
863  {
864  case ENCODE_PHASE: encodeFunc = &ophGen::Phase; LOG("ENCODE_PHASE\n"); break;
865  case ENCODE_AMPLITUDE: encodeFunc = &ophGen::Amplitude; LOG("ENCODE_AMPLITUDE\n"); break;
866  case ENCODE_REAL: encodeFunc = &ophGen::RealPart; LOG("ENCODE_REAL\n"); break;
867  case ENCODE_IMAGINARY: encodeFunc = &ophGen::ImaginaryPart; LOG("ENCODE_IMAGINARY\n"); break;
868  case ENCODE_SIMPLENI: encodeFunc = &ophGen::SimpleNI; LOG("ENCODE_SIMPLENI\n"); break;
869  case ENCODE_BURCKHARDT: encodeFunc = &ophGen::Burckhardt; LOG("ENCODE_BURCKHARDT\n"); break;
870  case ENCODE_TWOPHASE: encodeFunc = &ophGen::TwoPhase; LOG("ENCODE_TWOPHASE\n"); break;
871  default: LOG("<FAILED> WRONG PARAMETERS.\n"); return;
872  }
873 
874  if (holo == nullptr) holo = complex_H[0];
875  if (encoded == nullptr) encoded = m_lpEncoded[0];
876 
877  (this->*encodeFunc)(holo, encoded, m_vecEncodeSize[_X] * m_vecEncodeSize[_Y]);
878 
879  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
880 }
881 
882 void ophGen::encoding(unsigned int ENCODE_FLAG, unsigned int passband, Complex<Real>* holo, Real* encoded)
883 {
884  holo == nullptr ? holo = *complex_H : holo;
885  encoded == nullptr ? encoded = *m_lpEncoded : encoded;
886 
888  const long long int pnXY = context_.pixel_number[_X] * context_.pixel_number[_Y];
889  const uint nChannel = context_.waveNum;
890 
891  for (uint ch = 0; ch < nChannel; ch++) {
892  /* initialize */
893  long long int m_vecEncodeSize = pnXY;
894  if (m_lpEncoded[ch] != nullptr) delete[] m_lpEncoded[ch];
895  m_lpEncoded[ch] = new Real[m_vecEncodeSize];
896  memset(m_lpEncoded[ch], 0, sizeof(Real) * m_vecEncodeSize);
897 
898  if (m_lpNormalized[ch] != nullptr) delete[] m_lpNormalized[ch];
900  memset(m_lpNormalized[ch], 0, sizeof(uchar) * m_vecEncodeSize);
901 
902  switch (ENCODE_FLAG)
903  {
904  case ENCODE_SSB:
905  LOG("ENCODE_SSB");
906  singleSideBand((holo), m_lpEncoded[ch], context_.pixel_number, passband);
907  break;
908  case ENCODE_OFFSSB:
909  {
910  LOG("ENCODE_OFFSSB");
911  Complex<Real> *tmp = new Complex<Real>[pnXY];
912  memcpy(tmp, holo, sizeof(Complex<Real>) * pnXY);
913  freqShift(tmp, tmp, context_.pixel_number, 0, 100);
914  singleSideBand(tmp, m_lpEncoded[ch], context_.pixel_number, passband);
915  delete[] tmp;
916  break;
917  }
918  default:
919  LOG("<FAILED> WRONG PARAMETERS.\n");
920  return;
921  }
922  }
923 }
924 
925 void ophGen::encoding(unsigned int BIN_ENCODE_FLAG, unsigned int ENCODE_FLAG, Real threshold, Complex<Real>* holo, Real* encoded)
926 {
927  auto begin = CUR_TIME;
928  const uint nChannel = context_.waveNum;
929  const long long int pnXY = context_.pixel_number[_X] * context_.pixel_number[_Y];
930 
931  switch (BIN_ENCODE_FLAG) {
932  case ENCODE_SIMPLEBINARY:
933  LOG("ENCODE_SIMPLEBINARY\n");
934  if (holo == nullptr || encoded == nullptr)
935  for (uint ch = 0; ch < nChannel; ch++) {
936  binarization(complex_H[ch], m_lpEncoded[ch], pnXY, ENCODE_FLAG, threshold);
937  }
938  else
939  binarization(holo, encoded, pnXY, ENCODE_FLAG, threshold);
940  break;
941  case ENCODE_EDBINARY:
942  LOG("ENCODE_EDBINARY\n");
943  if (ENCODE_FLAG != ENCODE_REAL) {
944  LOG("<FAILED> WRONG PARAMETERS : %d\n", ENCODE_FLAG);
945  return;
946  }
947  if (holo == nullptr || encoded == nullptr)
948  for (uint ch = 0; ch < nChannel; ch++) {
950  }
951  else
952  binaryErrorDiffusion(holo, encoded, pnXY, FLOYD_STEINBERG, threshold);
953  break;
954  default:
955  LOG("<FAILED> WRONG PARAMETERS.\n");
956  return;
957  }
958 
959  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
960 }
961 
963 {
964  const long long int pnXY = context_.pixel_number[_X] * context_.pixel_number[_Y];
965  const uint nChannel = context_.waveNum;
966 
968  else if (ENCODE_METHOD == ENCODE_TWOPHASE) m_vecEncodeSize[_X] *= 2;
969 
970  for (uint ch = 0; ch < nChannel; ch++) {
971  /* initialize */
972  if (m_lpEncoded[ch] != nullptr) delete[] m_lpEncoded[ch];
974  memset(m_lpEncoded[ch], 0, sizeof(Real) * m_vecEncodeSize[_X] * m_vecEncodeSize[_Y]);
975 
976  if (m_lpNormalized[ch] != nullptr) delete[] m_lpNormalized[ch];
978  memset(m_lpNormalized[ch], 0, sizeof(uchar) * m_vecEncodeSize[_X] * m_vecEncodeSize[_Y]);
979 
980 
981  switch (ENCODE_METHOD)
982  {
983  case ENCODE_SIMPLENI:
984  LOG("ENCODE_SIMPLENI\n");
985  SimpleNI(complex_H[ch], m_lpEncoded[ch], pnXY);
986  break;
987  case ENCODE_REAL:
988  LOG("ENCODE_REAL\n");
989  realPart<Real>(complex_H[ch], m_lpEncoded[ch], pnXY);
990  break;
991  case ENCODE_BURCKHARDT:
992  LOG("ENCODE_BURCKHARDT\n");
993  Burckhardt(complex_H[ch], m_lpEncoded[ch], pnXY);
994  break;
995  case ENCODE_TWOPHASE:
996  LOG("ENCODE_TWOPHASE\n");
997  TwoPhase(complex_H[ch], m_lpEncoded[ch], pnXY);
998  break;
999  case ENCODE_PHASE:
1000  LOG("ENCODE_PHASE\n");
1001  Phase(complex_H[ch], m_lpEncoded[ch], pnXY);
1002  break;
1003  case ENCODE_AMPLITUDE:
1004  LOG("ENCODE_AMPLITUDE\n");
1005  getAmplitude(complex_H[ch], m_lpEncoded[ch], pnXY);
1006  break;
1007  case ENCODE_SSB:
1008  LOG("ENCODE_SSB\n");
1010  break;
1011  case ENCODE_OFFSSB:
1012  LOG("ENCODE_OFFSSB\n");
1013  freqShift(complex_H[ch], complex_H[ch], context_.pixel_number, 0, 100);
1015  break;
1016  default:
1017  LOG("<FAILED> WRONG PARAMETERS.\n");
1018  return;
1019  }
1020  }
1021 }
1022 
1023 void ophGen::singleSideBand(Complex<Real>* src, Real* dst, const ivec2 holosize, int SSB_PASSBAND)
1024 {
1025  const int nX = holosize[_X];
1026  const int nY = holosize[_Y];
1027  const int half_nX = nX >> 1;
1028  const int half_nY = nY >> 1;
1029 
1030  const long long int N = nX * nY;
1031  const long long int half_N = N >> 1;
1032 
1033  Complex<Real>* AS = new Complex<Real>[N];
1034  //fft2(holosize, holo, OPH_FORWARD, OPH_ESTIMATE);
1035  fft2(src, AS, nX, nY, OPH_FORWARD, false);
1036  //fftExecute(temp);
1037 
1038 
1039  switch (SSB_PASSBAND)
1040  {
1041  case SSB_LEFT:
1042  for (int i = 0; i < nY; i++)
1043  {
1044  std::memset(&AS[i * nX + half_nX], 0.0, sizeof(Complex<Real>) * half_nX);
1045  }
1046  break;
1047  case SSB_RIGHT:
1048  for (int i = 0; i < nY; i++)
1049  {
1050  std::memset(&AS[i * nX], 0.0, sizeof(Complex<Real>) * half_nX);
1051  }
1052  break;
1053  case SSB_TOP:
1054  std::memset(&AS[half_N], 0, sizeof(Complex<Real>) * half_N);
1055  break;
1056 
1057  case SSB_BOTTOM:
1058  std::memset(&AS[0], 0, sizeof(Complex<Real>) * half_N);
1059  break;
1060  }
1061 
1062  Complex<Real>* filtered = new Complex<Real>[N];
1063  //fft2(holosize, AS, OPH_BACKWARD, OPH_ESTIMATE);
1064  fft2(AS, filtered, nX, nY, OPH_BACKWARD, false);
1065 
1066  //fftExecute(filtered);
1067 
1068 
1069  Real* realFiltered = new Real[N];
1070  oph::realPart<Real>(filtered, realFiltered, N);
1071 
1072  oph::normalize(realFiltered, dst, N);
1073 
1074  delete[] AS;
1075  delete[] filtered;
1076  delete[] realFiltered;
1077 }
1078 
1079 void ophGen::freqShift(Complex<Real>* src, Complex<Real>* dst, const ivec2 holosize, int shift_x, int shift_y)
1080 {
1081  int N = holosize[_X] * holosize[_Y];
1082 
1083  Complex<Real>* AS = new Complex<Real>[N];
1084  fft2(holosize, src, OPH_FORWARD, OPH_ESTIMATE);
1085  fft2(src, AS, holosize[_X], holosize[_Y], OPH_FORWARD);
1086  //fftExecute(AS);
1087 
1088  Complex<Real>* shifted = new Complex<Real>[N];
1089  circShift<Complex<Real>>(AS, shifted, shift_x, shift_y, holosize.v[_X], holosize.v[_Y]);
1090 
1091  fft2(holosize, shifted, OPH_BACKWARD, OPH_ESTIMATE);
1092  fft2(shifted, dst, holosize[_X], holosize[_Y], OPH_BACKWARD);
1093  //fftExecute(dst);
1094 
1095  delete[] AS;
1096  delete[] shifted;
1097 }
1098 
1099 
1100 bool ophGen::saveRefImages(char* fnameW, char* fnameWC, char* fnameAS, char* fnameSSB, char* fnameHP, char* fnameFreq, char* fnameReal, char* fnameBin, char* fnameReconBin, char* fnameReconErr, char* fnameReconNo)
1101 {
1102  ivec2 holosize = context_.pixel_number;
1103  int nx = holosize[_X], ny = holosize[_Y];
1104  int ss = nx*ny;
1105 
1106  Real* temp1 = new Real[ss];
1107  uchar* temp2 = new uchar[ss];
1108 
1109  oph::normalize(weight, temp2, nx, ny);
1110  saveAsImg(fnameW, 8, temp2, nx, ny);
1111  cout << "W saved" << endl;
1112 
1113  oph::absCplxArr<Real>(weightC, temp1, ss);
1114  oph::normalize(temp1, temp2, nx, ny);
1115  saveAsImg(fnameWC, 8, temp2, nx, ny);
1116  cout << "WC saved" << endl;
1117 
1118  oph::absCplxArr<Real>(AS, temp1, ss);
1119  oph::normalize(temp1, temp2, nx, ny);
1120  saveAsImg(fnameAS, 8, temp2, nx, ny);
1121  cout << "AS saved" << endl;
1122 
1123  oph::normalize(maskSSB, temp2, nx, ny);
1124  saveAsImg(fnameSSB, 8, temp2, nx, ny);
1125  cout << "SSB saved" << endl;
1126 
1127  oph::normalize(maskHP, temp2, nx, ny);
1128  saveAsImg(fnameHP, 8, temp2, nx, ny);
1129  cout << "HP saved" << endl;
1130 
1131  oph::absCplxArr<Real>(freqW, temp1, ss);
1132  oph::normalize(temp1, temp2, nx, ny);
1133  saveAsImg(fnameFreq, 8, temp2, nx, ny);
1134  cout << "Freq saved" << endl;
1135 
1136  oph::normalize(realEnc, temp2, nx, ny);
1137  saveAsImg(fnameReal, 8, temp2, nx, ny);
1138  cout << "Real saved" << endl;
1139 
1140  oph::normalize(binary, temp2, nx, ny);
1141  saveAsImg(fnameBin, 8, temp2, nx, ny);
1142  cout << "Bin saved" << endl;
1143 
1144 
1145  Complex<Real>* temp = new Complex<Real>[ss];
1146  for (int i = 0; i < ss; i++) {
1147  temp[i][_RE] = binary[i];
1148  temp[i][_IM] = 0;
1149  }
1150  fft2(ivec2(nx, ny), temp, OPH_FORWARD);
1151  fft2(temp, temp, nx, ny, OPH_FORWARD);
1152  for (int i = 0; i < ss; i++) {
1153  temp[i][_RE] *= maskSSB[i];
1154  temp[i][_IM] *= maskSSB[i];
1155  }
1156  fft2(ivec2(nx, ny), temp, OPH_BACKWARD);
1157  fft2(temp, temp, nx, ny, OPH_BACKWARD);
1158 
1159  Complex<Real>* reconBin = new Complex<Real>[ss];
1160  memset(reconBin, 0, sizeof(Complex<Real>) * ss);
1161  //fresnelPropagation(temp, reconBin, 0.001, 0);
1162  Fresnel_FFT(temp, reconBin, context_.wave_length[0], 0.001);
1163 
1164  oph::absCplxArr<Real>(reconBin, temp1, ss);
1165  for (int i = 0; i < ss; i++) {
1166  temp1[i] = temp1[i] * temp1[i];
1167  }
1168  oph::normalize(temp1, temp2, nx, ny);
1169  saveAsImg(fnameReconBin, 8, temp2, nx, ny);
1170  cout << "recon bin saved" << endl;
1171 
1172 
1173  temp = new Complex<Real>[ss];
1174  for (int i = 0; i < ss; i++) {
1175  temp[i][_RE] = m_lpEncoded[0][i];
1176  temp[i][_IM] = 0;
1177  }
1178  fft2(ivec2(nx, ny), temp, OPH_FORWARD);
1179  fft2(temp, temp, holosize[_X], holosize[_Y], OPH_FORWARD);
1180  for (int i = 0; i < ss; i++) {
1181  temp[i][_RE] *= maskHP[i];
1182  temp[i][_IM] *= maskHP[i];
1183  }
1184  fft2(ivec2(nx, ny), temp, OPH_BACKWARD);
1185  fft2(temp, temp, nx, ny, OPH_BACKWARD);
1186 
1187  reconBin = new Complex<Real>[ss];
1188  //fresnelPropagation(temp, reconBin, 0.001, 0);
1189  Fresnel_FFT(temp, reconBin, context_.wave_length[0], 0.001);
1190 
1191  oph::absCplxArr<Real>(reconBin, temp1, ss);
1192  for (int i = 0; i < ss; i++) {
1193  temp1[i] = temp1[i] * temp1[i];
1194  }
1195  oph::normalize(temp1, temp2, nx, ny);
1196  saveAsImg(fnameReconErr, 8, temp2, nx, ny);
1197  cout << "recon error saved" << endl;
1198 
1199 
1200 
1201 
1202  temp = new Complex<Real>[ss];
1203  for (int i = 0; i < ss; i++) {
1204  temp[i][_RE] = normalized[i][_RE];
1205  temp[i][_IM] = normalized[i][_IM];
1206  }
1207  fft2(ivec2(nx, ny), temp, OPH_FORWARD);
1208  fft2(temp, temp, holosize[_X], holosize[_Y], OPH_FORWARD);
1209  for (int i = 0; i < ss; i++) {
1210  temp[i][_RE] *= maskSSB[i];
1211  temp[i][_IM] *= maskSSB[i];
1212  }
1213  fft2(ivec2(nx, ny), temp, OPH_BACKWARD);
1214  fft2(temp, temp, nx, ny, OPH_BACKWARD);
1215 
1216  reconBin = new Complex<Real>[ss];
1217  //fresnelPropagation(temp, reconBin, 0.001, 0);
1218  Fresnel_FFT(temp, reconBin, context_.wave_length[0], 0.001);
1219 
1220  oph::absCplxArr<Real>(reconBin, temp1, ss);
1221  for (int i = 0; i < ss; i++) {
1222  temp1[i] = temp1[i] * temp1[i];
1223  }
1224  oph::normalize(temp1, temp2, nx, ny);
1225  saveAsImg(fnameReconNo, 8, temp2, nx, ny);
1226 
1227 
1228  return true;
1229 }
1230 
1231 bool ophGen::binaryErrorDiffusion(Complex<Real>* holo, Real* encoded, const ivec2 holosize, const int type, Real threshold)
1232 {
1233 
1234  //cout << "\nin?" << endl;
1235  int ss = holosize[_X] * holosize[_Y];
1236  weight = new Real[ss];
1237  //cout << "?" << endl;
1238  weightC = new Complex<Real>[ss];
1239  //cout << "??" << endl;
1240  ivec2 Nw;
1241  memsetArr<Real>(weight, 0.0, 0, ss - 1);
1242  //cout << "???" << endl;
1243  if (!getWeightED(holosize, type, &Nw))
1244  return false;
1245  //cout << "1?" << endl;
1246  AS = new Complex<Real>[ss];
1247  fft2(ivec2(holosize[_X], holosize[_Y]), holo, OPH_FORWARD);
1248  fft2(holo, AS, holosize[_X], holosize[_Y], OPH_FORWARD);
1249  //cout << "2?" << endl;
1250  // SSB mask generation
1251  maskSSB = new Real[ss];
1252  for (int i = 0; i < ss; i++) {
1253  if (((Real)i / (Real)holosize[_X]) < ((Real)holosize[_Y] / 2.0))
1254  maskSSB[i] = 1;
1255  else
1256  maskSSB[i] = 0;
1257  AS[i] *= maskSSB[i];
1258  }
1259 
1260  //cout << "3?" << endl;
1261  Complex<Real>* filtered = new Complex<Real>[ss];
1262  fft2(ivec2(holosize[_X], holosize[_Y]), AS, OPH_BACKWARD);
1263  fft2(AS, filtered, holosize[_X], holosize[_Y], OPH_BACKWARD);
1264  //cout << "4?" << endl;
1265  normalized = new Complex<Real>[ss];
1266  oph::normalize(filtered, normalized, ss);
1267  LOG("normalize finishied..\n");
1268  if (encoded == nullptr)
1269  encoded = new Real[ss];
1270 
1271  shiftW(holosize);
1272  LOG("shiftW finishied..\n");
1273 
1274  // HP mask generation
1275  maskHP = new Real[ss];
1276  Real absFW;
1277  for (int i = 0; i < ss; i++) {
1278  oph::absCplx<Real>(freqW[i], absFW);
1279  if (((Real)i / (Real)holosize[_X]) < ((Real)holosize[_Y] / 2.0) && absFW < 0.6)
1280  maskHP[i] = 1;
1281  else
1282  maskHP[i] = 0;
1283  }
1284  //cout << "5?" << endl;
1285 
1286  // For checking
1287  binary = new Real[ss];
1288  realEnc = new Real[ss];
1289  for (int i = 0; i < ss; i++) {
1290  realEnc[i] = normalized[i][_RE];
1291  if (normalized[i][_RE] > threshold)
1292  binary[i] = 1;
1293  else
1294  binary[i] = 0;
1295  }
1296 
1297  Complex<Real>* toBeBin = new Complex<Real>[ss];
1298  for (int i = 0; i < ss; i++) {
1299  toBeBin[i] = normalized[i];
1300  }
1301  int ii, iii, jjj;
1302  int cx = (holosize[_X] + 1) / 2, cy = (holosize[_Y] + 1) / 2;
1303  Real error;
1304  for (int iy = 0; iy < holosize[_Y] - Nw[_Y]; iy++) {
1305  for (int ix = Nw[_X]; ix < holosize[_X] - Nw[_X]; ix++) {
1306 
1307  ii = ix + iy*holosize[_X];
1308  if (ix >= Nw[_X] && ix < (holosize[_X] - Nw[_X]) && iy < (holosize[_Y] - Nw[_Y])) {
1309 
1310  if (toBeBin[ii][_RE] > threshold)
1311  encoded[ii] = 1;
1312  else
1313  encoded[ii] = 0;
1314 
1315  error = toBeBin[ii][_RE] - encoded[ii];
1316 
1317  for (int iwy = 0; iwy < Nw[_Y] + 1; iwy++) {
1318  for (int iwx = -Nw[_X]; iwx < Nw[_X] + 1; iwx++) {
1319  iii = (ix + iwx) + (iy + iwy)*holosize[_X];
1320  jjj = (cx + iwx) + (cy + iwy)*holosize[_X];
1321 
1322  toBeBin[iii] += weightC[jjj] * error;
1323  }
1324  }
1325  }
1326  else {
1327  encoded[ii] = 0;
1328  }
1329  }
1330  }
1331  LOG("binary finishied..\n");
1332 
1333  return true;
1334 }
1335 
1336 
1337 bool ophGen::getWeightED(const ivec2 holosize, const int type, ivec2* pNw)
1338 {
1339 
1340  int cx = (holosize[_X] + 1) / 2;
1341  int cy = (holosize[_Y] + 1) / 2;
1342 
1343  ivec2 Nw;
1344 
1345  switch (type) {
1346  case FLOYD_STEINBERG:
1347  LOG("ERROR DIFFUSION : FLOYD_STEINBERG\n");
1348  weight[(cx + 1) + cy*holosize[_X]] = 7.0 / 16.0;
1349  weight[(cx - 1) + (cy + 1)*holosize[_X]] = 3.0 / 16.0;
1350  weight[(cx)+(cy + 1)*holosize[_X]] = 5.0 / 16.0;
1351  weight[(cx + 1) + (cy + 1)*holosize[_X]] = 1.0 / 16.0;
1352  Nw[_X] = 1; Nw[_Y] = 1;
1353  break;
1354  case SINGLE_RIGHT:
1355  LOG("ERROR DIFFUSION : SINGLE_RIGHT\n");
1356  weight[(cx + 1) + cy*holosize[_X]] = 1.0;
1357  Nw[_X] = 1; Nw[_Y] = 0;
1358  break;
1359  case SINGLE_DOWN:
1360  LOG("ERROR DIFFUSION : SINGLE_DOWN\n");
1361  weight[cx + (cy + 1)*holosize[_X]] = 1.0;
1362  Nw[_X] = 0; Nw[_Y] = 1;
1363  break;
1364  default:
1365  LOG("<FAILED> WRONG PARAMETERS.\n");
1366  return false;
1367  }
1368 
1369  *pNw = Nw;
1370  return true;
1371 
1372 }
1373 
1374 bool ophGen::shiftW(ivec2 holosize)
1375 {
1376  int ss = holosize[_X] * holosize[_Y];
1377 
1378  Complex<Real> term(0, 0);
1379  Complex<Real> temp(0, 0);
1380  int x, y;
1381  for (int i = 0; i < ss; i++) {
1382 
1383  x = i % holosize[_X] - holosize[_X] / 2; y = i / holosize[_X] - holosize[_Y];
1384  term[_IM] = 2.0 * M_PI*((1.0 / 4.0)*(Real)x + (0.0)*(Real)y);
1385  temp[_RE] = weight[i];
1386  weightC[i] = temp *exp(term);
1387  }
1388 
1389  freqW = new Complex<Real>[ss];
1390 
1391  fft2(ivec2(holosize[_X], holosize[_Y]), weightC, OPH_FORWARD);
1392  fft2(weightC, freqW, holosize[_X], holosize[_Y], OPH_FORWARD);
1393  for (int i = 0; i < ss; i++) {
1394  freqW[i][_RE] -= 1.0;
1395  }
1396  return true;
1397 
1398 }
1399 
1400 void ophGen::binarization(Complex<Real>* src, Real* dst, const int size, int ENCODE_FLAG, Real threshold)
1401 {
1402  oph::normalize(src, src, size);
1404 
1405 #ifdef _OPENMP
1406 #pragma omp parallel for firstprivate(threshold)
1407 #endif
1408  for (int i = 0; i < size; i++) {
1409  if (src[i][_RE] > threshold)
1410  dst[i] = 1;
1411  else
1412  dst[i] = 0;
1413  }
1414 }
1415 
1417 {
1418  const int pnX = context_.pixel_number[_X];
1419  const int pnY = context_.pixel_number[_Y];
1420  const Real ppX = context_.pixel_pitch[_X];
1421  const Real ppY = context_.pixel_pitch[_Y];
1422  const int pnXY = pnX * pnY;
1423  const Real lambda = context_.wave_length[channel];
1424  const Real ssX = pnX * ppX * 2;
1425  const Real ssY = pnY * ppY * 2;
1426  const Real z = 2 * M_PI * distance;
1427  const Real v = 1 / (lambda * lambda);
1428  const int hpnX = pnX / 2;
1429  const int hpnY = pnY / 2;
1430  const int pnX2 = pnX * 2;
1431  const int pnY2 = pnY * 2;
1432 
1433  Complex<Real>* temp = new Complex<Real>[pnXY * 4];
1434  memset(temp, 0, sizeof(Complex<Real>) * pnXY * 4);
1435 
1436 #ifdef _OPENMP
1437 #pragma omp parallel for firstprivate(pnX, pnX2, hpnX, hpnY)
1438 #endif
1439  for (int i = 0; i < pnY; i++)
1440  {
1441  int src = pnX * i;
1442  int dst = pnX2 * (i + hpnY) + hpnX;
1443  memcpy(&temp[dst], &in[src], sizeof(Complex<Real>) * pnX);
1444  }
1445 
1446  fft2(temp, temp, pnX2, pnY2, OPH_FORWARD, false);
1447 
1448 #ifdef _OPENMP
1449 #pragma omp parallel for firstprivate(ssX, ssY, z, v)
1450 #endif
1451  for (int j = 0; j < pnY2; j++)
1452  {
1453  Real fy = (-pnY + j) / ssY;
1454  Real fyy = fy * fy;
1455  int iWidth = j * pnX2;
1456  for (int i = 0; i < pnX2; i++)
1457  {
1458  Real fx = (-pnX + i) / ssX;
1459  Real fxx = fx * fx;
1460 
1461  Real sqrtPart = sqrt(v - fxx - fyy);
1462  Complex<Real> prop(0, z * sqrtPart);
1463  temp[iWidth + i] *= prop.exp();
1464  }
1465  }
1466 
1467  fft2(temp, temp, pnX2, pnY2, OPH_BACKWARD, true);
1468 
1469 #ifdef _OPENMP
1470 #pragma omp parallel for firstprivate(pnX, pnX2, hpnX, hpnY)
1471 #endif
1472  for (int i = 0; i < pnY; i++)
1473  {
1474  int src = pnX2 * (i + hpnY) + hpnX;
1475  int dst = pnX * i;
1476  memcpy(&out[dst], &temp[src], sizeof(Complex<Real>) * pnX);
1477  }
1478  delete[] temp;
1479 
1480 }
1481 
1483 {
1484  if (x == 0.0 && y == 0.0) return false;
1485 
1486  bool bAxisX = (x == 0.0) ? false : true;
1487  bool bAxisY = (y == 0.0) ? false : true;
1488  const uint nChannel = context_.waveNum;
1489  const int pnX = context_.pixel_number[_X];
1490  const int pnY = context_.pixel_number[_Y];
1491  const Real ppX = context_.pixel_pitch[_X];
1492  const Real ppY = context_.pixel_pitch[_Y];
1493  const vec2 ss = context_.ss;
1494  Real ppY2 = ppY * 2;
1495  Real ppX2 = ppX * 2;
1496  Real ssX = -ss[_X] / 2;
1497  Real ssY = -ss[_Y] / 2;
1498 
1499  Real *waveRatio = new Real[nChannel];
1500 
1501  Complex<Real> pi2(0.0, -2 * M_PI);
1502 
1503  for (uint i = 0; i < nChannel; i++) {
1504  waveRatio[i] = context_.wave_length[nChannel - 1] / context_.wave_length[i];
1505 
1506  Real ratioX = x * waveRatio[i];
1507  Real ratioY = y * waveRatio[i];
1508 
1509 #ifdef _OPENMP
1510 #pragma omp parallel for firstprivate(ppX, ppY, ppX2, ppY2, ssX, ssY, pi2)
1511 #endif
1512  for (int y = 0; y < pnY; y++) {
1513  Complex<Real> yy(0, 0);
1514  if (bAxisY) {
1515  Real startY = ssY + (ppY * y);
1516  Real shiftY = startY / ppY2 * ratioY;
1517  yy = (pi2 * shiftY).exp();
1518  }
1519  int offset = y * pnX;
1520 
1521  for (int x = 0; x < pnX; x++) {
1522  if (bAxisY) {
1523  complex_H[i][offset + x] = complex_H[i][offset + x] * yy;
1524  }
1525  if (bAxisX) {
1526  Real startX = ssX + (ppX * x);
1527  Real shiftX = startX / ppX2 * ratioX;
1528  Complex<Real> xx = (pi2 * shiftX).exp();
1529  complex_H[i][offset + x] = complex_H[i][offset + x] * xx;
1530  }
1531  }
1532  }
1533  }
1534  return true;
1535 }
1536 
1537 void ophGen::waveCarry(Real carryingAngleX, Real carryingAngleY, Real distance)
1538 {
1539  const int pnX = context_.pixel_number[_X];
1540  const int pnY = context_.pixel_number[_Y];
1541  const Real ppX = context_.pixel_pitch[_X];
1542  const Real ppY = context_.pixel_pitch[_Y];
1543  const long long int pnXY = pnX * pnY;
1544  const uint nChannel = context_.waveNum;
1545  Real dfx = 1 / ppX / pnX;
1546  Real dfy = 1 / ppY / pnY;
1547 
1548  int beginX = -pnX >> 1;
1549  int endX = pnX >> 1;
1550  int beginY = pnY >> 1;
1551  int endY = -pnY >> 1;
1552 
1553  Real carryX = distance * tan(carryingAngleX);
1554  Real carryY = distance * tan(carryingAngleY);
1555 
1556  for (uint ch = 0; ch < nChannel; ch++) {
1557  int k = 0;
1558  for (int i = beginY; i > endY; i--)
1559  {
1560  Real _carryY = carryY * i * dfy;
1561 
1562  for (int j = beginX; j < endX; j++)
1563  {
1564  Real x = j * dfx;
1565  Complex<Real> carrier(0, carryX * x + _carryY);
1566  complex_H[ch][k] = complex_H[ch][k] * exp(carrier);
1567 
1568  k++;
1569  }
1570  }
1571  }
1572 }
1573 
1574 void ophGen::waveCarry(Complex<Real>* src, Complex<Real>* dst, Real wavelength, int carryIdxX, int carryIdxY)
1575 {
1576  const int pnX = context_.pixel_number[_X];
1577  const int pnY = context_.pixel_number[_Y];
1578  const Real ppX = context_.pixel_pitch[_X];
1579  const Real ppY = context_.pixel_pitch[_Y];
1580  const long long int pnXY = pnX * pnY;
1581  Real dfx = 1 / ppX / pnX;
1582  Real dfy = 1 / ppY / pnY;
1583 
1584  int beginX = -pnX >> 1;
1585  int endX = pnX >> 1;
1586  int beginY = pnY >> 1;
1587  int endY = -pnY >> 1;
1588  Real pi2 = M_PI * 2;
1589 
1590  int k = 0;
1591  for (int i = beginY; i > endY; i--)
1592  {
1593  Real y = i * dfy * ppY * carryIdxY;
1594 
1595  for (int j = beginX; j < endX; j++)
1596  {
1597  Real x = j * dfx * ppX * carryIdxX;
1598 
1599  Complex<Real> carrier(0, pi2 * (x + y));
1600  dst[k] = src[k] * exp(carrier);
1601 
1602  k++;
1603  }
1604  }
1605 }
1606 
1607 void ophGen::encodeSideBand(unsigned int passband)
1608 {
1609  if (complex_H == nullptr) {
1610  LOG("Not found diffracted data.");
1611  return;
1612  }
1613 
1614  const uint pnX = context_.pixel_number[_X];
1615  const uint pnY = context_.pixel_number[_Y];
1616  ivec2 sig_location;
1617 
1618  int cropx1, cropx2, cropy1, cropy2;
1619 
1620  if (passband == SSB_TOP || passband == SSB_BOTTOM) {
1621 
1622  sig_location[0] = 0;
1623  sig_location[1] = passband == SSB_TOP ? 1 : -1;
1624  cropx1 = 1;
1625  cropx2 = pnX;
1626 
1627  int cropy = (int)floor(((Real)pnY) / 2);
1628  cropy1 = cropy - (int)floor(((Real)cropy) / 2);
1629  cropy2 = cropy1 + cropy - 1;
1630  }
1631  else {
1632  sig_location[0] = passband == SSB_LEFT ? -1 : 1;
1633  sig_location[1] = 0;
1634  cropy1 = 1;
1635  cropy2 = pnY;
1636 
1637  int cropx = (int)floor(((Real)pnX) / 2);
1638  cropx1 = cropx - (int)floor(((Real)cropx) / 2);
1639  cropx2 = cropx1 + cropx - 1;
1640  }
1641 
1642  cropx1 -= 1;
1643  cropx2 -= 1;
1644  cropy1 -= 1;
1645  cropy2 -= 1;
1646 
1647  bool bCPU = (m_mode & MODE_GPU) ? true : false;
1648 
1649  if (bCPU)
1650  encodeSideBand_CPU(cropx1, cropx2, cropy1, cropy2, sig_location);
1651  else
1652  encodeSideBand_GPU(cropx1, cropx2, cropy1, cropy2, sig_location);
1653 }
1654 
1655 void ophGen::encodeSideBand_CPU(int cropx1, int cropx2, int cropy1, int cropy2, oph::ivec2 sig_location)
1656 {
1657  const uint pnX = context_.pixel_number[_X];
1658  const uint pnY = context_.pixel_number[_Y];
1659  const long long int pnXY = pnX * pnY;
1660  const uint nChannel = context_.waveNum;
1661 
1662  Complex<Real>* h_crop = new Complex<Real>[pnXY];
1663 
1664  for (uint ch = 0; ch < nChannel; ch++) {
1665 
1666  memset(h_crop, 0.0, sizeof(Complex<Real>) * pnXY);
1667 #ifdef _OPENMP
1668 #pragma omp parallel for firstprivate(cropx1, cropx2, cropy1, cropy2, pnX)
1669 #endif
1670  for (int p = 0; p < pnXY; p++)
1671  {
1672  int x = p % pnX;
1673  int y = p / pnX;
1674  if (x >= cropx1 && x <= cropx2 && y >= cropy1 && y <= cropy2)
1675  h_crop[p] = complex_H[ch][p];
1676  }
1677 
1678  Complex<Real> *in = nullptr;
1679 
1680  fft2(ivec2(pnX, pnY), in, OPH_BACKWARD);
1681  fft2(h_crop, h_crop, pnX, pnY, OPH_BACKWARD, true);
1682 
1683  memset(m_lpEncoded[ch], 0.0, sizeof(Real) * pnXY);
1684 #ifdef _OPENMP
1685 #pragma omp parallel for firstprivate(sig_location)
1686 #endif
1687  for (int i = 0; i < pnXY; i++) {
1688  Complex<Real> shift_phase(1, 0);
1689  getShiftPhaseValue(shift_phase, i, sig_location);
1690 
1691  m_lpEncoded[ch][i] = (h_crop[i] * shift_phase).real();
1692  }
1693  }
1694  delete[] h_crop;
1695 }
1696 
1697 void ophGen::encodeSideBand_GPU(int cropx1, int cropx2, int cropy1, int cropy2, oph::ivec2 sig_location)
1698 {
1699  const int pnX = context_.pixel_number[_X];
1700  const int pnY = context_.pixel_number[_Y];
1701  const long long int pnXY = pnX * pnY;
1702  const Real ppX = context_.pixel_pitch[_X];
1703  const Real ppY = context_.pixel_pitch[_Y];
1704  const Real ssX = context_.ss[_X] = pnX * ppX;
1705  const Real ssY = context_.ss[_Y] = pnY * ppY;
1706  const uint nChannel = context_.waveNum;
1707 
1708  cufftDoubleComplex *k_temp_d_, *u_complex_gpu_;
1709  cudaStream_t stream_;
1710  cudaStreamCreate(&stream_);
1711 
1712  cudaMalloc((void**)&u_complex_gpu_, sizeof(cufftDoubleComplex) * pnXY);
1713  cudaMalloc((void**)&k_temp_d_, sizeof(cufftDoubleComplex) * pnXY);
1714 
1715  for (uint ch = 0; ch < nChannel; ch++) {
1716  cudaMemcpy(u_complex_gpu_, complex_H[ch], sizeof(cufftDoubleComplex) * pnXY, cudaMemcpyHostToDevice);
1717 
1718  cudaMemsetAsync(k_temp_d_, 0, sizeof(cufftDoubleComplex) * pnXY, stream_);
1719  cudaCropFringe(stream_, pnX, pnY, u_complex_gpu_, k_temp_d_, cropx1, cropx2, cropy1, cropy2);
1720 
1721  cudaMemsetAsync(u_complex_gpu_, 0, sizeof(cufftDoubleComplex) * pnXY, stream_);
1722  cudaFFT(stream_, pnX, pnY, k_temp_d_, u_complex_gpu_, 1, true);
1723 
1724  cudaMemsetAsync(k_temp_d_, 0, sizeof(cufftDoubleComplex) * pnXY, stream_);
1725  cudaGetFringe(stream_, pnX, pnY, u_complex_gpu_, k_temp_d_, sig_location[0], sig_location[1], ssX, ssY, ppX, ppY, M_PI);
1726 
1727  cufftDoubleComplex* sample_fd = (cufftDoubleComplex*)malloc(sizeof(cufftDoubleComplex) * pnXY);
1728  memset(sample_fd, 0.0, sizeof(cufftDoubleComplex) * pnXY);
1729 
1730  cudaMemcpyAsync(sample_fd, k_temp_d_, sizeof(cufftDoubleComplex) * pnXY, cudaMemcpyDeviceToHost, stream_);
1731  memset(m_lpEncoded[ch], 0.0, sizeof(Real) * pnXY);
1732 
1733  for (int i = 0; i < pnX * pnY; i++)
1734  m_lpEncoded[ch][i] = sample_fd[i].x;
1735 
1736  cudaFree(sample_fd);
1737  }
1738  cudaStreamDestroy(stream_);
1739 }
1740 
1741 void ophGen::getShiftPhaseValue(oph::Complex<Real>& shift_phase_val, int idx, oph::ivec2 sig_location)
1742 {
1743  const int pnX = context_.pixel_number[_X];
1744  const int pnY = context_.pixel_number[_Y];
1745  const Real ppX = context_.pixel_pitch[_X];
1746  const Real ppY = context_.pixel_pitch[_Y];
1747  const Real ssX = context_.ss[_X] = pnX * ppX;
1748  const Real ssY = context_.ss[_Y] = pnY * ppY;
1749 
1750  if (sig_location[1] != 0)
1751  {
1752  int r = idx / pnX;
1753  int c = idx % pnX;
1754  Real yy = (ssY / 2.0) - (ppY)*r - ppY;
1755 
1756  oph::Complex<Real> val;
1757  if (sig_location[1] == 1)
1758  val[_IM] = 2 * M_PI * (yy / (4 * ppY));
1759  else
1760  val[_IM] = 2 * M_PI * (-yy / (4 * ppY));
1761 
1762  val.exp();
1763  shift_phase_val *= val;
1764  }
1765 
1766  if (sig_location[0] != 0)
1767  {
1768  int r = idx / pnX;
1769  int c = idx % pnX;
1770  Real xx = (-ssX / 2.0) - (ppX)*c - ppX;
1771 
1772  oph::Complex<Real> val;
1773  if (sig_location[0] == -1)
1774  val[_IM] = 2 * M_PI * (-xx / (4 * ppX));
1775  else
1776  val[_IM] = 2 * M_PI * (xx / (4 * ppX));
1777 
1778  val.exp();
1779  shift_phase_val *= val;
1780  }
1781 }
1782 
1783 void ophGen::GetRandomPhaseValue(Complex<Real>& rand_phase_val, bool rand_phase)
1784 {
1785  if (rand_phase)
1786  {
1787  rand_phase_val[_RE] = 0.0;
1788  Real min, max;
1789 #if REAL_IS_DOUBLE & true
1790  min = 0.0;
1791  max = 1.0;
1792 #else
1793  min = 0.f;
1794  max = 1.f;
1795 #endif
1796  rand_phase_val[_IM] = 2 * M_PI * oph::rand(min, max);
1797  rand_phase_val.exp();
1798 
1799  }
1800  else {
1801  rand_phase_val[_RE] = 1.0;
1802  rand_phase_val[_IM] = 0.0;
1803  }
1804 }
1805 
1807 {
1808  // 2024.04.23. mwnam
1809  // set variable for resolution
1810  resCfg = resolution;
1811 
1812  // ±âÁ¸ ÇØ»óµµ¿Í ´Ù¸£¸é ¹öÆÛ¸¦ ´Ù½Ã »ý¼º.
1813  if (context_.pixel_number != resolution) {
1814  setPixelNumber(resolution);
1815  Openholo::setPixelNumberOHC(resolution);
1816  initialize();
1817  }
1818 }
1819 
1820 template <typename T>
1821 void ophGen::RealPart(Complex<T> *holo, T *encoded, const int size)
1822 {
1823 #ifdef _OPENMP
1824 #pragma omp parallel for
1825 #endif
1826  for (int i = 0; i < size; i++) {
1827  encoded[i] = real(holo[i]);
1828  }
1829 }
1830 
1831 template <typename T>
1832 void ophGen::ImaginaryPart(Complex<T> *holo, T *encoded, const int size)
1833 {
1834 #ifdef _OPENMP
1835 #pragma omp parallel for
1836 #endif
1837  for (int i = 0; i < size; i++) {
1838  encoded[i] = imag(holo[i]);
1839  }
1840 }
1841 
1842 template <typename T>
1843 void ophGen::Phase(Complex<T> *holo, T *encoded, const int size)
1844 {
1845  double pi2 = M_PI * 2;
1846 #ifdef _OPENMP
1847 #pragma omp parallel for firstprivate(pi2)
1848 #endif
1849  for (int i = 0; i < size; i++) {
1850  encoded[i] = (holo[i].angle() + M_PI) / pi2; // 0 ~ 1
1851  }
1852 }
1853 
1854 template <typename T>
1855 void ophGen::Amplitude(Complex<T> *holo, T *encoded, const int size)
1856 {
1857 #ifdef _OPENMP
1858 #pragma omp parallel for
1859 #endif
1860  for (int i = 0; i < size; i++) {
1861  encoded[i] = holo[i].mag();
1862  }
1863 }
1864 
1865 template <typename T>
1866 void ophGen::TwoPhase(Complex<T>* holo, T* encoded, const int size)
1867 {
1868  int resize = size >> 1;
1869  Complex<T>* normCplx = new Complex<T>[resize];
1870 
1871 #ifdef _OPENMP
1872 #pragma omp parallel for
1873 #endif
1874  for (int i = 0; i < resize; i++) {
1875  normCplx[i] = holo[i * 2];
1876  }
1877 
1878  oph::normalize<T>(normCplx, normCplx, resize);
1879 
1880  T* ampl = new T[resize];
1881  Amplitude(normCplx, ampl, resize);
1882 
1883  T* phase = new T[resize];
1884  Phase(normCplx, phase, resize);
1885 
1886 #ifdef _OPENMP
1887 #pragma omp parallel for
1888 #endif
1889  for (int i = 0; i < resize; i++) {
1890  T delPhase = acos(ampl[i]);
1891  encoded[i * 2] = (phase[i] + M_PI) + delPhase;
1892  encoded[i * 2 + 1] = (phase[i] + M_PI) - delPhase;
1893  }
1894 
1895  delete[] normCplx;
1896  delete[] ampl;
1897  delete[] phase;
1898 }
1899 
1900 template <typename T>
1901 void ophGen::Burckhardt(Complex<T>* holo, T* encoded, const int size)
1902 {
1903  int resize = size / 3;
1904  Complex<T>* norm = new Complex<T>[resize];
1905 #ifdef _OPENMP
1906 #pragma omp parallel for
1907 #endif
1908  for (int i = 0; i < resize; i++) {
1909  norm[i] = holo[i * 3];
1910  }
1911 
1912  oph::normalize(norm, norm, resize);
1913 
1914  T* phase = new T[resize];
1915  Phase(norm, phase, resize);
1916 
1917  T* ampl = new T[resize];
1918  Amplitude(norm, ampl, resize);
1919 
1920  T sqrt3 = sqrt(3);
1921  T pi2 = 2 * M_PI;
1922  T pi4 = 4 * M_PI;
1923 
1924 #ifdef _OPENMP
1925 #pragma omp parallel for firstprivate(pi2, pi4, sqrt3)
1926 #endif
1927  for (int i = 0; i < resize; i++) {
1928  int idx = 3 * i;
1929  if (phase[i] >= 0 && phase[i] < (pi2 / 3))
1930  {
1931  encoded[idx] = ampl[i] * (cos(phase[i]) + sin(phase[i]) / sqrt3);
1932  encoded[idx + 1] = 2 * sin(phase[i]) / sqrt3;
1933  }
1934  else if (phase[i] >= (pi2 / 3) && phase[i] < (pi4 / 3))
1935  {
1936  encoded[idx + 1] = ampl[i] * (cos(phase[i] - (pi2 / 3)) + sin(phase[i] - (pi2 / 3)) / sqrt3);
1937  encoded[idx + 2] = 2 * sin(phase[i] - (pi2 / 3)) / sqrt3;
1938  }
1939  else if (phase[i] >= (pi4 / 3) && phase[i] < (pi2))
1940  {
1941  encoded[idx + 2] = ampl[i] * (cos(phase[i] - (pi4 / 3)) + sin(phase[i] - (pi4 / 3)) / sqrt3);
1942  encoded[idx] = 2 * sin(phase[i] - (pi4 / 3)) / sqrt3;
1943  }
1944  }
1945 
1946  delete[] ampl;
1947  delete[] phase;
1948  delete[] norm;
1949 }
1950 
1951 
1952 template <typename T>
1953 void ophGen::SimpleNI(Complex<T>* holo, T* encoded, const int size)
1954 {
1955  T* tmp1 = new T[size];
1956 #ifdef _OPENMP
1957 #pragma omp parallel for
1958 #endif
1959  for (int i = 0; i < size; i++) {
1960  tmp1[i] = holo[i].mag();
1961  }
1962 
1963  T max = maxOfArr(tmp1, size);
1964  delete[] tmp1;
1965 
1966 #ifdef _OPENMP
1967 #pragma omp parallel for firstprivate(max)
1968 #endif
1969  for (int i = 0; i < size; i++) {
1970  T tmp = (holo[i] + max).mag();
1971  encoded[i] = tmp * tmp;
1972  }
1973 }
1974 
1975 void ophGen::transVW(int nVertex, Vertex* dst, Vertex* src)
1976 {
1977  Real fieldLens = m_dFieldLength;
1978  for (int i = 0; i < nVertex; i++)
1979  {
1980  dst[i].point.pos[_X] = -fieldLens * src[i].point.pos[_X] / (src[i].point.pos[_X] - fieldLens);
1981  dst[i].point.pos[_Y] = -fieldLens * src[i].point.pos[_Y] / (src[i].point.pos[_Y] - fieldLens);
1982  dst[i].point.pos[_Z] = -fieldLens * src[i].point.pos[_Z] / (src[i].point.pos[_Z] - fieldLens);
1983  }
1984 }
1985 
1986 void ophGen::transVW(int nVertex, Real *dst, Real *src)
1987 {
1988  Real fieldLens = m_dFieldLength;
1989  for (int i = 0; i < nVertex; i++) {
1990  dst[i] = -fieldLens * src[i] / (src[i] - fieldLens);
1991  }
1992 }
1993 
1994 void ophGen::ScaleChange(Real *src, Real *dst, int nSize, Real scaleX, Real scaleY, Real scaleZ)
1995 {
1996  Real x = scaleX;
1997  Real y = scaleY;
1998  Real z = scaleZ;
1999 
2000 #ifdef _OPENMP
2001 #pragma omp parallel for firstprivate(x, y, z)
2002 #endif
2003  for (int i = 0; i < nSize; i++) {
2004  dst[i + 0] = src[i + 0] * x;
2005  dst[i + 1] = src[i + 1] * y;
2006  dst[i + 2] = src[i + 2] * z;
2007  }
2008 }
2009 
2010 void ophGen::GetMaxMin(Real *src, int len, Real& max, Real& min)
2011 {
2012  Real maxTmp = MIN_DOUBLE;
2013  Real minTmp = MAX_DOUBLE;
2014 
2015  for (int i = 0; i < len; i++) {
2016  if (src[i] > maxTmp)
2017  maxTmp = src[i];
2018  if (src[i] < minTmp)
2019  minTmp = src[i];
2020  }
2021  max = maxTmp;
2022  min = minTmp;
2023 }
2024 
2025 
2026 void ophGen::CorrectionChromaticAberration(uchar* src, uchar* dst, int width, int height, int scaleFactor)
2027 {
2028  const uint nWave = context_.waveNum;
2029  if (nWave <= 1) return;
2030 
2031  const Real lambda = context_.wave_length[nWave - 1];
2032 
2033  for (int i = 0; i < nWave - 1; i++)
2034  {
2035  Real wavelengthRatio = lambda / context_.wave_length[i];
2036  int scale_x = round(width * wavelengthRatio * scaleFactor);
2037  int scale_y = round(height * wavelengthRatio * scaleFactor);
2038 
2039  int ww = width * scaleFactor;
2040  int hh = height * scaleFactor;
2041  int N = ww * hh;
2042  int M = scale_x * scale_y;
2043 
2044  uchar* img_tmp = new uchar[N];
2045  uchar* img_scaled = new uchar[M];
2046 
2047  memset(img_tmp, 0, sizeof(uchar) * N);
2048 
2049  imgScaleBilinear(src, img_scaled, width, height, scale_x, scale_y);
2050 
2051  int offset_x = round((ww - scale_x) / 2);
2052  int offset_y = round((hh - scale_y) / 2);
2053 
2054 #ifdef _OPENMP
2055 #pragma omp parallel for firstprivate(offset_x, offset_y, scale_x, ww)
2056 #endif
2057  for (int i = 0; i < M; i++) {
2058  int x = i % scale_x;
2059  int y = i / scale_x;
2060 
2061  img_tmp[(y + offset_y) * ww + x + offset_x] = img_scaled[y * scale_x + x];
2062  }
2063 
2064  imgScaleBilinear(img_tmp, dst, ww, hh, width, height);
2065 
2066  delete[] img_tmp;
2067  delete[] img_scaled;
2068  }
2069 }
2070 
2071 
2073 {
2075 
2076  const uint nChannel = context_.waveNum;
2077 
2078  if (m_lpEncoded != nullptr) {
2079  for (uint i = 0; i < nChannel; i++) {
2080  if (m_lpEncoded[i] != nullptr) {
2081  delete[] m_lpEncoded[i];
2082  m_lpEncoded[i] = nullptr;
2083  }
2084  }
2085  delete[] m_lpEncoded;
2086  m_lpEncoded = nullptr;
2087  }
2088 
2089  if (m_lpNormalized != nullptr) {
2090  for (uint i = 0; i < nChannel; i++) {
2091  if (m_lpNormalized[i] != nullptr) {
2092  delete[] m_lpNormalized[i];
2093  m_lpNormalized[i] = nullptr;
2094  }
2095  }
2096  delete[] m_lpNormalized;
2097  m_lpNormalized = nullptr;
2098  }
2099 
2100  if (freqW != nullptr) delete[] freqW;
2101 }
#define OPH_BACKWARD
Definition: define.h:67
bool loadPLY(const std::string &fileName, ulonglong &n_points, Vertex **vertices)
Definition: PLYparser.cpp:142
ENCODE_FLAG
Definition: ophGen.h:84
void abs(const oph::Complex< T > &src, oph::Complex< T > &dst)
Definition: function.h:113
void Phase(Complex< T > *holo, T *encoded, const int size)
Definition: ophGen.cpp:1843
void fresnelPropagation(Complex< Real > *in, Complex< Real > *out, Real distance, uint channel)
Fresnel propagation.
Definition: ophGen.cpp:1416
void RS_Diffraction(Point src, Complex< Real > *dst, Real lambda, Real distance, Real amplitude)
RS-diffraction method.
Definition: ophGen.cpp:361
Abstract class.
Definition: Openholo.h:145
Point point
Definition: struct.h:103
virtual bool saveAsImg(const char *fname, uint8_t bitsperpixel, uchar *src, int width, int height)
Function for creating image files.
Definition: Openholo.cpp:135
Real k
Definition: Openholo.h:103
void encodeSideBand(unsigned int passband)
Encode the CGH according to a passband parameter.
Definition: ophGen.cpp:1607
ResolutionConfig resCfg
Definition: Openholo.h:487
void cudaCropFringe(CUstream_st *stream, int nx, int ny, cufftDoubleComplex *in_field, cufftDoubleComplex *out_field, int cropx1, int cropx2, int cropy1, int cropy2)
Crop input data according to x, y coordinates on GPU.
T angle(void)
Definition: complex.h:387
void setResolution(ivec2 resolution)
Function for setting buffer size.
Definition: ophGen.cpp:1806
NONE
Definition: ImgControl.h:25
void conv_fft2(Complex< Real > *src1, Complex< Real > *src2, Complex< Real > *dst, ivec2 size)
Convolution between Complex arrays which have same size.
Definition: ophGen.cpp:632
void GetMaxMin(Real *src, int len, Real &max, Real &min)
Definition: ophGen.cpp:2010
vec3 shift
Definition: Openholo.h:102
bool getWeightED(const ivec2 holosize, const int type, ivec2 *pNw)
Definition: ophGen.cpp:1337
void AngularSpectrumMethod(Complex< Real > *src, Complex< Real > *dst, Real lambda, Real distance)
Angular spectrum propagation method.
Definition: ophGen.cpp:583
void encodeSideBand_CPU(int cropx1, int cropx2, int cropy1, int cropy2, ivec2 sig_location)
Encode the CGH according to a signal location parameter on the CPU.
Definition: ophGen.cpp:1655
void binarization(Complex< Real > *src, Real *dst, const int size, int ENCODE_FLAG, Real threshold)
Definition: ophGen.cpp:1400
Real * wave_length
Definition: Openholo.h:106
Real * weight
Definition: ophGen.h:429
void GetRandomPhaseValue(Complex< Real > &rand_phase_val, bool rand_phase)
Assign random phase value if random_phase == 1.
Definition: ophGen.cpp:1783
ulonglong n_points
Number of points.
Definition: ophGen.h:575
void setPixelNumberOHC(const ivec2 pixel_number)
getter/setter for OHC file read and write
Definition: Openholo.h:502
SSB_PASSBAND
Definition: ophGen.h:295
unsigned char uchar
Definition: typedef.h:64
Complex< Real > * weightC
Definition: ophGen.h:430
VERTICAL
Definition: ImgControl.h:25
#define MODE_GPU
Definition: define.h:156
Real m_dFieldLength
Definition: ophGen.h:348
long long int double_size
Definition: Openholo.h:69
Real ** m_lpEncoded
buffer to encoded.
Definition: ophGen.h:338
float Real
Definition: typedef.h:55
void initialize(void)
Initialize variables for Hologram complex field, encoded data, normalized data.
Definition: ophGen.cpp:146
long long int size
Definition: Openholo.h:67
#define CUR_TIME
Definition: function.h:58
Real norm(const vec2 &a)
Definition: vec.h:417
Definition: struct.h:86
void RealPart(Complex< T > *holo, T *encoded, const int size)
Encoding method.
Definition: ophGen.cpp:1821
void setPixelPitchOHC(const vec2 pixel_pitch)
Definition: Openholo.h:505
bool shiftW(ivec2 holosize)
Definition: ophGen.cpp:1374
vec2 ss
Definition: Openholo.h:104
void cudaFFT(CUstream_st *stream, int nx, int ny, cufftDoubleComplex *in_filed, cufftDoubleComplex *output_field, int direction, bool bNormailized=false)
Convert data from the spatial domain to the frequency domain using 2D FFT on GPU. ...
HORIZONTAL
Definition: ImgControl.h:25
void TwoPhase(Complex< T > *holo, T *encoded, const int size)
Definition: ophGen.cpp:1866
bool checkExtension(const char *fname, const char *ext)
Functions for extension checking.
Definition: Openholo.cpp:86
#define OPH_ESTIMATE
Definition: define.h:76
structure for 2-dimensional integer vector and its arithmetic.
Definition: ivec.h:66
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
Definition: tinyxml2.h:761
ivec2 offset
Definition: Openholo.h:100
void normalize(const Complex< T > *src, Complex< T > *dst, const int &size)
Normalize all elements of Complex<T>* src from 0 to 1.
Definition: function.h:176
bool rotate
Definition: Openholo.h:124
#define MIN_DOUBLE
Definition: define.h:148
#define _Y
Definition: define.h:96
#define _IM
Definition: complex.h:58
void Burckhardt(Complex< T > *holo, T *encoded, const int size)
Definition: ophGen.cpp:1901
ImageConfig imgCfg
Definition: Openholo.h:488
void setWavelengthOHC(const Real wavelength, const LenUnit wavelength_unit)
Definition: Openholo.h:508
ImgEncoderOhc * OHC_encoder
OHC file format Variables for read and write.
Definition: Openholo.h:495
vec2 pixel_pitch
Definition: Openholo.h:101
void ImaginaryPart(Complex< T > *holo, T *encoded, const int size)
Definition: ophGen.cpp:1832
PRECISION
Definition: ophGen.h:79
bool Shift(Real x, Real y)
Definition: ophGen.cpp:1482
void normalize(void)
Normalization function to save as image file after hologram creation.
Definition: ophGen.cpp:654
bool binaryErrorDiffusion(Complex< Real > *holo, Real *encoded, const ivec2 holosize, const int type, Real threshold)
Definition: ophGen.cpp:1231
bool save(const char *fname, uint8_t bitsperpixel=8, uchar *src=nullptr, uint px=0, uint py=0)
Function for saving image files.
Definition: ophGen.cpp:689
ivec2 m_vecEncodeSize
Encoded hologram size, varied from encoding type.
Definition: ophGen.h:330
#define _X
Definition: define.h:92
unsigned int m_mode
Definition: ophGen.h:350
Complex< Real > * freqW
Definition: ophGen.h:431
return true
Definition: Openholo.cpp:434
void singleSideBand(Complex< Real > *holo, Real *encoded, const ivec2 holosize, int passband)
Encoding method.
Definition: ophGen.cpp:1023
void encodeSideBand_GPU(int cropx1, int cropx2, int cropy1, int cropy2, ivec2 sig_location)
Encode the CGH according to a signal location parameter on the GPU.
Definition: ophGen.cpp:1697
void getShiftPhaseValue(Complex< Real > &shift_phase_val, int idx, ivec2 sig_location)
Calculate the shift phase value.
Definition: ophGen.cpp:1741
void imgScaleBilinear(uchar *src, uchar *dst, int w, int h, int neww, int newh, int channels=1)
Function for change image size.
Definition: Openholo.cpp:437
void * load(const char *fname)
Function for loading image files.
Definition: ophGen.cpp:771
void SimpleNI(Complex< T > *holo, T *encoded, const int size)
Definition: ophGen.cpp:1953
bool m_bRandomPhase
Definition: ophGen.h:436
void Fresnel_FFT(Complex< Real > *src, Complex< Real > *dst, Real lambda, Real distance)
Fresnel-fft method.
Definition: ophGen.cpp:516
#define _RE
Definition: complex.h:55
void waveCarry(Real carryingAngleX, Real carryingAngleY, Real distance)
Wave carry.
Definition: ophGen.cpp:1537
void fft2(ivec2 n, Complex< Real > *in, int sign=OPH_FORWARD, uint flag=OPH_ESTIMATE)
Functions for performing fftw 2-dimension operations inside Openholo.
Definition: Openholo.cpp:559
structure for 2-dimensional Real type vector and its arithmetic.
Definition: vec.h:66
Definition: struct.h:102
Real pos[3]
Definition: struct.h:87
#define MAX_DOUBLE
Definition: define.h:140
#define ELAPSED_TIME(x, y)
Definition: function.h:59
Real * realEnc
Definition: ophGen.h:432
void cudaGetFringe(CUstream_st *stream, int pnx, int pny, cufftDoubleComplex *in_field, cufftDoubleComplex *out_field, int sig_locationx, int sig_locationy, Real ssx, Real ssy, Real ppx, Real ppy, Real PI)
Encode the CGH according to a signal location parameter on the GPU.
uint waveNum
Definition: Openholo.h:105
void Amplitude(Complex< T > *holo, T *encoded, const int size)
Definition: ophGen.cpp:1855
Complex< T > & exp()
Definition: complex.h:395
ivec2 pixel_number
Definition: Openholo.h:99
bool saveRefImages(char *fnameW, char *fnameWC, char *fnameAS, char *fnameSSB, char *fnameHP, char *fnameFreq, char *fnameReal, char *fnameBin, char *fnameReconBin, char *fnameReconErr, char *fnameReconNo)
Definition: ophGen.cpp:1100
Vertex * vertices
Data of point clouds.
Definition: ophGen.h:579
virtual bool loadAsOhc(const char *fname)
Function to read OHC file.
Definition: Openholo.cpp:280
bool readConfig(const char *fname)
load to configuration file.
Definition: ophGen.cpp:221
XMLError LoadFile(const char *filename)
Definition: tinyxml2.cpp:2150
bool bUseDP
Definition: Openholo.h:98
virtual uchar * loadAsImg(const char *fname)
Function for loading image files.
Definition: Openholo.cpp:321
Real rand(const Real min, const Real max, oph::ulong _SEED_VALUE=0)
Get random Real value from min to max.
Definition: function.h:294
void getAmplitude(oph::Complex< Real > *src, Real *dst, const int &size)
Definition: function.h:330
void ScaleChange(Real *src, Real *dst, int nSize, Real scaleX, Real scaleY, Real scaleZ)
Definition: ophGen.cpp:1994
void CorrectionChromaticAberration(uchar *src, uchar *dst, int width, int height, int scaleFactor=2)
Definition: ophGen.cpp:2026
uchar ** m_lpNormalized
buffer to normalized.
Definition: ophGen.h:340
Complex< Real > * AS
Binary Encoding - Error diffusion.
Definition: ophGen.h:426
Real minOfArr(const std::vector< Real > &arr)
Definition: function.h:73
Data for Point Cloud.
Definition: ophGen.h:573
Real maxOfArr(const std::vector< Real > &arr)
Definition: function.h:87
void encoding()
Definition: ophGen.cpp:962
void resetBuffer()
reset buffer
Definition: ophGen.cpp:801
void setPixelNumber(ivec2 n)
Function for setting the output resolution.
Definition: Openholo.h:242
Complex< Real > * normalized
Definition: ophGen.h:427
int m_nStream
Definition: ophGen.h:349
ophGen(void)
Constructor.
Definition: ophGen.cpp:112
OphConfig context_
Definition: Openholo.h:486
#define OPH_FORWARD
Definition: define.h:66
void Fresnel_Diffraction(Point src, Complex< Real > *dst, Real lambda, Real distance, Real amplitude)
Fresnel-diffraction method.
Definition: ophGen.cpp:447
Complex< Real > ** complex_H
Definition: Openholo.h:490
virtual bool loadAsOhc(const char *fname)
Function to read OHC file.
Definition: ophGen.cpp:783
void transVW(int nVertex, Vertex *dst, Vertex *src)
Definition: ophGen.cpp:1975
T mag() const
Definition: complex.h:368
#define _Z
Definition: define.h:100
int ENCODE_METHOD
Encoding method flag.
Definition: ophGen.h:332
void freqShift(Complex< Real > *holo, Complex< Real > *encoded, const ivec2 holosize, int shift_x, int shift_y)
Frequency shift.
Definition: ophGen.cpp:1079
int loadPointCloud(const char *pc_file, OphPointCloudData *pc_data_)
load to point cloud data.
Definition: ophGen.cpp:207
const XMLElement * FirstChildElement(const char *name=0) const
Definition: tinyxml2.cpp:940
bool mergeColor(int idx, int width, int height, uchar *src, uchar *dst)
Function for generate RGB image from each grayscale image.
Definition: Openholo.cpp:103
unsigned int uint
Definition: typedef.h:62
virtual void ophFree(void)
Pure virtual function for override in child classes.
Definition: Openholo.cpp:811
Real * maskHP
Definition: ophGen.h:435
bool merge
Definition: Openholo.h:125
#define M_PI
Definition: define.h:52
Definition: ophGen.h:76
virtual void ophFree(void)
Pure virtual function for override in child classes.
Definition: ophGen.cpp:2072
virtual ~ophGen(void)=0
Destructor.
Definition: ophGen.cpp:141
Real * binary
Definition: ophGen.h:433
Real * maskSSB
Definition: ophGen.h:434