Openholo  v4.0
Open Source Digital Holographic Library
ophDepthMap.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 "ophDepthMap.h"
47 #include <random>
48 #ifdef _WIN64
49 #include <io.h>
50 #include <direct.h>
51 #else
52 #include <dirent.h>
53 #endif
54 #include "sys.h"
55 #include "tinyxml2.h"
56 #include "include.h"
57 
59  : ophGen()
60  , stream_(nullptr)
61  , m_nProgress(0)
62 {
63  // GPU Variables
64  img_src_gpu = nullptr;
65  dimg_src_gpu = nullptr;
66  depth_index_gpu = nullptr;
67 
68  depth_img = nullptr;
69  m_vecRGB.clear();
70 
71  // CPU Variables
72  dmap_src = nullptr;
73  depth_index = nullptr;
74  dmap = 0;
75  dstep = 0;
76  dlevel.clear();
77 
78  setViewingWindow(false);
79  LOG("*** DEPTH MAP : BUILD DATE: %s %s ***\n\n", __DATE__, __TIME__);
80 }
81 
83 {
84 }
85 
86 void ophDepthMap::setViewingWindow(bool is_ViewingWindow)
87 {
88  this->is_ViewingWindow = is_ViewingWindow;
89 }
90 
91 bool ophDepthMap::readConfig(const char * fname)
92 {
93  if (!ophGen::readConfig(fname))
94  return false;
95 
96  bool bRet = true;
97  /*XML parsing*/
98 
99  using namespace tinyxml2;
100  tinyxml2::XMLDocument xml_doc;
101  XMLNode *xml_node = nullptr;
102 
103  if (!checkExtension(fname, ".xml"))
104  {
105  LOG("<FAILED> Wrong file ext.\n");
106  return false;
107  }
108  auto ret = xml_doc.LoadFile(fname);
109  if (ret != XML_SUCCESS)
110  {
111  LOG("<FAILED> Loading file.\n");
112  return false;
113  }
114 
115 
116  xml_node = xml_doc.FirstChild();
117 
118  char szNodeName[32] = { 0, };
119  sprintf(szNodeName, "FlagChangeDepthQuantization");
120  auto next = xml_node->FirstChildElement(szNodeName);
121  if (!next || XML_SUCCESS != next->QueryBoolText(&dm_config_.change_depth_quantization))
122  {
123  LOG("<FAILED> Not found node : \'%s\' (Boolean) \n", szNodeName);
124  bRet = false;
125  }
126  sprintf(szNodeName, "DefaultDepthQuantization");
127  next = xml_node->FirstChildElement(szNodeName);
128  if (!next || XML_SUCCESS != next->QueryUnsignedText(&dm_config_.default_depth_quantization))
129  {
130  LOG("<FAILED> Not found node : \'%s\' (Unsinged Integer) \n", szNodeName);
131  bRet = false;
132  }
133  sprintf(szNodeName, "NumberOfDepthQuantization");
134  next = xml_node->FirstChildElement(szNodeName);
135  if (!next || XML_SUCCESS != next->QueryUnsignedText(&dm_config_.num_of_depth_quantization))
136  {
137  LOG("<FAILED> Not found node : \'%s\' (Unsinged Integer) \n", szNodeName);
138  bRet = false;
139  }
140 
141  if (dm_config_.change_depth_quantization == 0)
142  dm_config_.num_of_depth = dm_config_.default_depth_quantization;
143  else
144  dm_config_.num_of_depth = dm_config_.num_of_depth_quantization;
145 
146  string render_depth;
147  sprintf(szNodeName, "RenderDepth");
148  next = xml_node->FirstChildElement(szNodeName);
149  if (!next || XML_SUCCESS != next->QueryBoolText(&dm_config_.change_depth_quantization))
150  {
151  LOG("<FAILED> Not found node : \'%s\' (Boolean) \n", szNodeName);
152  bRet = false;
153  }
154  else
155  render_depth = (xml_node->FirstChildElement(szNodeName))->GetText();
156 
157  size_t found = render_depth.find(':');
158  if (found != string::npos)
159  {
160  string s = render_depth.substr(0, found);
161  string e = render_depth.substr(found + 1);
162  int start = stoi(s);
163  int end = stoi(e);
164  dm_config_.render_depth.clear();
165  for (int k = start; k <= end; k++)
166  dm_config_.render_depth.push_back(k);
167  }
168  else
169  {
170  stringstream ss(render_depth);
171  int render;
172 
173  while (ss >> render)
174  dm_config_.render_depth.push_back(render);
175  }
176 
177  if (dm_config_.render_depth.empty()) {
178  LOG("<FAILED> Not found node : \'%s\' (String) \n", szNodeName);
179  bRet = false;
180  }
181 
182  sprintf(szNodeName, "RandomPhase");
183  next = xml_node->FirstChildElement(szNodeName);
184  if (!next || XML_SUCCESS != next->QueryBoolText(&dm_config_.random_phase))
185  {
186  LOG("<FAILED> Not found node : \'%s\' (Boolean) \n", szNodeName);
187  bRet = false;
188  }
189  sprintf(szNodeName, "FieldLength");
190  next = xml_node->FirstChildElement(szNodeName);
191  if (!next || XML_SUCCESS != next->QueryDoubleText(&dm_config_.fieldLength))
192  {
193  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
194  bRet = false;
195  }
196  sprintf(szNodeName, "NearOfDepth");
197  next = xml_node->FirstChildElement(szNodeName);
198  if (!next || XML_SUCCESS != next->QueryDoubleText(&dm_config_.near_depthmap))
199  {
200  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
201  bRet = false;
202  }
203  sprintf(szNodeName, "FarOfDepth");
204  next = xml_node->FirstChildElement(szNodeName);
205  if (!next || XML_SUCCESS != next->QueryDoubleText(&dm_config_.far_depthmap))
206  {
207  LOG("<FAILED> Not found node : \'%s\' (Double) \n", szNodeName);
208  bRet = false;
209  }
210 
211  initialize();
212 
213  LOG("**************************************************\n");
214  LOG(" Read Config (Depth Map) \n");
215  LOG("1) Focal Length : %.5lf ~ %.5lf\n", dm_config_.near_depthmap, dm_config_.far_depthmap);
216  LOG("2) Render Depth : %d:%d\n", dm_config_.render_depth[0], dm_config_.render_depth[dm_config_.render_depth.size() - 1]);
217  LOG("3) Number of Depth Quantization : %d\n", dm_config_.num_of_depth_quantization);
218  LOG("**************************************************\n");
219 
220  return bRet;
221 }
222 
223 bool ophDepthMap::readImage(const char* fname, IMAGE_TYPE type)
224 {
225  auto begin = CUR_TIME;
226  const int pnX = context_.pixel_number[_X];
227  const int pnY = context_.pixel_number[_Y];
228  const int N = pnX * pnY;
229  const uint ch = context_.waveNum;
230 
231  int w, h, bytesperpixel;
232  // get image information
233  bool ret = getImgSize(w, h, bytesperpixel, fname);
234  // load image
235  uchar* pSrc = loadAsImg(fname);
236 
237  if (pSrc == nullptr) {
238  LOG("<FAILED> Load image: %s\n", fname);
239  return false;
240  }
241 
242  if (type == IMAGE_TYPE::COLOR)
243  {
244  for (vector<uchar*>::iterator it = m_vecRGB.begin(); it != m_vecRGB.end(); it++)
245  delete[](*it);
246  m_vecRGB.clear();
247 
248  int nSize = ((w * bytesperpixel + 3) & ~3) * h;
249  uchar* pBuf = new uchar[nSize];
250 
251  for (int i = 0; i < ch; i++)
252  {
253  // step 1. color relocation
254  if (ch == 1) // rgb to greyscale
255  {
256  if (bytesperpixel != 1)
257  convertToFormatGray8(pSrc, pBuf, w, h, bytesperpixel);
258  else
259  memcpy(pBuf, pSrc, nSize);
260  }
261  else if (ch == bytesperpixel)
262  {
263  // [B0,G0,R0,B1,G1,R1...] -> [R0,R1...] [G0,G1...] [B0,B1...]
264  if (!separateColor(i, w, h, pSrc, pBuf))
265  {
266  LOG("<FAILED> separateColor: %d", i);
267  }
268  }
269  else
270  {
271  memcpy(pBuf, pSrc, nSize);
272  }
273 
274  uchar* pDst = new uchar[N];
275 
276  if (w != pnX || h != pnY)
277  {
278  imgScaleBilinear(pBuf, pDst, w, h, pnX, pnY);
279  }
280  else
281  {
282  memcpy(pDst, pBuf, N);
283  }
284  m_vecRGB.push_back(pDst);
285  }
286  delete[] pSrc;
287  delete[] pBuf;
288 
289  // 2019-10-14 mwnam
290  m_vecRGBImg[_X] = pnX;
291  m_vecRGBImg[_Y] = pnY;
292  }
293  else if (type == IMAGE_TYPE::DEPTH)
294  {
295  if (depth_img) delete[] depth_img;
296 
297  depth_img = new uchar[N];
298  memset(depth_img, 0, N);
299 
300  uchar* pBuf = new uchar[((w + 3) & ~3) * h];
301  convertToFormatGray8(pSrc, pBuf, w, h, bytesperpixel);
302 
303  if (w != pnX || h != pnY)
304  imgScaleBilinear(pBuf, depth_img, w, h, pnX, pnY);
305  else
306  memcpy(depth_img, pBuf, N);
307 
308  delete[] pSrc;
309  delete[] pBuf;
310  // 2019-10-14 mwnam
311  m_vecDepthImg[_X] = pnX;
312  m_vecDepthImg[_Y] = pnY;
313  }
314  LOG("Load Image(%s)\n Path: %d\nResolution: %dx%d\nBytePerPixel: %d",
315  type == IMAGE_TYPE::COLOR ? "Color" : "Depth", fname, w, h, bytesperpixel);
316 
317  return true;
318 }
319 
320 bool ophDepthMap::convertImage()
321 {
322  auto begin = CUR_TIME;
323  const int pnX = context_.pixel_number[_X];
324  const int pnY = context_.pixel_number[_Y];
325  const int N = pnX * pnY;
326  const uint ch = context_.waveNum;
327 
328  // process color image.
329  for (int i = 0; i < ch; i++)
330  {
331  uchar* pSrc = m_vecRGB[i];
332  if (m_vecRGBImg != context_.pixel_number)
333  {
334  int nOldSize = ((m_vecRGBImg[_X] + 3) & ~3) * m_vecRGBImg[_Y];
335  int nNewSize = ((pnX + 3) & ~3) * pnY;
336 
337  uchar* pOrg = new uchar[nOldSize];
338  memcpy(pOrg, pSrc, sizeof(uchar) * nOldSize);
339  delete[] pSrc;
340 
341  m_vecRGB[i] = new uchar[nNewSize];
342  imgScaleBilinear(pOrg, m_vecRGB[i], m_vecRGBImg[_X], m_vecRGBImg[_Y], pnX, pnY);
343  delete[] pOrg;
344  LOG("Resized Image: (%dx%d) to (%dx%d)", m_vecRGBImg[_X], m_vecRGBImg[_Y], pnX, pnY);
345  }
346  }
347 
348  uchar* pSrc = depth_img;
349  if (m_vecDepthImg != context_.pixel_number)
350  {
351  int nOldSize = ((m_vecDepthImg[_X] + 3) & ~3) * m_vecDepthImg[_Y];
352  int nNewSize = ((pnX + 3) & ~3) * pnY;
353 
354  uchar* pOrg = new uchar[nOldSize];
355  memcpy(pOrg, pSrc, sizeof(uchar) * nOldSize);
356  delete[] pSrc;
357 
358  depth_img = new uchar[nNewSize];
359  imgScaleBilinear(pOrg, depth_img, m_vecDepthImg[_X], m_vecDepthImg[_Y], pnX, pnY);
360  delete[] pOrg;
361  LOG("Resized Image: (%dx%d) to (%dx%d)", m_vecDepthImg[_X], m_vecDepthImg[_Y], pnX, pnY);
362  }
363 
364  m_vecDepthImg = m_vecRGBImg = context_.pixel_number;
365 
366  return true;
367 }
368 
369 bool ophDepthMap::readImageDepth(const char* source_folder, const char* img_name, const char* depth_img_name)
370 {
371  auto begin = CUR_TIME;
372  const int pnX = context_.pixel_number[_X];
373  const int pnY = context_.pixel_number[_Y];
374  const int N = pnX * pnY;
375 
376  for (size_t i = 0; i < m_vecRGB.size(); i++)
377  {
378  delete[] m_vecRGB[i];
379  }
380  m_vecRGB.clear();
381 
382  // RGB Image
383  char imgPath[FILENAME_MAX] = { 0, };
384 #ifdef _WIN64
385  sprintf(imgPath, "%s\\%s.bmp", source_folder, img_name);
386 #else
387  sprintf(imgPath, "%s/%s.bmp", source_folder, img_name);
388 #endif
389 
390  int w, h, bytesperpixel;
391  bool ret = getImgSize(w, h, bytesperpixel, imgPath);
392 
393  // RGB Image
394  oph::uchar* buf = new uchar[w * h * bytesperpixel]; // 1-Dimension left top
395  ret = loadAsImgUpSideDown(imgPath, buf);
396  if (!ret) {
397  LOG("<FAILED> Image Load: %s\n", imgPath);
398  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
399  return false;
400  }
401  LOG(" <SUCCEEDED> Image Load: %s\n", imgPath);
402 
403  int ch = context_.waveNum;
404  uchar* img = new uchar[w * h];
405 
406  for (int i = 0; i < ch; i++)
407  {
408  if (ch == 1) // rgb img to grayscale
409  convertToFormatGray8(buf, img, w, h, bytesperpixel);
410  else if (ch == bytesperpixel) // rgb img to rgb
411  {
412  separateColor(i, w, h, buf, img);
413  }
414  else // grayscale img to rgb
415  {
416  memcpy(img, buf, sizeof(char) * w * h);
417  }
418 
419 
420  //resized image
421  uchar *rgb_img = new uchar[N];
422  memset(rgb_img, 0, sizeof(char) * N);
423 
424  if (w != pnX || h != pnY)
425  imgScaleBilinear(img, rgb_img, w, h, pnX, pnY);
426  else
427  memcpy(rgb_img, img, sizeof(char) * N);
428 
429  m_vecRGB.push_back(rgb_img);
430  }
431  delete[] buf;
432  delete[] img;
433 
434  // 2019-10-14 mwnam
435  m_vecRGBImg[_X] = pnX;
436  m_vecRGBImg[_Y] = pnY;
437 
438  // Depth Image
439  //=================================================================================
440  char dimgPath[FILENAME_MAX] = { 0, };
441 #ifdef _WIN64
442  sprintf(dimgPath, "%s\\%s.bmp", source_folder, depth_img_name);
443 #else
444  sprintf(dimgPath, "%s/%s.bmp", source_folder, depth_img_name);
445 #endif
446  ret = getImgSize(w, h, bytesperpixel, dimgPath);
447 
448  // Depth Image
449  uchar* dbuf = new uchar[w * h * bytesperpixel];
450  ret = loadAsImgUpSideDown(dimgPath, dbuf);
451  if (!ret) {
452  LOG("<FAILED> Image Load: %s\n", dimgPath);
453  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
454  return false;
455  }
456  LOG(" <SUCCEEDED> Image Load: %s\n", dimgPath);
457 
458  // 2019-10-14 mwnam
459  m_vecDepthImg[_X] = w;
460  m_vecDepthImg[_Y] = h;
461 
462  uchar* dimg = new uchar[w * h];
463  convertToFormatGray8(dbuf, dimg, w, h, bytesperpixel);
464 
465  delete[] dbuf;
466 
467  if (depth_img) delete[] depth_img;
468 
469  depth_img = new uchar[N];
470  memset(depth_img, 0, sizeof(char) * N);
471 
472  if (w != pnX || h != pnY)
473  imgScaleBilinear(dimg, depth_img, w, h, pnX, pnY);
474  else
475  memcpy(depth_img, dimg, sizeof(char) * N);
476 
477  // 2019-10-14 mwnam
478  m_vecDepthImg[_X] = pnX;
479  m_vecDepthImg[_Y] = pnY;
480 
481  delete[] dimg;
482 
483  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
484  return true;
485 }
486 
488 {
489  auto begin = CUR_TIME;
490  LOG("**************************************************\n");
491  LOG(" Generate Hologram \n");
492  LOG("1) Algorithm Method : Depth Map\n");
493  LOG("2) Generate Hologram with %s\n", m_mode & MODE_GPU ?
494  "GPU" :
495 #ifdef _OPENMP
496  "Multi Core CPU"
497 #else
498  "Single Core CPU"
499 #endif
500  );
501  LOG("**************************************************\n");
502 
503 
504  resetBuffer();
505  convertImage();
507  if (m_mode & MODE_GPU)
508  {
509  initGPU();
510  prepareInputdataGPU();
511  getDepthValues();
512  //if (is_ViewingWindow)
513  // transVW();
514  calcHoloGPU();
515  }
516  else
517  {
518  initCPU();
519  prepareInputdataCPU();
520  getDepthValues();
521  //if (is_ViewingWindow)
522  // transVW();
523  calcHoloCPU();
524  }
525  Real elapsed_time = ELAPSED_TIME(begin, CUR_TIME);
526  LOG("Total Elapsed Time: %lf (s)\n", elapsed_time);
527  m_nProgress = 0;
528  return elapsed_time;
529 }
530 
532 {
533  //ophGen::encoding(ENCODE_FLAG);
534  const uint pnX = context_.pixel_number[_X];
535  const uint pnY = context_.pixel_number[_Y];
536  const uint nChannel = context_.waveNum;
537  Complex<Real>** dst = new Complex<Real>*[nChannel];
538  for (uint ch = 0; ch < nChannel; ch++) {
539  dst[ch] = new Complex<Real>[pnX * pnY];
540  //fft2(context_.pixel_number, nullptr, OPH_BACKWARD);
541  fft2(complex_H[ch], dst[ch], pnX, pnY, OPH_BACKWARD, true);
543  }
544 
545  for (uint ch = 0; ch < nChannel; ch++)
546  delete[] dst[ch];
547  delete[] dst;
548 }
549 
550 void ophDepthMap::encoding(unsigned int ENCODE_FLAG, unsigned int SSB_PASSBAND)
551 {
552  auto begin = CUR_TIME;
553  const uint pnX = context_.pixel_number[_X];
554  const uint pnY = context_.pixel_number[_Y];
555  const uint nChannel = context_.waveNum;
556 
557  bool is_CPU = (m_mode & MODE_GPU) ? false : true;
558 
559  for (uint ch = 0; ch < nChannel; ch++) {
560 
562  ivec2 location = ivec2(0, 0);
563  switch (SSB_PASSBAND) {
564  case SSB_TOP:
565  location = ivec2(0, 1);
566  break;
567  case SSB_BOTTOM:
568  location = ivec2(0, -1);
569  break;
570  case SSB_LEFT:
571  location = ivec2(-1, 0);
572  break;
573  case SSB_RIGHT:
574  location = ivec2(1, 0);
575  break;
576  }
577 
578  encodeSideBand(is_CPU, location);
579  }
580  else
581  {
582  Complex<Real>* dst = new Complex<Real>[pnX * pnY];
584  fft2(complex_H[ch], dst, pnX, pnY, OPH_BACKWARD);
586  delete[] dst;
587  }
588  }
589  auto end = CUR_TIME;
590  LOG("Elapsed Time: %lf(s)\n", ELAPSED_TIME(begin, end));
591 }
592 
593 
594 void ophDepthMap::getDepthValues()
595 {
596  auto begin = CUR_TIME;
597  if (dm_config_.num_of_depth > 1)
598  {
599  dstep = (dm_config_.far_depthmap - dm_config_.near_depthmap) / (dm_config_.num_of_depth - 1);
600  Real val = dm_config_.near_depthmap;
601  while (val <= dm_config_.far_depthmap)
602  {
603  dlevel.push_back(val);
604  val += dstep;
605  }
606  }
607  else {
608 
609  dstep = (dm_config_.far_depthmap + dm_config_.near_depthmap) / 2;
610  dlevel.push_back(dm_config_.near_depthmap);
611  }
612 
613 
614  if (dm_config_.change_depth_quantization == 1)
615  {
616  bool is_CPU = m_mode & MODE_GPU ? false : true;
617  if (is_CPU)
618  changeDepthQuanCPU();
619  else
620  changeDepthQuanGPU();
621  }
622  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
623 }
624 
625 void ophDepthMap::transVW()
626 {
627  Real val;
628  dlevel_transform.clear();
629  for (size_t p = 0; p < dlevel.size(); p++)
630  {
631  val = -dm_config_.fieldLength * dlevel[p] / (dlevel[p] - dm_config_.fieldLength);
632  dlevel_transform.push_back(val);
633  }
634 }
635 
636 void ophDepthMap::initCPU()
637 {
638  const uint pnX = context_.pixel_number[_X];
639  const uint pnY = context_.pixel_number[_Y];
640  const uint N = pnX * pnY;
641  const uint nChannel = context_.waveNum;
642 
643  dlevel.clear();
644 
645  for (vector<Real *>::iterator it = m_vecImgSrc.begin(); it != m_vecImgSrc.end(); it++)
646  {
647  delete[](*it);
648  }
649  m_vecImgSrc.clear();
650  for (vector<int *>::iterator it = m_vecAlphaMap.begin(); it != m_vecAlphaMap.end(); it++)
651  {
652  delete[](*it);
653  }
654  m_vecAlphaMap.clear();
655 
656  for (uint ch = 0; ch < nChannel; ch++)
657  {
658  Real *img_src = new Real[N];
659  int *alpha_map = new int[N];
660 
661  m_vecImgSrc.push_back(img_src);
662  m_vecAlphaMap.push_back(alpha_map);
663  }
664 
665  if (dmap_src) delete[] dmap_src;
666  dmap_src = new Real[N];
667 
668  if (depth_index) delete[] depth_index;
669  depth_index = new uint[N];
670 
671  if (dmap) delete[] dmap;
672  dmap = new Real[N];
673 
674  fftw_cleanup();
675 }
676 
677 bool ophDepthMap::prepareInputdataCPU()
678 {
679  auto begin = CUR_TIME;
680  const long long int N = context_.pixel_number[_X] * context_.pixel_number[_Y];
681  const uint nChannel = context_.waveNum;
682 
683  memset(depth_index, 0, sizeof(uint) * N);
684 
685  if (depth_img == nullptr) // not used depth
686  {
687  depth_img = new uchar[N];
688  memset(depth_img, 0, N);
689  }
690 
691  Real gapDepth = dm_config_.far_depthmap - dm_config_.near_depthmap;
692  Real nearDepth = dm_config_.near_depthmap;
693 
694  for (uint ch = 0; ch < nChannel; ch++)
695  {
696 #ifdef _OPENMP
697 #pragma omp parallel for firstprivate(gapDepth, nearDepth)
698 #endif
699  for (long long int k = 0; k < N; k++)
700  {
701  m_vecImgSrc[ch][k] = Real(m_vecRGB[ch][k]) / 255.0; // RGB IMG
702  m_vecAlphaMap[ch][k] = (m_vecRGB[ch][k] > 0 ? 1 : 0); // RGB IMG
703 
704  // once
705  if (ch == 0)
706  {
707  dmap_src[k] = Real(depth_img[k]) / 255.0; // DEPTH IMG
708  dmap[k] = (1 - dmap_src[k]) * gapDepth + nearDepth;
709  if (dm_config_.change_depth_quantization == 0) {
710  depth_index[k] = dm_config_.default_depth_quantization - depth_img[k];
711  }
712  }
713  }
714  }
715 
716  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
717  return true;
718 }
719 
720 void ophDepthMap::changeDepthQuanCPU()
721 {
722  auto begin = CUR_TIME;
723  const long long int N = context_.pixel_number[_X] * context_.pixel_number[_Y];
724 
725  uint num_depth = dm_config_.num_of_depth;
726  Real near_depth = dm_config_.near_depthmap;
727  Real far_depth = dm_config_.far_depthmap;
728 
729  double nearv = dlevel[0];
730  double half_step = dstep / 2.0;
731  depth_fill.clear();
732  depth_fill.resize(dm_config_.render_depth.size() + 1, 0);
733  Real locDstep = dstep;
734 
735 #ifdef _OPENMP
736 #pragma omp parallel for firstprivate(nearv, half_step, locDstep)
737 #endif
738  for (long long int i = 0; i < N; i++)
739  {
740  int idx = int(((dmap[i] - nearv) + half_step) / locDstep);
741  depth_index[i] = idx + 1;
742  depth_fill[idx + 1] = 1;
743  }
744 
745  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
746 }
747 
748 void ophDepthMap::calcHoloCPU()
749 {
750  auto begin = CUR_TIME;
751 
752  const uint pnX = context_.pixel_number[_X];
753  const uint pnY = context_.pixel_number[_Y];
754  const long long int N = pnX * pnY;
755  const uint nChannel = context_.waveNum;
756 
757  size_t depth_sz = dm_config_.render_depth.size();
758 
759  const bool bRandomPhase = GetRandomPhase();
760  Complex<Real> *input = new Complex<Real>[N];
761 
763 
764  for (uint ch = 0; ch < nChannel; ch++)
765  {
766  Real lambda = context_.wave_length[ch];
767  Real k = context_.k = (2 * M_PI / lambda);
768  Real *img_src = m_vecImgSrc[ch];
769  int *alpha_map = m_vecAlphaMap[ch];
770 
771  for (size_t i = 0; i < depth_sz; i++)
772  {
773  int dtr = dm_config_.render_depth[i];
774  if (depth_fill[dtr])
775  {
776  memset(input, 0, sizeof(Complex<Real>) * N);
777  Real temp_depth = (is_ViewingWindow) ? dlevel_transform[dtr - 1] : dlevel[dtr - 1];
778 
779  Complex<Real> rand_phase_val;
780  GetRandomPhaseValue(rand_phase_val, bRandomPhase);
781 
782  Complex<Real> carrier_phase_delay(0, k * -temp_depth);
783  carrier_phase_delay.exp();
784 #ifdef _OPENMP
785 #pragma omp parallel for firstprivate(dtr, rand_phase_val, carrier_phase_delay)
786 #endif
787  for (long long int j = 0; j < N; j++)
788  {
789  input[j][_RE] = img_src[j] * alpha_map[j] * ((int)depth_index[j] == dtr ? 1.0 : 0.0);
790  input[j] *= rand_phase_val * carrier_phase_delay;
791  }
792 
793  fft2(input, input, pnX, pnY, OPH_FORWARD, false);
794  AngularSpectrumMethod(input, complex_H[ch], lambda, temp_depth);
795 
796  }
797  m_nProgress = (int)((Real)(ch * depth_sz + i) * 100 / (depth_sz * nChannel));
798  }
799  //fft2(complex_H[ch], complex_H[ch], pnX, pnY, OPH_BACKWARD, true);
800  }
801  delete[] input;
802  fftFree();
803  LOG("%s : %.5lf (sec)\n", __FUNCTION__, ELAPSED_TIME(begin, CUR_TIME));
804 }
805 
807 {
808  ophGen::ophFree();
809  if (depth_img) {
810  delete[] depth_img;
811  depth_img = nullptr;
812  }
813 
814 
815  for (vector<uchar *>::iterator it = m_vecRGB.begin(); it != m_vecRGB.end(); it++)
816  {
817  delete[](*it);
818  }
819  m_vecRGB.clear();
820 }
821 
823 {
824  if (context_.pixel_number != resolution) {
825  ophGen::setResolution(resolution);
826  initCPU();
827  initGPU();
828  }
829 }
830 
832 {
834 }
bytesperpixel
Definition: Openholo.cpp:431
#define OPH_BACKWARD
Definition: define.h:67
ENCODE_FLAG
Definition: ophGen.h:84
Real k
Definition: Openholo.h:67
void setViewingWindow(bool is_ViewingWindow)
Set the value of a variable is_ViewingWindow(true or false)
Definition: ophDepthMap.cpp:86
void setResolution(ivec2 resolution)
Function for setting buffer size.
Definition: ophGen.cpp:1902
void fftFree(void)
Resource release method.
Definition: Openholo.cpp:677
Real fieldLength
fieldLength variable for viewing window.
Definition: ophGen.h:615
void AngularSpectrumMethod(Complex< Real > *src, Complex< Real > *dst, Real lambda, Real distance)
Angular spectrum propagation method.
Definition: ophGen.cpp:597
Real * wave_length
Definition: Openholo.h:70
uint num_of_depth
Definition: ophGen.h:625
void GetRandomPhaseValue(Complex< Real > &rand_phase_val, bool rand_phase)
Assign random phase value if random_phase == 1.
Definition: ophGen.cpp:1879
bool readImageDepth(const char *source_folder, const char *img_prefix, const char *depth_img_prefix)
Read image and depth map.
SSB_PASSBAND
Definition: ophGen.h:296
unsigned char uchar
Definition: typedef.h:64
#define MODE_GPU
Definition: define.h:156
Real ** m_lpEncoded
buffer to encoded.
Definition: ophGen.h:339
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
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
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
ophDepthMap()
Constructor.
Definition: ophDepthMap.cpp:58
void normalize()
#define _Y
Definition: define.h:96
virtual ~ophDepthMap()
Destructor.
Definition: ophDepthMap.cpp:82
void encodeSideBand(bool bCPU, ivec2 sig_location)
Encode the CGH according to a signal location parameter.
Definition: ophGen.cpp:1709
void normalize(void)
Normalization function to save as image file after hologram creation.
Definition: ophGen.cpp:675
ivec2 m_vecEncodeSize
Encoded hologram size, varied from encoding type.
Definition: ophGen.h:331
#define _X
Definition: define.h:92
unsigned int m_mode
Definition: ophGen.h:351
Real near_depthmap
near value of depth in object
Definition: ophGen.h:617
bool readConfig(const char *fname)
Read parameters from a config file. (*.xml)
Definition: ophDepthMap.cpp:91
bool separateColor(int idx, int width, int height, uchar *src, uchar *dst)
Function for generate each grayscale image from RGB image.
Definition: Openholo.cpp:119
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
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
Real far_depthmap
far value of depth in object
Definition: ophGen.h:619
void setResolution(ivec2 resolution)
#define ELAPSED_TIME(x, y)
Definition: function.h:59
void fftInit2D(ivec2 size, int sign, unsigned int flag)
initialize method for 2D FFT
Definition: Openholo.cpp:660
uint waveNum
Definition: Openholo.h:69
ivec2 pixel_number
Definition: Openholo.h:63
bool readConfig(const char *fname)
load to configuration file.
Definition: ophGen.cpp:220
XMLError LoadFile(const char *filename)
Definition: tinyxml2.cpp:2150
void ophFree(void)
Pure virtual function for override in child classes.
virtual uchar * loadAsImg(const char *fname)
Function for loading image files.
Definition: Openholo.cpp:321
bool change_depth_quantization
if true, change the depth quantization from the default value.
Definition: ophGen.h:629
Real generateHologram(void)
Generate a hologram, main funtion. When the calculation is finished, the angular spectrum is performe...
void encoding()
Definition: ophGen.cpp:982
void resetBuffer()
reset buffer
Definition: ophGen.cpp:821
w
Definition: Openholo.cpp:429
bool readImage(const char *fname, IMAGE_TYPE type=COLOR)
Read image and depth map.
OphConfig context_
Definition: Openholo.h:449
#define OPH_FORWARD
Definition: define.h:66
Complex< Real > ** complex_H
Definition: Openholo.h:452
vector< int > render_depth
Used when only few specific depth levels are rendered, usually for test purpose.
Definition: ophGen.h:627
uint default_depth_quantization
default value of the depth quantization - 256
Definition: ophGen.h:631
bool loadAsImgUpSideDown(const char *fname, uchar *dst)
Function for loading image files | Output image data upside down.
Definition: Openholo.cpp:353
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
virtual void ophFree(void)
Pure virtual function for override in child classes.
Definition: ophGen.cpp:2158