Openholo  v4.2
Open Source Digital Holographic Library
ophWRP.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 "ophWRP.h"
47 #include "sys.h"
48 #include "tinyxml2.h"
49 
51  : ophGen()
52  , scaledVertex(nullptr)
53 {
54  n_points = -1;
55  p_wrp_ = nullptr;
56  is_ViewingWindow = false;
57  LOG("*** WRP : BUILD DATE: %s %s ***\n\n", __DATE__, __TIME__);
58 }
59 
61 {
62 }
63 
64 void ophWRP::setViewingWindow(bool is_ViewingWindow)
65 {
66  this->is_ViewingWindow = is_ViewingWindow;
67 }
68 
70 {
71  LOG("%s : ", __FUNCTION__);
72  auto begin = CUR_TIME;
73 
74  const uint pnX = context_.pixel_number[_X];
75  const uint pnY = context_.pixel_number[_Y];
76  const Real ppX = context_.pixel_pitch[_X];
77  const Real ppY = context_.pixel_pitch[_Y];
78 
79  Real size = pnY * ppY * 0.8 / 2.0;
80 
81  if (scaledVertex) {
82  delete[] scaledVertex;
83  scaledVertex = nullptr;
84  }
86 
87  std::memcpy(scaledVertex, obj_.vertices, sizeof(Vertex) * n_points);
88 
89  vec3 scale = wrp_config_.scale;
90 
91 #if 1
92  zmax_ = MIN_DOUBLE;
93  for (int i = 0; i < n_points; i++)
94  {
95  scaledVertex[i].point.pos[_X] = scaledVertex[i].point.pos[_X] * scale[_X];
96  scaledVertex[i].point.pos[_Y] = scaledVertex[i].point.pos[_Y] * scale[_Y];
97  scaledVertex[i].point.pos[_Z] = scaledVertex[i].point.pos[_Z] * scale[_Z];
98 
99  if (zmax_ < scaledVertex[i].point.pos[_Z]) zmax_ = scaledVertex[i].point.pos[_Z];
100  }
101 #else
102 
103  Real x_max, y_max, z_max;
104  x_max = y_max = z_max = MIN_DOUBLE;
105 
106  for (int i = 0; i < n_points; i++)
107  {
108  if (x_max < scaledVertex[i].point.pos[_X]) x_max = scaledVertex[i].point.pos[_X];
109  if (y_max < scaledVertex[i].point.pos[_Y]) y_max = scaledVertex[i].point.pos[_Y];
110  if (z_max < scaledVertex[i].point.pos[_Z]) z_max = scaledVertex[i].point.pos[_Z];
111  }
112 
113  Real maxXY = (x_max > y_max) ? x_max : y_max;
114  zmax_ = MIN_DOUBLE;
115  for (int j = 0; j < n_points; ++j)
116  { //Create Fringe Pattern
117  scaledVertex[j].point.pos[_X] = scaledVertex[j].point.pos[_X] / maxXY * size;
118  scaledVertex[j].point.pos[_Y] = scaledVertex[j].point.pos[_Y] / maxXY * size;
119  scaledVertex[j].point.pos[_Z] = scaledVertex[j].point.pos[_Z] / z_max * size;
120 
121  if (zmax_ < scaledVertex[j].point.pos[_Z]) zmax_ = scaledVertex[j].point.pos[_Z];
122  }
123 
124 #endif
125  LOG("%lf (s)\n", ELAPSED_TIME(begin, CUR_TIME));
126 }
127 
128 int ophWRP::loadPointCloud(const char* pc_file)
129 {
130  n_points = ophGen::loadPointCloud(pc_file, &obj_);
131 
132  return n_points;
133 
134 }
135 
136 bool ophWRP::readConfig(const char* fname)
137 {
138  if (!ophGen::readConfig(fname))
139  return false;
140 
141  bool bRet = true;
142  using namespace tinyxml2;
143  /*XML parsing*/
144  tinyxml2::XMLDocument xml_doc;
145  XMLNode* xml_node;
146 
147  if (!checkExtension(fname, ".xml"))
148  {
149  LOG("<FAILED> Wrong file ext.\n");
150  return false;
151  }
152  if (xml_doc.LoadFile(fname) != XML_SUCCESS)
153  {
154  LOG("<FAILED> Loading file.\n");
155  return false;
156  }
157  xml_node = xml_doc.FirstChild();
158 
159  char szNodeName[32] = { 0, };
160  // about viewing window
161  sprintf(szNodeName, "FieldLength");
162  auto next = xml_node->FirstChildElement(szNodeName);
163  if (!next || XML_SUCCESS != next->QueryDoubleText(&wrp_config_.fieldLength))
164  {
165  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
166  bRet = false;
167  }
168  // about point
169  sprintf(szNodeName, "ScaleX");
170  next = xml_node->FirstChildElement(szNodeName);
171  if (!next || XML_SUCCESS != next->QueryDoubleText(&wrp_config_.scale[_X]))
172  {
173  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
174  bRet = false;
175  }
176  sprintf(szNodeName, "ScaleY");
177  next = xml_node->FirstChildElement(szNodeName);
178  if (!next || XML_SUCCESS != next->QueryDoubleText(&wrp_config_.scale[_Y]))
179  {
180  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
181  bRet = false;
182  }
183  sprintf(szNodeName, "ScaleZ");
184  next = xml_node->FirstChildElement(szNodeName);
185  if (!next || XML_SUCCESS != next->QueryDoubleText(&wrp_config_.scale[_Z]))
186  {
187  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
188  bRet = false;
189  }
190  sprintf(szNodeName, "Distance");
191  next = xml_node->FirstChildElement(szNodeName);
192  if (!next || XML_SUCCESS != next->QueryDoubleText(&wrp_config_.propagation_distance))
193  {
194  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
195  bRet = false;
196  }
197  sprintf(szNodeName, "LocationOfWRP");
198  next = xml_node->FirstChildElement(szNodeName);
199  if (!next || XML_SUCCESS != next->QueryDoubleText(&wrp_config_.wrp_location))
200  {
201  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
202  bRet = false;
203  }
204  sprintf(szNodeName, "NumOfWRP");
205  next = xml_node->FirstChildElement(szNodeName);
206  if (!next || XML_SUCCESS != next->QueryIntText(&wrp_config_.num_wrp))
207  {
208  LOG("<FAILED> Not found node : \'%s\' (Integer) \n", szNodeName);
209  bRet = false;
210  }
211  initialize();
212 
213 
214  LOG("**************************************************\n");
215  LOG(" Read Config (WRP) \n");
216  LOG("1) Focal Length : %.5lf\n", wrp_config_.propagation_distance);
217  LOG("2) Object Scale : %.5lf / %.5lf / %.5lf\n", wrp_config_.scale[_X], wrp_config_.scale[_Y], wrp_config_.scale[_Z]);
218  LOG("3) Number of WRP : %d\n", wrp_config_.num_wrp);
219  LOG("**************************************************\n");
220 
221  return bRet;
222 }
223 
224 void ophWRP::addPixel2WRP(int x, int y, Complex<Real> temp)
225 {
226  const uint pnX = context_.pixel_number[_X];
227  const uint pnY = context_.pixel_number[_Y];
228 
229  if (x >= 0 && x < (int)pnX && y >= 0 && y < (int)pnY) {
230  uint adr = x + y * pnX;
231  if (adr == 0)
232  std::cout << ".0";
233  p_wrp_[adr] = p_wrp_[adr] + temp;
234  }
235 
236 }
237 
238 void ophWRP::addPixel2WRP(int x, int y, oph::Complex<Real> temp, oph::Complex<Real>* wrp)
239 {
240  long long int Nx = context_.pixel_number.v[0];
241  long long int Ny = context_.pixel_number.v[1];
242 
243  if (x >= 0 && x < Nx && y >= 0 && y < Ny) {
244  long long int adr = x + y*Nx;
245  wrp[adr] += temp[adr];
246  }
247 }
248 
249 oph::Complex<Real>* ophWRP::calSubWRP(double wrp_d, Complex<Real>* wrp, OphPointCloudData* pc)
250 {
251 
252  Real wave_num = context_.k; // wave_number
253  Real wave_len = context_.wave_length[0]; //wave_length
254 
255  int Nx = context_.pixel_number.v[0]; //slm_pixelNumberX
256  int Ny = context_.pixel_number.v[1]; //slm_pixelNumberY
257 
258  Real wpx = context_.pixel_pitch.v[0];//wrp pitch
259  Real wpy = context_.pixel_pitch.v[1];
260 
261 
262  int Nx_h = Nx >> 1;
263  int Ny_h = Ny >> 1;
264 
265  int num = n_points;
266 
267 
268 #ifdef _OPENMP
269 #pragma omp parallel for firstprivate(wrp_d, wpx, wpy, Nx_h, Ny_h, wave_num, wave_len)
270 #endif
271  for (int k = 0; k < num; k++) {
272 
273  uint idx = 3 * k;
274  uint color_idx = pc->n_colors * k;
275 
276  Real x = pc->vertices[k].point.pos[_X];
277  Real y = pc->vertices[k].point.pos[_Y];
278  Real z = pc->vertices[k].point.pos[_Z];
279  Real amplitude = pc->vertices[k].color.color[_R];
280 
281  float dz = wrp_d - z;
282  // float tw = (int)fabs(wave_len*dz / wpx / wpx / 2 + 0.5) * 2 - 1;
283  float tw = fabs(dz)*wave_len / wpx / wpx / 2;
284 
285  int w = (int)tw;
286 
287  int tx = (int)(x / wpx) + Nx_h;
288  int ty = (int)(y / wpy) + Ny_h;
289 
290  printf("num=%d, tx=%d, ty=%d, w=%d\n", k, tx, ty, w);
291 
292  for (int wy = -w; wy < w; wy++) {
293  for (int wx = -w; wx<w; wx++) {//WRP coordinate
294 
295  double dx = wx*wpx;
296  double dy = wy*wpy;
297  double dz = wrp_d - z;
298 
299  double sign = (dz>0.0) ? (1.0) : (-1.0);
300  double r = sign*sqrt(dx*dx + dy*dy + dz*dz);
301 
302  //double tmp_re,tmp_im;
303  Complex<Real> tmp;
304 
305  tmp[_RE] = (amplitude*cosf(wave_num*r)*cosf(wave_num*wave_len*rand(0, 1))) / (r + 0.05);
306  tmp[_IM] = (-amplitude*sinf(wave_num*r)*sinf(wave_num*wave_len*rand(0, 1))) / (r + 0.05);
307 
308  if (tx + wx >= 0 && tx + wx < Nx && ty + wy >= 0 && ty + wy < Ny)
309  {
310  addPixel2WRP(wx + tx, wy + ty, tmp, wrp);
311  }
312  }
313  }
314  }
315 
316  return wrp;
317 }
318 
320 {
321  LOG("%s\n", __FUNCTION__);
322  auto begin = CUR_TIME;
323 
324  const int pnX = context_.pixel_number[_X]; //slm_pixelNumberX
325  const int pnY = context_.pixel_number[_Y]; //slm_pixelNumberY
326  const Real ppX = context_.pixel_pitch[_X]; //wrp pitch
327  const Real ppY = context_.pixel_pitch[_Y];
328  const long long int N = pnX * pnY;
329  const uint nChannel = context_.waveNum;
330  const Real distance = wrp_config_.propagation_distance;
331  int hpnX = pnX >> 1;
332  int hpnY = pnY >> 1;
333 
334  OphPointCloudData pc = obj_;
335  Real wrp_d = wrp_config_.wrp_location;
336 
337  // Memory Location for Result Image
338 
339  if (p_wrp_) {
340  delete[] p_wrp_;
341  p_wrp_ = nullptr;
342  }
343  p_wrp_ = new Complex<Real>[N];
344  memset(p_wrp_, 0.0, sizeof(Complex<Real>) * N);
345 
346  int sum = 0;
347  m_nProgress = 0;
348  Real ppXX = ppX * ppX * 2;
349  Real pi2 = 2 * M_PI;
350  Real dz = wrp_d - zmax_;
351  Real dzz = dz * dz;
352 
353  bool bRandomPhase = GetRandomPhase();
354 
355  for (uint ch = 0; ch < nChannel; ch++)
356  {
357  Real lambda = context_.wave_length[ch]; //wave_length
358  Real k = context_.k = pi2 / lambda;
359  int iColor = ch;
360  int sum = 0;
361 #ifdef _OPENMP
362 #pragma omp parallel for firstprivate(iColor, ppXX, pnX, pnY, ppX, ppY, hpnX, hpnY, wrp_d, k, pi2, dz, dzz)
363 #endif
364  for (int i = 0; i < n_points; ++i)
365  {
366  uint idx = 3 * i;
367  uint color_idx = pc.n_colors * i;
368 
369  Real x = scaledVertex[i].point.pos[_X];
370  Real y = scaledVertex[i].point.pos[_Y];
371  Real z = scaledVertex[i].point.pos[_Z];
372  Real amplitude = pc.vertices[i].color.color[_R + ch];
373 
374  //Real dz = wrp_d - z;
375  //Real dzz = dz * dz;
376  bool sign = (dz > 0.0) ? true : false;
377  //Real tw = fabs(lambda * dz / ppXX + 0.5) * 2 - 1;
378  Real tw = fabs(lambda * dz / ppXX) * 2;
379 
380  int w = (int)tw;
381 
382  int tx = (int)(x / ppX) + hpnX;
383  int ty = (int)(y / ppY) + hpnY;
384 
385  for (int wy = -w; wy < w; wy++)
386  {
387  Real dy = wy * ppY;
388  Real dyy = dy * dy;
389  int tmpY = wy + ty;
390  int baseY = tmpY * pnX;
391 
392  for (int wx = -w; wx < w; wx++) //WRP coordinate
393  {
394  int tmpX = wx + tx;
395  if (tmpX >= 0 && tmpX < pnX && tmpY >= 0 && tmpY < pnY) {
396  uint adr = tmpX + baseY;
397 
398  Real dx = wx * ppX;
399  Real r = sign ? sqrt(dx * dx + dyy + dzz) : -sqrt(dx * dx + dyy + dzz);
400  Real kr = k * r;
401  Real randVal = bRandomPhase ? rand(0.0, 1.0) : 1.0;
402  Real randpi2 = pi2 * randVal;
403  Complex<Real> tmp;
404  tmp[_RE] = (amplitude * cos(kr) * cos(randpi2)) / r;
405  tmp[_IM] = (-amplitude * sin(kr) * sin(randpi2)) / r;
406 
407  if (adr == 0)
408  std::cout << ".0";
409 #ifdef _OPENMP
410 #pragma omp atomic
411  p_wrp_[adr][_RE] += tmp[_RE];
412 #pragma omp atomic
413  p_wrp_[adr][_IM] += tmp[_IM];
414 #else
415  p_wrp_[adr] += tmp;
416 #endif
417  }
418  }
419  }
420  }
421  fresnelPropagation(p_wrp_, complex_H[ch], distance, ch);
422  memset(p_wrp_, 0.0, sizeof(Complex<Real>) * N);
423  }
424  delete[] p_wrp_;
425  delete[] scaledVertex;
426  p_wrp_ = nullptr;
427  scaledVertex = nullptr;
428 
429  LOG("Total : %lf (s)\n", ELAPSED_TIME(begin, CUR_TIME));
430 
431  //return 0.;
432 }
433 
435 {
436  resetBuffer();
437 
438  auto begin = CUR_TIME;
439  LOG("**************************************************\n");
440  LOG(" Generate Hologram \n");
441  LOG("1) Algorithm Method : WRP\n");
442  LOG("2) Generate Hologram with %s\n", m_mode & MODE_GPU ?
443  "GPU" :
444 #ifdef _OPENMP
445  "Multi Core CPU"
446 #else
447  "Single Core CPU"
448 #endif
449  );
450  LOG("3) Random Phase Use : %s\n", GetRandomPhase() ? "Y" : "N");
451  LOG("4) Number of Point Cloud : %d\n", n_points);
452  LOG("5) Precision Level : %s\n", m_mode & MODE_FLOAT ? "Single" : "Double");
453  if (m_mode & MODE_GPU)
454  LOG("6) Use FastMath : %s\n", m_mode & MODE_FASTMATH ? "Y" : "N");
455  LOG("**************************************************\n");
456 
457  autoScaling();
459 
460  fftFree();
461  LOG("Total Elapsed Time: %lf (s)\n", ELAPSED_TIME(begin, CUR_TIME));
462 }
463 
465 {
466  int wrp_num = wrp_config_.num_wrp;
467 
468  if (wrp_num < 1)
469  return nullptr;
470 
471  Complex<Real>** wrp_list = nullptr;
472 
473  Real k = context_.k; // wave_number
474  Real lambda = context_.wave_length[0]; //wave_length
475  const long long int pnXY = context_.pixel_number[_X] * context_.pixel_number[_Y];
476 
477  Complex<Real>* wrp = new Complex<Real>[pnXY];
478 
479  //OphPointCloudData pc = obj_;
480 
481  for (int i = 0; i < wrp_num; i++)
482  {
483 // wrp = calSubWRP(wrp_d, wrp, &pc);
484  wrp_list[i] = wrp;
485  }
486 
487  return wrp_list;
488 }
489 
490 void ophWRP::ophFree(void)
491 {
492  if (obj_.vertices) {
493  delete[] obj_.vertices;
494  obj_.vertices = nullptr;
495  }
496 }
497 
498 void ophWRP::transVW(Real* dst, Real* src, int size)
499 {
500  Real fieldLens = getFieldLens();
501  for (int i = 0; i < size; i++) {
502  dst[i] = (-fieldLens * src[i]) / (src[i] - fieldLens);
503  }
504 }
Color color
Definition: struct.h:104
Vertex * scaledVertex
Definition: ophWRP.h:226
#define M_PI
Definition: define.h:52
Point point
Definition: struct.h:103
Real k
Definition: Openholo.h:103
w
Definition: Openholo.cpp:429
void fftFree(void)
Resource release method.
Definition: Openholo.cpp:677
#define _R
Definition: define.h:108
#define MIN_DOUBLE
Definition: define.h:148
#define MODE_FASTMATH
Definition: define.h:159
Real fieldLength
fieldLength variable for viewing window.
Definition: ophGen.h:657
OphPointCloudData obj_
Input Pointcloud Data.
Definition: ophWRP.h:225
#define MODE_FLOAT
Definition: define.h:158
#define MODE_GPU
Definition: define.h:156
void initialize(void)
Initialize variables for Hologram complex field, encoded data, normalized data.
Definition: ophGen.cpp:145
void setViewingWindow(bool is_ViewingWindow)
Set the value of a variable is_ViewingWindow(true or false)
Definition: ophWRP.cpp:64
return true
Definition: Openholo.cpp:434
int num_wrp
Number of wavefront recording plane(WRP)
Definition: ophGen.h:661
float Real
Definition: typedef.h:55
bool checkExtension(const char *fname, const char *ext)
Functions for extension checking.
Definition: Openholo.cpp:86
#define _IM
Definition: complex.h:58
def k(wvl)
Definition: Depthmap.py:16
ophWRP(void)
Constructor.
Definition: ophWRP.cpp:50
bool GetRandomPhase()
Function for getting the random phase.
Definition: ophGen.h:537
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
Definition: tinyxml2.h:761
int v[2]
Definition: ivec.h:67
virtual bool readConfig(const char *fname)
load to configuration file.
Definition: ophWRP.cpp:136
vec2 pixel_pitch
Definition: Openholo.h:101
vec3 scale
Scaling factor of coordinate of point cloud.
Definition: ophGen.h:659
#define _X
Definition: define.h:92
unsigned int m_mode
Definition: ophGen.h:350
virtual int loadPointCloud(const char *pc_file)
load to point cloud data.
Definition: ophWRP.cpp:128
Real wrp_location
Location distance of WRP.
Definition: ophGen.h:663
Complex< Real > * p_wrp_
wrp buffer - complex type
Definition: ophWRP.h:223
OphWRPConfig wrp_config_
structure variable for WRP hologram configuration
Definition: ophWRP.h:227
void calculateWRPCPU(void)
Definition: ophWRP.cpp:319
#define _RE
Definition: complex.h:55
void fresnelPropagation(OphConfig context, Complex< Real > *in, Complex< Real > *out, Real distance)
Fresnel propagation.
virtual ~ophWRP(void)
Destructor.
Definition: ophWRP.cpp:60
Definition: struct.h:102
uint waveNum
Definition: Openholo.h:105
structure for 3-dimensional Real type vector and its arithmetic.
Definition: vec.h:466
int n_colors
Number of color channel.
Definition: ophGen.h:586
ivec2 pixel_number
Definition: Openholo.h:99
bool readConfig(const char *fname)
load to configuration file.
Definition: ophGen.cpp:220
#define _Y
Definition: define.h:96
XMLError LoadFile(const char *filename)
Definition: tinyxml2.cpp:2150
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
int n_points
numbers of points
Definition: ophWRP.h:221
Vertex * vertices
Data of point clouds.
Definition: ophGen.h:588
void autoScaling()
Definition: ophWRP.cpp:69
Complex< Real > ** complex_H
Definition: Openholo.h:489
void calculateWRPGPU(void)
Definition: ophWRP_GPU.cpp:48
Data for Point Cloud.
Definition: ophGen.h:582
Real propagation_distance
Distance of Hologram plane.
Definition: ophGen.h:665
void resetBuffer()
reset buffer
Definition: ophGen.cpp:824
#define _Z
Definition: define.h:100
#define ELAPSED_TIME(x, y)
Definition: function.h:59
OphConfig context_
Definition: Openholo.h:485
Real v[2]
Definition: vec.h:67
Real sum(const vec2 &a)
Definition: vec.h:401
Real * wave_length
Definition: Openholo.h:106
int loadPointCloud(const char *pc_file, OphPointCloudData *pc_data_)
load to point cloud data.
Definition: ophGen.cpp:206
const XMLElement * FirstChildElement(const char *name=0) const
Definition: tinyxml2.cpp:940
const Real & getFieldLens()
Definition: ophWRP.h:135
unsigned int uint
Definition: typedef.h:62
#define CUR_TIME
Definition: function.h:58
Definition: ophGen.h:76
Real pos[3]
Definition: struct.h:87
void generateHologram(void)
Generate a hologram, main funtion.
Definition: ophWRP.cpp:434
Real color[3]
Definition: struct.h:95
Complex< Real > ** calculateMWRP(void)
Generate multiple wavefront recording planes, main funtion.
Definition: ophWRP.cpp:464