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