bazar  1.3.1
lightmap.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <iostream>
3 #include <fstream>
4 
5 //also includes opengl if available
6 #include "lightmap.h"
7 #include <highgui.h>
8 
9 
10 #ifndef M_PI
11 #define M_PI 3.1415926535897932384626433832795
12 #endif
13 
14 using namespace std;
15 
17 {
18  ARB=true;
19  initialized=false;
20  lightParams=0;
21  normals=0;
22  nbCam=0;
23 }
24 
26 {
27  ARB=a.ARB;
28  initialized=false;
29  if (a.map.getIm())
30  map.setImage(cvCloneImage(a.map.getIm()));
31  reflc.copy(a.reflc);
32  lightParams=0;
33  normals=0;
34  nbCam=0;
35 }
36 
38 {
39  IplImage *im = map.getIm();
40  if(im) cvReleaseImage(&im);
41  if (lightParams) cvReleaseMat(&lightParams);
42  if (normals) delete normals;
43 }
44 
45 bool LightMap::init(int nbCam, IplImage *model, float corners[4][2], int nx, int ny)
46 {
47  IplImage *im = map.getIm();
48  if(im) cvReleaseImage(&im);
49  map.setImage(cvCreateImage(cvSize(128,64), IPL_DEPTH_32F, model->nChannels));
50  cvSet(map.getIm(), cvScalarAll(.1));
51  if (model->nChannels == 3) {
52  im = map.getIm();
53  im->channelSeq[0]='B';
54  im->channelSeq[1]='G';
55  im->channelSeq[2]='R';
56  }
57 
58  if (!model) return false;
59 
60  reflc.genGrid(corners, nx, ny);
61  reflc.averageImage(model,0);
62 
63  /*
64  FILE *IRef= fopen("IRef.txt","w");
65  if (IRef) {
66  for (int i=0; i<reflc.nbTri; i++)
67  fprintf(IRef, "%.6f ", reflc.avg[i]);
68  fprintf(IRef, "\n");
69  fclose(IRef);
70  }
71  */
72 
73  setCamNum(nbCam);
74  return reflc.avg != 0;
75 }
76 
77 void LightMap::normal2uv(const float n[3], float uv[2]) {
78  float l = 1/sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
79  float n0 = n[0]*l;
80  float n1 = n[1]*l;
81  float n2 = n[2]*l;
82  uv[0] = n0*.25f +.25f + (n2>0 ? 0:.5f);
83  uv[1] = .5f+n1*.5f;
84 }
85 
86 void LightMap::uv2normal(const float uv[2], float n[3]) {
87  n[0] = (uv[0]-(uv[0]>.5f ? .5f : 0)-.25f)*4;
88  n[1] = 2*uv[1]-1;
89  float len = n[0]*n[0] + n[1]*n[1];
90  if (len>=1) {
91  float f = 1/sqrt(len);
92  n[0]*=f;
93  n[1]*=f;
94  n[2]=(uv[0]>.5f ? -0.0f : 0.0f);
95  }
96  else n[2] = sqrt(1-len)*(uv[0]>.5f ? -1 : 1);
97 
98  float l = 1/sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
99  n[0]*=l;
100  n[1]*=l;
101  n[2]*=l;
102 }
103 
104 CvScalar LightMap::readMap(const float normal[3])
105 {
106  if (!isReady()) return cvScalarAll(1);
107  float uv[2];
108  normal2uv(normal, uv);
109 
110  IplImage *im = map.getIm();
111  assert(im!=0);
112  int iu = cvRound(uv[0]*(double)im->width);
113  int iv = cvRound(uv[1]*(double)im->height);
114  if (iu<0) iu=0;
115  if (iv<0) iv=0;
116  if (iu>=im->width) iu = im->width-1;
117  if (iv>=im->height) iv = im->height-1;
118  return cvGet2D(im, iv, iu );
119 }
120 
121 bool LightMap::addNormal(float normal[3], LightCollector &lc, int cam)
122 {
123  if (lightParams)
124  return addNormalLightMap(normal,lc,cam);
125  else
126  return addNormalCalib(normal,lc,cam);
127 }
128 
129 const float *LightMap::getGain(int cam)
130 {
131  static const float ones[3] = {1, 1, 1};
132  if (!isReady()) return ones;
133  return &CV_MAT_ELEM(*lightParams, float, 2*cam, 0);
134 }
135 
136 const float *LightMap::getBias(int cam)
137 {
138  static const float zeroes[3] = {0, 0, 0};
139  if (!isReady()) return zeroes;
140  return &CV_MAT_ELEM(*lightParams, float, 2*cam+1, 0);
141 }
142 
143 bool LightMap::addNormalLightMap(float normal[3], LightCollector &lc, int cam)
144 {
145  if (lightParams==0) return false;
146  assert(map.getIm()!=0);
147  assert(cam < nbCam);
148 
149  float l = 1/sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
150  normal[0]*=l;
151  normal[1]*=l;
152  normal[2]*=l;
153 
154  float val[3];
155  if (lc.cmpWithRef(reflc, val, getGain(cam), getBias(cam)))
156  return updateLightMap(normal, val);
157  return false;
158 }
159 
160 bool LightMap::updateLightMap(float normal[3], float *val)
161 {
162  if (val[0]<0) return false;
163 
164  const int nc = map.getIm()->nChannels;
165 
166  for (int y=0; y<map.getIm()->height; y++) {
167  float *line = (float *)(map.getIm()->imageData + y*map.getIm()->widthStep);
168 
169  for (int x=0; x<map.getIm()->width; x++) {
170  float n[3];
171  float uv[2] = { float(x)/float(map.getIm()->width), float(y)/float(map.getIm()->height) };
172  uv2normal(uv, n);
173  float dot = n[0]*normal[0] + n[1]*normal[1] + n[2]*normal[2];
174 #if 0
175  if (dot>0) {
176  dot = acos(dot)*2/M_PI;
177  float s = .2;
178  float f = (1/sqrt(2*M_PI))*exp(-(1-dot)/(2*s*s));
179  line[x] = (1.0f-f)*line[x] + f*val;
180  }
181 #else
182  float min_dot=0;
183  if (dot>min_dot) {
184  //dot = pow(dot, 16)/2;
185  float angle = (float)(acos(dot)*2/M_PI);
186  //dot = (dot-min_dot)/(1-min_dot);
187  float s = .2f;
188  //float f = (1/sqrt(2*M_PI))*exp(-(1-dot)/(2*s*s));
189  //float f = (1/sqrt(2*M_PI))*exp(-(angle)/(2*s*s));
190  float f = exp(-(angle)/(2*s*s));
191  for (int c=0; c<nc; c++)
192  line[x*nc +c] = (1.0f-f)*line[x*nc + c] + f*val[c];
193  }
194 #endif
195  }
196  }
197  map.update();
198  return true;
199 }
200 
201 #ifdef HAVE_GLEW
202 static void printShaderInfoLog(GLuint obj, const char *str, bool ARB)
203 {
204  GLint infologLength = 0;
205  GLint charsWritten = 0;
206  char *infoLog;
207 
208  if (ARB) glGetObjectParameterivARB(obj, GL_INFO_LOG_LENGTH,&infologLength);
209  else glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
210 
211  if (infologLength > 0)
212  {
213  infoLog = (char *)malloc(infologLength);
214  if (ARB) glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog);
215  else glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
216  if (strlen(infoLog)>0) {
217  if (str) printf("%s\n", str);
218  printf("%s\n",infoLog);
219  }
220  free(infoLog);
221  }
222 }
223 #endif
224 
225 #ifdef HAVE_GLEW
226 static std::string readFile(const char * const file)
227 {
228  std::string ret = "";
229  FILE * fp = fopen(file, "rb");
230  if (!fp) return "";
231  fseek(fp, 0, SEEK_END);
232  int size = (int)ftell(fp);
233  fseek(fp, 0, SEEK_SET);
234  char * buf = new char[size + 1];
235  fread(buf, size, 1, fp);
236  fclose(fp);
237  buf[size] = 0;
238  ret = buf;
239  delete [] buf;
240  return ret;
241 }
242 
243 static bool checkErrors(const char *file, int line, bool exitOnFailure=false)
244 {
245  GLenum error;
246  bool r=true;
247  while ((error = glGetError()) != GL_NO_ERROR) {
248  fprintf(stderr, "%s:%d: %s\n",
249  file, line,
250  (char *) gluErrorString(error));
251  if (exitOnFailure)
252  exit(-1);
253  r=false;
254  }
255  return r;
256  }
257 #endif
258 
260 {
261 #ifdef HAVE_GLEW
262  if (initialized) return true;
263  glewInit();
264  initialized = true;
265 
266  ARB = GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader;
267  if (!ARB && !glewIsSupported("GL_VERSION_2_0"))
268  {
269  printf("No GLSL support\n");
270  return false;
271  }
272  std::string ret;
273  const char * shaderProg;
274 
275  bool ok=true;
276  ret = readFile("myvert.glsl");
277  shaderProg = ret.c_str();
278 
279  if (ARB) g_vertShader = glCreateShaderObjectARB(GL_VERTEX_SHADER);
280  else g_vertShader = glCreateShader(GL_VERTEX_SHADER);
281  ok = ok && checkErrors(__FILE__,__LINE__);
282 
283  if (ARB) glShaderSourceARB(g_vertShader, 1, &shaderProg, 0);
284  else glShaderSource(g_vertShader, 1, &shaderProg, 0);
285  printShaderInfoLog(g_vertShader, "Vertex shader myvert.glsl", ARB);
286  ok = ok && checkErrors(__FILE__,__LINE__);
287 
288  if (ARB) glCompileShaderARB(g_vertShader);
289  else glCompileShader(g_vertShader);
290 
291  printShaderInfoLog(g_vertShader, "Vertex shader myvert.glsl", ARB);
292  ok = ok && checkErrors(__FILE__,__LINE__);
293 
294  ret = readFile("myfrag.glsl");
295  shaderProg = ret.c_str();
296  if (ARB) g_fragShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
297  else g_fragShader = glCreateShader(GL_FRAGMENT_SHADER);
298 
299  if (ARB) glShaderSourceARB(g_fragShader, 1, &shaderProg, 0);
300  else glShaderSource(g_fragShader, 1, &shaderProg, 0);
301 
302  if (ARB) glCompileShaderARB(g_fragShader);
303  else glCompileShader(g_fragShader);
304 
305  printShaderInfoLog(g_fragShader, "Fragment shader myfrag.glsl", ARB);
306  ok = ok && checkErrors(__FILE__,__LINE__);
307  //if (!ok) return false;
308 
309  if (ARB) g_shaderProgram = glCreateProgramObjectARB();
310  else g_shaderProgram = glCreateProgram();
311 
312  if (ARB) glAttachObjectARB(g_shaderProgram, g_vertShader);
313  else glAttachShader(g_shaderProgram, g_vertShader);
314 
315  if (ARB) glAttachObjectARB(g_shaderProgram, g_fragShader);
316  else glAttachShader(g_shaderProgram, g_fragShader);
317 
318  if (ARB) glLinkProgramARB(g_shaderProgram);
319  else glLinkProgram(g_shaderProgram);
320  ok = ok && checkErrors(__FILE__,__LINE__);
321 
322  if (ARB) glValidateProgramARB(g_shaderProgram);
323  else glValidateProgram(g_shaderProgram);
324  ok = ok && checkErrors(__FILE__,__LINE__);
325  printShaderInfoLog(g_shaderProgram, "glValidateProgram(g_shaderProgram)", ARB);
326  if (ok) {
327  cout << "GLSL shaders sucessfully initialized using "
328  << (ARB ? "ARB extensions" : "OpenGL 2.0") << ".\n";
329  } else
330  cout << "Failed to initialize GLSL shaders.\n";
331  return ok;
332 #else
333  return false;
334 #endif
335 }
336 
337 void LightMap::enableShader(int cam, CvMat *obj2world)
338 {
339 #ifdef HAVE_GLEW
340  assert(cam < nbCam);
341  if (!initialized) {
342  if (!initGL()) return;
343  }
344  if (ARB) glUseProgramObjectARB(g_shaderProgram);
345  else glUseProgram(g_shaderProgram);
346  if (!checkErrors(__FILE__,__LINE__)) {
347  printShaderInfoLog(g_shaderProgram, "glUseProgram(g_shaderProgram)", ARB);
348  return;
349  }
350 
351  GLuint shaderTexture, worldToObjectNormal, gain, bias;
352  if (ARB) {
353  shaderTexture = glGetUniformLocationARB(g_shaderProgram, "main_texture");
354  worldToObjectNormal = glGetUniformLocationARB(g_shaderProgram, "worldToObjectNormal");
355  gain = glGetUniformLocationARB(g_shaderProgram, "gain");
356  bias = glGetUniformLocationARB(g_shaderProgram, "bias");
357  } else {
358  shaderTexture = glGetUniformLocation(g_shaderProgram, "main_texture");
359  worldToObjectNormal = glGetUniformLocation(g_shaderProgram, "worldToObjectNormal");
360  gain = glGetUniformLocation(g_shaderProgram, "gain");
361  bias = glGetUniformLocation(g_shaderProgram, "bias");
362  }
363  checkErrors(__FILE__,__LINE__);
364 
365  glActiveTexture(GL_TEXTURE0 + 0);
366  glBindTexture(GL_TEXTURE_2D, shaderTexture);
367  checkErrors(__FILE__,__LINE__);
368 
369  if (ARB) glUniform1iARB(shaderTexture, 0);
370  else glUniform1i(shaderTexture, 0);
371  checkErrors(__FILE__,__LINE__);
372 
373  // The sign change is required because we do not like OpenGL's Z axis direction.
374  // Thus, we flip all normals.
375  float mat[9];
376  for (int i=0; i<3; ++i)
377  for (int j=0; j<3; ++j)
378  mat[j*3 +i] = -(float)cvGet2D(obj2world, i, j).val[0];
379 
380  float g[3],b[3];
381  for (int i=0;i<lightParams->cols; i++) {
382  if (lightParams) {
383  g[i] = 1/cvGet2D(lightParams, cam*2, i).val[0];
384  b[i] = g[i]*cvGet2D(lightParams, cam*2+1, i).val[0];
385  } else {
386  g[i] = 1;
387  b[i] = 0;
388  }
389  }
390  if (ARB) {
391  glUniform1iARB(shaderTexture, 0);
392  glUniformMatrix3fvARB(worldToObjectNormal, 1, GL_FALSE, mat);
393  glUniform4fARB(gain, g[2], g[1], g[0], 1);
394  glUniform4fARB(bias, b[2], b[1], b[0], 0);
395  } else {
396  glUniform1i(shaderTexture, 0);
397  glUniformMatrix3fv(worldToObjectNormal, 1, GL_FALSE, mat);
398  glUniform4f(gain, g[2], g[1], g[0], 1);
399  glUniform4f(bias, b[2], b[1], b[0], 0);
400  }
401  checkErrors(__FILE__,__LINE__);
402  map.loadTexture();
403  checkErrors(__FILE__,__LINE__);
404 #endif
405 }
406 
408 {
409 #ifdef HAVE_GLEW
410  if (ARB) glUseProgramObjectARB(0);
411  else glUseProgram(0);
412  map.disableTexture();
413 #endif
414 }
415 
417 {
418  obs.clear();
419  obs.reserve(300000);
420 
421  if (normals) delete normals;
422  normals = new CvGrowMat(256,3, CV_32FC1);
423  normals->resize(0,3);
424  nbCam=n;
425 
426  if (lightParams)
427  cvReleaseMat(&lightParams);
428  lightParams=0;
429 }
430 
431 static void normalize(float normal[3])
432 {
433  float l = 1/sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
434  normal[0]*=l;
435  normal[1]*=l;
436  normal[2]*=l;
437 }
438 
439 bool LightMap::addNormalCalib(float normal[3], LightCollector &lc, int cam)
440 {
441  assert(nbCam>0);
442  if (lc.avg==0 || reflc.avg==0) return false;
443 
444  bool hasObs=false;
445 
446  assert(lc.nbTri == reflc.nbTri);
447 
448  int normIdx = normals->rows + nbCam*2;
449  bool newT=true;
450  float maxdot= .999;
451 
452  normalize(normal);
453 
454  // is the normal already in the database ?
455  for (int i=0; i<normals->rows; i++) {
456  float *n2 = (float *)CV_MAT_ELEM_PTR(*normals, i, 0);
457  float ndot = n2[0]*normal[0] +
458  n2[1]*normal[1] +
459  n2[2]*normal[2];
460  if (ndot > maxdot) {
461  newT=false;
462  maxdot = ndot;
463  normIdx = i + nbCam*2;
464  }
465  }
466 
467 // if (newT) {
468 // obsMat->resize(obsMat->rows, obsMat->cols+1);
469 // }
470 
471  for (int i=0; i<lc.nbTri; ++i) {
472  float *rv = reflc.avg+i*reflc.avgChannels;
473  float *v = lc.avg+i*lc.avgChannels;
474  bool ok=true;
475  for (int c=0; c<reflc.avgChannels; c++)
476  if (!(v[c]>5 && rv[c] >5 && v[c]<250 && rv[c] <250))
477  ok=false;
478  if (ok) {
479  hasObs = true;
480 
481  Observation o;
482  o.camCol = cam*2;
483  o.normalCol = normIdx;
484 
485  for (int c=0; c<reflc.avgChannels; c++) {
486  o.camVal[c] = - v[c]/255.0f;
487  o.normalVal[c] = rv[c]/255.0f;
488  }
489  obs.push_back(o);
490  }
491  }
492 
493  if (newT&&hasObs){
494  // add the normal vector
495  normals->resize(normals->rows+1, normals->cols);
496  float *n = (float *)CV_MAT_ELEM_PTR(*normals, normals->rows-1,0);
497  n[0] = normal[0];
498  n[1] = normal[1];
499  n[2] = normal[2];
500  }
501  return true;
502 }
503 
504 static bool saveMat(const CvMat *m, const char *fn)
505 {
506  ofstream f(fn);
507 
508  if (!f.good()) return false;
509 
510  for (int j=0; j<m->rows; j++) {
511  for (int i=0; i<m->cols; i++) {
512  double v = cvGet2D(m, j, i).val[0];
513  f << v;
514  if (i+1 < m->cols) f<<'\t';
515  }
516  f << endl;
517  }
518  f.close();
519  return true;
520 }
521 
522 static CvGrowMat *loadMat(const char *fn)
523 {
524  ifstream f(fn);
525 
526  if (!f.good()) return 0;
527 
528  CvGrowMat *m = new CvGrowMat(128,3, CV_32FC1);
529  m->resize(1,1);
530 
531  int nrow=0;
532  do {
533  char line[4096];
534  f.getline(line, 4095);
535  line[4095]=0;
536  if (!f.good()) break;
537 
538  ++nrow;
539 
540  int ncols=1;
541  int len = strlen(line);
542  char *last=line;
543  for (int i=0;i<len+1;i++) {
544  if (line[i]==' ' || line[i]=='\t' || line[i]==0) {
545  line[i] = 0;
546  float val;
547  if (sscanf(last, "%f", &val)==1) {
548  m->resize(nrow,max(ncols, m->cols));
549  cvSet2D(m, nrow-1, ncols-1, cvScalarAll(val));
550  ncols++;
551  }
552  last = line+i+1;
553  }
554  }
555  } while (f.good());
556 
557  return m;
558 }
559 
560 double LightMap::getObsMat(int i, int j, int c)
561 {
562  if (j == obs[i].camCol) return (double)obs[i].camVal[c];
563  if (j == (obs[i].camCol+1)) return 1;
564  if (j == obs[i].normalCol) return (double)obs[i].normalVal[c];
565  return 0;
566 }
567 
568 double LightMap::getObsElem(const vector<Observation>::iterator &it, int i, int c)
569 {
570  if (it->camCol == i) return it->camVal[c];
571  if (it->camCol+1 == i) return 1;
572  if (it->normalCol == i) return it->normalVal[c];
573  return 0;
574 }
575 
576 void LightMap::computeAtA(CvMat *AtA, int channel)
577 {
578  for (vector<Observation>::iterator it = obs.begin();
579  it!=obs.end(); ++it)
580  {
581  int idx[3] = {it->camCol, it->camCol+1, it->normalCol};
582  for (unsigned i=0; i<3; i++) {
583  for (unsigned j=0; j<3; j++) {
584  int i_ = idx[i];
585  int j_ = idx[j];
586  if (i_ <= j_) {
587  double v = getObsElem(it,i_, channel)*getObsElem(it,j_, channel);
588  if (v!=0) {
589  double d = v+cvGetReal2D(AtA, i_, j_);
590  cvSetReal2D(AtA, i_, j_, d);
591  cvSetReal2D(AtA, j_, i_, d);
592  }
593  }
594  }
595  }
596  }
597  /*
598  for (int y=1;y<AtA->height; y++)
599  for (int x=0;x<y; x++) {
600  CV_MAT_ELEM(*AtA, float, y, x) = CV_MAT_ELEM(*AtA, float, x, y);
601  }
602  */
603 }
604 
605 bool LightMap::save(const char *lightParamsFN, const char *normalsFN)
606 {
607  return saveMat(lightParams,lightParamsFN) &&
608  saveMat(normals, normalsFN);
609 }
610 
612 {
613  int obsMatCols=normals->rows+2*nbCam;
614  int sizes[] = {obs.size(), obsMatCols};
615 
616  if (lightParams) cvReleaseMat(&lightParams);
617  lightParams = cvCreateMat(obsMatCols, reflc.avgChannels, CV_32FC1);
618  sizes[0] = sizes[1] = obsMatCols;
619 
620  // create temporary matrices
621  CvMat *AtA = cvCreateMat(obsMatCols,obsMatCols, CV_32FC1);
622  CvMat *w = cvCreateMat(obsMatCols, 1, CV_32FC1);
623  CvMat *V = cvCreateMat(obsMatCols, obsMatCols, CV_32FC1);
624 
625  for (int c=0; c<reflc.avgChannels; c++) {
626  cvSetZero(AtA);
627  computeAtA(AtA, c);
628 
629  /* char atafn[64];
630  sprintf(atafn,"ata%d.mat",c);
631  saveMat(AtA, atafn);
632  */
633 
634  cvSVD(AtA, w, 0, V, CV_SVD_MODIFY_A);
635 
636  CvMat sub, lpc;
637  cvGetCol(V, &sub, V->cols-1);
638  cvGetCol(lightParams, &lpc, c);
639  cvScale(&sub, &lpc, 1.0/cvGet2D(&sub,0,0).val[0]);
640 
641  /*
642  std::cout << "Eigen values:";
643  for (int i=0; i<w->rows; ++i) {
644  float v = (float)cvGet2D(w, i, 0).val[0];
645  std::cout << " " << v;
646  }
647  std::cout << std::endl;
648  */
649  }
650  cvReleaseMat(&V);
651  cvReleaseMat(&AtA);
652 
653  // construct light map
654  cvSet(map.getIm(), cvScalarAll(.1));
655  cvReleaseMat(&w);
656 
657  /*
658  std::cout << "Camera Values:\n";
659  for (int c=0; c<nbCam; ++c) {
660  float g = (float)cvGet2D(lightParams, c*2, 0).val[0];
661  float b = (float)cvGet2D(lightParams, c*2+1, 0).val[0];
662  std::cout <<" cam " << c << ": "<< g <<", " << b << std::endl;
663  }
664  */
665  buildMapFromSamples();
666  return true;
667 }
668 
669 void LightMap::buildMapFromSamples()
670 {
671  for (int i=0; i<normals->rows; ++i) {
672  updateLightMap((float *)CV_MAT_ELEM_PTR(*normals, i, 0),
673  &CV_MAT_ELEM(*lightParams, float, i+2*nbCam, 0));
674  }
675 }
676 
677 bool LightMap::load(const char *lightParamsFN, const char *normalsFN)
678 {
679  CvGrowMat *lp= loadMat(lightParamsFN);
680  if (!lp) return false;
681  lightParams = cvCreateMat(lp->rows, lp->cols, CV_32FC1);
682  cvCopy(lp, lightParams);
683  printf("Loaded lightParams: %dx%d.\n", lp->rows, lp->cols);
684  delete lp;
685  normals = loadMat(normalsFN);
686  int nlights = lightParams->rows - 2*nbCam;
687  if (!normals || ((normals->rows) < nlights)) {
688  if (normals) {
689  printf("Not enough normals. Expecting %d cameras. Found %d normals and %d parameters.\n",
690  nbCam, normals->rows, lightParams->rows);
691  }
692  cvReleaseMat(&lightParams);
693  return false;
694  }
695  if (normals->rows > nlights)
696  normals->resize(nlights,3);
697 
698  /*
699  std::cout << "Camera Values:\n";
700  for (int c=0; c<nbCam; ++c) {
701  float g = (float)cvGet2D(lightParams, c*2, 0).val[0];
702  float b = (float)cvGet2D(lightParams, c*2+1, 0).val[0];
703  std::cout <<" cam " << c << ": "<< g <<", " << b << std::endl;
704  }
705  */
706 
707  buildMapFromSamples();
708 
709  return true;
710 }
711 
712 bool LightMap::saveImage(const char *filename)
713 {
714  IplImage *image = map.getIm();
715  if (image==0) return false;
716  IplImage *im = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U,image->nChannels);
717  //double min=0, max=2;
718  //cvMinMaxLoc(image, &min, &max);
719  cvConvertScale(image, im, 128, 0);
720  int r = cvSaveImage(filename, im);
721  cvReleaseImage(&im);
722  return r!=0;
723 }