Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LensDB.cpp
Go to the documentation of this file.
1 
8 /* This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This software is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this software. If not, see
20  * <http://www.gnu.org/licenses/>.
21  *
22  */
23 
24 #include "LensDB.h"
25 #include <iostream>
26 #include <sstream>
27 #include <fstream>
28 #include <hugin_utils/stl_utils.h>
29 #include <hugin_utils/utils.h>
30 #include <sqlite3.h>
33 
34 namespace HuginBase
35 {
36 
37 namespace LensDB
38 {
39 
40 LensDB* LensDB::m_instance=NULL;
41 
42 // internal class to handle all transfer from/to database
43 // to prevent including of sqlite3.h into hugin_base header
45 {
46 public:
47  //struct for retrieving lens data
48  struct HFOVData
49  {
50  double focallength;
51  double HFOV;
52  };
53  struct CropData
54  {
55  double focallength;
56  int left, right, top, bottom;
57  };
59  {
60  double focallength;
61  double a, b, c;
62  };
64  {
65  double focallength;
66  double aperture;
67  double distance;
68  double Vb, Vc, Vd;
69  };
70  struct TCAdata
71  {
72  double focallength;
73  double ra, rb, rc, rd;
74  double ba, bb, bc, bd;
75  };
76  //constructor, open database
77  explicit Database(const std::string& filename) : m_filename(filename), m_runningTransaction(false)
78  {
79  bool newDB = (!hugin_utils::FileExists(m_filename));
80  int error = sqlite3_open(m_filename.c_str(), &m_db);
81  if (error)
82  {
83  std::cerr << "Can't open database: " << sqlite3_errmsg(m_db) << std::endl;
84  m_db = NULL;
85  m_filename = std::string();
86  };
87  if (newDB)
88  {
89  if (!CreateTables())
90  {
91  //something went wrong with the generation of the database structure
92  sqlite3_close(m_db);
93  m_db = NULL;
94  m_filename = std::string();
95  };
96  }
97  else
98  {
99  // check version and update database when necessary
100  // not yet implemented
101  // if (GetDBVersion() < 2) UpdateDatabase();
102  };
103  };
104  // destructor, destroy database
106  {
107  if (m_db)
108  {
110  {
111  EndTransaction();
112  };
113  sqlite3_close(m_db);
114  };
115  };
116  // create the tables for the database
118  {
119  const char* createDB = "PRAGMA user_version=1;"
120  "CREATE TABLE CameraCropTable (Maker TEXT, Model TEXT, Cropfactor REAL, PRIMARY KEY (Maker, Model));"
121  "CREATE TABLE LensProjectionTable (Lens TEXT PRIMARY KEY, Projection INTEGER);"
122  "CREATE TABLE LensHFOVTable (Lens TEXT, Focallength REAL, HFOV REAL, Weight INTEGER);"
123  "CREATE INDEX HFOV_IndexLens ON LensHFOVTable (Lens);"
124  "CREATE INDEX HFOV_IndexLens2 ON LensHFOVTable (Lens, Focallength);"
125  "CREATE TABLE LensCropTable (Lens TEXT, Focallength REAL, Width INTEGER, Height INTEGER, CropLeft INTEGER, CropRight INTEGER, CropTop INTEGER, CropBottom INTEGER, PRIMARY KEY (Lens, Focallength, Width, Height));"
126  "CREATE TABLE DistortionTable(Lens TEXT, Focallength REAL, a REAL, b REAL, c REAL, Weight INTEGER);"
127  "CREATE INDEX Dist_IndexLens ON DistortionTable (Lens);"
128  "CREATE INDEX Dist_IndexLensFocal ON DistortionTable (Lens, Focallength);"
129  "CREATE TABLE VignettingTable (Lens TEXT, Focallength REAL, Aperture REAL, Distance REAL, Vb REAL, Vc REAL, Vd REAL, Weight INTEGER);"
130  "CREATE INDEX Vig_IndexLens ON VignettingTable (Lens);"
131  "CREATE INDEX Vig_IndexLensFocal ON VignettingTable (Lens, Focallength);"
132  "CREATE INDEX Vig_IndexLensFocalApertureDistance ON VignettingTable (Lens, Focallength, Aperture, Distance);"
133  "CREATE TABLE TCATable (Lens TEXT, Focallength REAL, ra REAL, rb REAL, rc REAL, rd REAL, ba REAL, bb REAL, bc REAL, bd REAL, Weight INTEGER);"
134  "CREATE INDEX TCA_IndexLens ON TCATable (Lens);"
135  "CREATE INDEX TCA_IndexLensFocal ON TCATable (Lens, Focallength);"
136  "CREATE TABLE EMORTable (Maker TEXT, Model TEXT, ISO INTEGER, Ra REAL, Rb REAL, Rc REAL, Rd REAL, Re REAL, Weight INTEGER);"
137  "CREATE INDEX EMOR_Index_Cam ON EMORTable (Maker, Model);"
138  "CREATE INDEX EMOR_Index_CamISO ON EMORTable (Maker, Model, ISO);";
139  if (m_db == NULL)
140  {
141  return false;
142  };
143  if (sqlite3_exec(m_db, createDB, NULL, NULL, NULL) == SQLITE_OK)
144  {
145  return true;
146  }
147  else
148  {
149  std::cerr << "Could not create database structure." << std::endl;
150  return false;
151  };
152  };
153  // report the database version, implemented by PRAGMA user_version
154  // currently not used, for further extensions of the database structure
155  // @return db version, or -1 if db could not opened/initialized
156  int GetDBVersion() const
157  {
158  if (m_db == NULL)
159  {
160  return -1;
161  };
162  sqlite3_stmt *statement;
163  const char *tail;
164  int version = 0;
165  if (sqlite3_prepare_v2(m_db, "PRAGMA user_version;", -1, &statement, &tail) == SQLITE_OK)
166  {
167  if (sqlite3_step(statement) == SQLITE_ROW)
168  {
169  version = sqlite3_column_int(statement, 0);
170  };
171  };
172  sqlite3_finalize(statement);
173  return version;
174  };
175  // returns the filename of the database
176  std::string GetDBFilename() const
177  {
178  return m_filename;
179  };
180  // search for the crop factor of the given camera in the database
181  // returns true of camera was found, otherwise false
182  bool GetCropFactor(const std::string& maker, const std::string& model, double &cropFactor) const
183  {
184  cropFactor = 0;
185  if (m_db == NULL)
186  {
187  return false;
188  };
189  sqlite3_stmt *statement;
190  const char *tail;
191  if (sqlite3_prepare_v2(m_db, "SELECT Cropfactor FROM CameraCropTable WHERE Maker=?1 AND Model=?2;", -1, &statement, &tail) == SQLITE_OK)
192  {
193  sqlite3_bind_text(statement, 1, maker.c_str(), -1, NULL);
194  sqlite3_bind_text(statement, 2, model.c_str(), -1, NULL);
195  if (sqlite3_step(statement) == SQLITE_ROW)
196  {
197  cropFactor = sqlite3_column_double(statement, 0);
198  };
199  };
200  sqlite3_finalize(statement);
201  if (cropFactor < 0.1 || cropFactor>100)
202  {
203  cropFactor = 0;
204  };
205  return cropFactor > 0.1;
206  };
207  // saves the crop factor for the given camera in the database
208  // returns true, if data were successful saved into db, false if errors occurred during saving
209  bool SaveCropFactor(const std::string& maker, const std::string& model, const double cropFactor)
210  {
211  if (m_db == NULL)
212  {
213  return false;
214  };
215  // do some range checking
216  if (cropFactor < 0.1 || cropFactor > 100)
217  {
218  return false;
219  };
220  sqlite3_stmt *statement;
221  const char *tail;
222  int returnValue = 0;
224  if (sqlite3_prepare_v2(m_db, "INSERT OR FAIL INTO CameraCropTable (Maker, Model, Cropfactor) VALUES(?1,?2,?3);", -1, &statement, &tail) == SQLITE_OK)
225  {
226  sqlite3_bind_text(statement, 1, maker.c_str(), -1, NULL);
227  sqlite3_bind_text(statement, 2, model.c_str(), -1, NULL);
228  sqlite3_bind_double(statement, 3, cropFactor);
229  returnValue = sqlite3_step(statement);
230  if (returnValue == SQLITE_CONSTRAINT)
231  {
232  sqlite3_finalize(statement);
233  if (sqlite3_prepare_v2(m_db, "UPDATE CameraCropTable SET Cropfactor=?3 WHERE Maker=?1 AND Model=?2;", -1, &statement, &tail) == SQLITE_OK)
234  {
235  sqlite3_bind_text(statement, 1, maker.c_str(), -1, NULL);
236  sqlite3_bind_text(statement, 2, model.c_str(), -1, NULL);
237  sqlite3_bind_double(statement, 3, cropFactor);
238  returnValue = sqlite3_step(statement);
239  };
240  };
241  };
242  sqlite3_finalize(statement);
243  EndTransaction();
244  return returnValue == SQLITE_DONE;
245  };
246  // search for the projection of the given lens in the database
247  // returns true if lens information were was found, otherwise false
248  bool GetLensProjection(const std::string& lens, int &projection) const
249  {
250  projection = -1;
251  if (m_db == NULL)
252  {
253  return false;
254  };
255  sqlite3_stmt *statement;
256  const char *tail;
257  if (sqlite3_prepare_v2(m_db, "SELECT Projection FROM LensProjectionTable WHERE Lens=?1;", -1, &statement, &tail) == SQLITE_OK)
258  {
259  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
260  if (sqlite3_step(statement) == SQLITE_ROW)
261  {
262  projection = sqlite3_column_int(statement, 0);
263  };
264  };
265  sqlite3_finalize(statement);
266  return projection != -1;
267  };
268  // saves the projection for the given lens in the database
269  // returns true, if data were successful saved into db, false if errors occurred during saving
270  bool SaveLensProjection(const std::string& lens, const int projection)
271  {
272  if (m_db == NULL)
273  {
274  return false;
275  };
276  sqlite3_stmt *statement;
277  const char *tail;
278  int returnValue = 0;
280  if (sqlite3_prepare_v2(m_db, "INSERT OR FAIL INTO LensProjectionTable (Lens, Projection) VALUES(?1,?2);", -1, &statement, &tail) == SQLITE_OK)
281  {
282  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
283  sqlite3_bind_int(statement, 2, projection);
284  returnValue = sqlite3_step(statement);
285  if (returnValue == SQLITE_CONSTRAINT)
286  {
287  sqlite3_finalize(statement);
288  if (sqlite3_prepare_v2(m_db, "UPDATE LensProjectionTable SET Projection=?2 WHERE Lens=?1;", -1, &statement, &tail) == SQLITE_OK)
289  {
290  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
291  sqlite3_bind_int(statement, 2, projection);
292  returnValue = sqlite3_step(statement);
293  };
294  };
295  };
296  sqlite3_finalize(statement);
297  EndTransaction();
298  return returnValue == SQLITE_DONE;
299  };
300  // search for the HFOV for the given lens in the database
301  // returns true of data for lens was found, otherwise false
302  // returns 2 datasets with the values for the 2 focal lengths
303  bool GetHFOV(const std::string& lens, const double focallength, std::vector<HFOVData>& hfovData) const
304  {
305  hfovData.clear();
306  if (m_db == NULL)
307  {
308  return false;
309  };
310  sqlite3_stmt *statement;
311  const char *tail;
312  if (sqlite3_prepare_v2(m_db, "SELECT Focallength, SUM(HFOV*Weight)/SUM(Weight) FROM LensHFOVTable WHERE Lens=?1 GROUP BY Focallength ORDER BY ABS(Focallength-?2) ASC LIMIT 2;", -1, &statement, &tail) == SQLITE_OK)
313  {
314  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
315  sqlite3_bind_double(statement, 2, focallength);
316  while (sqlite3_step(statement) == SQLITE_ROW)
317  {
318  HFOVData newhfovData;
319  newhfovData.focallength = sqlite3_column_double(statement, 0);
320  newhfovData.HFOV = sqlite3_column_double(statement, 1);
321  hfovData.push_back(newhfovData);
322  };
323  };
324  sqlite3_finalize(statement);
325  return !hfovData.empty();
326  };
327  // saves the HFOV data in the database
328  // returns true, if data were successful saved into db, false if errors occurred during saving
329  bool SaveHFOV(const std::string& lens, const double focallength, const double HFOV, const int weight = 10)
330  {
331  if (m_db == NULL)
332  {
333  return false;
334  };
335  // range checking
336  if (HFOV < 0.1 || HFOV>360)
337  {
338  return false;
339  };
340  sqlite3_stmt *statement;
341  const char *tail;
342  int returnValue = 0;
343  if (sqlite3_prepare_v2(m_db, "INSERT INTO LensHFOVTable(Lens, Focallength, HFOV, Weight) VALUES(?1,?2,?3,?4);", -1, &statement, &tail) == SQLITE_OK)
344  {
345  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
346  sqlite3_bind_double(statement, 2, focallength);
347  sqlite3_bind_double(statement, 3, HFOV);
348  sqlite3_bind_int(statement, 4, weight);
349  returnValue = sqlite3_step(statement);
350  };
351  sqlite3_finalize(statement);
352  return returnValue == SQLITE_DONE;
353  };
354  // search for the crop of the given lens in the database
355  // returns true if lens information were was found, otherwise false
356  bool GetLensCrop(const std::string& lens, const double focal, const int width, const int height, std::vector<CropData> &cropData) const
357  {
358  cropData.clear();
359  if (m_db == NULL)
360  {
361  return false;
362  };
363  sqlite3_stmt *statement;
364  const char *tail;
365  if (sqlite3_prepare_v2(m_db, "SELECT Focallength, CropLeft, CropRight, CropTop, CropBottom FROM LensCropTable WHERE Lens=?1 AND Width=?2 AND Height=?3 ORDER BY ABS(Focallength-?4) ASC LIMIT 2;", -1, &statement, &tail) == SQLITE_OK)
366  {
367  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
368  sqlite3_bind_int(statement, 2, width);
369  sqlite3_bind_int(statement, 3, height);
370  sqlite3_bind_double(statement, 4, focal);
371  while (sqlite3_step(statement) == SQLITE_ROW)
372  {
373  CropData newCropData;
374  newCropData.focallength = sqlite3_column_double(statement, 0);
375  newCropData.left = sqlite3_column_int(statement, 1);
376  newCropData.right = sqlite3_column_int(statement, 2);
377  newCropData.top = sqlite3_column_int(statement, 3);
378  newCropData.bottom = sqlite3_column_int(statement, 4);
379  cropData.push_back(newCropData);
380  };
381  };
382  sqlite3_finalize(statement);
383  return !cropData.empty();
384  };
385  // saves the crop for the given lens in the database
386  // returns true, if data were successful saved into db, false if errors occurred during saving
387  bool SaveLensCrop(const std::string& lens, const double focal, const int width, const int height, const int left, const int right, const int top, const int bottom)
388  {
389  if (m_db == NULL)
390  {
391  return false;
392  };
393  sqlite3_stmt *statement;
394  const char *tail;
395  int returnValue = 0;
397  if (sqlite3_prepare_v2(m_db, "INSERT OR FAIL INTO LensCropTable (Lens, Focallength, Width, Height, CropLeft, CropRight, CropTop, CropBottom) VALUES(?1,?2,?3,?4,?5,?6,?7,?8);", -1, &statement, &tail) == SQLITE_OK)
398  {
399  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
400  sqlite3_bind_double(statement, 2, focal);
401  sqlite3_bind_int(statement, 3, width);
402  sqlite3_bind_int(statement, 4, height);
403  sqlite3_bind_int(statement, 5, left);
404  sqlite3_bind_int(statement, 6, right);
405  sqlite3_bind_int(statement, 7, top);
406  sqlite3_bind_int(statement, 8, bottom);
407  returnValue = sqlite3_step(statement);
408  if (returnValue == SQLITE_CONSTRAINT)
409  {
410  sqlite3_finalize(statement);
411  if (sqlite3_prepare_v2(m_db, "UPDATE LensCropTable SET CropLeft=?5, CropRight=?6, CropTop=?7, CropBottom=?8 WHERE Lens=?1 AND Focallength=?2 AND Width=?3 AND Height=?4;", -1, &statement, &tail) == SQLITE_OK)
412  {
413  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
414  sqlite3_bind_double(statement, 2, focal);
415  sqlite3_bind_int(statement, 3, width);
416  sqlite3_bind_int(statement, 4, height);
417  sqlite3_bind_int(statement, 5, left);
418  sqlite3_bind_int(statement, 6, right);
419  sqlite3_bind_int(statement, 7, top);
420  sqlite3_bind_int(statement, 8, bottom);
421  returnValue = sqlite3_step(statement);
422  };
423  };
424  };
425  sqlite3_finalize(statement);
426  EndTransaction();
427  return returnValue == SQLITE_DONE;
428  };
429  // removes the crop information for the given focallength and imagesize
430  bool RemoveLensCrop(const std::string& lens, const double focal, const int width, const int height)
431  {
432  if (m_db == NULL)
433  {
434  return false;
435  };
436  sqlite3_stmt *statement;
437  const char *tail;
438  int returnValue = 0;
439  if (sqlite3_prepare_v2(m_db, "DELETE FROM LensCropTable WHERE Lens=?1 AND Focallength=?2 AND Width=?3 AND Height=?4;", -1, &statement, &tail) == SQLITE_OK)
440  {
441  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
442  sqlite3_bind_double(statement, 2, focal);
443  sqlite3_bind_int(statement, 3, width);
444  sqlite3_bind_int(statement, 4, height);
445  returnValue = sqlite3_step(statement);
446  };
447  sqlite3_finalize(statement);
448  EndTransaction();
449  return returnValue == SQLITE_DONE;
450  };
451 
452  // search for the distortion data for the given lens in the database
453  // returns true of data for lens was found, otherwise false
454  // returns 2 datasets with the values for the 2 nearest focal lengths
455  bool GetDistortionData(const std::string& lens, const double focallength, std::vector<Distortiondata>& distData) const
456  {
457  distData.clear();
458  if (m_db == NULL)
459  {
460  return false;
461  };
462  sqlite3_stmt *statement;
463  const char *tail;
464  if (sqlite3_prepare_v2(m_db, "SELECT Focallength, SUM(a*Weight)/SUM(Weight), SUM(b*Weight)/SUM(Weight), SUM(c*Weight)/SUM(Weight) FROM DistortionTable WHERE Lens=?1 GROUP BY Focallength ORDER BY ABS(Focallength-?2) ASC LIMIT 2;", -1, &statement, &tail) == SQLITE_OK)
465  {
466  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
467  sqlite3_bind_double(statement, 2, focallength);
468  while (sqlite3_step(statement) == SQLITE_ROW)
469  {
470  Distortiondata newDistData;
471  newDistData.focallength = sqlite3_column_double(statement, 0);
472  newDistData.a = sqlite3_column_double(statement, 1);
473  newDistData.b = sqlite3_column_double(statement, 2);
474  newDistData.c = sqlite3_column_double(statement, 3);
475  distData.push_back(newDistData);
476  };
477  };
478  sqlite3_finalize(statement);
479  return !distData.empty();
480  };
481  // saves the distortion data in the database
482  // returns true, if data were successful saved into db, false if errors occurred during saving
483  bool SaveDistortion(const std::string& lens, const double focallength, const double a, const double b, const double c, const int weight = 10)
484  {
485  if (m_db == NULL)
486  {
487  return false;
488  };
489  sqlite3_stmt *statement;
490  const char *tail;
491  int returnValue = 0;
492  if (sqlite3_prepare_v2(m_db, "INSERT INTO DistortionTable(Lens, Focallength, a, b, c, Weight) VALUES(?1,?2,?3,?4,?5,?6);", -1, &statement, &tail) == SQLITE_OK)
493  {
494  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
495  sqlite3_bind_double(statement, 2, focallength);
496  sqlite3_bind_double(statement, 3, a);
497  sqlite3_bind_double(statement, 4, b);
498  sqlite3_bind_double(statement, 5, c);
499  sqlite3_bind_int(statement, 6, weight);
500  returnValue = sqlite3_step(statement);
501  };
502  sqlite3_finalize(statement);
503  return returnValue == SQLITE_DONE;
504  };
505  // search for the vignetting data for the given lens in the database
506  // returns true of data for lens was found, otherwise false
507  // returns maximal 4 datasets: datasets of the 2 nearest focallengths and for each focallength the 2 nearest apertures
508  bool GetVignettingData(const std::string& lens, const double focallength, const double aperture, std::vector<Vignettingdata>& vigData) const
509  {
510  vigData.clear();
511  if (m_db == NULL)
512  {
513  return false;
514  };
515  sqlite3_stmt *statement;
516  const char *tail;
517  if (sqlite3_prepare_v2(m_db,
518  "SELECT Focallength, Aperture, SUM(Vb*Weight)/SUM(Weight), SUM(Vc*Weight)/SUM(Weight), SUM(Vd*Weight)/SUM(Weight) FROM VignettingTable "
519  "WHERE Lens = ?1 AND ("
520  "("
521  "Focallength IN "
522  "(SELECT Focallength FROM VignettingTable WHERE Lens=?1 GROUP BY Focallength ORDER BY ABS(Focallength-?2) LIMIT 1) "
523  "AND Aperture IN "
524  "(SELECT Aperture FROM VignettingTable WHERE Lens=?1 AND "
525  "Focallength IN "
526  "(SELECT Focallength from VignettingTable WHERE Lens=?1 GROUP BY Focallength ORDER BY ABS(Focallength-?2) LIMIT 1) "
527  "GROUP BY Aperture ORDER BY ABS(Aperture-?3) LIMIT 2)"
528  ") OR ("
529  "Focallength IN "
530  "(SELECT Focallength FROM VignettingTable WHERE Lens=?1 GROUP BY Focallength ORDER BY ABS(Focallength-?2) LIMIT 1 OFFSET 1) "
531  "AND Aperture IN "
532  "(SELECT Aperture FROM VignettingTable WHERE Lens=?1 AND "
533  "Focallength IN "
534  "(SELECT Focallength FROM VignettingTable WHERE Lens=?1 GROUP BY Focallength ORDER BY ABS(Focallength-?2) LIMIT 1 OFFSET 1) "
535  "GROUP BY Aperture ORDER BY ABS(Aperture-?3) LIMIT 2)"
536  ")"
537  ")"
538  "GROUP BY Focallength, Aperture ORDER BY Focallength, Aperture;",
539  -1, &statement, &tail) == SQLITE_OK)
540  {
541  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
542  sqlite3_bind_double(statement, 2, focallength);
543  sqlite3_bind_double(statement, 3, aperture);
544  while (sqlite3_step(statement) == SQLITE_ROW)
545  {
546  Vignettingdata newVigData;
547  newVigData.focallength = sqlite3_column_double(statement, 0);
548  newVigData.aperture = sqlite3_column_double(statement, 1);
549  newVigData.Vb = sqlite3_column_double(statement, 2);
550  newVigData.Vc = sqlite3_column_double(statement, 3);
551  newVigData.Vd = sqlite3_column_double(statement, 4);
552  vigData.push_back(newVigData);
553  };
554  };
555  sqlite3_finalize(statement);
556  return !vigData.empty();
557  };
558  // saves the vignetting data in the database
559  // returns true, if data were successful saved into db, false if errors occurred during saving
560  bool SaveVignetting(const std::string& lens, const double focallength, const double aperture, const double distance, const double Vb, const double Vc, const double Vd, const int weight = 10)
561  {
562  if (m_db == NULL)
563  {
564  return false;
565  };
566  sqlite3_stmt *statement;
567  const char *tail;
568  int returnValue = 0;
569  if (sqlite3_prepare_v2(m_db, "INSERT INTO VignettingTable(Lens, Focallength, Aperture, Distance, Vb, Vc, Vd, Weight) VALUES(?1,?2,?3,?4,?5,?6,?7,?8);", -1, &statement, &tail) == SQLITE_OK)
570  {
571  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
572  sqlite3_bind_double(statement, 2, focallength);
573  sqlite3_bind_double(statement, 3, aperture);
574  sqlite3_bind_double(statement, 4, distance);
575  sqlite3_bind_double(statement, 5, Vb);
576  sqlite3_bind_double(statement, 6, Vc);
577  sqlite3_bind_double(statement, 7, Vd);
578  sqlite3_bind_int(statement, 8, weight);
579  returnValue = sqlite3_step(statement);
580  };
581  sqlite3_finalize(statement);
582  return returnValue == SQLITE_DONE;
583  };
584  // search for the tca data for the given lens in the database
585  // returns true of data for lens was found, otherwise false
586  // returns 2 datasets with the values for the 2 nearest focal lengths
587  bool GetTCAData(const std::string& lens, const double focallength, std::vector<TCAdata>& tcaData) const
588  {
589  tcaData.clear();
590  if (m_db == NULL)
591  {
592  return false;
593  };
594  sqlite3_stmt *statement;
595  const char *tail;
596  if (sqlite3_prepare_v2(m_db, "SELECT Focallength, SUM(ra*Weight)/SUM(Weight), SUM(rb*Weight)/SUM(Weight), SUM(rc*Weight)/SUM(Weight), SUM(rd*Weight)/SUM(Weight), SUM(ba*Weight)/SUM(Weight), SUM(bb*Weight)/SUM(Weight), SUM(bc*Weight)/SUM(Weight), SUM(bd*Weight)/SUM(Weight) FROM TCATable WHERE Lens=?1 GROUP BY Focallength ORDER BY ABS(Focallength-?2) ASC LIMIT 2;", -1, &statement, &tail) == SQLITE_OK)
597  {
598  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
599  sqlite3_bind_double(statement, 2, focallength);
600  while (sqlite3_step(statement) == SQLITE_ROW)
601  {
602  TCAdata newTCAData;
603  newTCAData.focallength = sqlite3_column_double(statement, 0);
604  newTCAData.ra = sqlite3_column_double(statement, 1);
605  newTCAData.rb = sqlite3_column_double(statement, 2);
606  newTCAData.rc = sqlite3_column_double(statement, 3);
607  newTCAData.rd = sqlite3_column_double(statement, 4);
608  newTCAData.ba = sqlite3_column_double(statement, 5);
609  newTCAData.bb = sqlite3_column_double(statement, 6);
610  newTCAData.bc = sqlite3_column_double(statement, 7);
611  newTCAData.bd = sqlite3_column_double(statement, 8);
612  tcaData.push_back(newTCAData);
613  };
614  };
615  sqlite3_finalize(statement);
616  return !tcaData.empty();
617  };
618  // saves the tca data in the database
619  // returns true, if data were successful saved into db, false if errors occurred during saving
620  bool SaveTCAData(const std::string& lens, const double focallength, const double ra, const double rb, const double rc, const double rd,
621  const double ba, const double bb, const double bc, const double bd, const int weight = 10)
622  {
623  if (m_db == NULL)
624  {
625  return false;
626  };
627  sqlite3_stmt *statement;
628  const char *tail;
629  int returnValue = 0;
630  if (sqlite3_prepare_v2(m_db, "INSERT INTO TCATable(Lens, Focallength, ra, rb, rc, rd, ba, bb, bc, bd, Weight) VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11);", -1, &statement, &tail) == SQLITE_OK)
631  {
632  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
633  sqlite3_bind_double(statement, 2, focallength);
634  sqlite3_bind_double(statement, 3, ra);
635  sqlite3_bind_double(statement, 4, rb);
636  sqlite3_bind_double(statement, 5, rc);
637  sqlite3_bind_double(statement, 6, rd);
638  sqlite3_bind_double(statement, 7, ba);
639  sqlite3_bind_double(statement, 8, bb);
640  sqlite3_bind_double(statement, 9, bc);
641  sqlite3_bind_double(statement, 10, bd);
642  sqlite3_bind_int(statement, 11, weight);
643  returnValue = sqlite3_step(statement);
644  };
645  sqlite3_finalize(statement);
646  return returnValue == SQLITE_DONE;
647  };
648  // saves the EMoR data in the database
649  // returns true, if data were successful saved into db, false if errors occurred during saving
650  bool SaveEMoR(const std::string& maker, const std::string& model, const int iso, const double Ra, const double Rb, const double Rc, const double Rd, const double Re, const int weight = 10)
651  {
652  if (m_db == NULL)
653  {
654  return false;
655  };
656  sqlite3_stmt *statement;
657  const char *tail;
658  int returnValue = 0;
659  if (sqlite3_prepare_v2(m_db, "INSERT INTO EMORTable(Maker, Model, ISO, Ra, Rb, Rc, Rd, Re, Weight) VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9);", -1, &statement, &tail) == SQLITE_OK)
660  {
661  sqlite3_bind_text(statement, 1, maker.c_str(), -1, NULL);
662  sqlite3_bind_text(statement, 2, model.c_str(), -1, NULL);
663  sqlite3_bind_int(statement, 3, iso);
664  sqlite3_bind_double(statement, 4, Ra);
665  sqlite3_bind_double(statement, 5, Rb);
666  sqlite3_bind_double(statement, 6, Rc);
667  sqlite3_bind_double(statement, 7, Rd);
668  sqlite3_bind_double(statement, 8, Re);
669  sqlite3_bind_int(statement, 9, weight);
670  returnValue = sqlite3_step(statement);
671  };
672  sqlite3_finalize(statement);
673  return returnValue == SQLITE_DONE;
674  };
675  // return a list of lens names which has certain information
676  bool GetLensNames(const bool distortion, const bool vignetting, const bool tca, LensList& lensList) const
677  {
678  lensList.clear();
679  if (m_db == NULL)
680  {
681  return false;
682  };
683  sqlite3_stmt *statement;
684  const std::string statement_distortion("SELECT DISTINCT Lens FROM DistortionTable");
685  const std::string statement_vignetting("SELECT DISTINCT Lens FROM VignettingTable");
686  const std::string statement_tca("SELECT DISTINCT Lens FROM TCATable");
687  std::string statementString;
688  if (distortion)
689  {
690  statementString = statement_distortion;
691  };
692  if (vignetting)
693  {
694  if (!statementString.empty())
695  {
696  statementString.append(" UNION ");
697  };
698  statementString.append(statement_vignetting);
699  };
700  if (tca)
701  {
702  if (!statementString.empty())
703  {
704  statementString.append(" UNION ");
705  };
706  statementString.append(statement_tca);
707  };
708  if (statementString.empty())
709  {
710  return false;
711  };
712  const char *tail;
713  if (sqlite3_prepare_v2(m_db, statementString.c_str(), -1, &statement, &tail) == SQLITE_OK)
714  {
715  while (sqlite3_step(statement) == SQLITE_ROW)
716  {
717  std::stringstream stream;
718  stream << sqlite3_column_text(statement, 0);
719  lensList.push_back(stream.str());
720  };
721  };
722  sqlite3_finalize(statement);
723  return !lensList.empty();
724  };
725  // clean up data base
726  bool CleanUp()
727  {
728  if (m_db == NULL)
729  {
730  return false;
731  };
733  sqlite3_exec(m_db,
734  "INSERT INTO DistortionTable(Lens, Focallength, a, b, c, Weight) "
735  "SELECT Lens, Focallength, SUM(a*Weight)/SUM(Weight), SUM(b*Weight)/SUM(Weight), SUM(c*Weight)/SUM(Weight), SUM(Weight*Weight)/SUM(Weight)*-1 FROM DistortionTable GROUP By Lens, Focallength;"
736  "DELETE FROM DistortionTable WHERE Weight>=0;"
737  "UPDATE DistortionTable SET Weight=-Weight WHERE Weight<0;"
738  "INSERT INTO LensHFOVTable(Lens, Focallength, HFOV, Weight) "
739  "SELECT Lens, Focallength, SUM(HFOV*Weight)/SUM(Weight), SUM(Weight*Weight)/SUM(Weight)*-1 FROM LensHFOVTable GROUP By Lens, Focallength;"
740  "DELETE FROM LensHFOVTable WHERE Weight>=0;"
741  "UPDATE LensHFOVTable SET Weight=-Weight WHERE Weight<0;"
742  "INSERT INTO TCATable(Lens, Focallength, ra, rb, rc, rd, ba, bb, bc, bd, Weight) "
743  "SELECT Lens, Focallength, SUM(ra*Weight)/SUM(Weight), SUM(rb*Weight)/SUM(Weight), SUM(rc*Weight)/SUM(Weight), SUM(rd*Weight)/SUM(Weight), SUM(ba*Weight)/SUM(Weight), SUM(bb*Weight)/SUM(Weight), SUM(bc*Weight)/SUM(Weight), SUM(bd*Weight)/SUM(Weight), SUM(Weight*Weight)/SUM(Weight)*-1 FROM TCATable GROUP By Lens, Focallength;"
744  "DELETE FROM TCATable WHERE Weight>=0;"
745  "UPDATE TCATable SET Weight=-Weight WHERE Weight<0;"
746  "INSERT INTO VignettingTable(Lens, Focallength, Aperture, Distance, Vb, Vc, Vd, Weight) "
747  "SELECT Lens, Focallength, Aperture, Distance, SUM(Vb*Weight)/SUM(Weight), SUM(Vc*Weight)/SUM(Weight), SUM(Vd*Weight)/SUM(Weight), SUM(Weight*Weight)/SUM(Weight)*-1 FROM VignettingTable GROUP By Lens, Focallength, Aperture, Distance;"
748  "DELETE FROM VignettingTable WHERE Weight>=0;"
749  "UPDATE VignettingTable SET Weight=-Weight WHERE Weight<0;"
750  "INSERT INTO EMORTable(Maker, Model, ISO, Ra, Rb, Rc, Rd, Re, Weight) "
751  "SELECT Maker, Model, ISO, SUM(Ra*Weight)/SUM(Weight), SUM(Rb*Weight)/SUM(Weight), SUM(Rc*Weight)/SUM(Weight), SUM(Rd*Weight)/SUM(Weight), SUM(Re*Weight)/SUM(Weight), SUM(Weight*Weight)/SUM(Weight)*-1 FROM EMORTable GROUP By Maker, Model, ISO;"
752  "DELETE FROM EMORTable WHERE Weight>=0;"
753  "UPDATE EMORTable SET Weight=-Weight WHERE Weight<0;",
754  NULL, NULL, NULL);
755  EndTransaction();
756  return sqlite3_exec(m_db, "VACUUM;", NULL, NULL, NULL) == SQLITE_OK;
757  };
758  // remove lens from all tables
759  bool RemoveLens(const std::string& lensname)
760  {
761  if (m_db == NULL)
762  {
763  return false;
764  };
766  bool result = RemoveLensFromTable("LensProjectionTable", lensname);
767  result &= RemoveLensFromTable("LensHFOVTable", lensname);
768  result &= RemoveLensFromTable("LensCropTable", lensname);
769  result &= RemoveLensFromTable("DistortionTable", lensname);
770  result &= RemoveLensFromTable("VignettingTable", lensname);
771  result &= RemoveLensFromTable("TCATable", lensname);
772  EndTransaction();
773  return result;
774  };
775  // remove camera from database
776  bool RemoveCamera(const std::string& maker, const std::string& model)
777  {
778  if (m_db == NULL)
779  {
780  return false;
781  };
783  bool result = RemoveCameraFromTable("CameraCropTable", maker, model);
784  result &= RemoveCameraFromTable("EMORTable", maker, model);
785  EndTransaction();
786  return result;
787  };
788  // export to file
789  bool ExportToFile(const std::string& filename)
790  {
791  if (m_db == NULL)
792  {
793  return false;
794  };
795  CleanUp();
796  std::ofstream output(filename.c_str());
797  if (output.is_open())
798  {
799  output << "TABLE=CameraCropTable" << std::endl
800  << "COLUMNS=Maker;Model;Cropfactor" << std::endl;
801  OutputSQLToStream("SELECT Maker, Model, Cropfactor FROM CameraCropTable;", output);
802  output << "ENDTABLE" << std::endl
803  << "TABLE=LensProjectionTable" << std::endl
804  << "COLUMNS=Lens;Projection" << std::endl;
805  OutputSQLToStream("SELECT Lens, Projection FROM LensProjectionTable;", output);
806  output << "ENDTABLE" << std::endl
807  << "TABLE=LensHFOVTable" << std::endl
808  << "COLUMNS=Lens;Focallength;HFOV;Weight" << std::endl;
809  OutputSQLToStream("SELECT Lens, Focallength, HFOV, Weight FROM LensHFOVTable;", output);
810  output << "ENDTABLE" << std::endl
811  << "TABLE=LensCropTable" << std::endl
812  << "COLUMNS=Lens;Focallength;Width;Height;CropLeft;CropRight;CropTop;CropBottom" << std::endl;
813  OutputSQLToStream("SELECT Lens, Focallength, Width, Height, CropLeft, CropRight, CropTop, CropBottom FROM TABLE LensCropTable;", output);
814  output << "ENDTABLE" << std::endl
815  << "TABLE=DistortionTable" << std::endl
816  << "COLUMNS=Lens;Focallength;a;b;c;Weight" << std::endl;
817  OutputSQLToStream("SELECT Lens, Focallength, a, b, c, Weight FROM DistortionTable;", output);
818  output << "ENDTABLE" << std::endl
819  << "TABLE=VignettingTable" << std::endl
820  << "COLUMNS=Lens;Focallength;Aperture;Distance;Vb;Vc;Vd;Weight" << std::endl;
821  OutputSQLToStream("SELECT Lens, Focallength, Aperture, Distance, Vb, Vc, Vd, Weight FROM VignettingTable;", output);
822  output << "ENDTABLE" << std::endl
823  << "TABLE=TCATable" << std::endl
824  << "COLUMNS=Lens;Focallength;ra;rb;rc;rd;ba;bb;bc;bd;Weight" << std::endl;
825  OutputSQLToStream("SELECT Lens, Focallength, ra, rb, rc, rd, ba, bb, bc, bd, Weight FROM TCATable;", output);
826  output << "ENDTABLE" << std::endl
827  << "TABLE=EMORTable" << std::endl
828  << "COLUMNS=Maker;Model;ISO;Ra;Rb;Rc;Rd;Re;Weight" << std::endl;
829  OutputSQLToStream("SELECT Maker, Model, ISO, Ra, Rb, Rc, Rd, Re, Weight FROM EMORTable;", output);
830  output << "ENDTABLE" << std::endl;
831  output.close();
832  return true;
833  }
834  else
835  {
836  std::cerr << "Could not open file \"" << filename << "\"." << std::endl;
837  return false;
838  };
839  };
840  // import data from external file
841  bool ImportFromFile(const std::string& filename)
842  {
843  if (m_db == NULL)
844  {
845  return false;
846  };
847  std::ifstream input(filename);
848  if (input.is_open())
849  {
850  while (!input.eof())
851  {
852  std::string line;
853  std::getline(input, line);
854  if (line.empty())
855  {
856  continue;
857  };
858  if (line.compare(0, 6, "TABLE=") == 0)
859  {
860  std::vector<std::string> substring = hugin_utils::SplitString(line, "=");
861  if (substring.size() == 2)
862  {
863  if (substring[1] == "CameraCropTable")
864  {
865  std::cout << "\tImporting CameraCropTable..." << std::endl;
866  if (!ImportCropFactor(input))
867  {
868  input.close();
869  std::cerr << "Error in input file." << std::endl;
870  return false;
871  };
872  }
873  else
874  {
875  if (substring[1] == "LensProjectionTable")
876  {
877  std::cout << "\tImporting LensProjectionTable..." << std::endl;
878  if (!ImportProjection(input))
879  {
880  input.close();
881  std::cerr << "Error in input file." << std::endl;
882  return false;
883  };
884  }
885  else
886  {
887  if (substring[1] == "LensHFOVTable")
888  {
889  std::cout << "\tImporting LensHFOVTable..." << std::endl;
890  if (!ImportHFOV(input))
891  {
892  input.close();
893  std::cerr << "Error in input file." << std::endl;
894  return false;
895  };
896  }
897  else
898  {
899  if (substring[1] == "LensCropTable")
900  {
901  std::cout << "\tImporting LensCropTable..." << std::endl;
902  if (!ImportLensCrop(input))
903  {
904  input.close();
905  std::cerr << "Error in input file." << std::endl;
906  return false;
907  };
908  }
909  else
910  {
911  if (substring[1] == "DistortionTable")
912  {
913  std::cout << "\tImporting DistortionTable..." << std::endl;
914  if (!ImportDistortion(input))
915  {
916  input.close();
917  std::cerr << "Error in input file." << std::endl;
918  return false;
919  };
920  }
921  else
922  {
923  if (substring[1] == "VignettingTable")
924  {
925  std::cout << "\tImporting VignettingTable..." << std::endl;
926  if (!ImportVignetting(input))
927  {
928  input.close();
929  std::cerr << "Error in input file." << std::endl;
930  return false;
931  };
932  }
933  else
934  {
935  if (substring[1] == "TCATable")
936  {
937  std::cout << "\tImporting TCATable..." << std::endl;
938  if (!ImportTCA(input))
939  {
940  input.close();
941  std::cerr << "Error in input file." << std::endl;
942  return false;
943  };
944  }
945  else
946  {
947  if (substring[1] == "EMORTable")
948  {
949  std::cout << "\tImporting EMORTable..." << std::endl;
950  if (!ImportEMOR(input))
951  {
952  input.close();
953  std::cerr << "Error in input file." << std::endl;
954  return false;
955  };
956  }
957  else
958  {
959  input.close();
960  std::cerr << "Error in input file (Unknown table \"" << substring[1] << "\")." << std::endl;
961  return false;
962  };
963  };
964  };
965  };
966  };
967  };
968  };
969  };
970  }
971  else
972  {
973  std::cerr << "Error in input file (Could not parse table name)." << std::endl;
974  input.close();
975  return false;
976  };
977  }
978  else
979  {
980  std::cerr << "Error in input file (Could not find TABLE section)." << std::endl;
981  input.close();
982  return false;
983  };
984  };
985  input.close();
986  CleanUp();
987  return true;
988  }
989  else
990  {
991  std::cerr << "Could not open file \"" << filename << "\"." << std::endl;
992  return false;
993  };
994  };
995 private:
996  // helper functions for BEGIN/COMMIT TRANSACTION
998  {
1000  {
1001  m_runningTransaction = (sqlite3_exec(m_db, "BEGIN TRANSACTION;", NULL, NULL, NULL) == SQLITE_OK);
1002  };
1003  };
1005  {
1007  {
1008  sqlite3_exec(m_db, "COMMIT TRANSACTION;", NULL, NULL, NULL);
1009  m_runningTransaction = false;
1010  };
1011  };
1012 
1013  // removes the given lens from the selected table
1014  bool RemoveLensFromTable(const std::string& table, const std::string& lens)
1015  {
1016  sqlite3_stmt *statement;
1017  const char *tail;
1018  int returnValue = 0;
1019  std::string sqlStatement("DELETE FROM ");
1020  sqlStatement.append(table);
1021  sqlStatement.append(" WHERE Lens=?;");
1022  if (sqlite3_prepare_v2(m_db, sqlStatement.c_str(), -1, &statement, &tail) == SQLITE_OK)
1023  {
1024  sqlite3_bind_text(statement, 1, lens.c_str(), -1, NULL);
1025  returnValue = sqlite3_step(statement);
1026  };
1027  sqlite3_finalize(statement);
1028  return returnValue == SQLITE_DONE;
1029  };
1030  // remove given camera from selected table
1031  bool RemoveCameraFromTable(const std::string& table, const std::string& maker, const std::string& model)
1032  {
1033  sqlite3_stmt *statement;
1034  const char *tail;
1035  int returnValue = 0;
1036  std::string sqlStatement("DELETE FROM ");
1037  sqlStatement.append(table);
1038  sqlStatement.append(" WHERE Maker=?1 AND Model=?2;");
1039  if (sqlite3_prepare_v2(m_db, sqlStatement.c_str(), -1, &statement, &tail) == SQLITE_OK)
1040  {
1041  sqlite3_bind_text(statement, 1, maker.c_str(), -1, NULL);
1042  sqlite3_bind_text(statement, 2, model.c_str(), -1, NULL);
1043  returnValue = sqlite3_step(statement);
1044  };
1045  sqlite3_finalize(statement);
1046  return returnValue == SQLITE_DONE;
1047  };
1048  // write result of sql statement to stream, the columns are separated by ;
1049  void OutputSQLToStream(const std::string& sqlstatement, std::ostream& stream)
1050  {
1051  sqlite3_stmt *statement;
1052  const char *tail;
1053  if (sqlite3_prepare_v2(m_db, sqlstatement.c_str(), -1, &statement, &tail) == SQLITE_OK)
1054  {
1055  while (sqlite3_step(statement) == SQLITE_ROW)
1056  {
1057  const int count = sqlite3_column_count(statement);
1058  if (count > 0)
1059  {
1060  for (int i = 0; i < count; ++i)
1061  {
1062  stream << sqlite3_column_text(statement, i);
1063  if (i + 1 < count)
1064  {
1065  stream << ";";
1066  };
1067  };
1068  };
1069  stream << std::endl;
1070  };
1071  };
1072  sqlite3_finalize(statement);
1073  }
1074  // import cropfactors from stream
1075  bool ImportCropFactor(std::istream& input)
1076  {
1077  std::string s;
1078  std::getline(input, s);
1079  // first line should contains the column list
1080  if (s.compare(0, 8, "COLUMNS=") != 0)
1081  {
1082  return false;
1083  };
1084  std::vector<std::string> columns = hugin_utils::SplitString(s.substr(8), ";");
1085  int indexMaker = -1;
1086  int indexModel = -1;
1087  int indexCropfactor = -1;
1088  for (size_t i = 0; i < columns.size(); ++i)
1089  {
1090  if (columns[i] == "Maker")
1091  {
1092  indexMaker = i;
1093  };
1094  if (columns[i] == "Model")
1095  {
1096  indexModel = i;
1097  };
1098  if (columns[i] == "Cropfactor")
1099  {
1100  indexCropfactor = i;
1101  };
1102  };
1103  if (indexMaker == -1)
1104  {
1105  std::cerr << "ERROR: Missing column \"Maker\"." << std::endl;
1106  return false;
1107  };
1108  if (indexModel == -1)
1109  {
1110  std::cerr << "ERROR: Missing column \"Model\"." << std::endl;
1111  return false;
1112  };
1113  if (indexCropfactor == -1)
1114  {
1115  std::cerr << "ERROR: Missing column \"Cropfactor\"." << std::endl;
1116  return false;
1117  };
1118  if (input.eof())
1119  {
1120  return false;
1121  };
1122  std::getline(input, s);
1123  while (!input.eof())
1124  {
1125  if (s == "ENDTABLE")
1126  {
1127  return true;
1128  }
1129  std::vector<std::string> items = hugin_utils::SplitString(s, ";");
1130  if (items.size() == columns.size())
1131  {
1132  //ignore lines with not matching count of items
1133  double cropfactor;
1134  if (hugin_utils::stringToDouble(items[indexCropfactor], cropfactor))
1135  {
1136  SaveCropFactor(items[indexMaker], items[indexModel], cropfactor);
1137  };
1138  };
1139  std::getline(input, s);
1140  };
1141  return false;
1142  };
1143  // import projection settings from stream
1144  bool ImportProjection(std::istream& input)
1145  {
1146  std::string s;
1147  std::getline(input, s);
1148  // first line should contains the column list
1149  if (s.compare(0, 8, "COLUMNS=") != 0)
1150  {
1151  return false;
1152  };
1153  std::vector<std::string> columns = hugin_utils::SplitString(s.substr(8), ";");
1154  int indexLens = -1;
1155  int indexProjection = -1;
1156  for (size_t i = 0; i < columns.size(); ++i)
1157  {
1158  if (columns[i] == "Lens")
1159  {
1160  indexLens = i;
1161  };
1162  if (columns[i] == "Projection")
1163  {
1164  indexProjection = i;
1165  };
1166  };
1167  if (indexLens == -1)
1168  {
1169  std::cerr << "ERROR: Missing column \"Lens\"." << std::endl;
1170  return false;
1171  };
1172  if (indexProjection == -1)
1173  {
1174  std::cerr << "ERROR: Missing column \"Projection\"." << std::endl;
1175  return false;
1176  };
1177  if (input.eof())
1178  {
1179  return false;
1180  };
1181  std::getline(input, s);
1182  while (!input.eof())
1183  {
1184  if (s == "ENDTABLE")
1185  {
1186  return true;
1187  }
1188  std::vector<std::string> items = hugin_utils::SplitString(s, ";");
1189  if (items.size() == columns.size())
1190  {
1191  //ignore lines with not matching count of items
1192  int projection;
1193  if (hugin_utils::stringToInt(items[indexProjection], projection))
1194  {
1195  SaveLensProjection(items[indexLens], projection);
1196  };
1197  };
1198  std::getline(input, s);
1199  };
1200  return false;
1201  };
1202  // import hfov values from stream
1203  bool ImportHFOV(std::istream& input)
1204  {
1205  std::string s;
1206  std::getline(input, s);
1207  // first line should contains the column list
1208  if (s.compare(0, 8, "COLUMNS=") != 0)
1209  {
1210  return false;
1211  };
1212  std::vector<std::string> columns = hugin_utils::SplitString(s.substr(8), ";");
1213  int indexLens = -1;
1214  int indexFocallength = -1;
1215  int indexHFOV = -1;
1216  int indexWeight = -1;
1217  for (size_t i = 0; i < columns.size(); ++i)
1218  {
1219  if (columns[i] == "Lens")
1220  {
1221  indexLens = i;
1222  };
1223  if (columns[i] == "Focallength")
1224  {
1225  indexFocallength = i;
1226  };
1227  if (columns[i] == "HFOV")
1228  {
1229  indexHFOV = i;
1230  };
1231  if (columns[i] == "Weight")
1232  {
1233  indexWeight = i;
1234  };
1235  };
1236  if (indexLens == -1)
1237  {
1238  std::cerr << "ERROR: Missing column \"Lens\"." << std::endl;
1239  return false;
1240  };
1241  if (indexFocallength == -1)
1242  {
1243  std::cerr << "ERROR: Missing column \"Focallength\"." << std::endl;
1244  return false;
1245  };
1246  if (indexHFOV == -1)
1247  {
1248  std::cerr << "ERROR: Missing column \"HFOV\"." << std::endl;
1249  return false;
1250  };
1251  if (indexWeight == -1)
1252  {
1253  std::cerr << "ERROR: Missing column \"Weight\"." << std::endl;
1254  return false;
1255  };
1256  if (input.eof())
1257  {
1258  return false;
1259  };
1260  std::getline(input, s);
1261  while (!input.eof())
1262  {
1263  if (s == "ENDTABLE")
1264  {
1265  return true;
1266  }
1267  std::vector<std::string> items = hugin_utils::SplitString(s, ";");
1268  if (items.size() == columns.size())
1269  {
1270  //ignore lines with not matching count of items
1271  double focallength;
1272  double hfov;
1273  int weight;
1274  bool valid = hugin_utils::stringToDouble(items[indexFocallength], focallength);
1275  valid &= hugin_utils::stringToDouble(items[indexHFOV], hfov);
1276  valid &= hugin_utils::stringToInt(items[indexWeight], weight);
1277  if (valid)
1278  {
1279  SaveHFOV(items[indexLens], focallength, hfov, weight);
1280  };
1281  };
1282  std::getline(input, s);
1283  };
1284  return false;
1285  };
1286  // import crop values from stream
1287  bool ImportLensCrop(std::istream& input)
1288  {
1289  std::string s;
1290  std::getline(input, s);
1291  // first line should contains the column list
1292  if (s.compare(0, 8, "COLUMNS=") != 0)
1293  {
1294  return false;
1295  };
1296  std::vector<std::string> columns = hugin_utils::SplitString(s.substr(8), ";");
1297  int indexLens = -1;
1298  int indexFocallength = -1;
1299  int indexWidth = -1;
1300  int indexHeight = -1;
1301  int indexCropLeft = -1;
1302  int indexCropRight = -1;
1303  int indexCropTop = -1;
1304  int indexCropBottom = -1;
1305  for (size_t i = 0; i < columns.size(); ++i)
1306  {
1307  if (columns[i] == "Lens")
1308  {
1309  indexLens = i;
1310  };
1311  if (columns[i] == "Focallength")
1312  {
1313  indexFocallength = i;
1314  };
1315  if (columns[i] == "Width")
1316  {
1317  indexWidth = i;
1318  };
1319  if (columns[i] == "Height")
1320  {
1321  indexHeight = i;
1322  };
1323  if (columns[i] == "CropLeft")
1324  {
1325  indexCropLeft = i;
1326  };
1327  if (columns[i] == "CropRight")
1328  {
1329  indexCropRight = i;
1330  };
1331  if (columns[i] == "CropTop")
1332  {
1333  indexCropTop = i;
1334  };
1335  if (columns[i] == "CropBottom")
1336  {
1337  indexCropBottom = i;
1338  };
1339  };
1340  if (indexLens == -1)
1341  {
1342  std::cerr << "ERROR: Missing column \"Lens\"." << std::endl;
1343  return false;
1344  };
1345  if (indexFocallength == -1)
1346  {
1347  std::cerr << "ERROR: Missing column \"Focallength\"." << std::endl;
1348  return false;
1349  };
1350  if (indexWidth == -1)
1351  {
1352  std::cerr << "ERROR: Missing column \"Width\"." << std::endl;
1353  return false;
1354  };
1355  if (indexHeight == -1)
1356  {
1357  std::cerr << "ERROR: Missing column \"Height\"." << std::endl;
1358  return false;
1359  };
1360  if (indexCropLeft == -1)
1361  {
1362  std::cerr << "ERROR: Missing column \"CropLeft\"." << std::endl;
1363  return false;
1364  };
1365  if (indexCropRight == -1)
1366  {
1367  std::cerr << "ERROR: Missing column \"CropRight\"." << std::endl;
1368  return false;
1369  };
1370  if (indexCropTop == -1)
1371  {
1372  std::cerr << "ERROR: Missing column \"CropTop\"." << std::endl;
1373  return false;
1374  };
1375  if (indexCropBottom == -1)
1376  {
1377  std::cerr << "ERROR: Missing column \"CropBottom\"." << std::endl;
1378  return false;
1379  };
1380  if (input.eof())
1381  {
1382  return false;
1383  };
1384  std::getline(input, s);
1385  while (!input.eof())
1386  {
1387  if (s == "ENDTABLE")
1388  {
1389  return true;
1390  }
1391  std::vector<std::string> items = hugin_utils::SplitString(s, ";");
1392  if (items.size() == columns.size())
1393  {
1394  //ignore lines with not matching count of items
1395  double focallength;
1396  int width, height, cropLeft, cropRight, cropTop, cropBottom;
1397  bool valid = hugin_utils::stringToDouble(items[indexFocallength], focallength);
1398  valid &= hugin_utils::stringToInt(items[indexWidth], width);
1399  valid &= hugin_utils::stringToInt(items[indexHeight], height);
1400  valid &= hugin_utils::stringToInt(items[indexCropLeft], cropLeft);
1401  valid &= hugin_utils::stringToInt(items[indexCropRight], cropRight);
1402  valid &= hugin_utils::stringToInt(items[indexCropTop], cropTop);
1403  valid &= hugin_utils::stringToInt(items[indexCropBottom], cropBottom);
1404  if (valid)
1405  {
1406  SaveLensCrop(items[indexLens], focallength, width, height, cropLeft, cropRight, cropTop, cropBottom);
1407  };
1408  };
1409  std::getline(input, s);
1410  };
1411  return false;
1412  };
1413  // import distortion values from stream
1414  bool ImportDistortion(std::istream& input)
1415  {
1416  std::string s;
1417  std::getline(input, s);
1418  // first line should contains the column list
1419  if (s.compare(0, 8, "COLUMNS=") != 0)
1420  {
1421  return false;
1422  };
1423  std::vector<std::string> columns = hugin_utils::SplitString(s.substr(8), ";");
1424  int indexLens = -1;
1425  int indexFocallength = -1;
1426  int indexA = -1;
1427  int indexB = -1;
1428  int indexC = -1;
1429  int indexWeight = -1;
1430  for (size_t i = 0; i < columns.size(); ++i)
1431  {
1432  if (columns[i] == "Lens")
1433  {
1434  indexLens = i;
1435  };
1436  if (columns[i] == "Focallength")
1437  {
1438  indexFocallength = i;
1439  };
1440  if (columns[i] == "a")
1441  {
1442  indexA = i;
1443  };
1444  if (columns[i] == "b")
1445  {
1446  indexB = i;
1447  };
1448  if (columns[i] == "c")
1449  {
1450  indexC = i;
1451  };
1452  if (columns[i] == "Weight")
1453  {
1454  indexWeight = i;
1455  };
1456  };
1457  if (indexLens == -1)
1458  {
1459  std::cerr << "ERROR: Missing column \"Lens\"." << std::endl;
1460  return false;
1461  };
1462  if (indexFocallength == -1)
1463  {
1464  std::cerr << "ERROR: Missing column \"Focallength\"." << std::endl;
1465  return false;
1466  };
1467  if (indexA == -1)
1468  {
1469  std::cerr << "ERROR: Missing column \"a\"." << std::endl;
1470  return false;
1471  };
1472  if (indexB == -1)
1473  {
1474  std::cerr << "ERROR: Missing column \"b\"." << std::endl;
1475  return false;
1476  };
1477  if (indexC == -1)
1478  {
1479  std::cerr << "ERROR: Missing column \"c\"." << std::endl;
1480  return false;
1481  };
1482  if (indexWeight == -1)
1483  {
1484  std::cerr << "ERROR: Missing column \"Weight\"." << std::endl;
1485  return false;
1486  };
1487  if (input.eof())
1488  {
1489  return false;
1490  };
1491  std::getline(input, s);
1492  while (!input.eof())
1493  {
1494  if (s == "ENDTABLE")
1495  {
1496  return true;
1497  }
1498  std::vector<std::string> items = hugin_utils::SplitString(s, ";");
1499  if (items.size() == columns.size())
1500  {
1501  //ignore lines with not matching count of items
1502  double focallength, a, b, c;
1503  int weight;
1504  bool valid = hugin_utils::stringToDouble(items[indexFocallength], focallength);
1505  valid &= hugin_utils::stringToDouble(items[indexA], a);
1506  valid &= hugin_utils::stringToDouble(items[indexB], b);
1507  valid &= hugin_utils::stringToDouble(items[indexC], c);
1508  valid &= hugin_utils::stringToInt(items[indexWeight], weight);
1509  if (valid)
1510  {
1511  SaveDistortion(items[indexLens], focallength, a, b, c, weight);
1512  };
1513  };
1514  std::getline(input, s);
1515  };
1516  return false;
1517  };
1518  // import vignetting values from stream
1519  bool ImportVignetting(std::istream& input)
1520  {
1521  std::string s;
1522  std::getline(input, s);
1523  // first line should contains the column list
1524  if (s.compare(0, 8, "COLUMNS=") != 0)
1525  {
1526  return false;
1527  };
1528  std::vector<std::string> columns = hugin_utils::SplitString(s.substr(8), ";");
1529  int indexLens = -1;
1530  int indexFocallength = -1;
1531  int indexAperture = -1;
1532  int indexDistance = -1;
1533  int indexVb = -1;
1534  int indexVc = -1;
1535  int indexVd = -1;
1536  int indexWeight = -1;
1537  for (size_t i = 0; i < columns.size(); ++i)
1538  {
1539  if (columns[i] == "Lens")
1540  {
1541  indexLens = i;
1542  };
1543  if (columns[i] == "Focallength")
1544  {
1545  indexFocallength = i;
1546  };
1547  if (columns[i] == "Aperture")
1548  {
1549  indexAperture = i;
1550  };
1551  if (columns[i] == "Distance")
1552  {
1553  indexDistance = i;
1554  };
1555  if (columns[i] == "Vb")
1556  {
1557  indexVb = i;
1558  };
1559  if (columns[i] == "Vc")
1560  {
1561  indexVc = i;
1562  };
1563  if (columns[i] == "Vd")
1564  {
1565  indexVd = i;
1566  };
1567  if (columns[i] == "Weight")
1568  {
1569  indexWeight = i;
1570  };
1571  };
1572  if (indexLens == -1)
1573  {
1574  std::cerr << "ERROR: Missing column \"Lens\"." << std::endl;
1575  return false;
1576  };
1577  if (indexFocallength == -1)
1578  {
1579  std::cerr << "ERROR: Missing column \"Focallength\"." << std::endl;
1580  return false;
1581  };
1582  if (indexAperture == -1)
1583  {
1584  std::cerr << "ERROR: Missing column \"Aperture\"." << std::endl;
1585  return false;
1586  };
1587  if (indexDistance == -1)
1588  {
1589  std::cerr << "ERROR: Missing column \"Distance\"." << std::endl;
1590  return false;
1591  };
1592  if (indexVb == -1)
1593  {
1594  std::cerr << "ERROR: Missing column \"Vb\"." << std::endl;
1595  return false;
1596  };
1597  if (indexVc == -1)
1598  {
1599  std::cerr << "ERROR: Missing column \"Vc\"." << std::endl;
1600  return false;
1601  };
1602  if (indexVd == -1)
1603  {
1604  std::cerr << "ERROR: Missing column \"Vd\"." << std::endl;
1605  return false;
1606  };
1607  if (indexWeight == -1)
1608  {
1609  std::cerr << "ERROR: Missing column \"Weight\"." << std::endl;
1610  return false;
1611  };
1612  if (input.eof())
1613  {
1614  return false;
1615  };
1616  std::getline(input, s);
1617  while (!input.eof())
1618  {
1619  if (s == "ENDTABLE")
1620  {
1621  return true;
1622  }
1623  std::vector<std::string> items = hugin_utils::SplitString(s, ";");
1624  if (items.size() == columns.size())
1625  {
1626  //ignore lines with not matching count of items
1627  double focallength, aperture, distance, Vb, Vc, Vd;
1628  int weight;
1629  bool valid = hugin_utils::stringToDouble(items[indexFocallength], focallength);
1630  valid &= hugin_utils::stringToDouble(items[indexAperture], aperture);
1631  valid &= hugin_utils::stringToDouble(items[indexDistance], distance);
1632  valid &= hugin_utils::stringToDouble(items[indexVb], Vb);
1633  valid &= hugin_utils::stringToDouble(items[indexVc], Vc);
1634  valid &= hugin_utils::stringToDouble(items[indexVd], Vd);
1635  valid &= hugin_utils::stringToInt(items[indexWeight], weight);
1636  if (valid)
1637  {
1638  SaveVignetting(items[indexLens], focallength, aperture, distance, Vb, Vc, Vd, weight);
1639  };
1640  };
1641  std::getline(input, s);
1642  };
1643  return false;
1644  };
1645  // import tca values from stream
1646  bool ImportTCA(std::istream& input)
1647  {
1648  std::string s;
1649  std::getline(input, s);
1650  // first line should contains the column list
1651  if (s.compare(0, 8, "COLUMNS=") != 0)
1652  {
1653  return false;
1654  };
1655  std::vector<std::string> columns = hugin_utils::SplitString(s.substr(8), ";");
1656  int indexLens = -1;
1657  int indexFocallength = -1;
1658  int indexRa = -1;
1659  int indexRb = -1;
1660  int indexRc = -1;
1661  int indexRd = -1;
1662  int indexBa = -1;
1663  int indexBb = -1;
1664  int indexBc = -1;
1665  int indexBd = -1;
1666  int indexWeight = -1;
1667  for (size_t i = 0; i < columns.size(); ++i)
1668  {
1669  if (columns[i] == "Lens")
1670  {
1671  indexLens = i;
1672  };
1673  if (columns[i] == "Focallength")
1674  {
1675  indexFocallength = i;
1676  };
1677  if (columns[i] == "ra")
1678  {
1679  indexRa = i;
1680  };
1681  if (columns[i] == "rb")
1682  {
1683  indexRb = i;
1684  };
1685  if (columns[i] == "rc")
1686  {
1687  indexRc = i;
1688  };
1689  if (columns[i] == "rd")
1690  {
1691  indexRd = i;
1692  };
1693  if (columns[i] == "ba")
1694  {
1695  indexBa = i;
1696  };
1697  if (columns[i] == "bb")
1698  {
1699  indexBb = i;
1700  };
1701  if (columns[i] == "bc")
1702  {
1703  indexBc = i;
1704  };
1705  if (columns[i] == "bd")
1706  {
1707  indexBd = i;
1708  };
1709  if (columns[i] == "Weight")
1710  {
1711  indexWeight = i;
1712  };
1713  };
1714  if (indexLens == -1)
1715  {
1716  std::cerr << "ERROR: Missing column \"Lens\"." << std::endl;
1717  return false;
1718  };
1719  if (indexFocallength == -1)
1720  {
1721  std::cerr << "ERROR: Missing column \"Focallength\"." << std::endl;
1722  return false;
1723  };
1724  if (indexRa == -1)
1725  {
1726  std::cerr << "ERROR: Missing column \"ra\"." << std::endl;
1727  return false;
1728  };
1729  if (indexRb == -1)
1730  {
1731  std::cerr << "ERROR: Missing column \"rb\"." << std::endl;
1732  return false;
1733  };
1734  if (indexRc == -1)
1735  {
1736  std::cerr << "ERROR: Missing column \"rc\"." << std::endl;
1737  return false;
1738  };
1739  if (indexRd == -1)
1740  {
1741  std::cerr << "ERROR: Missing column \"rd\"." << std::endl;
1742  return false;
1743  };
1744  if (indexBa == -1)
1745  {
1746  std::cerr << "ERROR: Missing column \"ba\"." << std::endl;
1747  return false;
1748  };
1749  if (indexBb == -1)
1750  {
1751  std::cerr << "ERROR: Missing column \"bb\"." << std::endl;
1752  return false;
1753  };
1754  if (indexBc == -1)
1755  {
1756  std::cerr << "ERROR: Missing column \"bc\"." << std::endl;
1757  return false;
1758  };
1759  if (indexBd == -1)
1760  {
1761  std::cerr << "ERROR: Missing column \"bd\"." << std::endl;
1762  return false;
1763  };
1764  if (indexWeight == -1)
1765  {
1766  std::cerr << "ERROR: Missing column \"Weight\"." << std::endl;
1767  return false;
1768  };
1769  if (input.eof())
1770  {
1771  return false;
1772  };
1773  std::getline(input, s);
1774  while (!input.eof())
1775  {
1776  if (s == "ENDTABLE")
1777  {
1778  return true;
1779  }
1780  std::vector<std::string> items = hugin_utils::SplitString(s, ";");
1781  if (items.size() == columns.size())
1782  {
1783  //ignore lines with not matching count of items
1784  double focallength, ra, rb, rc, rd, ba, bb, bc, bd;
1785  int weight;
1786  bool valid = hugin_utils::stringToDouble(items[indexFocallength], focallength);
1787  valid &= hugin_utils::stringToDouble(items[indexRa], ra);
1788  valid &= hugin_utils::stringToDouble(items[indexRb], rb);
1789  valid &= hugin_utils::stringToDouble(items[indexRc], rc);
1790  valid &= hugin_utils::stringToDouble(items[indexRd], rd);
1791  valid &= hugin_utils::stringToDouble(items[indexBa], ba);
1792  valid &= hugin_utils::stringToDouble(items[indexBb], bb);
1793  valid &= hugin_utils::stringToDouble(items[indexBc], bc);
1794  valid &= hugin_utils::stringToDouble(items[indexBd], bd);
1795  valid &= hugin_utils::stringToInt(items[indexWeight], weight);
1796  if (valid)
1797  {
1798  SaveTCAData(items[indexLens], focallength, ra, rb, rc, rd, ba, bb, bc, bd, weight);
1799  };
1800  };
1801  std::getline(input, s);
1802  };
1803  return false;
1804  };
1805  // import emor values from stream
1806  bool ImportEMOR(std::istream& input)
1807  {
1808  std::string s;
1809  std::getline(input, s);
1810  // first line should contains the column list
1811  if (s.compare(0, 8, "COLUMNS=") != 0)
1812  {
1813  return false;
1814  };
1815  std::vector<std::string> columns = hugin_utils::SplitString(s.substr(8), ";");
1816  int indexMaker = -1;
1817  int indexModel = -1;
1818  int indexISO = -1;
1819  int indexRa = -1;
1820  int indexRb = -1;
1821  int indexRc = -1;
1822  int indexRd = -1;
1823  int indexRe = -1;
1824  int indexWeight = -1;
1825  for (size_t i = 0; i < columns.size(); ++i)
1826  {
1827  if (columns[i] == "Maker")
1828  {
1829  indexMaker = i;
1830  };
1831  if (columns[i] == "Model")
1832  {
1833  indexModel = i;
1834  };
1835  if (columns[i] == "ISO")
1836  {
1837  indexISO = i;
1838  };
1839  if (columns[i] == "Ra")
1840  {
1841  indexRa = i;
1842  };
1843  if (columns[i] == "Rb")
1844  {
1845  indexRb = i;
1846  };
1847  if (columns[i] == "Rc")
1848  {
1849  indexRc = i;
1850  };
1851  if (columns[i] == "Rd")
1852  {
1853  indexRd = i;
1854  };
1855  if (columns[i] == "Re")
1856  {
1857  indexRe = i;
1858  };
1859  if (columns[i] == "Weight")
1860  {
1861  indexWeight = i;
1862  };
1863  };
1864  if (indexMaker == -1)
1865  {
1866  std::cerr << "ERROR: Missing column \"Maker\"." << std::endl;
1867  return false;
1868  };
1869  if (indexModel == -1)
1870  {
1871  std::cerr << "ERROR: Missing column \"Model\"." << std::endl;
1872  return false;
1873  };
1874  if (indexISO == -1)
1875  {
1876  std::cerr << "ERROR: Missing column \"ISO\"." << std::endl;
1877  return false;
1878  };
1879  if (indexRa == -1)
1880  {
1881  std::cerr << "ERROR: Missing column \"Ra\"." << std::endl;
1882  return false;
1883  };
1884  if (indexRb == -1)
1885  {
1886  std::cerr << "ERROR: Missing column \"Rb\"." << std::endl;
1887  return false;
1888  };
1889  if (indexRc == -1)
1890  {
1891  std::cerr << "ERROR: Missing column \"Rc\"." << std::endl;
1892  return false;
1893  };
1894  if (indexRd == -1)
1895  {
1896  std::cerr << "ERROR: Missing column \"Rd\"." << std::endl;
1897  return false;
1898  };
1899  if (indexRe == -1)
1900  {
1901  std::cerr << "ERROR: Missing column \"Re\"." << std::endl;
1902  return false;
1903  };
1904  if (indexWeight == -1)
1905  {
1906  std::cerr << "ERROR: Missing column \"Weight\"." << std::endl;
1907  return false;
1908  };
1909  if (input.eof())
1910  {
1911  return false;
1912  };
1913  std::getline(input, s);
1914  while (!input.eof())
1915  {
1916  if (s == "ENDTABLE")
1917  {
1918  return true;
1919  }
1920  std::vector<std::string> items = hugin_utils::SplitString(s, ";");
1921  if (items.size() == columns.size())
1922  {
1923  //ignore lines with not matching count of items
1924  double Ra, Rb, Rc, Rd, Re;
1925  int iso, weight;
1926  bool valid = hugin_utils::stringToInt(items[indexISO], iso);
1927  valid &= hugin_utils::stringToDouble(items[indexRa], Ra);
1928  valid &= hugin_utils::stringToDouble(items[indexRb], Rb);
1929  valid &= hugin_utils::stringToDouble(items[indexRc], Rc);
1930  valid &= hugin_utils::stringToDouble(items[indexRd], Rd);
1931  valid &= hugin_utils::stringToDouble(items[indexRe], Re);
1932  valid &= hugin_utils::stringToInt(items[indexWeight], weight);
1933  if (valid)
1934  {
1935  SaveEMoR(items[indexMaker], items[indexModel], iso, Ra, Rb, Rc, Rd, Re, weight);
1936  };
1937  };
1938  std::getline(input, s);
1939  };
1940  return false;
1941  };
1942 
1943  std::string m_filename;
1944  sqlite3 *m_db;
1946 };
1947 
1948 double InterpolateValue(double x, double x0, double y0, double x1, double y1)
1949 {
1950  if (fabs(x1 - x0) < 1e-4)
1951  {
1952  // prevent division through 0, should normally not happens
1953  return y0;
1954  };
1955  return y0 + (y1 - y0) * (x - x0) / (x1 - x0);
1956 };
1957 
1958 double InterpolateValueTriangle(double x, double y,
1959  double x1, double y1, double z1,
1960  double x2, double y2, double z2,
1961  double x3, double y3, double z3)
1962 {
1963  const double a = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
1964  if (fabs(a) < 1e-6)
1965  {
1966  // this should never happens
1967  return z1;
1968  };
1969  return z1 + ((x - x1) * ((z2 - z1) * (y3 - y1) - (y2 - y1) * (z3 - z1)) + (y - y1) * ((x2 - x1) * (z3 - z1) - (z2 - z1) * (x3 - x1))) / a;
1970 };
1971 
1973 {
1974  std::string filename = hugin_utils::GetUserAppDataDir();
1975  if (filename.length() == 0)
1976  {
1977  m_db = NULL;
1978  }
1979  else
1980  {
1981 #if _WIN32
1982  filename.append("\\");
1983 #else
1984  filename.append("/");
1985 #endif
1986  filename.append("camlens.db");
1987  m_db = new LensDB::Database(filename);
1988  if (!m_db)
1989  {
1990  m_db = NULL;
1991  };
1992  };
1993 };
1994 
1995 LensDB::~LensDB()
1996 {
1997  if (m_db)
1998  delete m_db;
1999 };
2000 
2001 LensDB& LensDB::GetSingleton()
2002 {
2003  if(m_instance==NULL)
2004  {
2005  m_instance = new LensDB();
2006  };
2007  return *m_instance;
2008 };
2009 
2010 void LensDB::Clean()
2011 {
2012  if (m_instance != NULL)
2013  {
2014  delete m_instance;
2015  };
2016  m_instance = NULL;
2017 };
2018 
2019 std::string LensDB::GetDBFilename() const
2020 {
2021  if (m_db)
2022  {
2023  return m_db->GetDBFilename();
2024  }
2025  else
2026  {
2027  return std::string();
2028  };
2029 };
2030 
2031 bool LensDB::GetCropFactor(const std::string& maker, const std::string& model, double& cropFactor) const
2032 {
2033  if (m_db == NULL)
2034  {
2035  return false;
2036  };
2037  return m_db->GetCropFactor(maker, model, cropFactor);
2038 };
2039 
2040 bool LensDB::GetProjection(const std::string& lens, BaseSrcPanoImage::Projection& projection) const
2041 {
2042  if (m_db == NULL)
2043  {
2044  return false;
2045  };
2046  int proj;
2047  if (m_db->GetLensProjection(lens, proj))
2048  {
2049  projection = static_cast<BaseSrcPanoImage::Projection>(proj);
2050  return true;
2051  }
2052  else
2053  {
2054  return false;
2055  };
2056 };
2057 
2058 inline int fsign(double a)
2059 {
2060  return (a > 0) ? 1 : ((a < 0) ? -1 : 0);
2061 }
2062 
2064 bool IsFocallengthNearRange(const double focal, const double limit1, const double limit2, const double tol)
2065 {
2066  if (fsign(focal - limit1) != fsign(focal - limit2))
2067  {
2068  return true;
2069  };
2070  return fabs(focal - limit1) < tol * focal;
2071 }
2072 
2073 bool LensDB::GetCrop(const std::string& lens, const double focal, const vigra::Size2D& imageSize, vigra::Rect2D& cropRect) const
2074 {
2075  if(m_db == NULL)
2076  {
2077  return false;
2078  };
2079  std::vector<Database::CropData> cropData;
2080  if (!m_db->GetLensCrop(lens, focal, imageSize.width() , imageSize.height(), cropData))
2081  {
2082  return false;
2083  };
2084  int left, right, top, bottom;
2085  if (cropData.size() == 1)
2086  {
2087  // only one entry found
2088  // check focal length
2089  if (fabs(cropData[0].focallength - focal) < 0.075f * focal)
2090  {
2091  // focal length matches
2092  left = cropData[0].left;
2093  right = cropData[0].right;
2094  top = cropData[0].top;
2095  bottom = cropData[0].bottom;
2096  }
2097  else
2098  {
2099  // if focal length does not match we ignore crop
2100  return false;
2101  }
2102  }
2103  else
2104  {
2105  if (!IsFocallengthNearRange(focal, cropData[0].focallength, cropData[1].focallength, 0.15f))
2106  {
2107  return false;
2108  };
2109  left = hugin_utils::roundi(InterpolateValue(focal, cropData[0].focallength, cropData[0].left, cropData[1].focallength, cropData[1].left));
2110  right = hugin_utils::roundi(InterpolateValue(focal, cropData[0].focallength, cropData[0].right, cropData[1].focallength, cropData[1].right));
2111  top = hugin_utils::roundi(InterpolateValue(focal, cropData[0].focallength, cropData[0].top, cropData[1].focallength, cropData[1].top));
2112  bottom = hugin_utils::roundi(InterpolateValue(focal, cropData[0].focallength, cropData[0].bottom, cropData[1].focallength, cropData[1].bottom));
2113  };
2114  cropRect.setUpperLeft(vigra::Point2D(left, top));
2115  cropRect.setLowerRight(vigra::Point2D(right, bottom));
2116  return true;
2117 };
2118 
2119 bool LensDB::GetFov(const std::string& lens, const double focal, double& fov) const
2120 {
2121  if (m_db == NULL)
2122  {
2123  return false;
2124  };
2125  std::vector<Database::HFOVData> hfovdata;
2126  if (!m_db->GetHFOV(lens, focal, hfovdata))
2127  {
2128  return false;
2129  };
2130  fov = 0;
2131  if (hfovdata.size() == 1)
2132  {
2133  // only one entry found
2134  // check focal length
2135  if (fabs(hfovdata[0].focallength - focal) <= 0.075f * focal)
2136  {
2137  // focal length matches
2138  fov = hfovdata[0].HFOV;
2139  }
2140  else
2141  {
2142  // if focal length does not match we ignore HFOV
2143  return false;
2144  }
2145  }
2146  else
2147  {
2148  if (!IsFocallengthNearRange(focal, hfovdata[0].focallength, hfovdata[1].focallength, 0.15f))
2149  {
2150  // difference to nearest point too big, ignoring
2151  return false;
2152  }
2153  fov = InterpolateValue(focal, hfovdata[0].focallength, hfovdata[0].HFOV, hfovdata[1].focallength, hfovdata[1].HFOV);
2154  if (fov < 0.1)
2155  {
2156  fov = 0;
2157  };
2158  };
2159  return (fov > 0);
2160 };
2161 
2162 bool LensDB::GetDistortion(const std::string& lens, const double focal, std::vector<double>& distortion) const
2163 {
2164  distortion.clear();
2165  if (m_db == NULL)
2166  {
2167  return false;
2168  };
2169  std::vector<Database::Distortiondata> distdata;
2170  if (!m_db->GetDistortionData(lens, focal, distdata))
2171  {
2172  return false;
2173  };
2174  if (distdata.size() == 1)
2175  {
2176  // only one entry found
2177  // check focal length
2178  if (fabs(distdata[0].focallength - focal) <= 0.075f * focal)
2179  {
2180  distortion.push_back(distdata[0].a);
2181  distortion.push_back(distdata[0].b);
2182  distortion.push_back(distdata[0].c);
2183  return true;
2184  }
2185  else
2186  {
2187  std::cout << "Invalid focallength" << std::endl;
2188  return false;
2189  };
2190  }
2191  else
2192  {
2193  if (!IsFocallengthNearRange(focal, distdata[0].focallength, distdata[1].focallength, 0.15f))
2194  {
2195  // difference to nearest point too big, ignoring
2196  return false;
2197  }
2198  distortion.push_back(InterpolateValue(focal, distdata[0].focallength, distdata[0].a, distdata[1].focallength, distdata[1].a));
2199  distortion.push_back(InterpolateValue(focal, distdata[0].focallength, distdata[0].b, distdata[1].focallength, distdata[1].b));
2200  distortion.push_back(InterpolateValue(focal, distdata[0].focallength, distdata[0].c, distdata[1].focallength, distdata[1].c));
2201  return true;
2202  };
2203 };
2204 
2205 bool LensDB::GetVignetting(const std::string& lens, const double focal, const double aperture, const double distance, std::vector<double>& vignetting) const
2206 {
2207  vignetting.clear();
2208  if (m_db == NULL)
2209  {
2210  return false;
2211  };
2212  std::vector<Database::Vignettingdata> vigdata;
2213  if (!m_db->GetVignettingData(lens, focal, aperture, vigdata))
2214  {
2215  return false;
2216  };
2217  const bool unknownAperture = (fabs(aperture) < 0.001f);
2218  if (vigdata.size() == 1)
2219  {
2220  if ((fabs(vigdata[0].focallength - focal) <= 0.075f * focal) && (unknownAperture || fabs(vigdata[0].aperture - aperture) < 0.3f))
2221  {
2222  vignetting.push_back(1.0);
2223  vignetting.push_back(vigdata[0].Vb);
2224  vignetting.push_back(vigdata[0].Vc);
2225  vignetting.push_back(vigdata[0].Vd);
2226  return true;
2227  }
2228  else
2229  {
2230  return false;
2231  }
2232  }
2233  else
2234  {
2235  if (vigdata.size() == 2)
2236  {
2237  if (fabs(vigdata[0].focallength - vigdata[1].focallength) < 0.001f)
2238  {
2239  // variant a: 2 datasets with same focal length
2240  if (unknownAperture)
2241  {
2242  vignetting.push_back(1.0);
2243  vignetting.push_back(vigdata[0].Vb);
2244  vignetting.push_back(vigdata[0].Vc);
2245  vignetting.push_back(vigdata[0].Vd);
2246  return true;
2247  }
2248  else
2249  {
2250  if (vigdata[0].aperture - 0.3 <= aperture && aperture <= vigdata[1].aperture + 0.3)
2251  {
2252  vignetting.push_back(1.0);
2253  vignetting.push_back(InterpolateValue(aperture, vigdata[0].aperture, vigdata[0].Vb, vigdata[1].aperture, vigdata[1].Vb));
2254  vignetting.push_back(InterpolateValue(aperture, vigdata[0].aperture, vigdata[0].Vc, vigdata[1].aperture, vigdata[1].Vc));
2255  vignetting.push_back(InterpolateValue(aperture, vigdata[0].aperture, vigdata[0].Vd, vigdata[1].aperture, vigdata[1].Vd));
2256  return true;
2257  }
2258  else
2259  {
2260  return false;
2261  };
2262  };
2263  }
2264  else
2265  {
2266  // variant b: 2 datasets from different focal length
2267  if (!IsFocallengthNearRange(focal, vigdata[0].focallength, vigdata[1].focallength, 0.15f))
2268  {
2269  return false;
2270  };
2271  const double interpolatedAperture = InterpolateValue(focal, vigdata[0].focallength, vigdata[0].aperture, vigdata[1].focallength, vigdata[1].aperture);
2272  if (fabs(interpolatedAperture - aperture) < 0.3f || unknownAperture)
2273  {
2274  // return value only, if aperture matches the 2 found values
2275  vignetting.push_back(1.0);
2276  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, vigdata[0].Vb, vigdata[1].focallength, vigdata[1].Vb));
2277  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, vigdata[0].Vc, vigdata[1].focallength, vigdata[1].Vc));
2278  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, vigdata[0].Vd, vigdata[1].focallength, vigdata[1].Vd));
2279  return true;
2280  }
2281  else
2282  {
2283  return false;
2284  };
2285  };
2286  }
2287  else
2288  {
2289  if (vigdata.size() == 3)
2290  {
2291  if (!IsFocallengthNearRange(focal, vigdata[0].focallength, vigdata[2].focallength, 0.15f))
2292  {
2293  return false;
2294  };
2295  vignetting.push_back(1.0);
2296  vignetting.push_back(InterpolateValueTriangle(focal, aperture,
2297  vigdata[0].focallength, vigdata[0].aperture, vigdata[0].Vb,
2298  vigdata[1].focallength, vigdata[1].aperture, vigdata[1].Vb,
2299  vigdata[2].focallength, vigdata[2].aperture, vigdata[2].Vb
2300  ));
2301  vignetting.push_back(InterpolateValueTriangle(focal, aperture,
2302  vigdata[0].focallength, vigdata[0].aperture, vigdata[0].Vc,
2303  vigdata[1].focallength, vigdata[1].aperture, vigdata[1].Vc,
2304  vigdata[2].focallength, vigdata[2].aperture, vigdata[2].Vc
2305  ));
2306  vignetting.push_back(InterpolateValueTriangle(focal, aperture,
2307  vigdata[0].focallength, vigdata[0].aperture, vigdata[0].Vd,
2308  vigdata[1].focallength, vigdata[1].aperture, vigdata[1].Vd,
2309  vigdata[2].focallength, vigdata[2].aperture, vigdata[2].Vd
2310  ));
2311  return true;
2312  }
2313  else
2314  {
2315  // we have now 4 points for interpolation
2316  if (!IsFocallengthNearRange(focal, vigdata[0].focallength, vigdata[2].focallength, 0.15f))
2317  {
2318  return false;
2319  };
2320  if (unknownAperture)
2321  {
2322  // unknown aperture, take smallest aperture
2323  vignetting.push_back(1.0);
2324  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, vigdata[0].Vb, vigdata[2].focallength, vigdata[2].Vb));
2325  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, vigdata[0].Vc, vigdata[2].focallength, vigdata[2].Vc));
2326  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, vigdata[0].Vd, vigdata[2].focallength, vigdata[2].Vd));
2327  return true;
2328  }
2329  else
2330  {
2331  // interpolate for each focal length to desired aperture
2332  double Vb1, Vc1, Vd1, Vb2, Vc2, Vd2;
2333  if (vigdata[0].aperture - 0.3 <= aperture && aperture <= vigdata[1].aperture + 0.3)
2334  {
2335  Vb1 = InterpolateValue(aperture, vigdata[0].aperture, vigdata[0].Vb, vigdata[1].aperture, vigdata[1].Vb);
2336  Vc1 = InterpolateValue(aperture, vigdata[0].aperture, vigdata[0].Vc, vigdata[1].aperture, vigdata[1].Vc);
2337  Vd1 = InterpolateValue(aperture, vigdata[0].aperture, vigdata[0].Vd, vigdata[1].aperture, vigdata[1].Vd);
2338  }
2339  else
2340  {
2341  return false;
2342  };
2343  if (vigdata[2].aperture - 0.3 <= aperture && aperture <= vigdata[3].aperture + 0.3)
2344  {
2345  Vb2 = InterpolateValue(aperture, vigdata[2].aperture, vigdata[2].Vb, vigdata[3].aperture, vigdata[3].Vb);
2346  Vc2 = InterpolateValue(aperture, vigdata[2].aperture, vigdata[2].Vc, vigdata[3].aperture, vigdata[3].Vc);
2347  Vd2 = InterpolateValue(aperture, vigdata[2].aperture, vigdata[2].Vd, vigdata[3].aperture, vigdata[3].Vd);
2348  }
2349  else
2350  {
2351  return false;
2352  };
2353  // now we have 2 values for the same aperture, but different focal length
2354  // interpolate focal length
2355  vignetting.push_back(1.0);
2356  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, Vb1, vigdata[2].focallength, Vb2));
2357  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, Vc1, vigdata[2].focallength, Vc2));
2358  vignetting.push_back(InterpolateValue(focal, vigdata[0].focallength, Vd1, vigdata[2].focallength, Vd2));
2359  return true;
2360  };
2361  };
2362  };
2363  };
2364 };
2365 
2366 bool LensDB::GetTCA(const std::string& lens, const double focal, std::vector<double>& tca_red, std::vector<double>& tca_blue) const
2367 {
2368  tca_red.clear();
2369  tca_blue.clear();
2370  if (m_db == NULL)
2371  {
2372  return false;
2373  };
2374  std::vector<Database::TCAdata> tcadata;
2375  if (!m_db->GetTCAData(lens, focal, tcadata))
2376  {
2377  return false;
2378  };
2379  if (tcadata.size() == 1)
2380  {
2381  // only one entry found
2382  // check focal length
2383  if (fabs(tcadata[0].focallength - focal) <= 0.075f * focal)
2384  {
2385  tca_red.push_back(tcadata[0].ra);
2386  tca_red.push_back(tcadata[0].rb);
2387  tca_red.push_back(tcadata[0].rc);
2388  tca_red.push_back(tcadata[0].rd);
2389  tca_blue.push_back(tcadata[0].ba);
2390  tca_blue.push_back(tcadata[0].bb);
2391  tca_blue.push_back(tcadata[0].bc);
2392  tca_blue.push_back(tcadata[0].bd);
2393  return true;
2394  }
2395  else
2396  {
2397  return false;
2398  };
2399  }
2400  else
2401  {
2402  if (!IsFocallengthNearRange(focal, tcadata[0].focallength, tcadata[1].focallength, 0.15f))
2403  {
2404  // difference to nearest point too big, ignoring
2405  return false;
2406  };
2407  tca_red.push_back(InterpolateValue(focal, tcadata[0].focallength, tcadata[0].ra, tcadata[1].focallength, tcadata[1].ra));
2408  tca_red.push_back(InterpolateValue(focal, tcadata[0].focallength, tcadata[0].rb, tcadata[1].focallength, tcadata[1].rb));
2409  tca_red.push_back(InterpolateValue(focal, tcadata[0].focallength, tcadata[0].rc, tcadata[1].focallength, tcadata[1].rc));
2410  tca_red.push_back(InterpolateValue(focal, tcadata[0].focallength, tcadata[0].rd, tcadata[1].focallength, tcadata[1].rd));
2411  tca_blue.push_back(InterpolateValue(focal, tcadata[0].focallength, tcadata[0].ba, tcadata[1].focallength, tcadata[1].ba));
2412  tca_blue.push_back(InterpolateValue(focal, tcadata[0].focallength, tcadata[0].bb, tcadata[1].focallength, tcadata[1].bb));
2413  tca_blue.push_back(InterpolateValue(focal, tcadata[0].focallength, tcadata[0].bc, tcadata[1].focallength, tcadata[1].bc));
2414  tca_blue.push_back(InterpolateValue(focal, tcadata[0].focallength, tcadata[0].bd, tcadata[1].focallength, tcadata[1].bd));
2415  return true;
2416  };
2417 };
2418 
2419 bool LensDB::GetLensNames(const bool distortion, const bool vignetting, const bool tca, LensList& lensList) const
2420 {
2421  lensList.clear();
2422  if (m_db == NULL)
2423  {
2424  return false;
2425  };
2426  return m_db->GetLensNames(distortion, vignetting, tca, lensList);
2427 };
2428 
2429 bool LensDB::SaveCameraCrop(const std::string& maker, const std::string& model, const double cropfactor)
2430 {
2431  if (m_db == NULL)
2432  {
2433  return false;
2434  };
2435  return m_db->SaveCropFactor(maker, model, cropfactor);
2436 };
2437 
2438 bool LensDB::SaveEMoR(const std::string& maker, const std::string& model, const int iso, const std::vector<float>& emor, const int weight)
2439 {
2440  if (m_db == NULL || emor.size() != 5)
2441  {
2442  return false;
2443  };
2444  return m_db->SaveEMoR(maker, model, iso, emor[0], emor[1], emor[2], emor[3], emor[4], weight);
2445 };
2446 
2447 bool LensDB::SaveLensProjection(const std::string& lens, const BaseSrcPanoImage::Projection projection)
2448 {
2449  if (m_db == NULL)
2450  {
2451  return false;
2452  };
2453  return m_db->SaveLensProjection(lens, projection);
2454 };
2455 
2456 bool LensDB::SaveLensCrop(const std::string& lens, const double focal, const vigra::Size2D& imageSize, const vigra::Rect2D& cropRect)
2457 {
2458  if (m_db == NULL)
2459  {
2460  return false;
2461  };
2462  if (cropRect.isEmpty())
2463  {
2464  return m_db->RemoveLensCrop(lens, focal, imageSize.width(), imageSize.height());
2465  }
2466  else
2467  {
2468  return m_db->SaveLensCrop(lens, focal, imageSize.width(), imageSize.height(), cropRect.left(), cropRect.right(), cropRect.top(), cropRect.bottom());
2469  };
2470 };
2471 
2472 bool LensDB::SaveLensFov(const std::string& lens, const double focal, const double fov, const int weight)
2473 {
2474  if (m_db == NULL)
2475  {
2476  return false;
2477  };
2478  return m_db->SaveHFOV(lens, focal, fov, weight);
2479 };
2480 
2481 bool LensDB::SaveDistortion(const std::string& lens, const double focal, const std::vector<double>& distortion, const int weight)
2482 {
2483  if (m_db == NULL || distortion.size()!=4)
2484  {
2485  return false;
2486  };
2487  return m_db->SaveDistortion(lens, focal, distortion[0], distortion[1], distortion[2], weight);
2488 };
2489 
2490 bool LensDB::SaveVignetting(const std::string& lens, const double focal, const double aperture, const double distance, const std::vector<double>& vignetting, const int weight)
2491 {
2492  if (m_db == NULL || vignetting.size()!=4)
2493  {
2494  return false;
2495  };
2496  return m_db->SaveVignetting(lens, focal, aperture, distance, vignetting[1], vignetting[2], vignetting[3], weight);
2497 };
2498 
2499 bool LensDB::SaveTCA(const std::string& lens, const double focal, const std::vector<double>& tca_red, const std::vector<double>& tca_blue, const int weight)
2500 {
2501  if (m_db == NULL || tca_red.size()!=4 || tca_blue.size()!=4)
2502  {
2503  return false;
2504  };
2505  return m_db->SaveTCAData(lens, focal, tca_red[0], tca_red[1], tca_red[2], tca_red[3], tca_blue[0], tca_blue[1], tca_blue[2], tca_blue[3], weight);
2506 };
2507 
2508 bool LensDB::CleanUpDatabase()
2509 {
2510  if (m_db == NULL)
2511  {
2512  return false;
2513  };
2514  return m_db->CleanUp();
2515 };
2516 
2517 bool LensDB::RemoveLens(const std::string& lensname)
2518 {
2519  if (m_db == NULL)
2520  {
2521  return false;
2522  };
2523  return m_db->RemoveLens(lensname);
2524 };
2525 
2526 bool LensDB::RemoveCamera(const std::string& maker, const std::string& model)
2527 {
2528  if (m_db == NULL)
2529  {
2530  return false;
2531  };
2532  return m_db->RemoveCamera(maker, model);
2533 };
2534 
2535 bool LensDB::ExportToFile(const std::string& filename)
2536 {
2537  if (m_db == NULL)
2538  {
2539  return false;
2540  };
2541  return m_db->ExportToFile(filename);
2542 };
2543 
2544 bool LensDB::ImportFromFile(const std::string& filename)
2545 {
2546  if (m_db == NULL)
2547  {
2548  return false;
2549  };
2550  return m_db->ImportFromFile(filename);
2551 };
2552 
2554 {
2555  if (pano.getNrOfImages() < 2)
2556  {
2557  // ignore project with only one image
2558  return false;
2559  };
2561  if (lenses.getLenses().getNumberOfParts() == 1)
2562  {
2563  const SrcPanoImage& img0 = pano.getImage(0);
2564  // if the HFOV for a rectilinear lens is too big, ignore this settings
2565  if (img0.getProjection() == BaseSrcPanoImage::RECTILINEAR && img0.getHFOV() > 110)
2566  {
2567  return false;
2568  };
2569  LensDB& lensDB = LensDB::GetSingleton();
2570  const std::string camMaker = img0.getExifMake();
2571  const std::string camModel = img0.getExifModel();
2572  if (!camMaker.empty() && !camModel.empty())
2573  {
2574  if (img0.getExifCropFactor() < 0.1f)
2575  {
2576  double cropFactor = img0.getCropFactor();
2577  if (cropFactor == 1 && img0.getExifFocalLength() > 0)
2578  {
2579  // a cropfactor of 1 can also mean unknown crop factor
2580  // so recalculate crop factor with HFOV and EXIF focal length
2581  cropFactor = HuginBase::SrcPanoImage::calcCropFactor(img0.getProjection(), img0.getHFOV(), img0.getExifFocalLength(), img0.getSize());
2582  if (std::abs(cropFactor - 1) < 0.1)
2583  {
2584  cropFactor = 1;
2585  };
2586  };
2587  lensDB.SaveCameraCrop(camMaker, camModel, cropFactor);
2588  };
2589  // now check EMoR parameters
2590  const std::vector<float> emor=img0.getEMoRParams();
2591  if (emor.size() == 5)
2592  {
2593  float sum = 0;
2594  for (size_t i = 0; i < 5; ++i)
2595  {
2596  sum += fabs(emor[i]);
2597  };
2598  if (sum>0.001)
2599  {
2600  lensDB.SaveEMoR(camMaker, camModel, img0.getExifISO(), emor);
2601  };
2602  };
2603  };
2604  const std::string lensname = img0.getDBLensName();
2605  const double focal = img0.getExifFocalLength();
2606  if (!lensname.empty() && focal > 0)
2607  {
2608  bool success = lensDB.SaveLensProjection(lensname, img0.getProjection());
2609  if (img0.getCropMode() == BaseSrcPanoImage::NO_CROP)
2610  {
2611  // pass empty Rect2D to remove crop information
2612  success = success | lensDB.SaveLensCrop(lensname, focal, img0.getSize(), vigra::Rect2D(0, 0, 0, 0));
2613  }
2614  else
2615  {
2616  const BaseSrcPanoImage::CropMode cropMode = img0.getCropMode();
2617  const vigra::Rect2D cropRect = img0.getCropRect();
2618  bool sameCrop = true;
2619  for (size_t i = 1; i < pano.getNrOfImages() && sameCrop; ++i)
2620  {
2621  const SrcPanoImage& img = pano.getImage(i);
2622  sameCrop = (img.getCropMode() == cropMode) && (img.getCropRect() == cropRect);
2623  };
2624  if (sameCrop)
2625  {
2626  success = success | lensDB.SaveLensCrop(lensname, focal, img0.getSize(), cropRect);
2627  };
2628  };
2629  double min;
2630  double max;
2631  double mean;
2632  double var;
2633  // update cp errors
2634  CalculateCPStatisticsError::calcCtrlPntsErrorStats(pano, min, max, mean, var);
2635  if (pano.getNrOfCtrlPoints() > 3 * pano.getNrOfImages() && mean < 15)
2636  {
2637  // save hfov and distortion only if error is small enough
2638  //@TODO add more robust check which takes also distribution of cp into account
2639  // recalculate to default aspect ratio of 3:2
2640  const double newFocallength = SrcPanoImage::calcFocalLength(img0.getProjection(), img0.getHFOV(), img0.getCropFactor(), img0.getSize());
2641  const double newHFOV = SrcPanoImage::calcHFOV(img0.getProjection(), newFocallength, img0.getCropFactor(), vigra::Size2D(3000, 2000));
2642  success = success | lensDB.SaveLensFov(lensname, focal, newHFOV);
2643  const std::vector<double> dist = img0.getRadialDistortion();
2644  if (dist.size() == 4)
2645  {
2646  // check if values are plausible
2647  if (fabs(dist[0]) + fabs(dist[1]) + fabs(dist[2])>0.001 &&
2648  fabs(dist[0] + dist[1] + dist[2]) < 0.1)
2649  {
2650  success = success | lensDB.SaveDistortion(lensname, focal, dist);
2651  };
2652  };
2653  };
2654  // check if aperture matches for all images
2655  bool sameAperture = true;
2656  for (size_t i = 1; i < pano.getNrOfImages() && sameAperture; ++i)
2657  {
2658  sameAperture = fabs(pano.getImage(i).getExifAperture() - img0.getExifAperture()) < 0.05;
2659  }
2660  // save vignetting data only if all images were shoot with same aperture
2661  if (sameAperture)
2662  {
2663  const std::vector<double> vigParam = img0.getRadialVigCorrCoeff();
2664  if (vigParam.size() == 4)
2665  {
2666  // now check, if the vignetting parameter are plausible
2667  const double sum = vigParam[0] + vigParam[1] + vigParam[2] + vigParam[3];
2668  if (sum>0.5 && sum <= 1.01)
2669  {
2670  success = success | lensDB.SaveVignetting(lensname, focal, img0.getExifAperture(), img0.getExifDistance(), vigParam);
2671  };
2672  };
2673  };
2674  return success;
2675  }
2676  else
2677  {
2678  return false;
2679  };
2680  };
2681  return false;
2682 };
2683 
2684 } //namespace LensDB
2685 } //namespace HuginBase
bool GetLensProjection(const std::string &lens, int &projection) const
Definition: LensDB.cpp:248
bool GetCropFactor(const std::string &maker, const std::string &model, double &cropFactor) const
Definition: LensDB.cpp:182
bool RemoveLensFromTable(const std::string &table, const std::string &lens)
Definition: LensDB.cpp:1014
bool ImportHFOV(std::istream &input)
Definition: LensDB.cpp:1203
bool FileExists(const std::string &filename)
checks if file exists
Definition: utils.cpp:362
bool SaveEMoR(const std::string &maker, const std::string &model, const int iso, const std::vector< float > &emor, const int weight=10)
save the camera with the given EMoR parameters into the database
Definition: LensDB.cpp:2438
bool SaveVignetting(const std::string &lens, const double focal, const double aperture, const double distance, const std::vector< double > &vignetting, const int weight=10)
saves the vignetting parameters of the lens
Definition: LensDB.cpp:2490
static LensDB * m_instance
Definition: LensDB.h:195
int roundi(T x)
Definition: hugin_math.h:73
bool SaveHFOV(const std::string &lens, const double focallength, const double HFOV, const int weight=10)
Definition: LensDB.cpp:329
bool RemoveLensCrop(const std::string &lens, const double focal, const int width, const int height)
Definition: LensDB.cpp:430
bool ImportVignetting(std::istream &input)
Definition: LensDB.cpp:1519
bool ExportToFile(const std::string &filename)
Definition: LensDB.cpp:789
bool GetVignettingData(const std::string &lens, const double focallength, const double aperture, std::vector< Vignettingdata > &vigData) const
Definition: LensDB.cpp:508
static double calcCropFactor(SrcPanoImage::Projection proj, double hfov, double focalLength, vigra::Size2D imageSize)
calculate crop factor, given focal length and hfov
std::string getDBLensName() const
constructs the lens name for the database it is the lensname if known, for compact cameras it is cons...
Somewhere to specify what variables belong to what.
static void calcCtrlPntsErrorStats(const PanoramaData &pano, double &min, double &max, double &mean, double &var, const int &imgNr=-1, const bool onlyActive=false, const bool ignoreLineCp=false)
void OutputSQLToStream(const std::string &sqlstatement, std::ostream &stream)
Definition: LensDB.cpp:1049
bool SaveLensCrop(const std::string &lens, const double focal, const int width, const int height, const int left, const int right, const int top, const int bottom)
Definition: LensDB.cpp:387
std::size_t getNrOfCtrlPoints() const
number of control points
Definition: Panorama.h:306
bool SaveLensDataFromPano(const HuginBase::Panorama &pano)
routine for automatically saving information from pano into database
Definition: LensDB.cpp:2553
static char * line
Definition: svm.cpp:2784
std::string GetDBFilename() const
Definition: LensDB.cpp:176
bool ImportDistortion(std::istream &input)
Definition: LensDB.cpp:1414
bool SaveLensCrop(const std::string &lens, const double focal, const vigra::Size2D &imageSize, const vigra::Rect2D &cropRect)
saves the crop information of the lens in the database the information for landscape and portrait ima...
Definition: LensDB.cpp:2456
bool SaveDistortion(const std::string &lens, const double focallength, const double a, const double b, const double c, const int weight=10)
Definition: LensDB.cpp:483
bool ImportEMOR(std::istream &input)
Definition: LensDB.cpp:1806
main database class
Definition: LensDB.h:44
bool SaveCameraCrop(const std::string &maker, const std::string &model, const double cropfactor)
save the camera with the given cropfactor into the database
Definition: LensDB.cpp:2429
class to access Hugins camera and lens database
int fsign(double a)
Definition: LensDB.cpp:2058
LensDB()
constructor
Definition: LensDB.cpp:1972
double HFOV
Model for a panorama.
Definition: Panorama.h:152
ConstImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
bool SaveLensProjection(const std::string &lens, const BaseSrcPanoImage::Projection projection)
saves the projection for the lens in the database
Definition: LensDB.cpp:2447
bool ImportFromFile(const std::string &filename)
Definition: LensDB.cpp:841
bool ImportLensCrop(std::istream &input)
Definition: LensDB.cpp:1287
Make an ImageVariableGroup for lenses and other common concepts.
double InterpolateValueTriangle(double x, double y, double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3)
Definition: LensDB.cpp:1958
bool stringToInt(const std::string &s, int &val)
convert string to integer value, returns true, if sucessful
Definition: utils.cpp:264
static double calcFocalLength(SrcPanoImage::Projection proj, double hfov, double crop, vigra::Size2D imageSize)
calcualte focal length, given crop factor and hfov
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
Definition: utils.h:114
bool GetLensCrop(const std::string &lens, const double focal, const int width, const int height, std::vector< CropData > &cropData) const
Definition: LensDB.cpp:356
double InterpolateValue(double x, double x0, double y0, double x1, double y1)
Definition: LensDB.cpp:1948
bool ImportTCA(std::istream &input)
Definition: LensDB.cpp:1646
bool GetLensNames(const bool distortion, const bool vignetting, const bool tca, LensList &lensList) const
Definition: LensDB.cpp:676
bool RemoveCameraFromTable(const std::string &table, const std::string &maker, const std::string &model)
Definition: LensDB.cpp:1031
Database(const std::string &filename)
Definition: LensDB.cpp:77
bool SaveLensProjection(const std::string &lens, const int projection)
Definition: LensDB.cpp:270
bool SaveVignetting(const std::string &lens, const double focallength, const double aperture, const double distance, const double Vb, const double Vc, const double Vd, const int weight=10)
Definition: LensDB.cpp:560
bool IsFocallengthNearRange(const double focal, const double limit1, const double limit2, const double tol)
check if value is inside limit1...limit2 or it is nearer to limit1 than value*tol ...
Definition: LensDB.cpp:2064
bool SaveDistortion(const std::string &lens, const double focal, const std::vector< double > &distortion, const int weight=10)
saves the distortion parameters of the lens in the database
Definition: LensDB.cpp:2481
static T max(T x, T y)
Definition: svm.cpp:65
std::string GetUserAppDataDir()
returns the directory for user specific Hugin settings, e.g.
Definition: utils.cpp:497
std::vector< std::string > LensList
vector storing a list of lens names
Definition: LensDB.h:41
static double calcHFOV(SrcPanoImage::Projection proj, double fl, double crop, vigra::Size2D imageSize)
calculate hfov of an image given focal length, image size and crop factor
bool GetTCAData(const std::string &lens, const double focallength, std::vector< TCAdata > &tcaData) const
Definition: LensDB.cpp:587
bool GetDistortionData(const std::string &lens, const double focallength, std::vector< Distortiondata > &distData) const
Definition: LensDB.cpp:455
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
bool GetHFOV(const std::string &lens, const double focallength, std::vector< HFOVData > &hfovData) const
Definition: LensDB.cpp:303
bool ImportCropFactor(std::istream &input)
Definition: LensDB.cpp:1075
std::vector< std::string > SplitString(const std::string &s, const std::string &sep)
split string s at given sep, returns vector of strings
Definition: utils.cpp:294
bool ImportProjection(std::istream &input)
Definition: LensDB.cpp:1144
std::size_t getNumberOfParts() const
get the number of parts.
All variables of a source image.
Definition: SrcPanoImage.h:194
bool RemoveLens(const std::string &lensname)
Definition: LensDB.cpp:759
bool SaveLensFov(const std::string &lens, const double focal, const double fov, const int weight=10)
saves the field of view of the lens the fov should always calculated for a landscape image with aspec...
Definition: LensDB.cpp:2472
bool SaveEMoR(const std::string &maker, const std::string &model, const int iso, const double Ra, const double Rb, const double Rc, const double Rd, const double Re, const int weight=10)
Definition: LensDB.cpp:650
bool SaveCropFactor(const std::string &maker, const std::string &model, const double cropFactor)
Definition: LensDB.cpp:209
bool RemoveCamera(const std::string &maker, const std::string &model)
Definition: LensDB.cpp:776
static T min(T x, T y)
Definition: svm.cpp:62
bool SaveTCAData(const std::string &lens, const double focallength, const double ra, const double rb, const double rc, const double rd, const double ba, const double bb, const double bc, const double bd, const int weight=10)
Definition: LensDB.cpp:620