Hugin trunk 0.1
Loading...
Searching...
No Matches
PapywizardImport.cpp
Go to the documentation of this file.
1
9/* This is free software; you can redistribute it and/or
10* modify it under the terms of the GNU General Public
11* License as published by the Free Software Foundation; either
12* version 2 of the License, or (at your option) any later version.
13*
14* This software is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17* Lesser General Public License for more details.
18*
19* You should have received a copy of the GNU General Public
20* License along with this software. If not, see
21* <http://www.gnu.org/licenses/>.
22*
23*/
24
25#include "panoinc_WX.h"
26#include "PapywizardImport.h"
27
28#include "hugin_utils/utils.h"
29#include <wx/xml/xml.h>
30#include <wx/msgdlg.h>
31#include <wx/stdpaths.h>
32#include "hugin/huginApp.h"
34#include "base_wx/PanoCommand.h"
35#include "base_wx/platform.h"
36#include "base_wx/wxutils.h"
41
42namespace Papywizard
43{
44
47{
48public:
49 // read from header
51 double cropfactor;
53 // read from shoot section
55 {
56 size_t id;
57 size_t bracket;
58 double yaw, pitch, roll;
59 };
60
61 std::vector<PapywizardImage> images;
69
70 bool HasBracketImages() const
71 {
72 for (size_t i = 0; i < images.size(); ++i)
73 {
74 if (images[i].bracket > 1)
75 {
76 return true;
77 };
78 };
79 return false;
80 };
81};
82
85{
86 wxXmlNode* child = root->GetChildren();
87 while (child)
88 {
89 // section <camera>
90 if (child->GetName().CmpNoCase("camera") == 0)
91 {
92 wxXmlNode* camChild = child->GetChildren();
93 while (camChild)
94 {
95 // crop factor is saved as attribute in <sensor>
96 if (camChild->GetName().CmpNoCase("sensor") == 0)
97 {
99 if (camChild->GetAttribute("coef", &number))
100 {
101 if (!hugin_utils::stringToDouble(std::string(number.mb_str(wxConvLocal)), images.cropfactor))
102 {
103 return false;
104 };
105 };
106 }
107 camChild = camChild->GetNext();
108 }
109 }
110 // section <lens>
111 if (child->GetName().CmpNoCase("lens") == 0)
112 {
113 // projection as type attribute
114 wxString projection = child->GetAttribute("type", wxEmptyString).Trim().Trim(false);
115 if (!projection.empty())
116 {
117 if (projection.CmpNoCase("rectilinear") == 0)
118 {
120 }
121 else
122 {
123 if (projection.CmpNoCase("fisheye") == 0)
124 {
126 }
127 else
128 {
129 return false;
130 };
131 };
132 };
133 // focal length as own element
134 wxXmlNode* lensChild = child->GetChildren();
135 while (lensChild)
136 {
137 if (lensChild->GetName().CmpNoCase("focal") == 0)
138 {
139 wxString focallength = lensChild->GetNodeContent().Trim().Trim(false);
140 if(!hugin_utils::stringToDouble(std::string(focallength.mb_str(wxConvLocal)), images.focallength))
141 {
142 return false;
143 };
144 }
145 lensChild = lensChild->GetNext();
146 }
147 };
148 child = child->GetNext();
149 };
150 return true;
151};
152
155{
156 wxXmlNode* child = root->GetChildren();
157 size_t id = 1;
158 while (child)
159 {
160 if (child->GetName().CmpNoCase("pict") == 0)
161 {
163 long longVal;
164 wxString s;
165#ifdef PAPYWIZARD_USE_ID_CHECK
166 // according to the spec the id should be unique
167 // but not all programs write the id in this way
168 // e.g. PCPano is using the same id for each image in a bracket
169 // see https://bugs.launchpad.net/hugin/+bug/1840110
170 // so the check id code is disabled for now
171 // so activate the check again define PAPYWIZARD_USE_ID_CHECK
172 if (!child->GetAttribute("id", &s))
173 {
174 return false;
175 };
176 if (!s.ToLong(&longVal))
177 {
178 return false;
179 };
180 if (longVal < id)
181 {
182 return false;
183 };
184 image.id = longVal;
185#else
186 // instead simply store a continous id
187 image.id = id;
188#endif
189 ++id;
190 // read bracket attribute
191 if(!child->GetAttribute("bracket", &s))
192 {
193 return false;
194 };
195 if (!s.ToLong(&longVal))
196 {
197 return false;
198 };
199 image.bracket = longVal;
200 // now parse all position entries
201 wxXmlNode* posChild = child->GetChildren();
202 while (posChild)
203 {
204 if (posChild->GetName().CmpNoCase("position") == 0)
205 {
206 if (!posChild->GetAttribute("yaw", &s))
207 {
208 return false;
209 };
210 if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.yaw))
211 {
212 return false;
213 };
214 if (!posChild->GetAttribute("pitch", &s))
215 {
216 return false;
217 }
218 if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.pitch))
219 {
220 return false;
221 };
222 if (!posChild->GetAttribute("roll", &s))
223 {
224 return false;
225 };
226 if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.roll))
227 {
228 return false;
229 };
230 images.images.push_back(image);
231 // we are ignoring all further entries
232 break;
233 };
234 posChild = posChild->GetNext();
235 };
236 };
237 child = child->GetNext();
238 };
239 return true;
240};
241
242bool ParsePapywizardFile(const wxString& filename, PapywizardSettings& images)
243{
245 if (!xmlFile.Load(filename))
246 {
247 return false;
248 }
249 if (xmlFile.GetRoot()->GetName().CmpNoCase("papywizard") != 0)
250 {
251 // not a papywizard file
252 return false;
253 };
254 // iterate all children
255 wxXmlNode* child = xmlFile.GetRoot()->GetChildren();
256 while (child)
257 {
258 if (child->GetName().CmpNoCase("header") == 0)
259 {
260 if (!ParseHeader(child, images))
261 {
262 return false;
263 };
264 };
265 if (child->GetName().CmpNoCase("shoot") == 0)
266 {
267 if (!ParseShoot(child, images))
268 {
269 return false;
270 };
271 }
272 child = child->GetNext();
273 }
274 return true;
275};
276
277class PapywizardImportDialog: public wxDialog
278{
279public:
282 {
283 wxXmlResource::Get()->LoadDialog(this, parent, "papywizard_import_dialog");
284
285 m_linkPos = XRCCTRL(*this, "papywizard_link_positions", wxCheckBox);
286 m_cpfind = XRCCTRL(*this, "papywizard_cpfind", wxCheckBox);
288 m_cpfindParams = XRCCTRL(*this, "papywizard_cpfind_parameters", wxTextCtrl);
289 m_geocpset = XRCCTRL(*this, "papywizard_geocpset", wxCheckBox);
290 const wxString cpfindParams = wxConfig::Get()->Read("/PapywizardImportCpfind", wxEmptyString);
291 m_cpfindParams->SetValue(cpfindParams);
292 hugin_utils::RestoreFramePosition(this, "PapywizardImportDialog");
293 };
296 {
297 hugin_utils::StoreFramePosition(this, "PapywizardImportDialog");
298 if (m_cpfind->IsChecked())
299 {
300 wxConfig::Get()->Write("/PapywizardImportCpfind", m_cpfindParams->GetValue());
301 };
302 };
303 void EnableStack(const bool hasStacks)
304 {
305 m_linkPos->Enable(hasStacks);
306 m_linkPos->SetValue(hasStacks);
307 };
308 const bool LinkStacks() const
309 {
310 return m_linkPos->IsEnabled() && m_linkPos->IsChecked();
311 };
312 const bool RunCpfind() const
313 {
314 return m_cpfind->IsChecked();
315 };
317 {
318 return m_cpfindParams->GetValue();
319 };
320 const bool RunGeocpset() const
321 {
322 return m_geocpset->IsEnabled() && m_geocpset->IsChecked();
323 };
324protected:
325 void OnCpfindCheck(wxCommandEvent& e)
326 {
327 const bool cpfindActive = m_cpfind->IsChecked();
329 m_geocpset->Enable(cpfindActive);
330 };
331private:
334 wxTextCtrl* m_cpfindParams;
336};
337
339{
341 if (!ParsePapywizardFile(filename, papyImages))
342 {
343 hugin_utils::HuginMessageBox(wxString::Format(_("Could not parse file %s as Papywizard XML file."), filename),
344 _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
345 return false;
346 };
347 // check if number of images matches
348 if(papyImages.images.size()!=pano.getNrOfImages())
349 {
350 hugin_utils::HuginMessageBox(wxString::Format(_("The current project does not match with the Papywizard xml file.\nThe Papywizard file \"%s\" contains %lu images, but the Hugin project contains %lu images."), filename.c_str(), static_cast<unsigned long>(papyImages.images.size()), static_cast<unsigned long>(pano.getNrOfImages())),
351 _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
352 return false;
353 };
355 dialog.EnableStack(papyImages.HasBracketImages());
356 if(dialog.ShowModal()!=wxID_OK)
357 {
358 return false;
359 };
360 // now we can build all commands
361 std::vector<PanoCommand::PanoCommand *> commands;
362 HuginBase::UIntSet images;
363 fill_set(images, 0, pano.getNrOfImages() - 1);
364 // all images share the same lens
366 commands.push_back(new PanoCommand::ChangeImageProjectionCmd(pano, images, papyImages.projection));
367 if (papyImages.focallength > 0)
368 {
369 commands.push_back(new PanoCommand::UpdateCropFactorCmd(pano, images, papyImages.cropfactor));
370 commands.push_back(new PanoCommand::UpdateFocalLengthCmd(pano, images, papyImages.focallength));
371 };
372 // remove all existing stacks
373 for (size_t i = 1; i < pano.getNrOfImages(); i++)
374 {
376 imgs.insert(i);
378 };
379 // create stacks
380 if (papyImages.HasBracketImages())
381 {
382 size_t stackNr = 0;
383 size_t imgNr = 0;
384 while (imgNr < pano.getNrOfImages())
385 {
387 do
388 {
389 imgs.insert(imgNr);
390 imgNr++;
391 } while (imgNr < pano.getNrOfImages() && papyImages.images[imgNr].bracket != 1);
393 stackNr++;
394 };
395 // unlink position if wished by user
396 if (!dialog.LinkStacks())
397 {
398 std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> variables;
399 variables.insert(HuginBase::ImageVariableGroup::IVE_Yaw);
400 variables.insert(HuginBase::ImageVariableGroup::IVE_Pitch);
401 variables.insert(HuginBase::ImageVariableGroup::IVE_Roll);
402 variables.insert(HuginBase::ImageVariableGroup::IVE_X);
403 variables.insert(HuginBase::ImageVariableGroup::IVE_Y);
404 variables.insert(HuginBase::ImageVariableGroup::IVE_Z);
405 variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlaneYaw);
406 variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlanePitch);
407 commands.push_back(new PanoCommand::ChangePartImagesLinkingCmd(pano, images, variables, false, HuginBase::StandardImageVariableGroups::getStackVariables()));
408 }
409 };
410 // now set the positions
412 for (size_t i = 0; i < papyImages.images.size(); ++i)
413 {
414 map_get(variables[i], "y").setValue(papyImages.images[i].yaw);
415 map_get(variables[i], "p").setValue(papyImages.images[i].pitch);
416 map_get(variables[i], "r").setValue(papyImages.images[i].roll);
417 map_get(variables[i], "TrX").setValue(0);
418 map_get(variables[i], "TrY").setValue(0);
419 map_get(variables[i], "TrZ").setValue(0);
420 map_get(variables[i], "Tpy").setValue(0);
421 map_get(variables[i], "Tpp").setValue(0);
422 // fov gets updated when focal length is set, this has not yet been happen
423 // so remove fov from list to prevent overwritting with old value, because
424 // variables have not yet been updated yet
425 variables[i].erase("v");
426 };
427 commands.push_back(new PanoCommand::UpdateVariablesCmd(pano, variables));
429
430 // now create the cp
431 if (dialog.RunCpfind())
432 {
433 //save project into temp directory
434 wxString tempDir = wxConfig::Get()->Read("tempDir", wxEmptyString);
435 if (!tempDir.IsEmpty())
436 {
437 if (tempDir.Last() != wxFileName::GetPathSeparator())
438 {
439 tempDir.Append(wxFileName::GetPathSeparator());
440 }
441 };
442 wxFileName scriptFileName(wxFileName::CreateTempFileName(tempDir + "hp"));
443 const std::string scriptString(scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
445 // build command queue
446 const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
450 dialog.GetCPFindParam() + " --prealigned -o " + quotedProject + " " + quotedProject, _("Searching for control points...")));
451 if (dialog.RunGeocpset())
452 {
454 "-o " + quotedProject + " " + quotedProject, _("Connecting overlapping images")));
455 };
456 //execute queue
457 MyExecuteCommandQueue(commands, wxGetActiveWindow(), _("Searching control points"));
458 //read back panofile
460 (const char *)scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME),
462 false, false));
463 //delete temporary files
464 wxRemoveFile(scriptFileName.GetFullPath());
465 };
466 return true;
467}
468
469} // namespace Papywizard
470
int MyExecuteCommandQueue(HuginQueue::CommandQueue *queue, wxWindow *parent, const wxString &title, const wxString &comment)
execute all commands in queue with redirection of output to frame and allow canceling the queue will ...
read settings from papywizard xml file
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getLensVariables()
Get the set of lens image variables.
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getStackVariables()
Get the set of stack image variables.
Model for a panorama.
Definition Panorama.h:153
VariableMapVector getVariables() const
get variables of this panorama
Definition Panorama.cpp:118
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
normal command for queue, processing is stopped if an error occurred in program
Definition Executor.h:38
Change the linking of some variables across parts of an ImageVariableGroup containing some specified ...
Switch the part number of an image.
PanoCommand to combine other PanoCommands.
Definition PanoCommand.h:40
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
static GlobalCmdHist & getInstance()
Make a new part in a ImageVariableGroup for a set of images, given the variables that make up the gro...
Update the crop factor.
Update the focal length.
dump the current project and load a new one.
~PapywizardImportDialog()
destructor, save settings
void EnableStack(const bool hasStacks)
PapywizardImportDialog(wxWindow *parent)
Constructor, read from xrc ressource.
class which holds all read settings from a Papywizard xml file
HuginBase::SrcPanoImage::Projection projection
std::vector< PapywizardImage > images
PapywizardSettings()
constructor, initialize some values
implementation of huginApp Class
#define HUGIN_CONV_FILENAME
Definition platform.h:40
std::vector< VariableMap > VariableMapVector
std::set< unsigned int > UIntSet
str wxEscapeFilename(const str &arg)
special escaping routine for CommandQueues
Definition Executor.h:79
std::vector< NormalCommand * > CommandQueue
Definition Executor.h:61
wxString GetInternalProgram(const wxString &bindir, const wxString &name)
return path and name of external program, which comes bundled with Hugin
Definition Executor.cpp:129
bool ImportPapywizardFile(const wxString &filename, HuginBase::Panorama &pano)
import the settings from given filename into pano
bool ParseShoot(wxXmlNode *root, PapywizardSettings &images)
parse shoot section of papywizard file
bool ParseHeader(wxXmlNode *root, PapywizardSettings &images)
parse header of papywizard file
bool ParsePapywizardFile(const wxString &filename, PapywizardSettings &images)
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:176
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
Definition utils.h:114
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:106
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition utils.cpp:184
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:67
include file for the hugin project
Map::mapped_type & map_get(Map &m, const typename Map::key_type &key)
get a map element.
Definition stl_utils.h:98
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition stl_utils.h:81
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
wxwindows specific panorama commands