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