1 // -*- c-basic-offset: 4 -*-
2
3 /** @file hugin_lensdb.cpp
4 *
5 * @brief helper program for working with lens database
6 *
7 *
8 * @author T. Modes
9 *
10 */
11
12 /* This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This software is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public
23 * License along with this software. If not, see
24 * <http://www.gnu.org/licenses/>.
25 *
26 */
27
28 #include <iostream>
29 #include <string>
30 #include <fstream>
31 #include "hugin_config.h"
32 #include <hugin_utils/filesystem.h>
33 #include <getopt.h>
34 #include <panodata/Panorama.h>
35 #include <hugin_utils/stl_utils.h>
36 #include <lensdb/LensDB.h>
37 #include <panodata/StandardImageVariableGroups.h>
38 #include <hugin_base/panotools/PanoToolsUtils.h>
39
40 typedef std::vector<fs::path> pathVec;
41
42
43 template <class iteratorType>
iterateFileSystem(std::string src,pathVec & projectFiles)44 bool iterateFileSystem(std::string src, pathVec& projectFiles)
45 {
46 try
47 {
48 for(iteratorType it(src); it != iteratorType(); it++)
49 {
50 std::string ext=hugin_utils::toupper(it->path().extension().string());
51 if(ext==".PTO")
52 {
53 projectFiles.push_back(*it);
54 };
55 }
56 }
57 catch(fs::filesystem_error& e)
58 {
59 std::cout << e.what() << std::endl;
60 return false;
61 }
62 return true;
63 };
64
FindPTOFiles(pathVec & projectFiles,std::string src,bool recursive)65 void FindPTOFiles(pathVec& projectFiles, std::string src, bool recursive)
66 {
67 if(recursive)
68 {
69 iterateFileSystem<fs::recursive_directory_iterator>(src, projectFiles);
70 }
71 else
72 {
73 iterateFileSystem<fs::directory_iterator>(src, projectFiles);
74 };
75 };
76
CheckProjectFile(const fs::path filename)77 bool CheckProjectFile(const fs::path filename)
78 {
79 // open project file
80 HuginBase::Panorama pano;
81 std::string input = filename.string();
82 std::ifstream prjfile(input.c_str());
83 if (!prjfile.good())
84 {
85 std::cerr << "ERROR: Could not open script: " << filename.string() << endl;
86 return false;
87 }
88 std::string inputPathPrefix = hugin_utils::getPathPrefix(input);
89 pano.setFilePrefix(inputPathPrefix);
90 AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile);
91 if (err != AppBase::DocumentData::SUCCESSFUL)
92 {
93 std::cerr << "ERROR: error while parsing panos tool script: " << input << std::endl
94 << "DocumentData::ReadWriteError code: " << err << std::endl;
95 return false;
96 };
97 prjfile.close();
98 if (pano.getNrOfImages() == 0)
99 {
100 return false;
101 };
102 std::cout << "Checking " << filename.string() << "..." << std::endl;
103 HuginBase::StandardImageVariableGroups lenses(pano);
104 if (lenses.getLenses().getNumberOfParts()==1)
105 {
106 // read the EXIF data
107 for (size_t i = 0; i < pano.getNrOfImages(); ++i)
108 {
109 HuginBase::SrcPanoImage img = pano.getSrcImage(i);
110 if (!img.readEXIF())
111 {
112 std::cout << " Ignored (File missing or missing metadata)" << std::endl;
113 return false;
114 }
115 pano.setSrcImage(i, img);
116 };
117 // update cp errors
118 HuginBase::PTools::calcCtrlPointErrors(pano);
119 // now save in database
120 if (HuginBase::LensDB::SaveLensDataFromPano(pano))
121 {
122 std::cout << " Saved." << std::endl;
123 return true;
124 }
125 else
126 {
127 std::cout << " Ignored." << std::endl;
128 return false;
129 }
130 };
131 std::cout << " Ignored (More than one lens)." << std::endl;
132 return false;
133 };
134
usage(const char * name)135 static void usage(const char* name)
136 {
137 std::cout << name << ": tool for lens database maintenance" << std::endl
138 << name << " version " << hugin_utils::GetHuginVersion() << std::endl
139 << std::endl
140 << "Usage: hugin_lensdb [--recursive] --populate BASEPATH " << std::endl
141 << " Populate database with information from all pto files" << std::endl
142 << " in given BASEPATH" << std::endl
143 << " With --recursive switch all subfolders will also be" << std::endl
144 << " searched." << std::endl
145 << " hugin_lensdb --compress" << std::endl
146 << " Compresses the database by replacing single values" << std::endl
147 << " with averaged values." << std::endl
148 << " hugin_lensdb --remove-lens=LENS" << std::endl
149 << " Removes given lens from the database." << std::endl
150 << " hugin_lensdb --remove-camera=MAKER|MODEL" << std::endl
151 << " Removes given camera from the database." << std::endl
152 << " hugin_lensdb --export-database=FILENAME" << std::endl
153 << " Export data from database to external file." << std::endl
154 << " hugin_lensdb --import-from-file=FILENAME" << std::endl
155 << " Import data from external file." << std::endl
156 << std::endl;
157 };
158
main(int argc,char * argv[])159 int main(int argc, char* argv[])
160 {
161 // parse arguments
162 const char* optstring = "crph";
163 enum
164 {
165 REMOVE_LENS=1000,
166 REMOVE_CAM=1001,
167 EXPORT_DB=1002,
168 IMPORT_DB=1003,
169 };
170
171 static struct option longOptions[] =
172 {
173 { "compress", no_argument, NULL, 'c' },
174 { "recursive", no_argument, NULL, 'r' },
175 { "populate", required_argument, NULL, 'p' },
176 { "remove-lens", required_argument, NULL, REMOVE_LENS },
177 { "remove-camera", required_argument, NULL, REMOVE_CAM },
178 { "export-database", required_argument, NULL, EXPORT_DB },
179 { "import-from-file", required_argument, NULL, IMPORT_DB },
180 { "help", no_argument, NULL, 'h' },
181 0
182 };
183
184 bool recursive=false;
185 bool populate = false;
186 bool compress = false;
187 std::string basepath;
188 std::string lensToRemove;
189 std::string camToRemove;
190 std::string exportDatabase;
191 std::string importDatabase;
192 int c;
193 while ((c = getopt_long (argc, argv, optstring, longOptions,nullptr)) != -1)
194 {
195 switch (c)
196 {
197 case 'h':
198 usage(hugin_utils::stripPath(argv[0]).c_str());
199 return 0;
200 case 'c':
201 compress=true;
202 break;
203 case 'r':
204 recursive=true;
205 break;
206 case 'p':
207 populate = true;
208 basepath = hugin_utils::StrTrim(std::string(optarg));
209 break;
210 case REMOVE_LENS:
211 lensToRemove = hugin_utils::StrTrim(std::string(optarg));
212 break;
213 case REMOVE_CAM:
214 camToRemove = hugin_utils::StrTrim(std::string(optarg));
215 break;
216 case EXPORT_DB:
217 exportDatabase = hugin_utils::StrTrim(std::string(optarg));
218 break;
219 case IMPORT_DB:
220 importDatabase = hugin_utils::StrTrim(std::string(optarg));
221 break;
222 case ':':
223 case '?':
224 // missing argument or invalid switch
225 return 1;
226 break;
227 default:
228 // this should not happen
229 abort();
230 }
231 }
232
233 if (!exportDatabase.empty() && !importDatabase.empty())
234 {
235 std::cerr << hugin_utils::stripPath(argv[0]) << ": Export and import can not be done at the same time. " << std::endl;
236 return -1;
237 };
238
239 if (!populate && !compress && lensToRemove.empty() && camToRemove.empty() && exportDatabase.empty() && importDatabase.empty())
240 {
241 std::cout << "Lensdatabase file: " << HuginBase::LensDB::LensDB::GetSingleton().GetDBFilename() << std::endl;
242 std::cout << "Nothing to do." << std::endl;
243 };
244
245 if (populate)
246 {
247 fs::path p(basepath);
248 if (fs::exists(p))
249 {
250 p = fs::absolute(p);
251 if (fs::is_directory(p))
252 {
253 pathVec projectFiles;
254 FindPTOFiles(projectFiles, p.string(), recursive);
255 if (projectFiles.empty())
256 {
257 std::cerr << "ERROR: No project files found in given directory " << p.string() << std::endl;
258 return 1;
259 };
260 for (pathVec::const_iterator it = projectFiles.begin(); it != projectFiles.end(); ++it)
261 {
262 CheckProjectFile(*it);
263 };
264 }
265 else
266 {
267 std::cerr << "ERROR: " << basepath << " is not a directory." << std::endl;
268 return 1;
269 };
270 }
271 else
272 {
273 std::cerr << "ERROR: Path " << basepath << " does not exists." << std::endl;
274 return 1;
275 }
276 };
277
278 if (compress)
279 {
280 std::cout << "Compressing database..." << std::endl;
281 if(HuginBase::LensDB::LensDB::GetSingleton().CleanUpDatabase())
282 {
283 std::cout << "Successful." << std::endl;
284 }
285 else
286 {
287 std::cout << "FAILED." << std::endl;
288 }
289 };
290 // remove lens
291 if (!lensToRemove.empty())
292 {
293 std::cout << "Removing lens \"" << lensToRemove << "\"..." << std::endl;
294 if (HuginBase::LensDB::LensDB::GetSingleton().RemoveLens(lensToRemove))
295 {
296 std::cout << "Successful." << std::endl;
297 }
298 else
299 {
300 std::cout << "FAILED." << std::endl;
301 }
302 };
303 // remove camera
304 if (!camToRemove.empty())
305 {
306 std::vector<std::string> input = hugin_utils::SplitString(camToRemove, "|");
307 if (input.size() == 2)
308 {
309 std::cout << "Removing camera \"" << input[1] << "\" (Maker: \"" << input[0] << "\")..." << std::endl;
310 if (HuginBase::LensDB::LensDB::GetSingleton().RemoveCamera(input[0], input[1]))
311 {
312 std::cout << "Successful." << std::endl;
313 }
314 else
315 {
316 std::cout << "FAILED." << std::endl;
317 }
318 }
319 else
320 {
321 std::cout << "\"" << camToRemove << "\" is not a valid string for the camera." << std::endl
322 << " Use syntax MAKER|MODEL (separate camera maker and model by |)" << std::endl;
323 };
324 };
325 // export database
326 if (!exportDatabase.empty())
327 {
328 std::cout << "Exporting database to \"" << exportDatabase << "\"..." << std::endl;
329 if (HuginBase::LensDB::LensDB::GetSingleton().ExportToFile(exportDatabase))
330 {
331 std::cout << "Successful." << std::endl;
332 }
333 else
334 {
335 std::cout << "FAILED." << std::endl;
336 };
337 };
338 // import database
339 if (!importDatabase.empty())
340 {
341 std::cout << "Importing data from \"" << importDatabase << "\"..." << std::endl;
342 if (HuginBase::LensDB::LensDB::GetSingleton().ImportFromFile(importDatabase))
343 {
344 std::cout << "Successful." << std::endl;
345 }
346 else
347 {
348 std::cout << "FAILED." << std::endl;
349 };
350 };
351 HuginBase::LensDB::LensDB::Clean();
352 return 0;
353 }
354