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