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