Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CPEditorPanel.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
27 #include "hugin_config.h"
28 
29 // often necessary before panoinc.h
30 #include "panoinc_WX.h"
31 // standard hugin include
32 #include "panoinc.h"
33 // both includes above need to come before other wx includes on OSX
34 
35 // hugin's
36 #include "hugin/huginApp.h"
37 #include "hugin/config_defaults.h"
38 #include "base_wx/CommandHistory.h"
39 #include "base_wx/wxImageCache.h"
40 #include "hugin/CPImageCtrl.h"
42 #include "hugin/CPEditorPanel.h"
43 #include "base_wx/wxPanoCommand.h"
47 #include "base_wx/PTWXDlg.h"
48 #include "base_wx/wxPlatform.h"
49 #include "base_wx/wxutils.h"
50 
51 // more standard includes if needed
52 #include <algorithm>
53 #include <float.h>
54 #include <vector>
55 
56 // more vigra include if needed
57 #include "vigra/cornerdetection.hxx"
58 #include "vigra/localminmax.hxx"
59 #include "vigra_ext/openmp_vigra.h"
60 #include "vigra_ext/Correlation.h"
61 #include "vigra_ext/cms.h"
62 
63 // Celeste header
64 #include "Celeste.h"
65 
67 {
68  DEBUG_TRACE("**********************");
69  m_pano = 0;
70  m_countCP = 0;
71 }
72 
73 bool CPEditorPanel::Create(wxWindow* parent, wxWindowID id,
74  const wxPoint& pos,
75  const wxSize& size,
76  long style,
77  const wxString& name)
78 {
79  DEBUG_TRACE(" Create called *************");
80  if (! wxPanel::Create(parent, id, pos, size, style, name) ) {
81  return false;
82  }
83 
85  m_leftImageNr=UINT_MAX;
86  m_rightImageNr=UINT_MAX;
89  m_selectedPoint=UINT_MAX;
93 
94  DEBUG_TRACE("");
95  wxXmlResource::Get()->LoadPanel(this, "cp_editor_panel");
96  wxPanel * panel = XRCCTRL(*this, "cp_editor_panel", wxPanel);
97 
98  wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
99  topsizer->Add(panel, 1, wxEXPAND, 0);
100 
101  m_leftChoice = XRCCTRL(*this, "cp_editor_left_choice", CPImagesComboBox);
102  m_leftChoice->Bind(wxEVT_COMBOBOX, &CPEditorPanel::OnLeftChoiceChange, this);
103  m_leftImg = XRCCTRL(*this, "cp_editor_left_img", CPImageCtrl);
104  assert(m_leftImg);
105  m_leftImg->Init(this);
108 
109  // right image
110  m_rightChoice = XRCCTRL(*this, "cp_editor_right_choice", CPImagesComboBox);
111  m_rightChoice->Bind(wxEVT_COMBOBOX, &CPEditorPanel::OnRightChoiceChange, this);
112  m_rightImg = XRCCTRL(*this, "cp_editor_right_img", CPImageCtrl);
113  assert(m_rightImg);
114  m_rightImg->Init(this);
117 
118  // setup list view
119  m_cpList = XRCCTRL(*this, "cp_editor_cp_list", wxListCtrl);
120  m_cpList->InsertColumn( 0, _("#"), wxLIST_FORMAT_RIGHT, 35);
121  m_cpList->InsertColumn( 1, _("left x"), wxLIST_FORMAT_RIGHT, 65);
122  m_cpList->InsertColumn( 2, _("left y"), wxLIST_FORMAT_RIGHT, 65);
123  m_cpList->InsertColumn( 3, _("right x"), wxLIST_FORMAT_RIGHT, 65);
124  m_cpList->InsertColumn( 4, _("right y"), wxLIST_FORMAT_RIGHT, 65);
125  m_cpList->InsertColumn( 5, _("Alignment"), wxLIST_FORMAT_LEFT,110 );
126  m_cpList->InsertColumn( 6, _("Distance"), wxLIST_FORMAT_RIGHT, 110);
127  m_cpList->Bind(wxEVT_CHAR, &CPEditorPanel::OnKey, this);
128  m_cpList->Bind(wxEVT_LIST_ITEM_SELECTED, &CPEditorPanel::OnCPListSelect, this);
129  m_cpList->Bind(wxEVT_LIST_ITEM_DESELECTED, &CPEditorPanel::OnCPListDeselect, this);
130  m_cpList->Bind(wxEVT_LIST_COL_END_DRAG, &CPEditorPanel::OnColumnWidthChange, this);
131  m_cpList->Bind(wxEVT_LIST_COL_CLICK, &CPEditorPanel::OnColumnHeaderClick, this);
132 
133  //get saved width
134  wxConfigBase* config = wxConfig::Get();
135  for ( int j=0; j < m_cpList->GetColumnCount() ; j++ )
136  {
137  // -1 is auto
138  int width = config->Read(wxString::Format( "/CPEditorPanel/ColumnWidth%d", j ), -1);
139  if(width != -1)
140  m_cpList->SetColumnWidth(j, width);
141  }
142  m_sortCol = config->Read("/CPEditorPanel/SortColumn", -1);
143  m_sortAscending = config->Read("/CPEditorPanel/SortAscending", 1) == 1 ? true : false;
144  if (m_sortCol != -1)
145  {
146  m_cpList->ShowSortIndicator(m_sortCol, m_sortAscending);
147  };
148 
149  // other controls
150  m_x1Text = XRCCTRL(*this,"cp_editor_x1", wxTextCtrl);
151  m_x1Text->PushEventHandler(new TextKillFocusHandler(this));
152  m_x1Text->Bind(wxEVT_TEXT_ENTER, &CPEditorPanel::OnTextPointChange, this);
153  m_y1Text = XRCCTRL(*this,"cp_editor_y1", wxTextCtrl);
154  m_y1Text->PushEventHandler(new TextKillFocusHandler(this));
155  m_y1Text->Bind(wxEVT_TEXT_ENTER, &CPEditorPanel::OnTextPointChange, this);
156  m_x2Text = XRCCTRL(*this,"cp_editor_x2", wxTextCtrl);
157  m_x2Text->PushEventHandler(new TextKillFocusHandler(this));
158  m_x2Text->Bind(wxEVT_TEXT_ENTER, &CPEditorPanel::OnTextPointChange, this);
159  m_y2Text = XRCCTRL(*this,"cp_editor_y2", wxTextCtrl);
160  m_y2Text->PushEventHandler(new TextKillFocusHandler(this));
161  m_y2Text->Bind(wxEVT_TEXT_ENTER, &CPEditorPanel::OnTextPointChange, this);
162 
163  m_cpModeChoice = XRCCTRL(*this, "cp_editor_mode", wxChoice);
164  m_cpModeChoice->Bind(wxEVT_CHOICE, &CPEditorPanel::OnTextPointChange, this);
165  m_addButton = XRCCTRL(*this, "cp_editor_add", wxButton);
166  m_addButton->Bind(wxEVT_BUTTON, &CPEditorPanel::OnAddButton, this);
167  m_delButton = XRCCTRL(*this, "cp_editor_delete", wxButton);
168  m_delButton->Bind(wxEVT_BUTTON, &CPEditorPanel::OnDeleteButton, this);
169 
170  m_autoAddCB = XRCCTRL(*this,"cp_editor_auto_add", wxCheckBox);
172  m_fineTuneCB = XRCCTRL(*this,"cp_editor_fine_tune_check",wxCheckBox);
174 
175  m_estimateCB = XRCCTRL(*this,"cp_editor_auto_estimate", wxCheckBox);
177 
178  m_showLinesCB = XRCCTRL(*this, "cp_editor_show_lines", wxCheckBox);
180  m_showLinesCB->Bind(wxEVT_CHECKBOX, &CPEditorPanel::OnShowLinesCheckbox, this);
181 
182  m_finetuneButton = XRCCTRL(*this, "cp_editor_finetune_button", wxButton);
183  m_finetuneButton->Bind(wxEVT_BUTTON, &CPEditorPanel::OnFineTuneButton, this);
184  m_prevImgButton = XRCCTRL(*this, "cp_editor_previous_img", wxButton);
185  m_prevImgButton->Bind(wxEVT_BUTTON, &CPEditorPanel::OnPrevImg, this);
186  m_nextImgButton = XRCCTRL(*this, "cp_editor_next_img", wxButton);
187  m_nextImgButton->Bind(wxEVT_BUTTON, &CPEditorPanel::OnNextImg, this);
188 
189  m_actionButton = XRCCTRL(*this, "cp_editor_action_button", wxButton);
190  m_actionButton->Bind(wxEVT_CONTEXT_MENU, &CPEditorPanel::OnActionContextMenu, this);
191  m_actionButton->Bind(wxEVT_BUTTON, &CPEditorPanel::OnActionButton, this);
192  m_cpActionContextMenu = wxXmlResource::Get()->LoadMenu("cp_menu_action");
193  // setup scroll window for the controls under the images
194  m_cp_ctrls = XRCCTRL(*this, "cp_controls_panel", wxPanel);
196 
197  m_zoomChoice = XRCCTRL(*this, "cp_editor_choice_zoom", wxChoice);
198  m_zoomChoice->Bind(wxEVT_CHOICE, &CPEditorPanel::OnZoom, this);
199 
200  m_autoAddCB->SetValue(config->Read("/CPEditorPanel/autoAdd",0l) != 0 );
201  m_fineTuneCB->SetValue(config->Read("/CPEditorPanel/autoFineTune",1l) != 0 );
202  m_estimateCB->SetValue(config->Read("/CPEditorPanel/autoEstimate",1l) != 0 );
203  m_showLinesCB->SetValue(config->Read("/CPEditorPanel/showLines", 1l) != 0);
204  m_leftImg->ShowLines(m_showLinesCB->IsChecked());
205  m_rightImg->ShowLines(m_showLinesCB->IsChecked());
206 
207  // disable controls by default
208  m_cpModeChoice->Disable();
209  m_addButton->Disable();
210  m_delButton->Disable();
211  m_autoAddCB->Disable();
212  m_fineTuneCB->Disable();
213  m_estimateCB->Disable();
214  m_showLinesCB->Disable();
215  m_finetuneButton->Disable();
216  m_actionButton->Disable();
217  m_zoomChoice->Disable();
218  m_prevImgButton->Disable();
219  m_nextImgButton->Disable();
220  m_leftChoice->Disable();
221  m_rightChoice->Disable();
222 
223  // apply zoom specified in xrc file
224  wxCommandEvent dummy;
225  dummy.SetInt(m_zoomChoice->GetSelection());
226  OnZoom(dummy);
227 
228  SetSizer( topsizer );
229  // read last used action setting
230  m_cpActionButtonMode = static_cast<CPTabActionButtonMode>(config->Read("/CPEditorPanel/ActionMode", 1l));
231  switch (m_cpActionButtonMode)
232  {
234  m_cpActionContextMenu->Check(XRCID("cp_menu_create_cp"), true);
235  {
236  wxCommandEvent e;
238  };
239  break;
241  m_cpActionContextMenu->Check(XRCID("cp_menu_clean_cp"), true);
242  {
243  wxCommandEvent e;
245  };
246  break;
248  default:
249  m_cpActionContextMenu->Check(XRCID("cp_menu_celeste"), true);
250  {
251  wxCommandEvent e;
253  };
254  break;
255  };
256  Bind(EVT_CPEVENT, &CPEditorPanel::OnCPEvent, this);
257  Bind(wxEVT_CHAR, &CPEditorPanel::OnKey, this);
258  Bind(wxEVT_MENU, &CPEditorPanel::OnActionSelectCreate, this, XRCID("cp_menu_create_cp"));
259  Bind(wxEVT_MENU, &CPEditorPanel::OnActionSelectCeleste, this, XRCID("cp_menu_celeste"));
260  Bind(wxEVT_MENU, &CPEditorPanel::OnActionSelectCleanCP, this, XRCID("cp_menu_clean_cp"));
261 
262  return true;
263 }
264 
266 {
267  m_pano=pano;
268  // observe the panorama
269  m_pano->addObserver(this);
270 }
271 
273 {
274  DEBUG_TRACE("dtor");
275 
276  m_x1Text->PopEventHandler(true);
277  m_y1Text->PopEventHandler(true);
278  m_x2Text->PopEventHandler(true);
279  m_y2Text->PopEventHandler(true);
280 
281  wxConfigBase* config = wxConfig::Get();
282  config->Write("/CPEditorPanel/autoAdd", m_autoAddCB->IsChecked() ? 1 : 0);
283  config->Write("/CPEditorPanel/autoFineTune", m_fineTuneCB->IsChecked() ? 1 : 0);
284  config->Write("/CPEditorPanel/autoEstimate", m_estimateCB->IsChecked() ? 1 : 0);
285  config->Write("/CPEditorPanel/showLines", m_showLinesCB->IsChecked() ? 1 : 0);
286  config->Write("/CPEditorPanel/SortColumn", m_sortCol);
287  config->Write("/CPEditorPanel/SortAscending", m_sortAscending ? 1 : 0);
288  config->Flush();
289 
290  m_pano->removeObserver(this);
291  DEBUG_TRACE("dtor end");
292 }
293 
294 void CPEditorPanel::setLeftImage(unsigned int imgNr)
295 {
296  DEBUG_TRACE("image " << imgNr);
297  if (imgNr == UINT_MAX) {
299  m_leftImageNr = imgNr;
300  m_leftFile = "";
302  UpdateDisplay(true);
303  } else if (m_leftImageNr != imgNr) {
304  double yaw = const_map_get(m_pano->getImageVariables(imgNr),"y").getValue();
305  double pitch = const_map_get(m_pano->getImageVariables(imgNr),"p").getValue();
306  double roll = const_map_get(m_pano->getImageVariables(imgNr),"r").getValue();
307  m_leftRot = GetRot(yaw, pitch, roll);
308  m_leftImg->setImage(m_pano->getImage(imgNr).getFilename(), m_leftRot);
309  m_leftImageNr = imgNr;
310  if (m_leftChoice->GetSelection() != (int) imgNr) {
311  m_leftChoice->SetSelection(imgNr);
312  }
314  m_rightChoice->Refresh();
315  m_leftFile = m_pano->getImage(imgNr).getFilename();
317  UpdateDisplay(true);
318  }
319  m_selectedPoint = UINT_MAX;
320  // FIXME: lets hope that nobody holds references to these images..
321  ImageCache::getInstance().softFlush();
323 }
324 
325 
326 void CPEditorPanel::setRightImage(unsigned int imgNr)
327 {
328  DEBUG_TRACE("image " << imgNr);
329  if (imgNr == UINT_MAX) {
331  m_rightImageNr = imgNr;
332  m_rightFile = "";
335  UpdateDisplay(true);
336  } else if (m_rightImageNr != imgNr) {
337  // set the new image
338  double yaw = const_map_get(m_pano->getImageVariables(imgNr),"y").getValue();
339  double pitch = const_map_get(m_pano->getImageVariables(imgNr),"p").getValue();
340  double roll = const_map_get(m_pano->getImageVariables(imgNr),"r").getValue();
341  m_rightRot = GetRot(yaw, pitch, roll);
342  m_rightImg->setImage(m_pano->getImage(imgNr).getFilename(), m_rightRot);
343  // select tab
344  m_rightImageNr = imgNr;
345  if (m_rightChoice->GetSelection() != (int) imgNr) {
346  m_rightChoice->SetSelection(imgNr);
347  }
349  m_leftChoice->Refresh();
350  m_rightFile = m_pano->getImage(imgNr).getFilename();
351  // update the rest of the display (new control points etc)
353  UpdateDisplay(true);
354  }
355  m_selectedPoint = UINT_MAX;
356 
357  // FIXME: lets hope that nobody holds references to these images..
358  ImageCache::getInstance().softFlush();
360 }
361 
363 {
364  // these transformations are passed to the CPImageCtrl where they are used for
365  // a) generating the lines, use the user selected output projection
366  // b) generating the warped magnifier, use a equirectangular projection
369 
370  if(m_leftImageNr<m_pano->getNrOfImages())
371  {
375  // reset all positions
376  img.setYaw(0);
377  img.setPitch(0);
378  img.setRoll(0);
379  img.setX(0);
380  img.setY(0);
381  img.setZ(0);
382  img.setTranslationPlaneYaw(0);
383  img.setTranslationPlanePitch(0);
384  // calculate optimal scale factor
385  const double scale = 2.0 * HuginBase::CalculateOptimalScale::calcOptimalPanoScale(img, opts);
386  HuginBase::PanoramaOptions scaledOpts(opts);
387  scaledOpts.setWidth(scale * scaledOpts.getWidth());
388  m_leftTransformMag.createTransform(img, scaledOpts);
389  m_leftInvTransformMag.createInvTransform(img, scaledOpts);
390  };
391  if(m_rightImageNr<m_pano->getNrOfImages())
392  {
396  // reset all positions
397  img.setYaw(0);
398  img.setPitch(0);
399  img.setRoll(0);
400  img.setX(0);
401  img.setY(0);
402  img.setZ(0);
403  img.setTranslationPlaneYaw(0);
404  img.setTranslationPlanePitch(0);
405  // calculate optimal scale factor
406  const double scale = 2.0 * HuginBase::CalculateOptimalScale::calcOptimalPanoScale(img, opts);
407  HuginBase::PanoramaOptions scaledOpts(opts);
408  scaledOpts.setWidth(scale * scaledOpts.getWidth());
409  m_rightTransformMag.createTransform(img, scaledOpts);
411  };
412 }
413 
414 // define sorting callbacks
415 int wxCALLBACK SortIndexDescending(wxIntPtr item1, wxIntPtr item2, wxIntPtr WXUNUSED(sortData))
416 {
417  if (item1 < item2)
418  return 1;
419  if (item1 > item2)
420  return -1;
421  return 0;
422 }
423 
424 int wxCALLBACK SortIndexAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr WXUNUSED(sortData))
425 {
426  if (item1 > item2)
427  return 1;
428  if (item1 < item2)
429  return -1;
430  return 0;
431 }
432 
433 #define SORTASCENDING(functionName, var) \
434 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
435 {\
436  HuginBase::CPointVector* data = (HuginBase::CPointVector*)(sortData);\
437  if (data->at(item1).second.var > data->at(item2).second.var)\
438  return 1;\
439  if (data->at(item1).second.var < data->at(item2).second.var)\
440  return -1;\
441  return 0;\
442 }
443 
444 #define SORTDESCENDING(functionName, var) \
445 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
446 {\
447  HuginBase::CPointVector* data = (HuginBase::CPointVector*)(sortData); \
448  if (data->at(item1).second.var < data->at(item2).second.var)\
449  return 1; \
450  if (data->at(item1).second.var > data->at(item2).second.var)\
451  return -1; \
452  return 0; \
453 }
454 
455 SORTASCENDING(SortX1Ascending, x1)
456 SORTDESCENDING(SortX1Descending, x1)
457 SORTASCENDING(SortY1Ascending, y1)
458 SORTDESCENDING(SortY1Descending, y1)
459 SORTASCENDING(SortX2Ascending, x2)
460 SORTDESCENDING(SortX2Descending, x2)
461 SORTASCENDING(SortY2Ascending, y2)
462 SORTDESCENDING(SortY2Descending, y2)
463 SORTASCENDING(SortModeAscending, mode)
464 SORTDESCENDING(SortModeDescending, mode)
465 SORTASCENDING(SortErrorAscending, error)
466 SORTDESCENDING(SortErrorDescending, error)
467 
468 #undef SORTASCENDING
469 #undef SORTDESCENDING
470 
472 {
473  if (m_sortCol > -1)
474  {
475  switch (m_sortCol)
476  {
477  case 0: // index
478  if (m_sortAscending)
479  {
480  m_cpList->SortItems(SortIndexAscending, 0);
481  }
482  else
483  {
484  m_cpList->SortItems(SortIndexDescending, 0);
485  };
486  break;
487  case 1: // x1
488  if (m_sortAscending)
489  {
490  m_cpList->SortItems(SortX1Ascending, wxIntPtr(&currentPoints));
491  }
492  else
493  {
494  m_cpList->SortItems(SortX1Descending, wxIntPtr(&currentPoints));
495  };
496  break;
497  case 2: // y1
498  if (m_sortAscending)
499  {
500  m_cpList->SortItems(SortY1Ascending, wxIntPtr(&currentPoints));
501  }
502  else
503  {
504  m_cpList->SortItems(SortY1Descending, wxIntPtr(&currentPoints));
505  };
506  break;
507  case 3: // x2
508  if (m_sortAscending)
509  {
510  m_cpList->SortItems(SortX2Ascending, wxIntPtr(&currentPoints));
511  }
512  else
513  {
514  m_cpList->SortItems(SortX2Descending, wxIntPtr(&currentPoints));
515  };
516  break;
517  case 4: // y2
518  if (m_sortAscending)
519  {
520  m_cpList->SortItems(SortY2Ascending, wxIntPtr(&currentPoints));
521  }
522  else
523  {
524  m_cpList->SortItems(SortY2Descending, wxIntPtr(&currentPoints));
525  };
526  break;
527  case 5: // mode
528  if (m_sortAscending)
529  {
530  m_cpList->SortItems(SortModeAscending, wxIntPtr(&currentPoints));
531  }
532  else
533  {
534  m_cpList->SortItems(SortModeDescending, wxIntPtr(&currentPoints));
535  };
536  break;
537  case 6: // error
538  if (m_sortAscending)
539  {
540  m_cpList->SortItems(SortErrorAscending, wxIntPtr(&currentPoints));
541  }
542  else
543  {
544  m_cpList->SortItems(SortErrorDescending, wxIntPtr(&currentPoints));
545  };
546  break;
547  };
548  };
549 }
550 
552 {
553  DEBUG_TRACE("");
554  wxString text;
555  unsigned int nr = ev.getPointNr();
556  hugin_utils::FDiff2D point = ev.getPoint();
557  bool left (TRUE);
558  if (ev.GetEventObject() == m_leftImg) {
559  left = true;
560  } else if (ev.GetEventObject() == m_rightImg){
561  left = false;
562  } else {
563  DEBUG_FATAL("UNKNOWN SOURCE OF CPEvent");
564  }
565 
566  switch (ev.getMode()) {
567  case CPEvent::NONE:
568  text = "NONE";
569  break;
571  NewPointChange(ev.getPoint(),left);
572  break;
574  // need to reset cpEditState
575  DEBUG_DEBUG("selected point " << nr);
576  {
577  // user clicked a cp in one windows
578  // scroll only the other window, the scrolling of the originating
579  // window is done in the CPImageCtrl::mouseReleaseLMBEvent or in
580  // CPEvent POINT_CHANGED
581  // we can't use SelectLocalPoint here because this interferes with
582  // selection in wxListCtrl
583  if (left)
584  {
586  }
587  else
588  {
590  };
591  const long selectedPoint = m_cpList->FindItem(-1, nr);
592  // SetItemState will send the EVT_LIST_ITEM_SELECTED event,
593  // the work is done there
594  m_cpList->SetItemState(selectedPoint, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
595  };
597  break;
599  {
600  float vertBias = getVerticalCPBias();
604  bool hor = std::abs(cp.x1 - cp.x2) > (std::abs(cp.y1 - cp.y2) * vertBias);
605  switch (m_leftRot)
606  {
607  case CPImageCtrl::ROT0:
608  case CPImageCtrl::ROT180:
609  if (hor)
611  else
613  break;
614  default:
615  if (hor)
617  else
619  break;
620  }
622  // create points
624  // select new control Point
625  unsigned int lPoint = m_pano->getNrOfCtrlPoints()-1;
626  SelectGlobalPoint(lPoint);
628  MainFrame::Get()->SetStatusText(_("new control point added"));
631  break;
632  };
634  {
635  DEBUG_DEBUG("move point("<< nr << ")");
636  if (nr >= currentPoints.size()) {
637  DEBUG_ERROR("invalid point number while moving point")
638  return;
639  }
642  DEBUG_DEBUG("changing point to: " << cp.x1 << "," << cp.y1
643  << " " << cp.x2 << "," << cp.y2);
644 
647  );
648 
649  break;
650  }
652  {
654  DEBUG_DEBUG("right click -> adding point");
655  CreateNewPoint();
656  } else {
657  DEBUG_DEBUG("right click without two points..");
659  }
660  break;
661  }
662  case CPEvent::CANCELED:
663  {
664  if (cpCreationState != NO_POINT)
665  {
667  };
668  break;
669  };
670  case CPEvent::SCROLLED:
671  {
672  wxPoint d(hugin_utils::roundi(point.x), hugin_utils::roundi(point.y));
673  d = m_rightImg->MaxScrollDelta(d);
674  d = m_leftImg->MaxScrollDelta(d);
677  // after scrolling the canvas is redrawn, no need to
678  // force a redraw at the end of OnCPEvent
679  return;
680  }
681  break;
683  {
684  HuginBase::UIntSet cpToRemove;
685  if(!currentPoints.empty())
686  {
687  wxRect rect=ev.getRect();
688  for(unsigned int i=0;i<currentPoints.size();i++)
689  {
690  HuginBase::ControlPoint cp = currentPoints[i].second;
692  {
693  //checking only normal control points
694  if(left)
695  {
696  if (rect.Contains(hugin_utils::roundi(cp.x1), hugin_utils::roundi(cp.y1)))
697  {
698  cpToRemove.insert(localPNr2GlobalPNr(i));
699  };
700  }
701  else
702  {
703  if (rect.Contains(hugin_utils::roundi(cp.x2), hugin_utils::roundi(cp.y2)))
704  {
705  cpToRemove.insert(localPNr2GlobalPNr(i));
706  };
707  };
708  };
709  };
710  };
712  if(!cpToRemove.empty())
713  {
715  };
716  break;
717  }
718  } //end switch
719  m_leftImg->Refresh();
720  m_rightImg->Refresh();
721 }
722 
723 
725 {
726  DEBUG_TRACE("");
730  point.image1Nr = m_leftImageNr;
731  point.x1 = p1.x;
732  point.y1 = p1.y;
733  point.image2Nr = m_rightImageNr;
734  point.x2 = p2.x;
735  point.y2 = p2.y;
736  if (point.image1Nr == point.image2Nr) {
737  if (m_cpModeChoice->GetSelection()>=3) {
738  // keep line until user chooses new mode
739  point.mode = m_cpModeChoice->GetSelection();
740  } else {
741  // Most projections will have a bias to creating vertical
742  // constraints.
743  float vertBias = getVerticalCPBias();
744  bool hor = std::abs(p1.x - p2.x) > (std::abs(p1.y - p2.y) * vertBias);
745  switch (m_leftRot) {
746  case CPImageCtrl::ROT0:
747  case CPImageCtrl::ROT180:
748  if (hor)
750  else
752  break;
753  default:
754  if (hor)
756  else
758  break;
759  }
760  }
761  } else {
763  }
764 
766 
767  // create points
770  );
771 
772 
773  // select new control Point
774  unsigned int lPoint = m_pano->getNrOfCtrlPoints() -1;
775  SelectGlobalPoint(lPoint);
777  MainFrame::Get()->SetStatusText(_("new control point added"));
780 }
781 
782 
784 {
787  float bias;
788  switch (projFormat)
789  {
791  bias = 1.0;
792  break;
793  default:
794  bias = 2.0;
795  break;
796  }
797  return bias;
798 }
799 
800 
802 {
803  if (m_selectedPoint == UINT_MAX) {
804  // no point selected, no need to select one.
805  return;
806  }
807  const long selectedPoint = m_cpList->FindItem(-1, m_selectedPoint);
808  if (selectedPoint != wxNOT_FOUND)
809  {
810  m_cpList->SetItemState(selectedPoint, 0, wxLIST_STATE_SELECTED);
811  };
812 
813  m_selectedPoint=UINT_MAX;
815  m_leftImg->deselect();
816  m_rightImg->deselect();
817  UpdateDisplay(false);
818 }
819 
820 void CPEditorPanel::SelectLocalPoint(unsigned int LVpointNr, bool scrollLeft, bool scrollRight)
821 {
822  DEBUG_TRACE("selectLocalPoint(" << LVpointNr << ")");
823 
824  if ( m_selectedPoint == LVpointNr) {
825  DEBUG_DEBUG("already selected");
826  m_leftImg->selectPoint(LVpointNr, scrollLeft);
827  m_rightImg->selectPoint(LVpointNr, scrollRight);
828  return;
829  }
830  m_selectedPoint = LVpointNr;
831 
832  const HuginBase::ControlPoint & p = currentPoints[LVpointNr].second;
833  m_x1Text->SetValue(wxString::Format("%.2f",p.x1));
834  m_y1Text->SetValue(wxString::Format("%.2f",p.y1));
835  m_x2Text->SetValue(wxString::Format("%.2f",p.x2));
836  m_y2Text->SetValue(wxString::Format("%.2f",p.y2));
837  m_cpModeChoice->SetSelection(p.mode);
838  m_leftImg->selectPoint(LVpointNr, scrollLeft);
839  m_rightImg->selectPoint(LVpointNr, scrollRight);
840  const long selectedPoint = m_cpList->FindItem(-1, LVpointNr);
841  if (scrollLeft && scrollRight)
842  {
843  // SetItemState will generate a EVT_LIST_ITEM_SELECTED event
844  // do so only if both images are scrolled
845  m_cpList->SetItemState(selectedPoint, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
846  };
847  m_cpList->EnsureVisible(selectedPoint);
848 
849  EnablePointEdit(true);
850 }
851 
852 void CPEditorPanel::SelectGlobalPoint(unsigned int globalNr)
853 {
854  unsigned int localNr;
855  if (globalPNr2LocalPNr(localNr,globalNr)) {
856  DEBUG_DEBUG("CPEditor::setGlobalPoint(" << globalNr << ") found local point " << localNr);
857  SelectLocalPoint(localNr);
858  } else {
859  DEBUG_ERROR("CPEditor::setGlobalPoint: point " << globalNr << " not found in currentPoints");
860  }
861 }
862 
863 bool CPEditorPanel::globalPNr2LocalPNr(unsigned int & localNr, unsigned int globalNr) const
864 {
865  HuginBase::CPointVector::const_iterator it = currentPoints.begin();
866 
867  while(it != currentPoints.end() && (*it).first != globalNr) {
868  ++it;
869  }
870 
871  if (it != currentPoints.end()) {
872  localNr = it - currentPoints.begin();
873  return true;
874  } else {
875  return false;
876  }
877 }
878 
879 unsigned int CPEditorPanel::localPNr2GlobalPNr(unsigned int localNr) const
880 {
881  assert(localNr < currentPoints.size());
882  return currentPoints[localNr].first;
883 }
884 
885 
887  bool left,
888  CPImageCtrl * thisImg,
889  unsigned int thisImgNr,
890  CPCreationState THIS_POINT,
891  CPCreationState THIS_POINT_RETRY,
892  CPImageCtrl * otherImg,
893  unsigned int otherImgNr,
894  CPCreationState OTHER_POINT,
895  CPCreationState OTHER_POINT_RETRY)
896 {
898  op = EstimatePoint(hugin_utils::FDiff2D(p.x, p.y), left);
899  // check if point is in image.
900  const HuginBase::SrcPanoImage & pImg = m_pano->getImage(otherImgNr);
901  if (op.x < (int) pImg.getSize().width() && op.x >= 0
902  && op.y < (int) pImg.getSize().height() && op.y >= 0)
903  {
904  otherImg->setNewPoint(op);
905  // if fine-tune is checked, run a fine-tune session as well.
906  // hmm probably there should be another separate function for this..
907  if (m_fineTuneCB->IsChecked()) {
908  MainFrame::Get()->SetStatusText(_("searching similar points..."),0);
909  hugin_utils::FDiff2D newPoint = otherImg->getNewPoint();
910 
911  long templWidth = wxConfigBase::Get()->Read("/Finetune/TemplateSize", HUGIN_FT_TEMPLATE_SIZE);
912  const HuginBase::SrcPanoImage & img = m_pano->getImage(thisImgNr);
913  double sAreaPercent = wxConfigBase::Get()->Read("/Finetune/SearchAreaPercent",HUGIN_FT_SEARCH_AREA_PERCENT);
914  int sWidth = std::min((int)(img.getWidth() * sAreaPercent / 100.0), 500);
916  bool corrOk=false;
917  vigra::Diff2D roundp(p.toDiff2D());
918  try {
919  corrOk = PointFineTune(thisImgNr,
920  roundp,
921  templWidth,
922  otherImgNr,
923  newPoint,
924  sWidth,
925  corrPoint);
926  } catch (std::exception & e) {
927  hugin_utils::HuginMessageBox(wxString::Format(_("Error during Fine-tune (%s)"), wxString(e.what(), wxConvLocal)), _("Hugin"), wxOK, this);
928  }
929  if (! corrOk) {
930  // just set point, PointFineTune already complained
931  if (corrPoint.corrPos.x >= 0 && corrPoint.corrPos.y >= 0 && corrPoint.maxpos.x > 0 && corrPoint.maxpos.y > 0)
932  {
933  otherImg->setScale(m_detailZoomFactor);
934  otherImg->setNewPoint(corrPoint.maxpos);
935  thisImg->setNewPoint(corrPoint.corrPos);
937  };
938  } else {
939  // show point & zoom in if auto add is not set
940  if (!m_autoAddCB->IsChecked()) {
941  otherImg->setScale(m_detailZoomFactor);
942  otherImg->setNewPoint(corrPoint.maxpos);
943  thisImg->setNewPoint(corrPoint.corrPos);
945  wxString s1;
946  s1.Printf(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f"),
947  corrPoint.maxAngle, corrPoint.maxi, corrPoint.curv.x, corrPoint.curv.y );
948 
949  wxString s2 = s1 + " -- " + wxString(_("change points, or press right mouse button to add the pair"));
950  MainFrame::Get()->SetStatusText(s2,0);
951  } else {
952  // add point
953  otherImg->setNewPoint(corrPoint.maxpos);
954  thisImg->setNewPoint(corrPoint.corrPos);
956  CreateNewPoint();
957  }
958  }
959  } else {
960  // no fine-tune, set 100% scale and set both points to selected
961  otherImg->setScale(m_detailZoomFactor);
962  otherImg->showPosition(op);
964  }
965 
966  } else {
967  // estimate was outside of image
968  // do nothing special
969  wxBell();
970  MainFrame::Get()->SetStatusText(_("Estimated point outside image"),0);
971  }
972 }
973 
975 {
976  DEBUG_TRACE("");
977 
978  wxString corrMsg;
979 
980  CPImageCtrl * thisImg = m_leftImg;
981  unsigned int thisImgNr = m_leftImageNr;
982  CPImageCtrl * otherImg = m_rightImg;
983  unsigned int otherImgNr = m_rightImageNr;
984  CPCreationState THIS_POINT = LEFT_POINT;
985  CPCreationState THIS_POINT_RETRY = LEFT_POINT_RETRY;
986  CPCreationState OTHER_POINT = RIGHT_POINT;
987  CPCreationState OTHER_POINT_RETRY = RIGHT_POINT_RETRY;
988 
989  bool estimate = m_estimateCB->IsChecked();
990 
991  if (!left) {
992  thisImg = m_rightImg;
993  thisImgNr = m_rightImageNr;
994  otherImg = m_leftImg;
995  otherImgNr = m_leftImageNr;
996  THIS_POINT = RIGHT_POINT;
997  THIS_POINT_RETRY = RIGHT_POINT_RETRY;
998  OTHER_POINT = LEFT_POINT;
999  OTHER_POINT_RETRY = LEFT_POINT_RETRY;
1000  }
1001 
1002 
1003  if (cpCreationState == NO_POINT) {
1004  //case NO_POINT
1005  changeState(THIS_POINT);
1006  // zoom into our window
1007  if (thisImg->getScale() < 1) {
1008  thisImg->setScale(m_detailZoomFactor);
1009  thisImg->showPosition(p);
1010  } else {
1011  // run auto-estimate procedure?
1012  bool hasNormalCP = false;
1013  for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end() && !hasNormalCP; ++it)
1014  {
1015  hasNormalCP = (it->second.mode == HuginBase::ControlPoint::X_Y);
1016  };
1017  if (estimate && (thisImgNr != otherImgNr) && hasNormalCP) {
1018  estimateAndAddOtherPoint(p, left,
1019  thisImg, thisImgNr, THIS_POINT, THIS_POINT_RETRY,
1020  otherImg, otherImgNr, OTHER_POINT, OTHER_POINT_RETRY);
1021  };
1022  }
1023 
1024  } else if (cpCreationState == OTHER_POINT_RETRY) {
1025  thisImg->showPosition(p);
1026  } else if (cpCreationState == THIS_POINT) {
1027  thisImg->showPosition(p);
1028 
1029  bool hasNormalCP = false;
1030  for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end() && !hasNormalCP; ++it)
1031  {
1032  hasNormalCP = (it->second.mode == HuginBase::ControlPoint::X_Y);
1033  };
1034  if (estimate && (thisImgNr != otherImgNr) && hasNormalCP) {
1035  estimateAndAddOtherPoint(p, left,
1036  thisImg, thisImgNr, THIS_POINT, THIS_POINT_RETRY,
1037  otherImg, otherImgNr, OTHER_POINT, OTHER_POINT_RETRY);
1038  }
1039  } else if (cpCreationState == OTHER_POINT || cpCreationState == THIS_POINT_RETRY) {
1040  // the try for the second point.
1041  if (cpCreationState == OTHER_POINT) {
1042  // other point already selected, finalize point.
1043 
1044  // TODO: option to ignore the auto fine tune button when multiple images are selected.
1045  if (m_fineTuneCB->IsChecked() ) {
1047 
1048  hugin_utils::FDiff2D newPoint = otherImg->getNewPoint();
1049 
1050  long templWidth = wxConfigBase::Get()->Read("/Finetune/TemplateSize",HUGIN_FT_TEMPLATE_SIZE);
1051  const HuginBase::SrcPanoImage & img = m_pano->getImage(thisImgNr);
1052  double sAreaPercent = wxConfigBase::Get()->Read("/Finetune/SearchAreaPercent",
1054  int sWidth = std::min((int) (img.getWidth() * sAreaPercent / 100.0), 500);
1055  bool corrOk = false;
1056  // corr point
1057  vigra::Diff2D newPoint_round = newPoint.toDiff2D();
1058  try {
1059  corrOk = PointFineTune(otherImgNr,
1060  newPoint_round,
1061  templWidth,
1062  thisImgNr,
1063  p,
1064  sWidth,
1065  corrRes);
1066  } catch (std::exception & e) {
1067  hugin_utils::HuginMessageBox(wxString::Format(_("Error during Fine-tune (%s)"), wxString(e.what(), wxConvLocal)), _("Hugin"), wxOK, this);
1068  }
1069 
1070  if (! corrOk) {
1071  // low xcorr
1072  // zoom to 100 percent. & set second stage
1073  // to abandon finetune this time.
1074  if (corrRes.corrPos.x >= 0 && corrRes.corrPos.y >= 0 && corrRes.maxpos.x >= 0 && corrRes.maxpos.y >= 0)
1075  {
1076  thisImg->setScale(m_detailZoomFactor);
1077  thisImg->setNewPoint(corrRes.maxi > -1 ? corrRes.maxpos : p);
1078  thisImg->Refresh();
1079  otherImg->setNewPoint(corrRes.maxi > -1 ? corrRes.corrPos : newPoint);
1081  };
1082  } else {
1083  // show point & zoom in if auto add is not set
1085  if (!m_autoAddCB->IsChecked()) {
1086  thisImg->setScale(m_detailZoomFactor);
1087  }
1088  thisImg->setNewPoint(corrRes.maxpos);
1089  otherImg->setNewPoint(corrRes.corrPos);
1090  wxString s1;
1091  s1.Printf(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f"),
1092  corrRes.maxAngle, corrRes.maxi, corrRes.curv.x, corrRes.curv.y );
1093 
1094  corrMsg = s1 + " -- " + wxString(_("change points, or press right mouse button to add the pair"));
1095  MainFrame::Get()->SetStatusText(corrMsg,0);
1096 
1097  }
1098  } else {
1099  // no finetune. but zoom into picture, when we where zoomed out
1100  if (thisImg->getScale() < 1) {
1101  // zoom to 100 percent. & set second stage
1102  // to abandon finetune this time.
1103  thisImg->setScale(m_detailZoomFactor);
1104  thisImg->clearNewPoint();
1105  thisImg->showPosition(p);
1106  //thisImg->setNewPoint(p.x, p.y);
1107  changeState(THIS_POINT_RETRY);
1108  return;
1109  } else {
1110  // point is already set. no need to move.
1111  // setNewPoint(p);
1113  }
1114  }
1115  } else {
1116  // selection retry
1117  // nothing special, no second stage fine-tune yet.
1118  }
1119 
1120  // ok, we have determined the other point.. apply if auto add is on
1121  if (m_autoAddCB->IsChecked()) {
1122  CreateNewPoint();
1123  } else {
1124  // keep both point floating around, until they are
1125  // added with a right mouse click or the add button
1127  if (corrMsg != wxEmptyString) {
1128  MainFrame::Get()->SetStatusText(corrMsg,0);
1129  }
1130  }
1131 
1132  } else if (cpCreationState == BOTH_POINTS_SELECTED) {
1133  // nothing to do.. maybe a special fine-tune with
1134  // a small search region
1135 
1136  } else {
1137  // should never reach this, else state machine is broken.
1138  DEBUG_ASSERT(0);
1139  }
1140 }
1141 
1142 // return a SrcPanoImage so that the given point is in the center
1143 HuginBase::SrcPanoImage GetImageRotatedTo(const HuginBase::SrcPanoImage& img, const vigra::Diff2D& point, int testWidth, double& neededHFOV)
1144 {
1145  // copy only necessary information into temporary SrcPanoImage
1146  HuginBase::SrcPanoImage imgMod;
1147  imgMod.setSize(img.getSize());
1148  imgMod.setProjection(img.getProjection());
1149  imgMod.setHFOV(img.getHFOV());
1150  // calculate, where the interest point lies
1153  opt.setHFOV(360);
1154  opt.setWidth(360);
1155  opt.setHeight(180);
1156 
1157  HuginBase::PTools::Transform transform;
1158  transform.createInvTransform(imgMod, opt);
1159  double x1, y1;
1160  if (!transform.transformImgCoord(x1, y1, point.x, point.y))
1161  {
1162  neededHFOV = -1;
1163  return imgMod;
1164  }
1165  // equirect image coordinates -> equirectangular coordinates
1166  // transformImgCoord places the origin at the upper left corner and negate
1167  Matrix3 rotY;
1168  rotY.SetRotationPT(DEG_TO_RAD(180 - (x1 + 0.5)), 0, 0);
1169  Matrix3 rotP;
1170  rotP.SetRotationPT(0, DEG_TO_RAD((y1 + 0.5) - 90), 0);
1171  double y, p, r;
1172  // calculate the necessary rotation angles and remember
1173  Matrix3 rot = rotP * rotY;
1174  rot.GetRotationPT(y, p, r);
1175  imgMod.setYaw(RAD_TO_DEG(y));
1176  imgMod.setPitch(RAD_TO_DEG(p));
1177  imgMod.setRoll(RAD_TO_DEG(r));
1178 
1179  // new we calculate the needed HFOV for template/search area width
1180  double x2, y2;
1181  // check a point left from our interest point
1182  if (transform.transformImgCoord(x2, y2, point.x - testWidth / 2.0, point.y))
1183  {
1184  if (x2 < x1)
1185  {
1186  neededHFOV = 2.0 * (x1 - x2);
1187  }
1188  else
1189  {
1190  // we crossed the 360 deg border
1191  neededHFOV = 2.0 * (360 - x2 + x1);
1192  };
1193  // limit maximum HFOV for remapping to stereographic projection done as next step
1194  if (neededHFOV > 90)
1195  {
1196  neededHFOV = 90;
1197  };
1198  return imgMod;
1199  };
1200  // this goes wrong, maybe the tested point is outside the image area of a fisheye image
1201  // now test the right point
1202  if (transform.transformImgCoord(x2, y2, point.x + testWidth / 2.0, point.y))
1203  {
1204  if (x1 < x2)
1205  {
1206  neededHFOV = 2.0 * (x2 - x1);
1207  }
1208  else
1209  {
1210  // we crossed the 360 deg border
1211  neededHFOV = 2.0 * (360 + x2 - x1);
1212  };
1213  // limit maximum HFOV for remapping to stereographic projection done as next step
1214  if (neededHFOV > 90)
1215  {
1216  neededHFOV = 90;
1217  };
1218  return imgMod;
1219  };
1220  // we can't calculate the needed HFOV, return -1
1221  neededHFOV = -1;
1222  return imgMod;
1223 };
1224 
1225 vigra_ext::CorrelationResult PointFineTuneProjectionAware(const HuginBase::SrcPanoImage& templ, const vigra::UInt8RGBImage& templImg,
1226  vigra::Diff2D templPos, int templSize,
1227  const HuginBase::SrcPanoImage& search, const vigra::UInt8RGBImage& searchImg,
1228  vigra::Diff2D searchPos, int sWidth)
1229 {
1230  wxBusyCursor busy;
1231  // read settings
1232  wxConfigBase *cfg = wxConfigBase::Get();
1233  bool rotatingFinetune = cfg->Read("/Finetune/RotationSearch", HUGIN_FT_ROTATION_SEARCH) == 1;
1234  double startAngle = HUGIN_FT_ROTATION_START_ANGLE;
1235  cfg->Read("/Finetune/RotationStartAngle", &startAngle, HUGIN_FT_ROTATION_START_ANGLE);
1236  startAngle = DEG_TO_RAD(startAngle);
1237  double stopAngle = HUGIN_FT_ROTATION_STOP_ANGLE;
1238  cfg->Read("/Finetune/RotationStopAngle", &stopAngle, HUGIN_FT_ROTATION_STOP_ANGLE);
1239  stopAngle = DEG_TO_RAD(stopAngle);
1240  int nSteps = cfg->Read("/Finetune/RotationSteps", HUGIN_FT_ROTATION_STEPS);
1241  // if both images have the same projection and the angle does not differ to much use normal point fine-tune
1242  if (templ.getProjection() == search.getProjection()
1243  && templ.getHFOV() < 65 && search.getHFOV() < 65
1244  && fabs(templ.getHFOV() - search.getHFOV()) < 5)
1245  {
1247  if (rotatingFinetune)
1248  {
1249  res = vigra_ext::PointFineTuneRotSearch(templImg, templPos, templSize,
1250  searchImg, searchPos, sWidth, startAngle, stopAngle, nSteps);
1251  }
1252  else
1253  {
1254  res = vigra_ext::PointFineTune(templImg, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >(), templPos, templSize,
1255  searchImg, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >(), searchPos, sWidth);
1256  };
1257  res.corrPos = templPos;
1258  return res;
1259  };
1260  // images have different projections or the HFOV is different
1261  // so we reproject the image to stereographic projection and fine tune point there
1262  // rotate image so that interest point is in the center
1263  double templHFOV = 0;
1264  double searchHFOV = 0;
1265  HuginBase::SrcPanoImage templMod = GetImageRotatedTo(templ, templPos, templSize, templHFOV);
1266  HuginBase::SrcPanoImage searchMod = GetImageRotatedTo(search, searchPos, sWidth + templSize + 5, searchHFOV);
1268  res.maxpos = hugin_utils::FDiff2D(-1, -1);
1269  res.corrPos = hugin_utils::FDiff2D(-1, -1);
1270  if (templHFOV < 0 || searchHFOV < 0)
1271  {
1272  //something went wrong, e.g. image outside of projection circle for fisheye lenses
1273  return res;
1274  }
1275  // populate PanoramaOptions
1278  opts.setHFOV(std::max(templHFOV, searchHFOV));
1279  // calculate a sensible scale factor
1280  double scaleTempl = HuginBase::CalculateOptimalScale::calcOptimalPanoScale(templMod, opts);
1281  double scaleSearch = HuginBase::CalculateOptimalScale::calcOptimalPanoScale(searchMod, opts);
1282  opts.setWidth(std::max<unsigned int>(opts.getWidth()*std::min(scaleTempl, scaleSearch), 3 * templSize));
1283  opts.setHeight(opts.getWidth());
1284  // transform coordinates to transform system
1285  HuginBase::PTools::Transform transform;
1286  transform.createInvTransform(templMod, opts);
1287  double templX, templY, searchX, searchY;
1288  transform.transformImgCoord(templX, templY, templPos.x, templPos.y);
1289  transform.createInvTransform(searchMod, opts);
1290  transform.transformImgCoord(searchX, searchY, searchPos.x, searchPos.y);
1291  // now transform the images
1294  transform.createTransform(searchMod, opts);
1295  vigra::UInt8RGBImage searchImgMod(opts.getSize());
1296  vigra::BImage alpha(opts.getSize());
1297  vigra_ext::transformImage(srcImageRange(searchImg), destImageRange(searchImgMod), destImage(alpha),
1298  vigra::Diff2D(0, 0), transform, ptf, false, vigra_ext::INTERP_CUBIC, &dummy);
1299  // now remap template, we need to remap a little bigger area to have enough information when the template
1300  // is rotated in PointFineTuneRotSearch
1301  vigra::Diff2D templPointInt(hugin_utils::roundi(templX), hugin_utils::roundi(templY));
1302  vigra::Rect2D rect(templPointInt.x - templSize - 2, templPointInt.y - templSize - 2,
1303  templPointInt.x + templSize + 2, templPointInt.y + templSize + 2);
1304  rect &= vigra::Rect2D(opts.getSize());
1305  transform.createTransform(templMod, opts);
1306  vigra::UInt8RGBImage templImgMod(opts.getSize());
1307  vigra_ext::transformImage(srcImageRange(templImg), destImageRange(templImgMod, rect), destImage(alpha),
1308  vigra::Diff2D(rect.left(), rect.top()), transform, ptf, false, vigra_ext::INTERP_CUBIC, &dummy);
1309 #if defined DEBUG_EXPORT_FINE_TUNE_REMAPPING
1310  {
1311  vigra::ImageExportInfo templExport("template_remapped.tif");
1312  vigra::exportImage(srcImageRange(templImgMod), templExport.setPixelType("UINT8"));
1313  vigra::ImageExportInfo searchExport("search_remapped.tif");
1314  vigra::exportImage(srcImageRange(searchImgMod), searchExport.setPixelType("UINT8"));
1315  }
1316 #endif
1317  // now we can finetune the point in stereographic projection
1318  // we are always using the rotate fine-tune algorithm, because for this case
1319  // often a rotation is involved
1320  res = vigra_ext::PointFineTuneRotSearch(templImgMod, templPointInt, templSize,
1321  searchImgMod, vigra::Diff2D(hugin_utils::roundi(searchX), hugin_utils::roundi(searchY)), sWidth, startAngle, stopAngle, nSteps);
1322  // we transfer also the new found template position back to the original image
1323  transform.createTransform(templMod, opts);
1324  transform.transformImgCoord(res.corrPos.x, res.corrPos.y, templPointInt.x + 0.00001, templPointInt.y + 0.00001);
1325  // we need to move the finetune point back to position in original image
1326  transform.createTransform(searchMod, opts);
1327  transform.transformImgCoord(res.maxpos.x, res.maxpos.y, res.maxpos.x, res.maxpos.y);
1328  return res;
1329 };
1330 
1331 bool CPEditorPanel::PointFineTune(unsigned int tmplImgNr,
1332  const vigra::Diff2D & tmplPoint,
1333  int templSize,
1334  unsigned int subjImgNr,
1335  const hugin_utils::FDiff2D & o_subjPoint,
1336  int sWidth,
1338 {
1339  DEBUG_TRACE("tmpl img nr: " << tmplImgNr << " corr src: "
1340  << subjImgNr);
1341  if (tmplImgNr == subjImgNr)
1342  {
1343  // for line control points (assumed when both points are in the same image)
1344  // check the distance before running fine-tune
1345  // if both points are in the search area decrease search area
1346  const double distance = (tmplPoint - o_subjPoint.toDiff2D()).magnitude();
1347  if (distance < sWidth)
1348  {
1349  sWidth = 0.9 * distance;
1350  };
1351  if (sWidth < 1.1 * templSize)
1352  {
1353  MainFrame::Get()->SetStatusText(_("Distance between line control points too short, skipping fine-tune."));
1354  wxBell();
1355  return false;
1356  };
1357  };
1358  MainFrame::Get()->SetStatusText(_("searching similar points..."),0);
1359 
1360  double corrThresh=HUGIN_FT_CORR_THRESHOLD;
1361  wxConfigBase::Get()->Read("/Finetune/CorrThreshold",&corrThresh,
1363 
1364  double curvThresh = HUGIN_FT_CURV_THRESHOLD;
1365  // use default curvature threshold for line control points
1366  if (tmplImgNr != subjImgNr)
1367  {
1368  wxConfigBase::Get()->Read("/Finetune/CurvThreshold", &curvThresh, HUGIN_FT_CURV_THRESHOLD);
1369  };
1370 
1371  // fixme: just cutout suitable gray
1372  ImageCache::ImageCacheRGB8Ptr subjImg = ImageCache::getInstance().getImage(m_pano->getImage(subjImgNr).getFilename())->get8BitImage();
1373  ImageCache::ImageCacheRGB8Ptr tmplImg = ImageCache::getInstance().getImage(m_pano->getImage(tmplImgNr).getFilename())->get8BitImage();
1374 
1375  res = PointFineTuneProjectionAware(m_pano->getImage(tmplImgNr), *(tmplImg), tmplPoint, templSize,
1376  m_pano->getImage(subjImgNr), *(subjImg), o_subjPoint.toDiff2D(), sWidth);
1377 
1378  // invert curvature. we always assume its a maxima, the curvature there is negative
1379  // however, we allow the user to specify a positive threshold, so we need to
1380  // invert it
1381  res.curv.x = - res.curv.x;
1382  res.curv.y = - res.curv.y;
1383 
1384  MainFrame::Get()->SetStatusText(wxString::Format(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f"),
1385  res.maxAngle, res.maxi, res.curv.x, res.curv.y ),0);
1386  if (res.corrPos.x < 0 || res.corrPos.y < 0 || res.maxpos.x < 0 || res.maxpos.y < 0)
1387  {
1388  // invalid transformation in fine tune
1389  hugin_utils::MessageDialog dlg=hugin_utils::GetMessageDialog(_("No similar point found."), _("Hugin"), wxICON_ERROR | wxOK, this);
1390  dlg->SetExtendedMessage(_("An internal transformation went wrong.\nCheck that the point is inside the image."));
1391  dlg->ShowModal();
1392  return false;
1393  }
1394  if (res.maxi < corrThresh || res.curv.x < curvThresh || res.curv.y < curvThresh )
1395  {
1396  // Bad correlation result.
1397  hugin_utils::MessageDialog dlg=hugin_utils::GetMessageDialog(_("No similar point found."), _("Hugin"), wxICON_ERROR | wxOK, this);
1398  dlg->SetExtendedMessage(wxString::Format(_("Check the similarity visually.\nCorrelation coefficient (%.3f) is lower than the threshold set in the preferences."),
1399  res.maxi));
1400  dlg->ShowModal();
1401  return false;
1402  }
1403 
1404  return true;
1405 }
1406 
1408 {
1409  int nGui = m_cpModeChoice->GetCount();
1410  int nPano = pano.getNextCPTypeLineNumber()+1;
1411  DEBUG_DEBUG("mode choice: " << nGui << " entries, required: " << nPano);
1412 
1413  if (nGui > nPano)
1414  {
1415  m_cpModeChoice->Freeze();
1416  // remove some items.
1417  for (int i = nGui-1; i > nPano-1; --i) {
1418  m_cpModeChoice->Delete(i);
1419  }
1420  if (nPano > 3) {
1421  m_cpModeChoice->SetString(nPano-1, _("Add new Line"));
1422  }
1423  m_cpModeChoice->Thaw();
1424  } else if (nGui < nPano) {
1425  m_cpModeChoice->Freeze();
1426  if (nGui > 3) {
1427  m_cpModeChoice->SetString(nGui-1, wxString::Format(_("Line %d"), nGui-1));
1428  }
1429  for (int i = nGui; i < nPano-1; i++) {
1430  m_cpModeChoice->Append(wxString::Format(_("Line %d"), i));
1431  }
1432  m_cpModeChoice->Append(_("Add new Line"));
1433  m_cpModeChoice->Thaw();
1434  }
1435  UpdateTransforms();
1436  // check if number of control points has changed, if so we need to update our variables
1437  if (pano.getNrOfCtrlPoints() != m_countCP)
1438  {
1439  m_countCP = pano.getNrOfCtrlPoints();
1440  UpdateDisplay(false);
1441  };
1442  // update header if necessary
1443  wxListItem item;
1444  if (m_cpList->GetColumn(6, item))
1445  {
1447  {
1448  item.SetText(_("Correlation"));
1449  }
1450  else
1451  {
1452  item.SetText(_("Distance"));
1453  }
1454  m_cpList->SetColumn(6, item);
1455  };
1457  m_leftChoice->Refresh();
1459  m_rightChoice->Refresh();
1460 
1461  DEBUG_TRACE("");
1462 }
1463 
1465 {
1466  unsigned int nrImages = pano.getNrOfImages();
1467  unsigned int nrTabs = m_leftChoice->GetCount();
1468  DEBUG_TRACE("nrImages:" << nrImages << " nrTabs:" << nrTabs);
1469 
1470 #ifdef __WXMSW__
1471  int oldLeftSelection = m_leftChoice->GetSelection();
1472  int oldRightSelection = m_rightChoice->GetSelection();
1473 #endif
1474 
1475  if (nrImages == 0)
1476  {
1477  // disable controls
1478  m_cpModeChoice->Disable();
1479  m_addButton->Disable();
1480  m_delButton->Disable();
1481  m_autoAddCB->Disable();
1482  m_fineTuneCB->Disable();
1483  m_estimateCB->Disable();
1484  m_showLinesCB->Disable();
1485  m_finetuneButton->Disable();
1486  m_actionButton->Disable();
1487  m_zoomChoice->Disable();
1488  m_prevImgButton->Disable();
1489  m_nextImgButton->Disable();
1490  m_leftChoice->Disable();
1491  m_rightChoice->Disable();
1492  }
1493  else
1494  {
1495  // enable controls
1496  m_cpModeChoice->Enable();
1497  m_autoAddCB->Enable();
1498  m_fineTuneCB->Enable();
1499  m_estimateCB->Enable();
1500  m_showLinesCB->Enable();
1501  m_finetuneButton->Enable();
1502  m_actionButton->Enable();
1503  m_zoomChoice->Enable();
1504  m_prevImgButton->Enable();
1505  m_nextImgButton->Enable();
1506  m_leftChoice->Enable();
1507  m_rightChoice->Enable();
1508 
1509  ImageCache::getInstance().softFlush();
1510 
1511  m_leftChoice->Freeze();
1512  m_rightChoice->Freeze();
1513  for (unsigned int i=0; i < ((nrTabs < nrImages)? nrTabs: nrImages); i++) {
1514  wxFileName fileName(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
1515  m_leftChoice->SetString(i, wxString::Format("%d", i) + ". - " + fileName.GetFullName());
1516  m_rightChoice->SetString(i, wxString::Format("%d", i) + ". - " + fileName.GetFullName());
1517  }
1518  // wxChoice on windows looses the selection when setting new labels. Restore selection
1519 #ifdef __WXMSW__
1520  m_leftChoice->SetSelection(oldLeftSelection);
1521  m_rightChoice->SetSelection(oldRightSelection);
1522 #endif
1523  // add tab bar entries, if needed
1524  if (nrTabs < nrImages)
1525  {
1526  for (unsigned int i=nrTabs; i < nrImages; i++)
1527  {
1528  wxFileName fileName(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
1529  m_leftChoice->Append(wxString::Format("%d", i) + ". - " + fileName.GetFullName());
1530  m_rightChoice->Append(wxString::Format("%d", i) + ". - " + fileName.GetFullName());
1531  }
1532  }
1533  m_leftChoice->Thaw();
1534  m_rightChoice->Thaw();
1535  }
1536  if (nrTabs > nrImages)
1537  {
1538  // remove tab bar entries if needed
1539  // we have to disable listening to notebook selection events,
1540  // else we might update to a noexisting image
1541  m_listenToPageChange = false;
1542  m_leftChoice->Freeze();
1543  m_rightChoice->Freeze();
1544  for (int i=nrTabs-1; i >= (int)nrImages; i--) {
1545  m_leftChoice->Delete(i);
1546  m_rightChoice->Delete(i);
1547  }
1548  m_leftChoice->Thaw();
1549  m_rightChoice->Thaw();
1550  m_listenToPageChange = true;
1551  if (nrImages > 0) {
1552  // select some other image if we deleted the current image
1553  if (m_leftImageNr >= nrImages) {
1554  setLeftImage(nrImages -1);
1555  }
1556  if (m_rightImageNr >= nrImages) {
1557  setRightImage(nrImages -1);
1558  }
1559  } else {
1560  DEBUG_DEBUG("setting no images");
1561  m_leftImageNr = UINT_MAX;
1562  m_leftFile = "";
1563  m_rightImageNr = UINT_MAX;
1564  m_rightFile = "";
1565  // no image anymore..
1568  }
1569  }
1570 
1571  // update changed images
1572  bool update(false);
1573  for(HuginBase::UIntSet::const_iterator it = changed.begin(); it != changed.end(); ++it) {
1574  unsigned int imgNr = *it;
1575  // we only need to update the view if the currently
1576  // selected images were changed.
1577  // changing the images via the tabbar will always
1578  // take the current state directly from the pano
1579  // object
1580  DEBUG_DEBUG("image changed "<< imgNr);
1581  double yaw = const_map_get(m_pano->getImageVariables(imgNr), "y").getValue();
1582  double pitch = const_map_get(m_pano->getImageVariables(imgNr), "p").getValue();
1583  double roll = const_map_get(m_pano->getImageVariables(imgNr), "r").getValue();
1584  CPImageCtrl::ImageRotation rot = GetRot(yaw, pitch, roll);
1585  if (m_leftImageNr == imgNr) {
1586  DEBUG_DEBUG("left image dirty "<< imgNr);
1587  if (m_leftFile != pano.getImage(imgNr).getFilename()
1588  || m_leftRot != rot )
1589  {
1590  m_leftRot = rot;
1591  m_leftFile = pano.getImage(imgNr).getFilename();
1593  }
1594  update=true;
1595  }
1596 
1597  if (m_rightImageNr == imgNr) {
1598  DEBUG_DEBUG("right image dirty "<< imgNr);
1599  if (m_rightFile != pano.getImage(imgNr).getFilename()
1600  || m_rightRot != rot )
1601  {
1602  m_rightRot = rot;
1603  m_rightFile = pano.getImage(imgNr).getFilename();
1605  }
1606  update=true;
1607  }
1608  }
1609  // check if number of control points has changed, if so we need to update our variables
1610  if (pano.getNrOfCtrlPoints() != m_countCP)
1611  {
1612  m_countCP = pano.getNrOfCtrlPoints();
1613  update = true;
1614  };
1615 
1616  // if there is no selection, select the first one.
1617  m_leftChoice->Freeze();
1618  m_rightChoice->Freeze();
1619  if (m_rightImageNr == UINT_MAX && nrImages > 0) {
1620  setRightImage(0);
1621  }
1622  if (m_leftImageNr == UINT_MAX && nrImages > 0) {
1623  setLeftImage(0);
1624  }
1625  m_leftChoice->Thaw();
1626  m_rightChoice->Thaw();
1627 
1628  if (update || nrImages == 0) {
1629  UpdateDisplay(false);
1630  }
1633 }
1634 
1636 {
1637  DEBUG_DEBUG("")
1638  int fI = m_leftChoice->GetSelection();
1639  int sI = m_rightChoice->GetSelection();
1640 
1641  // valid selection and already set left image
1642  if (fI >= 0 && m_leftImageNr != UINT_MAX)
1643  {
1644  // set image number to selection
1645  m_leftImageNr = (unsigned int) fI;
1646  }
1647  // valid selection and already set right image
1648  if (sI >= 0 && m_rightImageNr != UINT_MAX)
1649  {
1650  // set image number to selection
1651  m_rightImageNr = (unsigned int) sI;
1652  }
1653  // reset selection
1654  m_x1Text->Clear();
1655  m_y1Text->Clear();
1656  m_x2Text->Clear();
1657  m_y2Text->Clear();
1658  if (m_cpModeChoice->GetSelection() < 3) {
1659  m_cpModeChoice->SetSelection(0);
1660  }
1661 
1664 
1665  // update control points
1666  const HuginBase::CPVector & controlPoints = m_pano->getCtrlPoints();
1667  const size_t oldCurrentPointSize = currentPoints.size();
1668  currentPoints.clear();
1669  mirroredPoints.clear();
1670 
1671  // create a list of all control points
1672  HuginBase::CPVector::size_type i = 0;
1675  for (HuginBase::CPVector::size_type index = 0; index < controlPoints.size(); ++index)
1676  {
1677  HuginBase::ControlPoint point(controlPoints[index]);
1678  if ((point.image1Nr == m_leftImageNr) && (point.image2Nr == m_rightImageNr)){
1679  m_leftImg->setCtrlPoint(point, false);
1680  m_rightImg->setCtrlPoint(point, true);
1681  currentPoints.push_back(std::make_pair(index, point));
1682  i++;
1683  } else if ((point.image2Nr == m_leftImageNr) && (point.image1Nr == m_rightImageNr)){
1684  m_leftImg->setCtrlPoint(point, true);
1685  m_rightImg->setCtrlPoint(point, false);
1686  point.mirror();
1687  mirroredPoints.insert(i);
1688  currentPoints.push_back(std::make_pair(index, point));
1689  i++;
1690  }
1691  }
1692  m_leftImg->Refresh();
1693  m_rightImg->Refresh();
1694 
1695  // put these control points into our listview.
1696  unsigned int selectedItem = UINT_MAX;
1697  long selectedCP = -1;
1698  for (int i = 0; i < m_cpList->GetItemCount(); i++)
1699  {
1700  if ( m_cpList->GetItemState( i, wxLIST_STATE_SELECTED))
1701  {
1702  selectedItem = (unsigned int) i; // remembers the old selection, only one can be selected
1703  selectedCP = m_cpList->GetItemData(i);
1704  break;
1705  }
1706  }
1707  m_cpList->Freeze();
1708  m_cpList->DeleteAllItems();
1709 
1710  for (unsigned int i=0; i < currentPoints.size(); ++i) {
1711  const HuginBase::ControlPoint & p(currentPoints[i].second);
1712  DEBUG_DEBUG("inserting LVItem " << i);
1713  long item = m_cpList->InsertItem(i, wxString::Format("%d", i), -1);
1714  // store index in list data field
1715  m_cpList->SetItemData(item, i);
1716  m_cpList->SetItem(i,1,wxString::Format("%.2f",p.x1));
1717  m_cpList->SetItem(i,2,wxString::Format("%.2f",p.y1));
1718  m_cpList->SetItem(i,3,wxString::Format("%.2f",p.x2));
1719  m_cpList->SetItem(i,4,wxString::Format("%.2f",p.y2));
1720  wxString mode;
1721  switch (p.mode) {
1723  mode = _("normal");
1724  break;
1726  mode = _("vert. Line");
1727  break;
1729  mode = _("horiz. Line");
1730  break;
1731  default:
1732  mode = wxString::Format(_("Line %d"), p.mode);
1733  break;
1734  }
1735  m_cpList->SetItem(i,5,mode);
1736  m_cpList->SetItem(i,6,wxString::Format("%.2f",p.error));
1737  }
1738  SortList();
1739 
1740  if (selectedItem <= (unsigned int)m_cpList->GetItemCount() && !newPair && m_cpList->GetItemCount() > 0)
1741  {
1742  // sets an old selection again, only if the images have not changed
1743  if (oldCurrentPointSize == currentPoints.size())
1744  {
1745  // number of control points is not changed, so select the same cp
1746  // as before
1747  long selected = m_cpList->FindItem(-1, selectedCP);
1748  m_cpList->SetItemState(selected, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
1749  m_cpList->EnsureVisible(selected);
1750  m_selectedPoint = selectedCP;
1751  }
1752  else
1753  {
1754  // number of cp has change, so keep the next item seleteced
1755  if (selectedItem == (unsigned int)m_cpList->GetItemCount())
1756  {
1757  // previously last item was selected, move selected to now last item
1758  selectedItem = m_cpList->GetItemCount() - 1;
1759  };
1760  m_cpList->SetItemState(selectedItem, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
1761  m_cpList->EnsureVisible(selectedItem);
1762  m_selectedPoint = m_cpList->GetItemData(selectedItem);
1763  };
1764  EnablePointEdit(true);
1765 
1767  m_x1Text->SetValue(wxString::Format("%.2f",p.x1));
1768  m_y1Text->SetValue(wxString::Format("%.2f",p.y1));
1769  m_x2Text->SetValue(wxString::Format("%.2f",p.x2));
1770  m_y2Text->SetValue(wxString::Format("%.2f",p.y2));
1771  m_cpModeChoice->SetSelection(p.mode);
1774 
1775  } else {
1776  m_selectedPoint = UINT_MAX;
1777  EnablePointEdit(false);
1778  }
1779 
1780  for ( int j=0; j < m_cpList->GetColumnCount() ; j++ )
1781  {
1782  //get saved width
1783  // -1 is auto
1784  int width = wxConfigBase::Get()->Read(wxString::Format( "/CPEditorPanel/ColumnWidth%d", j ), -1);
1785  if(width != -1)
1786  m_cpList->SetColumnWidth(j, width);
1787  }
1788 
1789  m_cpList->Thaw();
1790 }
1791 
1793 {
1794  m_delButton->Enable(state);
1795  m_finetuneButton->Enable(state);
1796  m_x1Text->Enable(state);
1797  m_y1Text->Enable(state);
1798  m_x2Text->Enable(state);
1799  m_y2Text->Enable(state);
1800  m_cpModeChoice->Enable(state);
1801 }
1802 
1803 void CPEditorPanel::OnTextPointChange(wxCommandEvent &e)
1804 {
1805  DEBUG_TRACE("");
1806  // find selected point
1807  long item = -1;
1808  item = m_cpList->GetNextItem(item,
1809  wxLIST_NEXT_ALL,
1810  wxLIST_STATE_SELECTED);
1811  // no selected item.
1812  if (item == -1) {
1813  return;
1814  }
1815  const unsigned int nr = m_cpList->GetItemData(item);
1816  assert(nr < currentPoints.size());
1817  HuginBase::ControlPoint cp = currentPoints[nr].second;
1818 
1819  // update point state
1820  double oldValue=cp.x1;
1821  bool valid_input=hugin_utils::str2double(m_x1Text->GetValue(), cp.x1);
1822  if(valid_input)
1823  valid_input=(cp.x1>=0) && (cp.x1<=m_pano->getSrcImage(cp.image1Nr).getWidth());
1824  if (!valid_input) {
1825  m_x1Text->Clear();
1826  *m_x1Text << oldValue;
1827  return;
1828  }
1829  oldValue=cp.y1;
1830  valid_input = hugin_utils::str2double(m_y1Text->GetValue(), cp.y1);
1831  if(valid_input)
1832  valid_input=(cp.y1>=0) && (cp.y1<=m_pano->getSrcImage(cp.image1Nr).getHeight());
1833  if (!valid_input) {
1834  m_y1Text->Clear();
1835  *m_y1Text << oldValue;
1836  return;
1837  }
1838  oldValue=cp.x2;
1839  valid_input = hugin_utils::str2double(m_x2Text->GetValue(), cp.x2);
1840  if(valid_input)
1841  valid_input=(cp.x2>=0) && (cp.x2<=m_pano->getSrcImage(cp.image2Nr).getWidth());
1842  if (!valid_input) {
1843  m_x2Text->Clear();
1844  *m_x2Text << oldValue;
1845  return;
1846  }
1847  oldValue=cp.y2;
1848  valid_input = hugin_utils::str2double(m_y2Text->GetValue(), cp.y2);
1849  if(valid_input)
1850  valid_input=(cp.y2>=0) && (cp.y2<=m_pano->getSrcImage(cp.image1Nr).getHeight());
1851  if (!valid_input) {
1852  m_y2Text->Clear();
1853  *m_y2Text << oldValue;
1854  return;
1855  }
1856 
1857  cp.mode = m_cpModeChoice->GetSelection();
1858  // if point was mirrored, reverse before setting it.
1859  if (set_contains(mirroredPoints, nr)) {
1860  cp.mirror();
1861  }
1864  );
1865 
1866 }
1867 
1868 void CPEditorPanel::OnLeftChoiceChange(wxCommandEvent & e)
1869 {
1870  DEBUG_TRACE("OnLeftChoiceChange() to " << e.GetSelection());
1871  if (m_listenToPageChange && e.GetSelection() >= 0) {
1872  setLeftImage((unsigned int) e.GetSelection());
1873  }
1874 }
1875 
1876 void CPEditorPanel::OnRightChoiceChange(wxCommandEvent & e)
1877 {
1878  DEBUG_TRACE("OnRightChoiceChange() to " << e.GetSelection());
1879  if (m_listenToPageChange && e.GetSelection() >= 0) {
1880  setRightImage((unsigned int) e.GetSelection());
1881  }
1882 }
1883 void CPEditorPanel::OnCPListSelect(wxListEvent & ev)
1884 {
1885  int t = ev.GetIndex();
1886  DEBUG_TRACE("selected: " << t);
1887  if (t >=0) {
1889  {
1890  // default behaviour, scroll both CPImageCtrls
1891  SelectLocalPoint(m_cpList->GetItemData(t));
1892  }
1893  else
1894  {
1895  // special case: scroll only one image
1897  // reset scroll status
1898  m_scrollHint = CP_SCROLL_BOTH;
1899  };
1901  }
1902  EnablePointEdit(true);
1903 }
1904 
1905 void CPEditorPanel::OnCPListDeselect(wxListEvent & ev)
1906 {
1907  // disable controls
1908  // when doing changes to this procedure do also check
1909  // interaction with control point table
1910  // e.g. m_selectedPoint=UINT_MAX will result in a endless loop and crash
1912  EnablePointEdit(false);
1913  m_leftImg->deselect();
1914  m_rightImg->deselect();
1915 }
1916 
1917 void CPEditorPanel::OnZoom(wxCommandEvent & e)
1918 {
1919  int leftX = 0;
1920  int leftY = 0;
1921  int rightX = 0;
1922  int rightY = 0;
1923  const wxSize leftSize = m_leftImg->GetClientSize();
1924  const wxSize rightSize = m_rightImg->GetClientSize();
1925  if (m_leftImg->getScale() > 0)
1926  {
1927  // remember old scroll position
1928  leftX = (m_leftImg->GetScrollPos(wxHORIZONTAL) + leftSize.GetWidth() / 2 )/ m_leftImg->getScale();
1929  leftY = (m_leftImg->GetScrollPos(wxVERTICAL) + leftSize.GetHeight() / 2) / m_leftImg->getScale();
1930  rightX = (m_rightImg->GetScrollPos(wxHORIZONTAL) + rightSize.GetWidth() / 2) / m_rightImg->getScale();
1931  rightY = (m_rightImg->GetScrollPos(wxVERTICAL) + rightSize.GetHeight() / 2) / m_rightImg->getScale();
1932  };
1933  double factor;
1934  switch (e.GetSelection()) {
1935  case 0:
1936  factor = 1;
1937  m_detailZoomFactor = factor;
1938  break;
1939  case 1:
1940  // fit to window
1941  factor = 0;
1942  break;
1943  case 2:
1944  factor = 2;
1945  m_detailZoomFactor = factor;
1946  break;
1947  case 3:
1948  factor = 1.5;
1949  m_detailZoomFactor = factor;
1950  break;
1951  case 4:
1952  factor = 0.75;
1953  break;
1954  case 5:
1955  factor = 0.5;
1956  break;
1957  case 6:
1958  factor = 0.25;
1959  break;
1960  default:
1961  DEBUG_ERROR("unknown scale factor");
1962  factor = 1;
1963  }
1964  m_leftImg->setScale(factor);
1965  m_rightImg->setScale(factor);
1966  // if a point is selected, keep it in view
1967  if (m_selectedPoint < UINT_MAX) {
1969  }
1970  else
1971  {
1972  if (factor > 0)
1973  {
1974  // scroll to keep old position in view
1975  m_leftImg->Scroll(leftX*factor - leftSize.GetWidth() / 2, leftY*factor - leftSize.GetHeight() / 2);
1976  m_rightImg->Scroll(rightX*factor - rightSize.GetWidth() / 2, rightY*factor - rightSize.GetHeight() / 2);
1977  };
1978  }
1979 }
1980 
1981 void CPEditorPanel::OnKey(wxKeyEvent & e)
1982 {
1983  DEBUG_DEBUG("key " << e.GetKeyCode()
1984  << " origin: id:" << e.GetId() << " obj: "
1985  << e.GetEventObject());
1986 
1987  if (e.m_keyCode == WXK_DELETE){
1988  DEBUG_DEBUG("Delete pressed");
1989  // remove working points..
1990  if (cpCreationState != NO_POINT) {
1992  } else {
1993  // remove selected point
1994  // find selected point
1995  long item = -1;
1996  item = m_cpList->GetNextItem(item,
1997  wxLIST_NEXT_ALL,
1998  wxLIST_STATE_SELECTED);
1999  // no selected item.
2000  if (item == -1) {
2001  wxBell();
2002  return;
2003  }
2004  unsigned int pNr = localPNr2GlobalPNr(m_cpList->GetItemData(item));
2005  DEBUG_DEBUG("about to delete point " << pNr);
2008  );
2009  }
2010  } else if (e.m_keyCode == '0') {
2011  wxCommandEvent dummy;
2012  dummy.SetInt(1);
2013  OnZoom(dummy);
2014  m_zoomChoice->SetSelection(1);
2015  } else if (e.m_keyCode == '1') {
2016  wxCommandEvent dummy;
2017  dummy.SetInt(0);
2018  OnZoom(dummy);
2019  m_zoomChoice->SetSelection(0);
2020  } else if (e.m_keyCode == '2') {
2021  wxCommandEvent dummy;
2022  dummy.SetInt(2);
2023  OnZoom(dummy);
2024  m_zoomChoice->SetSelection(2);
2025  } else if (e.CmdDown() && e.GetKeyCode() == WXK_LEFT) {
2026  // move to previous
2027  wxCommandEvent dummy;
2028  OnPrevImg(dummy);
2029  } else if (e.CmdDown() && e.GetKeyCode() == WXK_RIGHT) {
2030  // move to next
2031  wxCommandEvent dummy;
2032  OnNextImg(dummy);
2033  } else if (e.GetKeyCode() == 'f') {
2034  bool left = e.GetEventObject() == m_leftImg;
2035  if (cpCreationState == NO_POINT) {
2036  FineTuneSelectedPoint(left);
2037  } else if (cpCreationState == BOTH_POINTS_SELECTED) {
2038  FineTuneNewPoint(left);
2039  }
2040  } else if (e.GetKeyCode() == 'g') {
2041  // generate keypoints
2042  long th = wxGetNumberFromUser(_("Create control points.\nTo create less points,\nenter a higher number."), _("Corner Detection threshold"), _("Create control points"), 400, 0, 32000);
2043  if (th == -1) {
2044  return;
2045  }
2046  long scale = wxGetNumberFromUser(_("Create control points"), _("Corner Detection scale"), _("Create control points"), 2);
2047  if (scale == -1) {
2048  return;
2049  }
2050 
2051  try {
2052  wxBusyCursor busy;
2053  DEBUG_DEBUG("corner threshold: " << th << " scale: " << scale);
2056  );
2057  } catch (std::exception & e) {
2058  wxLogError(_("Error during control point creation:\n") + wxString(e.what(), wxConvLocal));
2059  }
2060  } else {
2061  e.Skip();
2062  }
2063 }
2064 
2065 void CPEditorPanel::OnAddButton(wxCommandEvent & e)
2066 {
2067  // check if the point can be created..
2069  CreateNewPoint();
2070  }
2071 }
2072 
2073 void CPEditorPanel::OnDeleteButton(wxCommandEvent & e)
2074 {
2075  DEBUG_TRACE("");
2076  // check if a point has been selected, but not added.
2077  if (cpCreationState != NO_POINT) {
2079  } else {
2080  // find selected point
2081  long item = -1;
2082  item = m_cpList->GetNextItem(item,
2083  wxLIST_NEXT_ALL,
2084  wxLIST_STATE_SELECTED);
2085  // no selected item.
2086  if (item == -1) {
2087  wxBell();
2088  return;
2089  }
2090  // get the global point number
2091  unsigned int pNr = localPNr2GlobalPNr(m_cpList->GetItemData(item));
2092 
2095  );
2098  }
2099 }
2100 
2101 // show a global control point
2102 void CPEditorPanel::ShowControlPoint(unsigned int cpNr)
2103 {
2104  const HuginBase::ControlPoint & p = m_pano->getCtrlPoint(cpNr);
2107  // FIXME reset display state
2109 
2110  SelectGlobalPoint(cpNr);
2111 }
2112 
2114 {
2115  DEBUG_TRACE(cpCreationState << " --> " << newState);
2116  // handle global state changes.
2117  bool fineTune = m_fineTuneCB->IsChecked() && (m_leftImageNr != m_rightImageNr);
2118  switch(newState) {
2119  case NO_POINT:
2120  // disable all drawing search boxes.
2121  m_leftImg->showSearchArea(false);
2122  m_rightImg->showSearchArea(false);
2123  // but draw template size, if fine-tune enabled
2124  m_leftImg->showTemplateArea(fineTune);
2125  m_rightImg->showTemplateArea(fineTune);
2126  m_addButton->Enable(false);
2127  if (m_selectedPoint < UINT_MAX) {
2128  m_delButton->Enable(true);
2129  } else {
2130  m_delButton->Enable(false);
2131  }
2132  if (cpCreationState != NO_POINT) {
2133  // reset zoom to previous setting
2134  wxCommandEvent tmpEvt;
2135  tmpEvt.SetInt(m_zoomChoice->GetSelection());
2136  OnZoom(tmpEvt);
2139  }
2140  break;
2141  case LEFT_POINT:
2142  // disable search area on left window
2143  m_leftImg->showSearchArea(false);
2144  // show search area on right window
2145  m_rightImg->showSearchArea(fineTune);
2146 
2147  // show template area
2148  m_leftImg->showTemplateArea(fineTune);
2149  m_rightImg->showTemplateArea(false);
2150 
2151  // unselect point
2152  ClearSelection();
2153  m_addButton->Enable(false);
2154  m_delButton->Enable(false);
2155  MainFrame::Get()->SetStatusText(_("Select point in right image"),0);
2156  break;
2157  case RIGHT_POINT:
2158  m_leftImg->showSearchArea(fineTune);
2159  m_rightImg->showSearchArea(false);
2160 
2161  m_leftImg->showTemplateArea(false);
2162  m_rightImg->showTemplateArea(fineTune);
2163 
2164  ClearSelection();
2165  m_addButton->Enable(false);
2166  m_delButton->Enable(false);
2167  MainFrame::Get()->SetStatusText(_("Select point in left image"),0);
2168  break;
2169  case LEFT_POINT_RETRY:
2170  case RIGHT_POINT_RETRY:
2171  m_leftImg->showSearchArea(false);
2172  m_rightImg->showSearchArea(false);
2173  // but draw template size, if fine-tune enabled
2174  m_leftImg->showTemplateArea(false);
2175  m_rightImg->showTemplateArea(false);
2176  m_addButton->Enable(false);
2177  m_delButton->Enable(false);
2178  break;
2179  case BOTH_POINTS_SELECTED:
2180  m_leftImg->showTemplateArea(false);
2181  m_rightImg->showTemplateArea(false);
2182  m_leftImg->showSearchArea(false);
2183  m_rightImg->showSearchArea(false);
2184  m_addButton->Enable(true);
2185  m_delButton->Enable(false);
2186  }
2187  // apply the change
2188  cpCreationState = newState;
2189 }
2190 
2191 void CPEditorPanel::OnPrevImg(wxCommandEvent & e)
2192 {
2193  if (m_pano->getNrOfImages() < 2) return;
2194  int nImgs = m_pano->getNrOfImages();
2195  int left = m_leftImageNr -1;
2196  int right = m_rightImageNr -1;
2197  if (left < 0) {
2198  left += nImgs;
2199  } else if (left >= nImgs) {
2200  left -= nImgs;
2201  }
2202 
2203  if (right < 0) {
2204  right += nImgs;
2205  } else if (right >= nImgs) {
2206  right -= nImgs;
2207  }
2208  setLeftImage((unsigned int) left);
2209  setRightImage((unsigned int) right);
2210 }
2211 
2212 void CPEditorPanel::OnNextImg(wxCommandEvent & e)
2213 {
2214  if (m_pano->getNrOfImages() < 2) return;
2215  int nImgs = m_pano->getNrOfImages();
2216  int left = m_leftImageNr + 1;
2217  int right = m_rightImageNr + 1;
2218  if (left < 0) {
2219  left += nImgs;
2220  } else if (left >= nImgs) {
2221  left -= nImgs;
2222  }
2223 
2224  if (right < 0) {
2225  right += nImgs;
2226  } else if (right >= nImgs) {
2227  right -= nImgs;
2228  }
2229  setLeftImage((unsigned int) left);
2230  setRightImage((unsigned int) right);
2231 }
2232 
2233 void CPEditorPanel::OnFineTuneButton(wxCommandEvent & e)
2234 {
2235  if (cpCreationState == NO_POINT) {
2236  FineTuneSelectedPoint(false);
2237  } else if (cpCreationState == BOTH_POINTS_SELECTED) {
2238  FineTuneNewPoint(false);
2239  }
2240 }
2241 
2242 void CPEditorPanel::OnActionContextMenu(wxContextMenuEvent& e)
2243 {
2244  m_cpActionContextMenu->SetLabel(XRCID("cp_menu_create_cp"), wxString::Format(_("Create cp (Current setting: %s)"), MainFrame::Get()->GetSelectedCPGenerator().c_str()));
2245  PopupMenu(m_cpActionContextMenu);
2246 };
2247 
2248 void CPEditorPanel::OnActionButton(wxCommandEvent& e)
2249 {
2250  switch (m_cpActionButtonMode)
2251  {
2253  OnCreateCPButton(e);
2254  break;
2255  case CPTAB_ACTION_CLEAN_CP:
2256  OnCleanCPButton(e);
2257  break;
2258  case CPTAB_ACTION_CELESTE:
2259  default:
2260  OnCelesteButton(e);
2261  break;
2262  };
2263 };
2264 
2265 void CPEditorPanel::OnCreateCPButton(wxCommandEvent& e)
2266 {
2268  {
2269  // when the same image is selected left and right we are running linefind
2270  // with default parameters
2271  CPDetectorSetting linefindSetting;
2272 #ifdef __WXMSW__
2273  linefindSetting.SetProg("linefind.exe");
2274 #else
2275  linefindSetting.SetProg("linefind");
2276 #endif
2277  linefindSetting.SetArgs("-o %o %s");
2278  HuginBase::UIntSet imgs;
2279  imgs.insert(m_leftImageNr);
2280  MainFrame::Get()->RunCPGenerator(linefindSetting, imgs);
2281  }
2282  else
2283  {
2284  HuginBase::UIntSet imgs;
2285  imgs.insert(m_leftImageNr);
2286  imgs.insert(m_rightImageNr);
2287  MainFrame::Get()->RunCPGenerator(imgs);
2288  };
2289 };
2290 
2291 void CPEditorPanel::OnCelesteButton(wxCommandEvent & e)
2292 {
2293  if (currentPoints.empty())
2294  {
2295  hugin_utils::HuginMessageBox(_("Cannot run celeste without at least one control point connecting the two images"), _("Hugin"), wxOK | wxICON_INFORMATION, this);
2296  std::cout << "Cannot run celeste without at least one control point connecting the two images" << std::endl;
2297  }
2298  else
2299  {
2300  ProgressReporterDialog progress(4, _("Running Celeste"), _("Running Celeste"), this);
2301  progress.updateDisplayValue(_("Loading model file"));
2302 
2303  struct celeste::svm_model* model=MainFrame::Get()->GetSVMModel();
2304  if(model==NULL)
2305  {
2306  return;
2307  };
2308 
2309  // Get Celeste parameters
2310  wxConfigBase *cfg = wxConfigBase::Get();
2311  // SVM threshold
2313  cfg->Read("/Celeste/Threshold", &threshold, HUGIN_CELESTE_THRESHOLD);
2314 
2315  // Mask resolution - 1 sets it to fine
2316  bool t = (cfg->Read("/Celeste/Filter", HUGIN_CELESTE_FILTER) == 0);
2317  int radius=(t)?10:20;
2318  DEBUG_TRACE("Running Celeste");
2319 
2320  if (!progress.updateDisplayValue(_("Running Celeste")))
2321  {
2322  return;
2323  }
2324  // Image to analyse
2325  ImageCache::EntryPtr img=ImageCache::getInstance().getImage(m_pano->getImage(m_leftImageNr).getFilename());
2326  vigra::UInt16RGBImage in;
2327  if(img->image16->width()>0)
2328  {
2329  in.resize(img->image16->size());
2330  vigra::omp::copyImage(srcImageRange(*(img->image16)),destImage(in));
2331  }
2332  else
2333  {
2334  ImageCache::ImageCacheRGB8Ptr im8=img->get8BitImage();
2335  in.resize(im8->size());
2336  vigra::omp::transformImage(srcImageRange(*im8),destImage(in),vigra::functor::Arg1()*vigra::functor::Param(65535/255));
2337  };
2338  // convert to sRGB if icc profile found in file
2339  if (!img->iccProfile->empty())
2340  {
2341  HuginBase::Color::ApplyICCProfile(in, *(img->iccProfile), TYPE_RGB_16);
2342  };
2343  if (!progress.updateDisplayValue())
2344  {
2345  return;
2346  };
2347  HuginBase::UIntSet cloudCP = celeste::getCelesteControlPoints(model, in, currentPoints, radius, threshold, 800);
2348  in.resize(0,0);
2349  if (!progress.updateDisplay())
2350  {
2351  return;
2352  }
2353 
2354  if(!cloudCP.empty())
2355  {
2358  );
2359  };
2360 
2361  progress.updateDisplayValue();
2362  hugin_utils::HuginMessageBox(wxString::Format(_("Removed %lu control points"), static_cast<unsigned long int>(cloudCP.size())), _("Hugin"), wxOK | wxICON_INFORMATION, this);
2363  DEBUG_TRACE("Finished running Celeste");
2364  }
2365 }
2366 
2367 void CPEditorPanel::OnCleanCPButton(wxCommandEvent& e)
2368 {
2369  if (currentPoints.size() < 2)
2370  {
2371  wxBell();
2372  return;
2373  };
2374  // calculate mean and variance only for currently active cp
2375  double mean = 0;
2376  double var = 0;
2377  size_t n = 0;
2378  for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it)
2379  {
2380  n++;
2381  double x = it->second.error;
2382  double delta = x - mean;
2383  mean += delta / n;
2384  var += delta*(x - mean);
2385  }
2386  var = var / (n - 1);
2387  const double limit = (sqrt(var) > mean) ? mean : (mean + sqrt(var));
2388  HuginBase::UIntSet removedCPs;
2389  for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it)
2390  {
2391  if (it->second.error > limit)
2392  {
2393  removedCPs.insert(it->first);
2394  };
2395  };
2396  if (!removedCPs.empty())
2397  {
2398  hugin_utils::HuginMessageBox(wxString::Format(_("Removed %lu control points"), (unsigned long int)removedCPs.size()), _("Hugin"), wxOK | wxICON_INFORMATION, this);
2400  }
2401  else
2402  {
2403  wxBell();
2404  }
2405 };
2406 
2408 {
2410  wxString s(_("Create cp"));
2411  s.Append(wxUniChar(0x25bc));
2412  m_actionButton->SetLabel(s);
2413  m_actionButton->SetToolTip(_("Create control points for image pair with currently selected control point detector on photos tab."));
2414  Layout();
2415  wxConfig::Get()->Write("/CPEditorPanel/ActionMode", static_cast<long>(m_cpActionButtonMode));
2416 };
2417 
2419 {
2421  wxString s(_("Celeste"));
2422  s.Append(wxUniChar(0x25bc));
2423  m_actionButton->SetLabel(s);
2424  m_actionButton->SetToolTip(_("Tries to remove control points from clouds"));
2425  Layout();
2426  wxConfig::Get()->Write("/CPEditorPanel/ActionMode", static_cast<long>(m_cpActionButtonMode));
2427 };
2428 
2430 {
2432  wxString s(_("Clean cp"));
2433  s.Append(wxUniChar(0x25bc));
2434  m_actionButton->SetLabel(s);
2435  m_actionButton->SetToolTip(_("Remove outlying control points by statistical method"));
2436  Layout();
2437  wxConfig::Get()->Write("/CPEditorPanel/ActionMode", static_cast<long>(m_cpActionButtonMode));
2438 };
2439 
2441  const vigra::Diff2D & srcPnt,
2442  hugin_utils::FDiff2D & movedSrcPnt,
2443  unsigned int moveNr,
2444  const hugin_utils::FDiff2D & movePnt)
2445 {
2446  long templWidth = wxConfigBase::Get()->Read("/Finetune/TemplateSize",HUGIN_FT_TEMPLATE_SIZE);
2447  long sWidth = templWidth + wxConfigBase::Get()->Read("/Finetune/LocalSearchWidth",HUGIN_FT_LOCAL_SEARCH_WIDTH);
2449  if (!PointFineTune(srcNr, srcPnt, templWidth, moveNr, movePnt, sWidth, result))
2450  {
2451  return hugin_utils::FDiff2D(-1, -1);
2452  };
2453  movedSrcPnt = result.corrPos;
2454  if (result.corrPos.x < 0 || result.corrPos.y < 0 || result.maxpos.x < 0 || result.maxpos.y < 0)
2455  {
2456  return hugin_utils::FDiff2D(-1, -1);
2457  }
2458  return result.maxpos;
2459 }
2460 
2462 {
2463  DEBUG_DEBUG(" selected Point: " << m_selectedPoint);
2464  if (m_selectedPoint == UINT_MAX) return;
2466 
2468 
2469  unsigned int srcNr = cp.image1Nr;
2470  unsigned int moveNr = cp.image2Nr;
2471  vigra::Diff2D srcPnt(hugin_utils::roundi(cp.x1), hugin_utils::roundi(cp.y1));
2472  vigra::Diff2D movePnt(hugin_utils::roundi(cp.x2), hugin_utils::roundi(cp.y2));
2473  if (left) {
2474  srcNr = cp.image2Nr;
2475  moveNr = cp.image1Nr;
2476  srcPnt = vigra::Diff2D(hugin_utils::roundi(cp.x2), hugin_utils::roundi(cp.y2));
2477  movePnt = vigra::Diff2D(hugin_utils::roundi(cp.x1), hugin_utils::roundi(cp.y1));
2478  }
2479 
2480  hugin_utils::FDiff2D movedSrcPnt;
2481  hugin_utils::FDiff2D result = LocalFineTunePoint(srcNr, srcPnt, movedSrcPnt, moveNr, movePnt);
2482 
2483  if (result.x < 0 || result.y < 0)
2484  {
2485  wxBell();
2486  return;
2487  };
2488 
2489  if (left) {
2490  cp.x1 = result.x;
2491  cp.y1 = result.y;
2492  cp.x2 = movedSrcPnt.x;
2493  cp.y2 = movedSrcPnt.y;
2494  } else {
2495  cp.x2 = result.x;
2496  cp.y2 = result.y;
2497  cp.x1 = movedSrcPnt.x;
2498  cp.y1 = movedSrcPnt.y;
2499  }
2500 
2501  // if point was mirrored, reverse before setting it.
2503  cp.mirror();
2504  }
2507  );
2508 }
2509 
2510 
2512 {
2516  {
2517  return;
2518  }
2519 
2522 
2523  unsigned int srcNr = m_leftImageNr;
2524  vigra::Diff2D srcPnt(leftP.toDiff2D());
2525  unsigned int moveNr = m_rightImageNr;
2526  vigra::Diff2D movePnt(rightP.toDiff2D());
2527  if (left) {
2528  srcNr = m_rightImageNr;
2529  srcPnt = rightP.toDiff2D();
2530  moveNr = m_leftImageNr;
2531  movePnt = leftP.toDiff2D();
2532  }
2533 
2534  hugin_utils::FDiff2D movedSrcPnt;
2535  hugin_utils::FDiff2D result = LocalFineTunePoint(srcNr, srcPnt, movedSrcPnt, moveNr, movePnt);
2536 
2537  if (result.x < 0 || result.y < 0)
2538  {
2539  wxBell();
2540  return;
2541  };
2542  if (left) {
2543  m_leftImg->setNewPoint(result);
2544  m_leftImg->Refresh();
2545  m_rightImg->setNewPoint(movedSrcPnt);
2546  m_rightImg->Refresh();
2547 
2548  } else {
2549  m_rightImg->setNewPoint(result);
2550  m_rightImg->Refresh();
2551  m_leftImg->setNewPoint(movedSrcPnt);
2552  m_leftImg->Refresh();
2553  }
2554 }
2555 
2557 {
2558  size_t nrNormalCp = 0;
2559  for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it)
2560  {
2561  if (it->second.mode == HuginBase::ControlPoint::X_Y)
2562  {
2563  ++nrNormalCp;
2564  };
2565  };
2566  if (nrNormalCp==0)
2567  {
2568  DEBUG_WARN("Cannot estimate position without at least one point");
2569  return hugin_utils::FDiff2D(0, 0);
2570  }
2571 
2572  // get copy of SrcPanoImage and reset position
2574  leftImg.setYaw(0);
2575  leftImg.setPitch(0);
2576  leftImg.setRoll(0);
2577  leftImg.setX(0);
2578  leftImg.setY(0);
2579  leftImg.setZ(0);
2580  HuginBase::SrcPanoImage rightImg = m_pano->getSrcImage(left ? m_rightImageNr : m_leftImageNr);
2581  rightImg.setYaw(0);
2582  rightImg.setPitch(0);
2583  rightImg.setRoll(0);
2584  rightImg.setX(0);
2585  rightImg.setY(0);
2586  rightImg.setZ(0);
2587  // generate a temporary pano
2588  HuginBase::Panorama optPano;
2589  optPano.addImage(leftImg);
2590  optPano.addImage(rightImg);
2591  // construct OptimizeVector
2593  std::set<std::string> opt;
2594  optVec.push_back(opt);
2595  opt.insert("y");
2596  opt.insert("p");
2597  if (nrNormalCp > 1)
2598  {
2599  opt.insert("r");
2600  };
2601  optVec.push_back(opt);
2602  optPano.setOptimizeVector(optVec);
2603  // now add control points, need to check image numbers
2604  HuginBase::CPVector cps;
2605  for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it)
2606  {
2607  HuginBase::ControlPoint cp(it->second);
2609  {
2610  cp.image1Nr = left ? 0 : 1;
2611  cp.image2Nr = left ? 1 : 0;
2612  cps.push_back(cp);
2613  };
2614  };
2615  optPano.setCtrlPoints(cps);
2617  HuginBase::PTools::optimize(optPano);
2619 
2620  // now transform the wanted point p to other image
2621  HuginBase::PTools::Transform transformBackward;
2622  transformBackward.createInvTransform(optPano.getImage(0), optPano.getOptions());
2623  HuginBase::PTools::Transform transformForward;
2624  transformForward.createTransform(optPano.getImage(1), optPano.getOptions());
2626  if (transformBackward.transformImgCoord(t, p))
2627  {
2628  if (transformForward.transformImgCoord(t, t))
2629  {
2630  // clip to fit to
2631  if (t.x < 0) t.x = 0;
2632  if (t.y < 0) t.y = 0;
2633  if (t.x > optPano.getImage(1).getWidth()) t.x = optPano.getImage(1).getWidth();
2634  if (t.y > optPano.getImage(1).getHeight()) t.y = optPano.getImage(1).getHeight();
2635  DEBUG_DEBUG("estimated point " << t.x << "," << t.y);
2636  return t;
2637  };
2638  };
2639  wxBell();
2640  return hugin_utils::FDiff2D(0, 0);
2641 }
2642 
2643 void CPEditorPanel::OnColumnWidthChange( wxListEvent & e )
2644 {
2645  int colNum = e.GetColumn();
2646  wxConfigBase::Get()->Write( wxString::Format("/CPEditorPanel/ColumnWidth%d",colNum), m_cpList->GetColumnWidth(colNum) );
2647 }
2648 
2650 {
2651  const int newCol = e.GetColumn();
2652  if (m_sortCol == newCol)
2653  {
2655  }
2656  else
2657  {
2658  m_sortCol = newCol;
2659  m_sortAscending = true;
2660  };
2661  m_cpList->ShowSortIndicator(m_sortCol, m_sortAscending);
2662  SortList();
2663  Refresh();
2664 }
2665 
2666 void CPEditorPanel::OnShowLinesCheckbox(wxCommandEvent& e)
2667 {
2668  m_leftImg->ShowLines(e.IsChecked());
2669  m_rightImg->ShowLines(e.IsChecked());
2670  Refresh();
2671 }
2672 
2673 CPImageCtrl::ImageRotation CPEditorPanel::GetRot(double yaw, double pitch, double roll)
2674 {
2676  // normalize roll angle
2677  while (roll > 360) roll-= 360;
2678  while (roll < 0) roll += 360;
2679 
2680  while (pitch > 180) pitch -= 360;
2681  while (pitch < -180) pitch += 360;
2682  bool headOver = (pitch > 90 || pitch < -90);
2683 
2684  if (wxConfig::Get()->Read("/CPEditorPanel/AutoRot",1L)) {
2685  if (roll >= 315 || roll < 45) {
2686  rot = headOver ? CPImageCtrl::ROT180 : CPImageCtrl::ROT0;
2687  } else if (roll >= 45 && roll < 135) {
2688  rot = headOver ? CPImageCtrl::ROT270 : CPImageCtrl::ROT90;
2689  } else if (roll >= 135 && roll < 225) {
2690  rot = headOver ? CPImageCtrl::ROT0 : CPImageCtrl::ROT180;
2691  } else {
2692  rot = headOver ? CPImageCtrl::ROT90 : CPImageCtrl::ROT270;
2693  }
2694  }
2695  return rot;
2696 }
2697 
2699 
2701  : wxXmlResourceHandler()
2702 {
2703  AddWindowStyles();
2704 }
2705 
2707 {
2708  XRC_MAKE_INSTANCE(cp, CPEditorPanel)
2709 
2710  cp->Create(m_parentAsWindow,
2711  GetID(),
2712  GetPosition(), GetSize(),
2713  GetStyle("style"),
2714  GetName());
2715 
2716  SetupWindow( cp);
2717 
2718  return cp;
2719 }
2720 
2722 {
2723  return IsOfClass(node, "CPEditorPanel");
2724 }
2725 
2726 IMPLEMENT_DYNAMIC_CLASS(CPEditorPanelXmlHandler, wxXmlResourceHandler)
2727 
void CalcCPDistance(HuginBase::Panorama *pano)
Get maximum CP distance for all images pairs containing the reference image.
wxButton * m_finetuneButton
PanoramaOptions::ProjectionFormat getProjection() const
void ScrollDelta(const wxPoint &delta)
scroll the window by delta pixels
void OnColumnHeaderClick(wxListEvent &e)
Dummy progress display, without output.
void SelectGlobalPoint(unsigned int globalNr)
Select a point.
void NewPointChange(hugin_utils::FDiff2D p, bool left)
static double calcOptimalPanoScale(const SrcPanoImage &src, const PanoramaOptions &dest)
function to calculate the scaling factor so that the distances in the input image and panorama image ...
wxButton * m_prevImgButton
HuginBase::PTools::Transform m_leftInvTransformMag
void setHeight(unsigned int h)
set panorama height
bool updateDisplayValue(const wxString &message, const wxString &filename=wxEmptyString)
virtual wxObject * DoCreateResource()
int roundi(T x)
Definition: hugin_math.h:73
void setNewPoint(const hugin_utils::FDiff2D &p)
set new point to a specific point
void transformImage(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
Transform an image into the panorama.
CPEventMode getMode()
accessor functions (they could check mode to see if a getXYZ() is allowed
Definition: CPImageCtrl.h:69
wxCheckBox * m_autoAddCB
#define HUGIN_FT_LOCAL_SEARCH_WIDTH
vigra_ext::CorrelationResult PointFineTuneProjectionAware(const HuginBase::SrcPanoImage &templ, const vigra::UInt8RGBImage &templImg, vigra::Diff2D templPos, int templSize, const HuginBase::SrcPanoImage &search, const vigra::UInt8RGBImage &searchImg, vigra::Diff2D searchPos, int sWidth)
function for fine-tune with remapping to stereographic projection
#define HUGIN_FT_SEARCH_AREA_PERCENT
bool str2double(const wxString &s, double &d)
Definition: wxPlatform.cpp:37
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
void deselect()
remove selection.
wxMenu * m_cpActionContextMenu
CPImagesComboBox * m_leftChoice
wxButton * m_addButton
void SortList()
sorting functions
control point editor panel.
Definition: CPEditorPanel.h:64
bool PointFineTune(unsigned int tmplImgNr, const vigra::Diff2D &tmplPoint, int tmplWidth, unsigned int subjImgNr, const hugin_utils::FDiff2D &subjPoint, int searchWidth, vigra_ext::CorrelationResult &tunedPos)
search for region in destImg
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
Definition: Panorama.cpp:1551
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
void OnCPListDeselect(wxListEvent &e)
std::unique_ptr< wxMessageDialogBase > MessageDialog
Definition: wxutils.h:87
CPImagesComboBox * m_rightChoice
virtual bool CanHandle(wxXmlNode *node)
remove a control point
Definition: PanoCommand.h:294
hugin_utils::FDiff2D corrPos
Definition: Correlation.h:66
CorrelationResult PointFineTune(const IMAGET &templImg, ACCESSORT access_t, vigra::Diff2D templPos, int templSize, const IMAGES &searchImg, ACCESSORS access_s, vigra::Diff2D searchPos, int sWidth)
fine tune a point with normalized cross correlation
Definition: Correlation.h:504
#define DEBUG_TRACE(msg)
Definition: utils.h:67
void OnAddButton(wxCommandEvent &e)
no point selected
void OnCreateCPButton(wxCommandEvent &e)
#define HUGIN_FT_CURV_THRESHOLD
void registerPTWXDlgFcn()
Definition: PTWXDlg.cpp:178
void OnCPListSelect(wxListEvent &e)
#define HUGIN_FT_ROTATION_STEPS
CPTabActionButtonMode m_cpActionButtonMode
void selectPoint(unsigned int, bool scrollTo=true)
select a point for usage
Events to notify about new point / region / point change.
Definition: CPImageCtrl.h:40
CPImageCtrl * m_rightImg
wxTextCtrl * m_x1Text
void FineTuneSelectedPoint(bool left)
int wxCALLBACK SortIndexAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr WXUNUSED(sortData))
void OnKey(wxKeyEvent &e)
void deregisterPTWXDlgFcn()
Definition: PTWXDlg.cpp:185
int getNextCPTypeLineNumber() const
get the number of a control point
Definition: Panorama.cpp:2010
general : Matrix3 is a class for handling 3x3 Matrix manipulation.
Definition: Matrix3.h:37
std::size_t getNrOfCtrlPoints() const
number of control points
Definition: Panorama.h:306
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition: stl_utils.h:74
#define SORTASCENDING(functionName, var)
wxButton * m_nextImgButton
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
HuginBase::ImageCache::ImageCacheRGB8Ptr ImageCacheRGB8Ptr
Definition: wxImageCache.h:33
void SetArgs(wxString new_args)
sets arguments of one step detector or feature descriptor
void OnFineTuneButton(wxCommandEvent &e)
wxTextCtrl * m_y1Text
include file for the hugin project
void setLeftImage(unsigned int imgNr)
set left image
void GetRotationPT(double &Yaw, double &Pitch, double &Roll)
GetRotation in panotools style.
Definition: Matrix3.cpp:157
wxTextCtrl * m_y2Text
Owner Drawn ComboBox for showing connected images on CP tab.
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition: Panorama.h:319
int getHeight() const
Get the height of the image in pixels.
Definition: SrcPanoImage.h:276
void EnablePointEdit(bool state)
enable or disable controls for editing other points
brief description.
Definition: CPImageCtrl.h:169
void OnNextImg(wxCommandEvent &e)
add a control point
Definition: PanoCommand.h:268
unsigned int getPointNr()
Definition: CPImageCtrl.h:78
remove several control points
Definition: PanoCommand.h:307
represents a control point
Definition: ControlPoint.h:38
const Map::mapped_type & const_map_get(const Map &m, const typename Map::key_type &key)
Definition: stl_utils.h:110
void SetRotationPT(double yaw, double pitch, double roll)
set rotation in panotools style, code adapted from Panotools-Script by Bruno Postle ...
Definition: Matrix3.cpp:110
void ShowControlPoint(unsigned int cpNr)
show a control point
void setOptimizeVector(const OptimizeVector &optvec)
set optimize setting
Definition: Panorama.cpp:297
CorrelationResult PointFineTuneRotSearch(const IMAGET &templImg, vigra::Diff2D templPos, int templSize, const IMAGES &searchImg, vigra::Diff2D searchPos, int sWidth, double startAngle, double stopAngle, int angleSteps)
fine tune a point with normalized cross correlation, searches x,y and phi (rotation around z) ...
Definition: Correlation.h:631
MessageDialog GetMessageDialog(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition: wxutils.cpp:212
void OnActionContextMenu(wxContextMenuEvent &e)
virtual ~CPEditorPanel()
dtor.
void OnActionButton(wxCommandEvent &e)
#define DEBUG_FATAL(msg)
Definition: utils.h:78
unsigned int m_leftImageNr
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
void OnCleanCPButton(wxCommandEvent &e)
void OnTextPointChange(wxCommandEvent &e)
void clearNewPoint()
clear new point
#define DEBUG_WARN(msg)
Definition: utils.h:74
Model for a panorama.
Definition: Panorama.h:152
wxCheckBox * m_fineTuneCB
double getScale()
return scale factor, 0 for autoscale
Definition: CPImageCtrl.h:289
right point, finetune for left point failed
void OnLeftChoiceChange(wxCommandEvent &e)
#define HUGIN_FT_TEMPLATE_SIZE
class, which stores all settings of one cp detector
void CreateNewPoint()
this is used to finally create the point in the panorama model
wxCheckBox * m_showLinesCB
const VariableMap getImageVariables(unsigned int imgNr) const
Get the variables of an image.
Definition: Panorama.cpp:128
void OnZoom(wxCommandEvent &e)
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name="panel")
wxPanel * m_cp_ctrls
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
static MainFrame * Get()
hack.. kind of a pseudo singleton...
Definition: MainFrame.cpp:2129
void Init(CPEditorPanel *parent)
void clearCtrlPointList()
clear internal control point list
CPCreationState
the state machine for point selection: it is set to the current selection
void createInvTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
create image-&gt;pano transformation
void FineTuneNewPoint(bool left)
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be &#39;add&#39; method?)
Definition: Panorama.cpp:449
void SetProg(wxString new_prog)
sets program for one step detector or feature descriptor
#define HUGIN_CELESTE_FILTER
int getWidth() const
Get the width of the image in pixels.
Definition: SrcPanoImage.h:266
CPImageCtrl::ImageRotation GetRot(double yaw, double roll, double pitch)
calculate rotation required for upright image display from roll, pitch and yaw angles ...
const ControlPoint & getCtrlPoint(std::size_t nr) const
get a control point, counting starts with 0
Definition: Panorama.h:312
hugin_utils::FDiff2D EstimatePoint(const hugin_utils::FDiff2D &p, bool left)
Estimate position of point in the other image.
#define HUGIN_CELESTE_THRESHOLD
HuginBase::PTools::Transform m_rightTransform
CPImageCtrl * m_leftImg
void showTemplateArea(bool show=true)
wxPoint MaxScrollDelta(wxPoint delta)
calculate maximum delta that is allowed when scrolling
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
Maximum of correlation, position and value.
Definition: Correlation.h:56
void OnDeleteButton(wxCommandEvent &e)
hugin_utils::FDiff2D curv
Definition: Correlation.h:68
bool globalPNr2LocalPNr(unsigned int &localNr, unsigned int globalNr) const
map a global point nr to a local one, if possible
#define SORTDESCENDING(functionName, var)
wxListCtrl * m_cpList
CPCreationState cpCreationState
wxwindows specific panorama commands
evaluate x, points are on a vertical line
Definition: ControlPoint.h:47
unsigned int localPNr2GlobalPNr(unsigned int localNr) const
find a local point
void OnActionSelectCleanCP(wxCommandEvent &e)
static GlobalCmdHist & getInstance()
options wxIntPtr item2
void OnActionSelectCeleste(wxCommandEvent &e)
point in left image selected
void OnShowLinesCheckbox(wxCommandEvent &e)
std::set< unsigned int > mirroredPoints
TDiff2D< double > FDiff2D
Definition: hugin_math.h:155
const hugin_utils::FDiff2D & getPoint()
Definition: CPImageCtrl.h:75
CPImageCtrl::ImageRotation m_rightRot
HuginBase::PTools::Transform m_leftTransformMag
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
std::string m_leftFile
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
void ClearSelection()
unselect a point
HuginBase::PTools::Transform m_leftInvTransform
#define DEBUG_ERROR(msg)
Definition: utils.h:76
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
Definition: ROIImage.h:287
void setTransforms(HuginBase::PTools::Transform *firstTrans, HuginBase::PTools::Transform *firstInvTrans, HuginBase::PTools::Transform *secondInvTrans)
!! from PTOptimise.h 1951
HuginBase::PTools::Transform m_rightInvTransform
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
Definition: Panorama.cpp:319
void showSearchArea(bool show=true)
show/hide the search area rectangle
std::string m_rightFile
CPImageCtrl::ImageRotation m_leftRot
void RunCPGenerator(CPDetectorSetting &setting, const HuginBase::UIntSet &img)
run the cp generator with the given setting on selected images
Definition: MainFrame.cpp:2103
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
wxButton * m_delButton
wxButton * m_actionButton
unsigned int m_rightImageNr
void Init(HuginBase::Panorama *pano)
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
int wxCALLBACK SortIndexDescending(wxIntPtr item1, wxIntPtr item2, wxIntPtr WXUNUSED(sortData))
void addObserver(PanoramaObserver *o)
add a panorama observer.
Definition: Panorama.cpp:1546
void estimateAndAddOtherPoint(const hugin_utils::FDiff2D &p, bool left, CPImageCtrl *thisImg, unsigned int thisImgNr, CPCreationState THIS_POINT, CPCreationState THIS_POINT_RETRY, CPImageCtrl *otherImg, unsigned int otherImgNr, CPCreationState OTHER_POINT, CPCreationState OTHER_POINT_RETRY)
estimate and set point in other image
struct celeste::svm_model * GetSVMModel()
Definition: MainFrame.cpp:2186
unsigned int getWidth() const
hugin_utils::FDiff2D getNewPoint()
get the new point
void OnCPEvent(CPEvent &ev)
void changeState(CPCreationState newState)
#define HUGIN_FT_ROTATION_START_ANGLE
include file for the hugin project
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
like transform, but return image coordinates, not cartesian coordinates
void UpdateTransforms()
updated the internal transform object for drawing line in controls
void OnPrevImg(wxCommandEvent &e)
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
void OnRightChoiceChange(wxCommandEvent &e)
Handle EVT_KILL_FOCUS and convert it to a EVT_TEXT_ENTER event.
#define RAD_TO_DEG(x)
Definition: hugin_math.h:45
void SelectLocalPoint(unsigned int LVpointNr, bool scrollLeft=true, bool scrollRight=true)
select a local point.
HuginBase::UIntSet getCelesteControlPoints(struct svm_model *model, vigra::UInt16RGBImage &input, HuginBase::CPointVector cps, int radius, float threshold, int resize_dimension, bool verbose)
Definition: Celeste.cpp:363
HuginBase::Panorama * m_pano
void setRightImage(unsigned int imgNr)
set right image
#define HUGIN_FT_CORR_THRESHOLD
CPScrollHint m_scrollHint
void panoramaChanged(HuginBase::Panorama &pano)
called when the panorama changes and we should update our display
void OnActionSelectCreate(wxCommandEvent &e)
void OnColumnWidthChange(wxListEvent &e)
static T max(T x, T y)
Definition: svm.cpp:65
CPEditorPanel()
ctor.
Holds transformations for Image -&gt; Pano and the other way.
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
wxChoice * m_zoomChoice
unsigned int optimize(PanoramaData &pano, const char *userScript)
optimize the images imgs, for variables optvec, using vars as start.
void setCtrlPoint(const HuginBase::ControlPoint &cp, const bool mirrored)
add control piont to internal cp list
HuginBase::PTools::Transform m_rightInvTransformMag
void setSize(vigra::Size2D val)
Set the image size in pixels.
void setScale(double factor)
set the scaling factor for cp display.
hugin_utils::FDiff2D maxpos
Definition: Correlation.h:64
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
vigra::triple< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImageRange(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:312
platform/compiler specific stuff.
void transformImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
Definition: openmp_vigra.h:330
const float getVerticalCPBias()
#define DEG_TO_RAD(x)
Definition: hugin_math.h:44
void copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
Definition: openmp_vigra.h:305
std::vector< std::set< std::string > > OptimizeVector
const HuginBase::ControlPoint & getControlPoint()
Definition: CPImageCtrl.h:81
vigra::Diff2D toDiff2D() const
Definition: hugin_math.h:134
void setImage(const std::string &filename, ImageRotation rot)
display img.
bool updateDisplay(const wxString &message)
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
bool m_listenToPageChange
HuginBase::PTools::Transform m_rightTransformMag
void setMagTransforms(HuginBase::PTools::Transform *magTrans, HuginBase::PTools::Transform *magInvTrans)
void showPosition(hugin_utils::FDiff2D point, bool warpPointer=false)
Show point x, y.
ProjectionFormat
Projection of final panorama.
wxCheckBox * m_estimateCB
selected point in right image
wxChoice * m_cpModeChoice
const wxRect & getRect()
Definition: CPImageCtrl.h:72
void setSameImage(bool sameImage)
point in left image selected, finetune failed in right image
hugin_utils::FDiff2D LocalFineTunePoint(unsigned int srcNr, const vigra::Diff2D &srcPnt, hugin_utils::FDiff2D &movedSrcPnt, unsigned int moveNr, const hugin_utils::FDiff2D &movePnt)
HuginBase::PTools::Transform m_leftTransform
All variables of a source image.
Definition: SrcPanoImage.h:194
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
HuginBase::CPointVector currentPoints
Panorama image options.
bool IsShowingCorrelation() const
Definition: MainFrame.cpp:2145
vigra::Size2D getSize() const
get size of output image
#define HUGIN_FT_ROTATION_STOP_ANGLE
evaluate y, points are on a horizontal line
Definition: ControlPoint.h:48
functions to handle icc profiles in images
left and right point selected, waiting for add point.
double m_detailZoomFactor
static T min(T x, T y)
Definition: svm.cpp:62
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition: wxutils.cpp:176
void OnCelesteButton(wxCommandEvent &e)
ImageRotation
image rotation.
Definition: CPImageCtrl.h:241
#define HUGIN_FT_ROTATION_SEARCH
HuginBase::SrcPanoImage GetImageRotatedTo(const HuginBase::SrcPanoImage &img, const vigra::Diff2D &point, int testWidth, double &neededHFOV)
void mirror()
swap (image1Nr,x1,y1) with (image2Nr,x2,y2)
void panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &imgNr)
notifies about changes to images
change a control point
Definition: PanoCommand.h:320
unsigned int m_selectedPoint
void createTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
initialize pano-&gt;image transformation
void ApplyICCProfile(ImageType &image, const vigra::ImageImportInfo::ICCProfile &iccProfile, const cmsUInt32Number imageFormat)
converts given image with iccProfile to sRGB/gray space, need to give pixel type in lcms2 format work...
Definition: cms.h:37
void SetRefImage(HuginBase::Panorama *pano, unsigned int newRefImg)
Set new reference image.
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
void UpdateDisplay(bool newImages)
updates the display after another image has been selected.
wxTextCtrl * m_x2Text
void ShowLines(bool isShown)