Openholo  v5.0
Open Source Digital Holographic Library
ophPAS.cpp
Go to the documentation of this file.
1 
2 #include "ophPAS.h"
3 #include <fstream>
4 #include <iostream>
5 #include <string>
6 #include <iomanip>
7 
8 #include "sys.h"
9 
10 #include "tinyxml2.h"
11 #include "PLYparser.h"
12 
14  : ophGen()
15  ,coefficient_cx(nullptr)
16  ,coefficient_cy(nullptr)
17  ,compensation_cx(nullptr)
18  ,compensation_cy(nullptr)
19  ,xc(nullptr)
20  ,yc(nullptr)
21  ,input(nullptr)
22 {
23  LOG("*** PHASE-ADDED STEREOGRAM: BUILD DATE: %s %s ***\n\n", __DATE__, __TIME__);
24 }
25 
27 {
28  if (coefficient_cx != nullptr)
29  delete[] coefficient_cx;
30  if (coefficient_cy != nullptr)
31  delete[] coefficient_cy;
32  if (compensation_cx != nullptr)
33  delete[] compensation_cx;
34  if (compensation_cy != nullptr)
35  delete[] compensation_cy;
36  if (xc != nullptr)
37  delete[] xc;
38  if (yc != nullptr)
39  delete[] yc;
40 }
41 
42 bool ophPAS::readConfig(const char* fname)
43 {
44  if (!ophGen::readConfig(fname))
45  return false;
46 
47  bool bRet = true;
48 
49  using namespace tinyxml2;
50  /*XML parsing*/
51  tinyxml2::XMLDocument xml_doc;
52  XMLNode *xml_node;
53 
54  if (!checkExtension(fname, ".xml"))
55  {
56  LOG("<FAILED> Wrong file ext.\n");
57  return false;
58  }
59  if (xml_doc.LoadFile(fname) != XML_SUCCESS)
60  {
61  LOG("<FAILED> Loading file.\n");
62  return false;
63  }
64  xml_node = xml_doc.FirstChild();
65 
66 
67  char szNodeName[32] = { 0, };
68  sprintf(szNodeName, "ScaleX");
69  // about point
70  auto next = xml_node->FirstChildElement(szNodeName);
71  if (!next || XML_SUCCESS != next->QueryDoubleText(&pc_config.scale[_X]))
72  {
73  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
74  bRet = false;
75  }
76  sprintf(szNodeName, "ScaleY");
77  next = xml_node->FirstChildElement(szNodeName);
78  if (!next || XML_SUCCESS != next->QueryDoubleText(&pc_config.scale[_Y]))
79  {
80  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
81  bRet = false;
82  }
83  sprintf(szNodeName, "ScaleZ");
84  next = xml_node->FirstChildElement(szNodeName);
85  if (!next || XML_SUCCESS != next->QueryDoubleText(&pc_config.scale[_Z]))
86  {
87  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
88  bRet = false;
89  }
90  sprintf(szNodeName, "Distance");
91  next = xml_node->FirstChildElement(szNodeName);
92  if (!next || XML_SUCCESS != next->QueryDoubleText(&pc_config.distance))
93  {
94  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
95  bRet = false;
96  }
97 
98  initialize();
99 
100  LOG("**************************************************\n");
101  LOG(" Read Config (Phase-Added Stereogram) \n");
102  LOG("1) Focal Length : %.5lf\n", pc_config.distance);
103  LOG("2) Object Scale : %.5lf / %.5lf / %.5lf\n", pc_config.scale[_X], pc_config.scale[_Y], pc_config.scale[_Z]);
104  LOG("**************************************************\n");
105 
106  return bRet;
107 }
108 
109 int ophPAS::loadPoint(const char* _filename)
110 {
111  int n_points = ophGen::loadPointCloud(_filename, &pc_data);
112  return n_points;
113 }
114 
115 
117 {
118  auto begin = CUR_TIME;
119  resetBuffer();
120  Init();
122  PAS();
123  LOG("Total Elapsed Time: %lf (s)\n", ELAPSED_TIME(begin, CUR_TIME));
124 }
125 
126 
128 {
129  const int pnX = context_.pixel_number[_X];
130  const int pnY = context_.pixel_number[_Y];
131  const int segSize = is_accurate ? SEG_SIZE : FFT_SEGMENT_SIZE;
132  const int snX = pnX / segSize;
133  const int snY = pnY / segSize;
134 
135  if (coefficient_cx == nullptr)
136  coefficient_cx = new int[snX];
137  if (coefficient_cy == nullptr)
138  coefficient_cy = new int[snY];
139  if (compensation_cx == nullptr)
140  compensation_cx = new Real[snX];
141  if (compensation_cy == nullptr)
142  compensation_cy = new Real[snY];
143  if (xc == nullptr)
144  xc = new Real[snX];
145  if (yc == nullptr)
146  yc = new Real[snY];
147 }
148 
150 {
151  Real pi2 = M_PI * 2;
152  for (int i = 0; i < NUMTBL; i++) {
153  Real theta = pi2 * (i + i - 1) / (2 * NUMTBL);
154  LUTCos[i] = cos(theta);
155  LUTSin[i] = sin(theta);
156  }
157 }
158 
160 {
161  const int pnX = context_.pixel_number[_X];
162  const int pnY = context_.pixel_number[_Y];
163  const Real ppX = context_.pixel_pitch[_X];
164  const Real ppY = context_.pixel_pitch[_Y];
165 
166  const int hpnX = pnX >> 1;
167  const int hpnY = pnY >> 1;
168 
169  const Real distance = pc_config.distance;
170  const int N = pnX * pnY;
171  const int segSize = is_accurate ? SEG_SIZE : FFT_SEGMENT_SIZE;
172  const int hSegSize = segSize >> 1;
173  const int sSegSize = segSize * segSize;
174 
175  const int fftSegSize = FFT_SEGMENT_SIZE;
176  const int ffthSegSize = fftSegSize >> 1;
177  const int fftsSegSize = fftSegSize * fftSegSize;
178 
179  const int snX = pnX / segSize;
180  const int snY = pnY / segSize;
181  const int hsnX = snX >> 1;
182  const int hsnY = snY >> 1;
183 
184  const int snXY = snX * snY;
185 
186  // base spatial frequency
187 
188  int n_points = pc_data.n_points;
189  const Real sf_base = 1.0 / (ppX * fftSegSize);
190 
191  input = new Complex<Real>*[snXY];
192  for (int i = 0; i < snXY; i++) {
193  input[i] = new Complex<Real>[fftsSegSize];
194  memset(input[i], 0x00, sizeof(Complex<Real>) * fftsSegSize);
195  }
196 
197  Complex<Real>* result = new Complex<Real>[fftsSegSize];
198 
199 
200  for (int ch = 0; ch < context_.waveNum; ch++)
201  {
202  Real lambda = context_.wave_length[ch];
203 
204  for (int i = 0; i < n_points; i++)
205  {
206  Point pt = pc_data.vertices[i].point;
207  //Real ampitude = pc_data.vertices[i].phase; // why phase?
208  Real amplitude = pc_data.vertices[i].color.color[ch]; // red
209  Real phase = pc_data.vertices[i].phase;
210  pt.pos[_X] *= pc_config.scale[_X];
211  pt.pos[_Y] *= pc_config.scale[_Y];
212  pt.pos[_Z] *= pc_config.scale[_Z];
213  pt.pos[_Z] -= distance;
214 
215  CalcSpatialFrequency(&pt, lambda, is_accurate);
216  CalcCompensatedPhase(&pt, amplitude, phase, lambda, is_accurate);
217  }
218  if (is_accurate)
219  {
220  for (int y = 0; y < snY; y++) {
221 
222  for (int x = 0; x < snX; x++) {
223 
224  int segyy = y * snX + x;
225  int segxx = coefficient_cy[y] * fftSegSize + coefficient_cx[x];
226 
227  if (segyy < snXY)
228  {
229  fft2(input[segyy], result, fftSegSize, fftSegSize, OPH_BACKWARD, false, false);
230 
231  for (int m = 0; m < segSize; m++)
232  {
233  int yy = y * segSize + m;
234  int xx = x * segSize;
235  int mm = m + ffthSegSize;
236  for (int n = 0; n < segSize; n++)
237  {
238  complex_H[ch][yy * pnX + (xx + n)] += result[(m + ffthSegSize - hSegSize) * fftSegSize + (n + ffthSegSize - hSegSize)][_RE];
239  }
240  }
241  }
242  }
243  }
244  }
245  else
246  {
247  for (int y = 0; y < snY; y++) {
248 
249  for (int x = 0; x < snX; x++) {
250 
251  int segyy = y * snX + x;
252  int segxx = coefficient_cy[y] * segSize + coefficient_cx[x];
253 
254  if (segyy < snXY)
255  {
256  fft2(input[segyy], result, segSize, segSize, OPH_BACKWARD, false, false);
257 
258  for (int m = 0; m < segSize; m++)
259  {
260  for (int n = 0; n < segSize; n++)
261  {
262  int segxx = m * segSize + n;
263 
264  complex_H[ch][(y * segSize + m) * pnX + (x * segSize + n)] = result[m * segSize + n][_RE];
265  }
266  }
267  }
268  }
269  }
270  }
271  }
272 
273 
274  //fftFree();
275  delete[] result;
276 
277  for (int i = 0; i < snXY; i++) {
278  delete[] input[i];
279  }
280  delete[] input;
281 }
282 
283 
284 void ophPAS::CalcSpatialFrequency(Point *pt, Real lambda, bool accurate)
285 {
286  int segSize = FFT_SEGMENT_SIZE;
287  int hSegSize = segSize >> 1;
288  int snX = context_.pixel_number[_X] / segSize;
289  int snY = context_.pixel_number[_Y] / segSize;
290  Real ppX = context_.pixel_pitch[_X];
291  Real ppY = context_.pixel_pitch[_Y];
292  int hsnX = snX >> 1;
293  int hsnY = snY >> 1;
294 
295  Real thetaX = pc_config.tilt_angle[_X];
296  Real thetaY = pc_config.tilt_angle[_Y];
297  Real sf_base = 1.0 / (ppX * segSize);
298 
299 
300  if (accurate)
301  {
302  Real pi2 = M_PI * 2;
303  Real tempX = sf_base * hSegSize * ppX;
304  Real tempY = sf_base * hSegSize * ppY;
305 
306  for (int x = 0; x < snX; x++) {
307  xc[x] = ((x - hsnX) * segSize + hSegSize) * ppX;
308  Real theta_cx = (xc[x] - pt->pos[_X]) / pt->pos[_Z];
309  Real sf_cx = (theta_cx + thetaX) / lambda;
310  Real val = sf_cx >= 0 ? 0.5 : -0.5;
311  int pp_cx = (int)(sf_cx / sf_base + val);
312  coefficient_cx[x] = (abs(pp_cx) < hSegSize) ? ((segSize - pp_cx) % segSize) : 0;
313  compensation_cx[x] = pi2 * ((xc[x] - pt->pos[_X]) * sf_cx + pp_cx * tempX);
314  }
315 
316  for (int y = 0; y < snY; y++) {
317  yc[y] = ((y - hsnY) * segSize + hSegSize) * ppY;
318  Real theta_cy = (yc[y] - pt->pos[_Y]) / pt->pos[_Z];
319  Real sf_cy = (theta_cy + thetaY) / lambda;
320  Real val = sf_cy >= 0 ? 0.5 : -0.5;
321  int pp_cy = (int)(sf_cy / sf_base + val);
322  coefficient_cy[y] = (abs(pp_cy) < hSegSize) ? ((segSize - pp_cy) % segSize) : 0;
323  compensation_cy[y] = pi2 * ((yc[y] - pt->pos[_Y]) * sf_cy + pp_cy * tempY);
324  }
325  }
326  else
327  {
328  for (int x = 0; x < snX; x++) {
329  xc[x] = ((x - hsnX) * segSize + hSegSize) * ppX;
330  Real theta_cx = (xc[x] - pt->pos[_X]) / pt->pos[_Z];
331  Real sf_cx = (theta_cx + thetaX) / lambda;
332  Real val = sf_cx >= 0 ? 0.5 : -0.5;
333  int pp_cx = (int)(sf_cx / sf_base + val);
334  coefficient_cx[x] = (abs(pp_cx) < hSegSize) ? ((segSize - pp_cx) % segSize) : 0;
335  }
336 
337  for (int y = 0; y < snY; y++) {
338  yc[y] = ((y - hsnY) * segSize + hSegSize) * ppY;
339  Real theta_cy = (yc[y] - pt->pos[_Y]) / pt->pos[_Z];
340  Real sf_cy = (theta_cy + thetaY) / lambda;
341  Real val = sf_cy >= 0 ? 0.5 : -0.5;
342  int pp_cy = (int)(sf_cy / sf_base + val);
343  coefficient_cy[y] = (abs(pp_cy) < hSegSize) ? ((segSize - pp_cy) % segSize) : 0;
344  }
345  }
346 }
347 
348 void ophPAS::CalcCompensatedPhase(Point *pt, Real amplitude, Real phase, Real lambda, bool accurate)
349 {
350  int segSize = FFT_SEGMENT_SIZE;
351  int hSegSize = segSize >> 1;
352  int snX = context_.pixel_number[_X] / segSize;
353  int snY = context_.pixel_number[_Y] / segSize;
354  Real ppX = context_.pixel_pitch[_X];
355  Real ppY = context_.pixel_pitch[_Y];
356  int hsnX = snX >> 1;
357  int hsnY = snY >> 1;
358  Real zz = pt->pos[_Z] * pt->pos[_Z];
359  Real pi2 = M_PI * 2;
360 
361  if (accurate)
362  {
363  for (int y = 0; y < snY; y++)
364  {
365  Real yy = (yc[y] - pt->pos[_Y]) * (yc[y] - pt->pos[_Y]);
366  for (int x = 0; x < snX; x++)
367  {
368  int segyy = y * snX + x;
369  int segxx = coefficient_cy[y] * segSize + coefficient_cx[x];
370  Real xx = (xc[x] - pt->pos[_X]) * (xc[x] - pt->pos[_X]);
371  Real r = sqrt(xx + yy + zz);
372 
373  Real theta = lambda * r + phase + compensation_cy[y] + compensation_cx[x];
374  Real theta_c = theta;
375  Real theta_s = theta + M_PI;
376 
377  int idx_c = ((int)(theta_c * NUMTBL / pi2)) & NUMTBL2;
378  int idx_s = ((int)(theta_s * NUMTBL / pi2)) & NUMTBL2;
379  input[segyy][segxx][_RE] += amplitude * LUTCos[idx_c];
380  input[segyy][segxx][_IM] += amplitude * LUTSin[idx_s];
381  }
382  }
383  }
384  else
385  {
386  for (int y = 0; y < snY; y++)
387  {
388  Real yy = (yc[y] - pt->pos[_Y]) * (yc[y] - pt->pos[_Y]);
389  for (int x = 0; x < snX; x++)
390  {
391  int segyy = y * snX + x;
392  int segxx = coefficient_cy[y] * segSize + coefficient_cx[x];
393  Real xx = (xc[x] - pt->pos[_X]) * (xc[x] - pt->pos[_X]);
394  Real r = sqrt(xx + yy + zz);
395 
396  Real theta = lambda * r;
397  Real theta_c = theta;
398  Real theta_s = theta + M_PI;
399 
400  int idx_c = ((int)(theta_c * NUMTBL / pi2)) & NUMTBL2;
401  int idx_s = ((int)(theta_s * NUMTBL / pi2)) & NUMTBL2;
402  input[segyy][segxx][_RE] += amplitude * LUTCos[idx_c];
403  input[segyy][segxx][_IM] += amplitude * LUTSin[idx_s];
404  }
405  }
406  }
407 }
408 
409 void ophPAS::encodeHologram(const vec2 band_limit, const vec2 spectrum_shift)
410 {
411  if (complex_H == nullptr) {
412  LOG("Not found diffracted data.");
413  return;
414  }
415 
416 
417  const uint nChannel = context_.waveNum;
418  const uint pnX = context_.pixel_number[_X];
419  const uint pnY = context_.pixel_number[_Y];
420  const Real ppX = context_.pixel_pitch[_X];
421  const Real ppY = context_.pixel_pitch[_Y];
422  const long long int pnXY = pnX * pnY;
423 
424  m_vecEncodeSize = ivec2(pnX, pnY);
425  context_.ss[_X] = pnX * ppX;
426  context_.ss[_Y] = pnY * ppY;
427  vec2 ss = context_.ss;
428 
429  Real cropx = floor(pnX * band_limit[_X]);
430  Real cropx1 = cropx - floor(cropx / 2);
431  Real cropx2 = cropx1 + cropx - 1;
432 
433  Real cropy = floor(pnY * band_limit[_Y]);
434  Real cropy1 = cropy - floor(cropy / 2);
435  Real cropy2 = cropy1 + cropy - 1;
436 
437  Real* x_o = new Real[pnX];
438  Real* y_o = new Real[pnY];
439 
440  for (uint i = 0; i < pnX; i++)
441  x_o[i] = (-ss[_X] / 2) + (ppX * i) + (ppX / 2);
442 
443  for (uint i = 0; i < pnY; i++)
444  y_o[i] = (ss[_Y] - ppY) - (ppY * i);
445 
446  Real* xx_o = new Real[pnXY];
447  Real* yy_o = new Real[pnXY];
448 
449  for (int i = 0; i < pnXY; i++)
450  xx_o[i] = x_o[i % pnX];
451 
452 
453  for (uint i = 0; i < pnX; i++)
454  for (uint j = 0; j < pnY; j++)
455  yy_o[i + j * pnX] = y_o[j];
456 
457  Complex<Real>* h = new Complex<Real>[pnXY];
458 
459  for (uint ch = 0; ch < nChannel; ch++) {
460  fft2(complex_H[ch], h, pnX, pnY, OPH_FORWARD);
461  fft2(ivec2(pnX, pnY), h, OPH_FORWARD);
462  fftExecute(h);
463  fft2(h, h, pnX, pnY, OPH_BACKWARD);
464 
465  fft2(h, h, pnX, pnY, OPH_FORWARD);
466  fft2(ivec2(pnX, pnY), h, OPH_BACKWARD);
467  fftExecute(h);
468  fft2(h, h, pnX, pnY, OPH_BACKWARD);
469 
470  for (int i = 0; i < pnXY; i++) {
471  Complex<Real> shift_phase(1.0, 0.0);
472  int r = i / pnX;
473  int c = i % pnX;
474 
475  Real X = (M_PI * xx_o[i] * spectrum_shift[_X]) / ppX;
476  Real Y = (M_PI * yy_o[i] * spectrum_shift[_Y]) / ppY;
477 
478  shift_phase[_RE] = shift_phase[_RE] * (cos(X) * cos(Y) - sin(X) * sin(Y));
479 
480  m_lpEncoded[ch][i] = (h[i] * shift_phase).real();
481  }
482  }
483  delete[] h;
484  delete[] x_o;
485  delete[] xx_o;
486  delete[] y_o;
487  delete[] yy_o;
488 
489 }
490 
491 void ophPAS::encoding(unsigned int ENCODE_FLAG)
492 {
494 }
#define OPH_BACKWARD
Definition: define.h:67
Color color
Definition: struct.h:104
ENCODE_FLAG
Definition: ophGen.h:84
void abs(const oph::Complex< T > &src, oph::Complex< T > &dst)
Definition: function.h:113
void encodeHologram(const vec2 band_limit, const vec2 spectrum_shift)
Definition: ophPAS.cpp:409
Point point
Definition: struct.h:103
void CreateLookupTables()
Definition: ophPAS.cpp:149
#define NUMTBL2
Definition: ophPAS.h:8
void Init()
Definition: ophPAS.cpp:127
Real distance
Offset value of point cloud.
Definition: ophGen.h:550
Real * wave_length
Definition: Openholo.h:106
ulonglong n_points
Number of points.
Definition: ophGen.h:575
Real ** m_lpEncoded
buffer to encoded.
Definition: ophGen.h:338
vec2 tilt_angle
Tilt angle for spatial filtering.
Definition: ophGen.h:562
bool readConfig(const char *fname)
Definition: ophPAS.cpp:42
float Real
Definition: typedef.h:55
void initialize(void)
Initialize variables for Hologram complex field, encoded data, normalized data.
Definition: ophGen.cpp:146
#define CUR_TIME
Definition: function.h:58
Definition: struct.h:86
vec2 ss
Definition: Openholo.h:104
bool checkExtension(const char *fname, const char *ext)
Functions for extension checking.
Definition: Openholo.cpp:86
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
void PAS()
Definition: ophPAS.cpp:159
virtual ~ophPAS()
Definition: ophPAS.cpp:26
#define _Y
Definition: define.h:96
#define _IM
Definition: complex.h:58
Real phase
Definition: struct.h:105
vec2 pixel_pitch
Definition: Openholo.h:101
ophPAS()
Definition: ophPAS.cpp:13
vec3 scale
Scaling factor of coordinate of point cloud.
Definition: ophGen.h:548
#define FFT_SEGMENT_SIZE
Definition: ophPAS.h:10
int loadPoint(const char *_filename)
Definition: ophPAS.cpp:109
ivec2 m_vecEncodeSize
Encoded hologram size, varied from encoding type.
Definition: ophGen.h:330
#define _X
Definition: define.h:92
void CalcSpatialFrequency(Point *pt, Real lambda, bool accurate=false)
Definition: ophPAS.cpp:284
void CalcCompensatedPhase(Point *pt, Real amplitude, Real phase, Real lambda, bool accurate=false)
Definition: ophPAS.cpp:348
#define _RE
Definition: complex.h:55
void fftExecute(Complex< Real > *out, bool bReverse=false)
Execution functions to be called after fft1, fft2, and fft3.
Definition: Openholo.cpp:623
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
Real pos[3]
Definition: struct.h:87
#define ELAPSED_TIME(x, y)
Definition: function.h:59
uint waveNum
Definition: Openholo.h:105
ivec2 pixel_number
Definition: Openholo.h:99
Vertex * vertices
Data of point clouds.
Definition: ophGen.h:579
bool readConfig(const char *fname)
load to configuration file.
Definition: ophGen.cpp:221
XMLError LoadFile(const char *filename)
Definition: tinyxml2.cpp:2150
#define SEG_SIZE
Definition: ophPAS.h:11
void encoding()
Definition: ophGen.cpp:962
void resetBuffer()
reset buffer
Definition: ophGen.cpp:801
OphConfig context_
Definition: Openholo.h:486
#define OPH_FORWARD
Definition: define.h:66
Complex< Real > ** complex_H
Definition: Openholo.h:490
void generateHologram()
Definition: ophPAS.cpp:116
#define _Z
Definition: define.h:100
#define NUMTBL
Definition: ophPAS.h:7
int loadPointCloud(const char *pc_file, OphPointCloudData *pc_data_)
load to point cloud data.
Definition: ophGen.cpp:207
Real color[3]
Definition: struct.h:95
const XMLElement * FirstChildElement(const char *name=0) const
Definition: tinyxml2.cpp:940
unsigned int uint
Definition: typedef.h:62
#define M_PI
Definition: define.h:52
h
Definition: Openholo.cpp:430
Definition: ophGen.h:76