Openholo  v4.0
Open Source Digital Holographic Library
ophLightField.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 "ophLightField.h"
47 #include "include.h"
48 #include "sys.h"
49 #include "tinyxml2.h"
50 #include <fstream>
51 #ifdef _WIN64
52 #include <io.h>
53 #include <direct.h>
54 #else
55 #include <dirent.h>
56 #include <sys/stat.h>
57 #include <algorithm>
58 #endif
59 
61  : num_image(ivec2(0, 0))
62  , resolution_image(ivec2(0, 0))
63  , distanceRS2Holo(0.0)
64  , fieldLens(0.0)
65  , is_ViewingWindow(false)
66  , nImages(-1)
67 {
68  LOG("*** LIGHT FIELD : BUILD DATE: %s %s ***\n\n", __DATE__, __TIME__);
69 }
70 
71 void ophLF::setViewingWindow(bool is_ViewingWindow)
72 {
73  this->is_ViewingWindow = is_ViewingWindow;
74 }
75 
76 bool ophLF::readConfig(const char* fname)
77 {
78  if (!ophGen::readConfig(fname))
79  return false;
80 
81  bool bRet = true;
82 
83  using namespace tinyxml2;
84  /*XML parsing*/
85  tinyxml2::XMLDocument xml_doc;
86  XMLNode *xml_node;
87 
88  if (!checkExtension(fname, ".xml"))
89  {
90  LOG("<FAILED> Wrong file ext.\n");
91  return false;
92  }
93  if (xml_doc.LoadFile(fname) != XML_SUCCESS)
94  {
95  LOG("<FAILED> Loading file.\n");
96  return false;
97  }
98 
99  xml_node = xml_doc.FirstChild();
100 
101  char szNodeName[32] = { 0, };
102  sprintf(szNodeName, "FieldLength");
103  // about viewing window
104  auto next = xml_node->FirstChildElement(szNodeName);
105  if (!next || XML_SUCCESS != next->QueryDoubleText(&fieldLens))
106  {
107  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
108  bRet = false;
109  }
110 
111  // about image
112  sprintf(szNodeName, "Image_NumOfX");
113  next = xml_node->FirstChildElement(szNodeName);
114  if (!next || XML_SUCCESS != next->QueryIntText(&num_image[_X]))
115  {
116  LOG("<FAILED> Not found node : \'%s\' (Integer) \n", szNodeName);
117  bRet = false;
118  }
119  sprintf(szNodeName, "Image_NumOfY");
120  next = xml_node->FirstChildElement(szNodeName);
121  if (!next || XML_SUCCESS != next->QueryIntText(&num_image[_Y]))
122  {
123  LOG("<FAILED> Not found node : \'%s\' (Integer) \n", szNodeName);
124  bRet = false;
125  }
126  sprintf(szNodeName, "Image_Width");
127  next = xml_node->FirstChildElement(szNodeName);
128  if (!next || XML_SUCCESS != next->QueryIntText(&resolution_image[_X]))
129  {
130  LOG("<FAILED> Not found node : \'%s\' (Integer) \n", szNodeName);
131  bRet = false;
132  }
133  sprintf(szNodeName, "Image_Height");
134  next = xml_node->FirstChildElement(szNodeName);
135  if (!next || XML_SUCCESS != next->QueryIntText(&resolution_image[_Y]))
136  {
137  LOG("<FAILED> Not found node : \'%s\' (Integer) \n", szNodeName);
138  bRet = false;
139  }
140  sprintf(szNodeName, "Distance");
141  next = xml_node->FirstChildElement(szNodeName);
142  if (!next || XML_SUCCESS != next->QueryDoubleText(&distanceRS2Holo))
143  {
144  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
145  bRet = false;
146  }
147 
148  initialize();
149 
150  LOG("**************************************************\n");
151  LOG(" Read Config (Light Field) \n");
152  LOG("1) Focal Length : %.5lf\n", distanceRS2Holo);
153  LOG("2) Number of Images : %d x %d\n", num_image[_X], num_image[_Y]);
154  LOG("3) Resolution of Each Image : %d x %d\n", resolution_image[_X], resolution_image[_Y]);
155  LOG("4) Field Length (Unused) : %.5lf\n", fieldLens);
156  LOG("**************************************************\n");
157 
158  return bRet;
159 }
160 
161 int ophLF::loadLF(const char* directory, const char* exten)
162 {
163  int nWave = context_.waveNum;
164 
165  initializeLF();
166 
167 #ifdef _WIN64
168  _finddata_t data;
169 
170  string sdir = std::string(directory).append("\\").append("*.").append(exten);
171  intptr_t ff = _findfirst(sdir.c_str(), &data);
172 
173  if (ff != -1)
174  {
175  int num = 0;
176  ivec2 sizeOut;
177  int bytesperpixel;
178 
179  while (true)
180  {
181  string imgfullname = std::string(directory).append("/").append(data.name);
182  getImgSize(sizeOut[_X], sizeOut[_Y], bytesperpixel, imgfullname.c_str());
183 
184  int size = (((sizeOut[_X] * bytesperpixel) + 3) & ~3) * sizeOut[_Y];
185 
186  if (nWave == 1)
187  {
188  size = ((sizeOut[_X] + 3) & ~3) * sizeOut[_Y];
189  uchar* img = loadAsImg(imgfullname.c_str());
190  m_vecImages[num] = new uchar[size];
191  convertToFormatGray8(img, m_vecImages[num], sizeOut[_X], sizeOut[_Y], bytesperpixel);
192  m_vecImgSize[num] = size;
193  if (img == nullptr) {
194  LOG("<FAILED> Load image.\n");
195  return -1;
196  }
197  }
198  else
199  {
200  m_vecImages[num] = loadAsImg(imgfullname.c_str());
201  m_vecImgSize[num] = size;
202  if (m_vecImages[num] == nullptr) {
203  LOG("<FAILED> Load image.\n");
204  return -1;
205  }
206  }
207  num++;
208 
209  int out = _findnext(ff, &data);
210  if (out == -1)
211  break;
212  }
213  _findclose(ff);
214 
215  if (num_image[_X] * num_image[_Y] != num) {
216  LOG("<FAILED> Not matching image.\n");
217  }
218  return 1;
219 }
220  else
221  {
222  LOG("<FAILED> Load image.\n");
223  return -1;
224  }
225 
226 #else
227 
228  string sdir;
229  DIR* dir = nullptr;
230  if (directory[0] != '/') {
231  char buf[PATH_MAX] = { 0, };
232  if (getcwd(buf, sizeof(buf)) != nullptr) {
233  sdir = sdir.append(buf).append("/").append(directory);
234  }
235  }
236  else
237  sdir = string(directory);
238  string ext = string(exten);
239 
240  if ((dir = opendir(sdir.c_str())) != nullptr) {
241 
242  int num = 0;
243  ivec2 sizeOut;
244  int bytesperpixel;
245  struct dirent* ent;
246 
247  // Add file
248  int cnt = 0;
249  vector<string> fileList;
250  while ((ent = readdir(dir)) != nullptr) {
251  string filePath;
252  filePath = filePath.append(sdir.c_str()).append("/").append(ent->d_name);
253  if (filePath != "." && filePath != "..") {
254  struct stat fileInfo;
255  if (stat(filePath.c_str(), &fileInfo) == 0 && S_ISREG(fileInfo.st_mode)) {
256  if (filePath.substr(filePath.find_last_of(".") + 1) == ext) {
257  fileList.push_back(filePath);
258  cnt++;
259  }
260  }
261  }
262  }
263  closedir(dir);
264  std::sort(fileList.begin(), fileList.end());
265 
266  for (size_t i = 0; i < fileList.size(); i++)
267  {
268  // to do
269  getImgSize(sizeOut[_X], sizeOut[_Y], bytesperpixel, fileList[i].c_str());
270  int size = (((sizeOut[_X] * bytesperpixel) + 3) & ~3) * sizeOut[_Y];
271 
272  if (nWave == 1)
273  {
274  size = ((sizeOut[_X] + 3) & ~3) * sizeOut[_Y];
275  uchar* img = loadAsImg(fileList[i].c_str());
276  m_vecImages[i] = new uchar[size];
277  convertToFormatGray8(img, m_vecImages[i], sizeOut[_X], sizeOut[_Y], bytesperpixel);
278  m_vecImgSize[i] = size;
279  if (img == nullptr) {
280  LOG("<FAILED> Load image.\n");
281  return -1;
282  }
283  }
284  else
285  {
286  m_vecImages[i] = loadAsImg(fileList[i].c_str());
287  m_vecImgSize[i] = size;
288  if (m_vecImages[i] == nullptr) {
289  LOG("<FAILED> Load image.\n");
290  return -1;
291  }
292  }
293  }
294  if (num_image[_X] * num_image[_Y] != (int)fileList.size()) {
295  LOG("<FAILED> Not matching image.\n");
296  }
297  return 1;
298 
299  }
300  else
301  {
302  LOG("<FAILED> Load image : %s\n", sdir.c_str());
303  return -1;
304  }
305 #endif
306 }
307 
308 
310 {
311  resetBuffer();
312  LOG("**************************************************\n");
313  LOG(" Generate Hologram \n");
314  LOG("1) Algorithm Method : Light Field\n");
315  LOG("2) Generate Hologram with %s\n", m_mode & MODE_GPU ?
316  "GPU" :
317 #ifdef _OPENMP
318  "Multi Core CPU"
319 #else
320  "Single Core CPU"
321 #endif
322  );
323  LOG("3) Use Random Phase : %s\n", GetRandomPhase() ? "Y" : "N");
324  LOG("**************************************************\n");
325 
326  auto begin = CUR_TIME;
327 
328  if (m_mode & MODE_GPU)
329  {
331  }
332  else
333  {
335 
336  for (uint ch = 0; ch < context_.waveNum; ch++)
337  {
338  fresnelPropagation(m_vecRSplane[ch], complex_H[ch], distanceRS2Holo, ch);
339  }
340  }
341  fftFree();
342  LOG("Total Elapsed Time: %.5lf (sec)\n", ELAPSED_TIME(begin, CUR_TIME));
343 }
344 
346 {
347  for (vector<uchar *>::iterator it = m_vecImages.begin(); it != m_vecImages.end(); it++) delete[](*it);
348  m_vecImages.clear();
349  m_vecImgSize.clear();
350 
351  const int nX = num_image[_X];
352  const int nY = num_image[_Y];
353  const int N = nX * nY;
354 
355  m_vecImages.resize(N);
356  m_vecImgSize.resize(N);
357  nImages = N;
358 }
359 
361 {
362  auto begin = CUR_TIME;
363 
364  const uint nX = num_image[_X];
365  const uint nY = num_image[_Y];
366  const long long int N = nX * nY; // Image count
367 
368  const uint rX = resolution_image[_X];
369  const uint rY = resolution_image[_Y];
370  const uint R = rX * rY; // LF Image resolution
371  const uint nWave = context_.waveNum;
372  const bool bRandomPhase = GetRandomPhase();
373 
374  // initialize
375  for (vector<Complex<Real>*>::iterator it = m_vecRSplane.begin(); it != m_vecRSplane.end(); it++) delete[](*it);
376  m_vecRSplane.clear();
377  m_vecRSplane.resize(nWave);
378 
379  for (uint i = 0; i < nWave; i++)
380  {
381  m_vecRSplane[i] = new Complex<Real>[N * R];
382  //memset(m_vecRSplane[i], 0.0, sizeof(Complex<Real>) * N * R);
383  }
384 
385  Complex<Real> *tmp = new Complex<Real>[N];
386  Real pi2 = M_PI * 2;
387  for (uint ch = 0; ch < nWave; ch++)
388  {
389  int iColor = nWave - ch - 1;
390  for (uint r = 0; r < R; r++) // pixel num
391  {
392  int w = r % rX;
393  int h = r / rX;
394  int iWidth = r * nWave;
395 
396  for (uint n = 0; n < N; n++) // image num
397  {
398  tmp[n][_RE] = (Real)(m_vecImages[n][iWidth + iColor]);
399  tmp[n][_IM] = 0.0;
400  }
401 
402  fft2(tmp, tmp, nX, nY, OPH_FORWARD);
403 
404  int base1 = N * rX * h;
405  int base2 = w * nX;
406  for (uint n = 0; n < N; n++)
407  {
408  uint j = n % nX;
409  uint i = n / nX;
410 
411  Real randVal = bRandomPhase ? rand(0.0, 1.0) : 1.0;
412  Complex<Real> phase(0, pi2 * randVal);
413  m_vecRSplane[ch][base1 + base2 + ((n - j) * rX) + j] = tmp[n] * phase.exp();
414  }
415  }
416  }
417 
418 
419  delete[] tmp;
420  fftFree();
421  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
422 }
423 
424 void ophLF::writeIntensity_gray8_bmp(const char* fileName, int nx, int ny, Complex<Real>* complexvalue, int k)
425 {
426  const int n = nx * ny;
427 
428  double* intensity = (double*)malloc(sizeof(double)*n);
429  for (int i = 0; i < n; i++)
430  intensity[i] = complexvalue[i].real();
431  //intensity[i] = complexvalue[i].mag2();
432 
433  double min_val, max_val;
434  min_val = intensity[0];
435  max_val = intensity[0];
436 
437  for (int i = 0; i < n; ++i)
438  {
439  if (min_val > intensity[i])
440  min_val = intensity[i];
441  else if (max_val < intensity[i])
442  max_val = intensity[i];
443  }
444 
445  char fname[100];
446  strcpy(fname, fileName);
447  if (k != -1)
448  {
449  char num[30];
450  sprintf(num, "_%d", k);
451  strcat(fname, num);
452  }
453  strcat(fname, ".bmp");
454 
455  //LOG("minval %e, max val %e\n", min_val, max_val);
456 
457  unsigned char* cgh = (unsigned char*)malloc(sizeof(unsigned char)*n);
458 
459  for (int i = 0; i < n; ++i) {
460  double val = (intensity[i] - min_val) / (max_val - min_val);
461  //val = pow(val, 1.0 / 1.5);
462  val = val * 255.0;
463  unsigned char v = (uchar)val;
464 
465  cgh[i] = v;
466  }
467 
468  int ret = Openholo::saveAsImg(fname, 8, cgh, nx, ny);
469 
470  free(intensity);
471  free(cgh);
472 }
473 
475 {
476  ophGen::ophFree();
477 
478  for (vector<uchar *>::iterator it = m_vecImages.begin(); it != m_vecImages.end(); it++) delete[](*it);
479  for (vector<Complex<Real> *>::iterator it = m_vecRSplane.begin(); it != m_vecRSplane.end(); it++) delete[](*it);
480  m_vecImages.clear();
481  m_vecImgSize.clear();
482  m_vecRSplane.clear();
483 
484 }
bytesperpixel
Definition: Openholo.cpp:431
void convertLF2ComplexField()
virtual bool saveAsImg(const char *fname, uint8_t bitsperpixel, uchar *src, int width, int height)
Function for creating image files.
Definition: Openholo.cpp:135
void fftFree(void)
Resource release method.
Definition: Openholo.cpp:677
void setViewingWindow(bool is_ViewingWindow)
Set the value of a variable is_ViewingWindow(true or false)
unsigned char uchar
Definition: typedef.h:64
bool readConfig(const char *fname)
Light Field based CGH configuration file load.
#define MODE_GPU
Definition: define.h:156
float Real
Definition: typedef.h:55
void initialize(void)
Initialize variables for Hologram complex field, encoded data, normalized data.
Definition: ophGen.cpp:145
#define CUR_TIME
Definition: function.h:58
void convertLF2ComplexField_GPU()
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
void ophFree()
Pure virtual function for override in child classes.
bool GetRandomPhase()
Function for getting the random phase.
Definition: ophGen.h:538
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
Definition: tinyxml2.h:761
void generateHologram()
Hologram generation.
#define _Y
Definition: define.h:96
#define _IM
Definition: complex.h:58
#define _X
Definition: define.h:92
unsigned int m_mode
Definition: ophGen.h:351
bool getImgSize(int &w, int &h, int &bytesperpixel, const char *fname)
Function for getting the image size.
Definition: Openholo.cpp:402
#define _RE
Definition: complex.h:55
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
void convertToFormatGray8(uchar *src, uchar *dst, int w, int h, int bytesperpixel)
Function for convert image format to gray8.
Definition: Openholo.cpp:511
void fresnelPropagation(OphConfig context, Complex< Real > *in, Complex< Real > *out, Real distance)
Fresnel propagation.
Definition: ophGen.cpp:1441
ophLF(void)
Constructor.
#define ELAPSED_TIME(x, y)
Definition: function.h:59
uint waveNum
Definition: Openholo.h:69
Complex< T > & exp()
Definition: complex.h:395
bool readConfig(const char *fname)
load to configuration file.
Definition: ophGen.cpp:220
XMLError LoadFile(const char *filename)
Definition: tinyxml2.cpp:2150
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 writeIntensity_gray8_bmp(const char *fileName, int nx, int ny, Complex< Real > *complexvalue, int k=-1)
void resetBuffer()
reset buffer
Definition: ophGen.cpp:821
w
Definition: Openholo.cpp:429
OphConfig context_
Definition: Openholo.h:449
void initializeLF()
#define OPH_FORWARD
Definition: define.h:66
Complex< Real > ** complex_H
Definition: Openholo.h:452
int loadLF(const char *directory, const char *exten)
Light Field images load.
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
virtual void ophFree(void)
Pure virtual function for override in child classes.
Definition: ophGen.cpp:2158