Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LensCalImageCtrl.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
11 /* This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This software is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this software. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #include "panoinc_WX.h"
28 #include "panoinc.h"
29 #include "base_wx/platform.h"
30 #include "LensCalImageCtrl.h"
31 #include "vigra/transformimage.hxx"
32 #include "nona/RemappedPanoImage.h"
33 #include "nona/ImageRemapper.h"
34 #include "LensCalApp.h"
35 #include "base_wx/wxcms.h"
36 
37 BEGIN_EVENT_TABLE(LensCalImageCtrl, wxPanel)
38  EVT_SIZE(LensCalImageCtrl::Resize)
39  EVT_PAINT(LensCalImageCtrl::OnPaint)
40  EVT_MOUSE_EVENTS(LensCalImageCtrl::OnMouseEvent)
42 
43 // init some values
45 {
46  m_showLines=true;
47  m_imageLines=NULL;
48  m_edge.Create(0,0,true);
49  m_previewMode=mode_original;
51  m_focallength=30;
52  m_cropfactor=1;
53  m_a=0;
54  m_b=0;
55  m_c=0;
56  m_d=0;
57  m_e=0;
58  m_monitorProfile = NULL;
59  // load monitor profile
60  wxString profileName;
61  HuginBase::Color::GetMonitorProfile(profileName, m_monitorProfile);
62  m_hasMonitorProfile = !profileName.IsEmpty();
63 };
64 
66 {
67  return m_previewMode;
68 };
69 
70 void LensCalImageCtrl::OnMouseEvent(wxMouseEvent &e)
71 {
72  if(e.Entering() || e.Leaving())
73  {
74  e.Skip();
75  return;
76  };
77  if(!e.LeftIsDown() && !e.RightIsDown())
78  {
79  e.Skip();
80  return;
81  };
82  if(m_imageLines==NULL)
83  {
84  return;
85  };
86  vigra::Point2D pos(e.GetPosition().x,e.GetPosition().y);
88  if(lines.empty())
89  return;
90  int found_line=-1;
92  {
95  double x;
96  double y;
97  if(!trans.transformImgCoord(x,y,pos.x,pos.y))
98  return;
99  pos.x=x;
100  pos.y=y;
101  }
102  else
103  {
104  pos.x=hugin_utils::roundi(pos.x/m_scale);
105  pos.y=hugin_utils::roundi(pos.y/m_scale);
106  };
107 
108  //find line which is nearest the clicked position
109  std::vector<double> min_distance(lines.size(),10000);
110  double shortest_distance=10000;
111  for(unsigned int i=0;i<lines.size();i++)
112  {
113  if(lines[i].status==HuginLines::valid_line || lines[i].status==HuginLines::valid_line_disabled)
114  {
115  for(unsigned int j=0;j<lines[i].line.size();j++)
116  {
117  double distance=(lines[i].line[j]-pos).magnitude();
118  if(distance<min_distance[i])
119  min_distance[i]=distance;
120  };
121  };
122  if(min_distance[i]<shortest_distance)
123  {
124  shortest_distance=min_distance[i];
125  if(shortest_distance<50)
126  {
127  found_line=i;
128  };
129  };
130  };
131  if(found_line==-1)
132  {
133  return;
134  };
135  if(e.LeftIsDown())
136  {
137  lines[found_line].status=HuginLines::valid_line_disabled;
138  }
139  else
140  {
141  lines[found_line].status=HuginLines::valid_line;
142  };
143  m_imageLines->SetLines(lines);
144  wxGetApp().GetLensCalFrame()->UpdateListString(m_imageIndex);
145  DrawView();
146  Refresh();
147 };
148 
150 {
151  if(m_imageLines==NULL)
152  return;
154  {
155  m_display_img.Create(m_remapped_img.GetWidth(), m_remapped_img.GetHeight());
156  }
157  else
158  {
159  m_display_img.Create(m_scaled_img.GetWidth(), m_scaled_img.GetHeight());
160  };
161  wxMemoryDC memDC(m_display_img);
163  // copy resized image into buffer
165  {
167  memDC.DrawBitmap(m_remapped_img,0,0,false);
168  }
169  else
170  {
171  memDC.DrawBitmap(m_scaled_img,0,0,false);
172  };
173  if(m_showLines)
174  {
176  for(unsigned int i=0;i<lines.size();i++)
177  {
178  if(lines[i].line.size()<2)
179  continue;
180  switch(lines[i].status)
181  {
183  memDC.SetPen(wxPen(wxColour(0,255,0), 1, wxPENSTYLE_SOLID));
184  break;
186  memDC.SetPen(wxPen(wxColour(255, 0, 0), 1, wxPENSTYLE_SOLID));
187  break;
188  default:
189  memDC.SetPen(wxPen(wxColour(128, 128, 128), 1, wxPENSTYLE_SOLID));
190  break;
191  };
192  for(unsigned int j=0;j<lines[i].line.size()-1;j++)
193  {
194  int x1,y1,x2,y2;
196  {
197  double x,y;
198  if(!trans.transformImgCoord(x,y,lines[i].line[j].x,lines[i].line[j].y))
199  continue;
200  x1=hugin_utils::roundi(x);
201  y1=hugin_utils::roundi(y);
202  if(!trans.transformImgCoord(x,y,lines[i].line[j+1].x,lines[i].line[j+1].y))
203  continue;
204  x2=hugin_utils::roundi(x);
205  y2=hugin_utils::roundi(y);
206  }
207  else
208  {
209  x1=hugin_utils::roundi(m_scale*lines[i].line[j].x);
210  y1=hugin_utils::roundi(m_scale*lines[i].line[j].y);
211  x2=hugin_utils::roundi(m_scale*lines[i].line[j+1].x);
212  y2=hugin_utils::roundi(m_scale*lines[i].line[j+1].y);
213  };
214  memDC.DrawLine(x1,y1,x2,y2);
215  };
216  };
217  };
218  memDC.SelectObject(wxNullBitmap);
219 };
220 
221 void LensCalImageCtrl::Resize( wxSizeEvent & e )
222 {
223  if(m_imageLines==NULL || !m_img.Ok() || (m_previewMode==mode_edge && !m_edge.Ok()))
224  {
225  m_scaled_img = wxBitmap();
226  m_display_img = wxBitmap();
227  Refresh(true);
228  return;
229  }
230  int x = GetSize().x;
231  int y = GetSize().y;
232  // scale to fit the window
233  int new_width;
234  int new_height;
235 
236  float r_img = (float)m_img.GetWidth() / (float)m_img.GetHeight();
237  float r_window = (float)x/(float)y;
238  if ( r_img > r_window )
239  {
240  m_scale = (float)x / m_img.GetWidth();
241  new_width = x;
242  new_height = hugin_utils::roundi(m_scale * m_img.GetHeight());
243  }
244  else
245  {
246  m_scale = (float)y / m_img.GetHeight();
247  new_height = y;
248  new_width = hugin_utils::roundi(m_scale * m_img.GetWidth());
249  }
250  switch(m_previewMode)
251  {
252  case mode_original:
253  m_scaled_img = wxBitmap(m_img.Scale (new_width, new_height));
254  break;
255  case mode_edge:
256  m_scaled_img = wxBitmap(m_edge.Scale(new_width,new_height,wxIMAGE_QUALITY_HIGH));
257  break;
258  case mode_corrected:
259  GenerateRemappedImage(new_width,new_height);
260  break;
261  };
262  // draw new view into offscreen buffer
263  DrawView();
264  // eventually update the view
265  Refresh(false);
266 };
267 
268 // Define the repainting behaviour
269 void LensCalImageCtrl::OnPaint(wxPaintEvent & dc)
270 {
271  wxPaintDC paintDC(this);
272 #ifdef __WXGTK3__
273  // wxGTK3 prints an assert when trying to draw empty bitmap, Ok() is returning true in this case
274  // so check also bitmap dimensions
275  if (m_display_img.Ok() && m_display_img.GetWidth() > 0 && m_display_img.GetHeight() > 0)
276 #else
277  if ( m_display_img.Ok() )
278 #endif
279  {
280  paintDC.DrawBitmap(m_display_img, 0,0, FALSE);
281  }
282 }
283 
284 void LensCalImageCtrl::SetImage(ImageLineList* newList, unsigned int newIndex)
285 {
286  m_imageLines=newList;
287  m_imageIndex=newIndex;
288  std::string filename(newList->GetFilename().mb_str(HUGIN_CONV_FILENAME));
289  ImageCache::EntryPtr img = ImageCache::getInstance().getImage(filename);
290  // we need to create a copy, otherwise the color management function will modifiy the image
291  // directly in the ImageCache
292  m_img = imageCacheEntry2wxImage(img).Copy();
293  if (!img->iccProfile->empty() || m_hasMonitorProfile)
294  {
296  }
297  SetEdgeImage();
298 
299  wxSizeEvent e;
300  Resize (e);
301 }
302 
304 {
305  m_imageLines=NULL;
306  m_img.Create(0,0,true);
307  m_edge.Create(0,0,true);
308  m_remapped_img.Create(0,0,true);
309 
310  wxSizeEvent e;
311  Resize(e);
312 };
313 
314 void LensCalImageCtrl::SetShowLines(bool showLines)
315 {
316  m_showLines=showLines;
317  // draw new view into offscreen buffer
318  DrawView();
319  // eventually update the view
320  Refresh(false);
321 };
322 
324 {
325  m_previewMode=newMode;
326  wxSizeEvent e;
327  Resize (e);
328  Refresh(true);
329 };
330 
331 void LensCalImageCtrl::SetLens(const HuginBase::SrcPanoImage::Projection newProjection,const double newFocallength, const double newCropfactor)
332 {
333  m_projection=newProjection;
334  m_focallength=newFocallength;
335  m_cropfactor=newCropfactor;
336 };
337 
338 void LensCalImageCtrl::SetLensDistortions(const double newA, const double newB, const double newC, const double newD, const double newE)
339 {
340  m_a=newA;
341  m_b=newB;
342  m_c=newC;
343  m_d=newD;
344  m_e=newE;
346  {
347  wxSizeEvent e;
348  Resize(e);
349  };
350 };
351 
352 vigra::RGBValue<vigra::UInt8> gray2RGB(vigra::UInt8 const& v)
353 {
354  return vigra::RGBValue<vigra::UInt8>(v,v,v);
355 }
356 
358 {
359  vigra::BImage* edgeImage=m_imageLines->GetEdgeImage();
360  if(edgeImage->width()>0 && edgeImage->height()>0)
361  {
362  // we need to convert to RGB
363  m_edgeImage.resize(edgeImage->width(),edgeImage->height());
365  m_edge.SetData((unsigned char*)m_edgeImage.data(),m_edgeImage.width(),m_edgeImage.height(),true);
366  }
367  else
368  {
369  m_edgeImage.resize(0,0);
370  m_edge.Create(0,0,true);
371  };
372  wxSizeEvent e;
373  Resize(e);
374 };
375 
376 void LensCalImageCtrl::GenerateRemappedImage(const unsigned int newWidth,const unsigned int newHeight)
377 {
379  //generate SrcPanoImage with current settings
381  m_panoimage.setProjection(m_projection);
382  m_panoimage.setExifFocalLength(m_focallength);
383  m_panoimage.setCropFactor(m_cropfactor);
384  m_panoimage.setExposureValue(0);
385  m_panoimage.setVar("a",m_a);
386  m_panoimage.setVar("b",m_b);
387  m_panoimage.setVar("c",m_c);
388  m_panoimage.setVar("d",m_d);
389  m_panoimage.setVar("e",m_e);
390  double hfov=HuginBase::SrcPanoImage::calcHFOV(m_panoimage.getProjection(),m_panoimage.getExifFocalLength(),m_panoimage.getCropFactor(),m_panoimage.getSize());
391  m_panoimage.setHFOV(hfov);
392 
393  std::string filename(m_imageLines->GetFilename().mb_str(HUGIN_CONV_FILENAME));
394  ImageCache::EntryPtr img = ImageCache::getInstance().getImage(filename);
395  //fill options with current settings
396  switch(m_projection)
397  {
400  break;
403  break;
407  break;
410  break;
413  break;
416  break;
419  break;
422  break;
423  };
424  m_opts.setHeight(newHeight);
425  m_opts.setWidth(newWidth,false);
426  m_opts.setHFOV(m_panoimage.getHFOV(),false);
427  m_opts.setROI(vigra::Rect2D(0,0,m_opts.getWidth(),m_opts.getHeight()));
428  //now remap image
430  remapped->remapImage(vigra::srcImageRange(*(img->get8BitImage())),vigra_ext::INTERP_CUBIC, wxGetApp().GetLensCalFrame());
431  m_remappedImage=remapped->m_image;
432  m_remapped_img.SetData((unsigned char*)m_remappedImage.data(),m_remappedImage.width(),m_remappedImage.height(),true);
433  // apply color profiles
434  if (!img->iccProfile->empty() || m_hasMonitorProfile)
435  {
437  }
438  delete remapped;
439 };
440 
442 
444 {
445  AddWindowStyles();
446 }
447 
449 {
450  XRC_MAKE_INSTANCE(cp, LensCalImageCtrl)
451  cp->Create(m_parentAsWindow, GetID(), GetPosition(), GetSize(), GetStyle(wxT("style")), GetName());
452  SetupWindow(cp);
453  return cp;
454 }
455 
457 {
458  return IsOfClass(node, wxT("LensCalCanvas"));
459 }
460 
implementation of huginApp Class
xrc handler for LensCalImageCtrl
void SetEmptyImage()
set preview to empty image
void SetLines(HuginLines::Lines lines)
store given lines in member variable
void setHeight(unsigned int h)
set panorama height
int roundi(T x)
Definition: hugin_math.h:73
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.
void setPanoImage(const SrcPanoImage &src, const PanoramaOptions &dest, vigra::Rect2D roi)
vigra::RGBValue< vigra::UInt8 > gray2RGB(vigra::UInt8 const &v)
image previewer for lens calibration GUI
bool m_hasMonitorProfile
true, if we found a real monitor profile
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
void GenerateRemappedImage(const unsigned int newWidth, const unsigned int newHeight)
generates the remapped image suitable for wxImage
HuginBase::SrcPanoImage * GetPanoImage()
return the SrcPanoImage from the given filename
unsigned int getHeight() const
get panorama height
wxBitmap m_scaled_img
the scaled image to save resizing
Contains functions to transform whole images.
LensCalPreviewMode m_previewMode
which image should be drawn
void SetEdgeImage()
converts the edge image into wxImage
wxImage m_remapped_img
the remapped image as wxImage
ImageLineList * m_imageLines
struct with filename, edge image and detected lines
END_EVENT_TABLE()
include file for the hugin project
static char * line
Definition: svm.cpp:2784
void DrawView()
draw the view into the offscreen buffer
void OnPaint(wxPaintEvent &dc)
paint event
HuginBase::PanoramaOptions m_opts
const vigra::Rect2D & getROI() const
vigra::BRGBImage m_remappedImage
the remapped image
void CorrectImage(wxImage &image, const vigra::ImageImportInfo::ICCProfile &iccProfile, const cmsHPROFILE &monitorProfile)
apply color correction to given image using input iccProfile and monitor profile
Definition: wxcms.cpp:218
void setVar(const std::string &name, double val)
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
wxImage imageCacheEntry2wxImage(ImageCache::EntryPtr e)
void remapImage(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra_ext::Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
remap a image without alpha channel
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
virtual bool CanHandle(wxXmlNode *node)
virtual wxObject * DoCreateResource()
void Resize(wxSizeEvent &e)
resize event, recalculates the offscreen buffer
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
wxImage m_edge
the edge detect image (resized scale)
declaration of preview for lens calibration gui
void setROI(const vigra::Rect2D &val)
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
HuginBase::SrcPanoImage::Projection m_projection
unsigned int m_imageIndex
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
void OnMouseEvent(wxMouseEvent &e)
unsigned int getWidth() const
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
const LensCalPreviewMode GetMode()
return actual preview mode
std::vector< SingleLine > Lines
vector of extracted lines from image
Definition: LinesTypes.h:50
Holds transformations for Image -&gt; Pano and the other way.
void SetImage(ImageLineList *newList, unsigned int newIndex)
set preview setting to given ImageLineList
const HuginLines::Lines GetLines()
returns the list of detected lines
static double calcHFOV(SrcPanoImage::Projection proj, double fl, double crop, vigra::Size2D imageSize)
calculate hfov of an image given focal length, image size and crop factor
wxBitmap m_display_img
the image to display, e.g.
declaration of application class for lens calibrate application
cmsHPROFILE m_monitorProfile
monitor profile
vigra::BImage * GetEdgeImage()
return pointer to edge image
const wxString GetFilename()
returns the filename
HuginBase::SrcPanoImage m_panoimage
void SetLens(const HuginBase::SrcPanoImage::Projection newProjection, const double newFocallength, const double newCropfactor)
updates the internal values of the lens (needed only for remapped image)
wxImage m_img
the image to adjust (full scale)
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
bool m_showLines
true, if the lines should be drawn above the image
void SetMode(const LensCalPreviewMode newMode)
set which image (original, edge, remapped/corrected) should be drawn
void SetLensDistortions(const double newA, const double newB, const double newC, const double newD, const double newE)
updates the internal values of the lens distortions parameters (needed only for remapped image) ...
struct to hold a image state for stitching
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
float m_scale
scale factor for scaling from m_img to m_scaled_img
void SetShowLines(bool showLines)
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
vigra::BRGBImage m_edgeImage
the edge image as RGBImage (in m_imageLines the edge image is grayscale (vigra::BImage)) ...
void GetMonitorProfile(wxString &profileName, cmsHPROFILE &profile)
retrieve monitor profile from system
Definition: wxcms.cpp:201