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 // init some values
39 {
40  m_showLines=true;
41  m_imageLines=NULL;
42  m_edge.Create(0,0,true);
45  m_focallength=30;
46  m_cropfactor=1;
47  m_a=0;
48  m_b=0;
49  m_c=0;
50  m_d=0;
51  m_e=0;
52  m_monitorProfile = NULL;
53  // load monitor profile
54  wxString profileName;
56  m_hasMonitorProfile = !profileName.IsEmpty();
57  // bind event handler
58  Bind(wxEVT_SIZE, &LensCalImageCtrl::Resize, this);
59  Bind(wxEVT_PAINT, &LensCalImageCtrl::OnPaint, this);
60  Bind(wxEVT_LEFT_DOWN, &LensCalImageCtrl::OnMouseEvent, this);
61  Bind(wxEVT_RIGHT_DOWN, &LensCalImageCtrl::OnMouseEvent, this);
62 };
63 
65 {
66  return m_previewMode;
67 };
68 
69 void LensCalImageCtrl::OnMouseEvent(wxMouseEvent &e)
70 {
71  if(m_imageLines==NULL)
72  {
73  return;
74  };
75  vigra::Point2D pos(e.GetPosition().x,e.GetPosition().y);
77  if(lines.empty())
78  return;
79  int found_line=-1;
81  {
84  double x;
85  double y;
86  if(!trans.transformImgCoord(x,y,pos.x,pos.y))
87  return;
88  pos.x=x;
89  pos.y=y;
90  }
91  else
92  {
93  pos.x=hugin_utils::roundi(pos.x/m_scale);
94  pos.y=hugin_utils::roundi(pos.y/m_scale);
95  };
96 
97  //find line which is nearest the clicked position
98  std::vector<double> min_distance(lines.size(),10000);
99  double shortest_distance=10000;
100  for(unsigned int i=0;i<lines.size();i++)
101  {
102  if(lines[i].status==HuginLines::valid_line || lines[i].status==HuginLines::valid_line_disabled)
103  {
104  for(unsigned int j=0;j<lines[i].line.size();j++)
105  {
106  double distance=(lines[i].line[j]-pos).magnitude();
107  if(distance<min_distance[i])
108  min_distance[i]=distance;
109  };
110  };
111  if(min_distance[i]<shortest_distance)
112  {
113  shortest_distance=min_distance[i];
114  if(shortest_distance<50)
115  {
116  found_line=i;
117  };
118  };
119  };
120  if(found_line==-1)
121  {
122  return;
123  };
124  if(e.LeftIsDown())
125  {
126  lines[found_line].status=HuginLines::valid_line_disabled;
127  }
128  else
129  {
130  lines[found_line].status=HuginLines::valid_line;
131  };
132  m_imageLines->SetLines(lines);
133  wxGetApp().GetLensCalFrame()->UpdateListString(m_imageIndex);
134  DrawView();
135  Refresh();
136 };
137 
139 {
140  if(m_imageLines==NULL)
141  return;
143  {
144  m_display_img.Create(m_remapped_img.GetWidth(), m_remapped_img.GetHeight());
145  }
146  else
147  {
148  m_display_img.Create(m_scaled_img.GetWidth(), m_scaled_img.GetHeight());
149  };
150  wxMemoryDC memDC(m_display_img);
152  // copy resized image into buffer
154  {
156  memDC.DrawBitmap(m_remapped_img,0,0,false);
157  }
158  else
159  {
160  memDC.DrawBitmap(m_scaled_img,0,0,false);
161  };
162  if(m_showLines)
163  {
165  for(unsigned int i=0;i<lines.size();i++)
166  {
167  if(lines[i].line.size()<2)
168  continue;
169  switch(lines[i].status)
170  {
172  memDC.SetPen(wxPen(wxColour(0,255,0), 1, wxPENSTYLE_SOLID));
173  break;
175  memDC.SetPen(wxPen(wxColour(255, 0, 0), 1, wxPENSTYLE_SOLID));
176  break;
177  default:
178  memDC.SetPen(wxPen(wxColour(128, 128, 128), 1, wxPENSTYLE_SOLID));
179  break;
180  };
181  for(unsigned int j=0;j<lines[i].line.size()-1;j++)
182  {
183  int x1,y1,x2,y2;
185  {
186  double x,y;
187  if(!trans.transformImgCoord(x,y,lines[i].line[j].x,lines[i].line[j].y))
188  continue;
189  x1=hugin_utils::roundi(x);
190  y1=hugin_utils::roundi(y);
191  if(!trans.transformImgCoord(x,y,lines[i].line[j+1].x,lines[i].line[j+1].y))
192  continue;
193  x2=hugin_utils::roundi(x);
194  y2=hugin_utils::roundi(y);
195  }
196  else
197  {
198  x1=hugin_utils::roundi(m_scale*lines[i].line[j].x);
199  y1=hugin_utils::roundi(m_scale*lines[i].line[j].y);
200  x2=hugin_utils::roundi(m_scale*lines[i].line[j+1].x);
201  y2=hugin_utils::roundi(m_scale*lines[i].line[j+1].y);
202  };
203  memDC.DrawLine(x1,y1,x2,y2);
204  };
205  };
206  };
207  memDC.SelectObject(wxNullBitmap);
208 };
209 
210 void LensCalImageCtrl::Resize( wxSizeEvent & e )
211 {
212  if(m_imageLines==NULL || !m_img.Ok() || (m_previewMode==mode_edge && !m_edge.Ok()))
213  {
214  m_scaled_img = wxBitmap();
215  m_display_img = wxBitmap();
216  Refresh(true);
217  return;
218  }
219  int x = GetSize().x;
220  int y = GetSize().y;
221  // scale to fit the window
222  int new_width;
223  int new_height;
224 
225  float r_img = (float)m_img.GetWidth() / (float)m_img.GetHeight();
226  float r_window = (float)x/(float)y;
227  if ( r_img > r_window )
228  {
229  m_scale = (float)x / m_img.GetWidth();
230  new_width = x;
231  new_height = hugin_utils::roundi(m_scale * m_img.GetHeight());
232  }
233  else
234  {
235  m_scale = (float)y / m_img.GetHeight();
236  new_height = y;
237  new_width = hugin_utils::roundi(m_scale * m_img.GetWidth());
238  }
239  switch(m_previewMode)
240  {
241  case mode_original:
242  m_scaled_img = wxBitmap(m_img.Scale (new_width, new_height));
243  break;
244  case mode_edge:
245  m_scaled_img = wxBitmap(m_edge.Scale(new_width,new_height,wxIMAGE_QUALITY_HIGH));
246  break;
247  case mode_corrected:
248  GenerateRemappedImage(new_width,new_height);
249  break;
250  };
251  // draw new view into offscreen buffer
252  DrawView();
253  // eventually update the view
254  Refresh(false);
255 };
256 
257 // Define the repainting behaviour
258 void LensCalImageCtrl::OnPaint(wxPaintEvent & dc)
259 {
260  wxPaintDC paintDC(this);
261 #ifdef __WXGTK3__
262  // wxGTK3 prints an assert when trying to draw empty bitmap, Ok() is returning true in this case
263  // so check also bitmap dimensions
264  if (m_display_img.Ok() && m_display_img.GetWidth() > 0 && m_display_img.GetHeight() > 0)
265 #else
266  if ( m_display_img.Ok() )
267 #endif
268  {
269  paintDC.DrawBitmap(m_display_img, 0,0, FALSE);
270  }
271 }
272 
273 void LensCalImageCtrl::SetImage(ImageLineList* newList, unsigned int newIndex)
274 {
275  m_imageLines=newList;
276  m_imageIndex=newIndex;
277  std::string filename(newList->GetFilename().mb_str(HUGIN_CONV_FILENAME));
278  ImageCache::EntryPtr img = ImageCache::getInstance().getImage(filename);
279  // we need to create a copy, otherwise the color management function will modifiy the image
280  // directly in the ImageCache
281  m_img = imageCacheEntry2wxImage(img).Copy();
282  if (!img->iccProfile->empty() || m_hasMonitorProfile)
283  {
285  }
286  SetEdgeImage();
287 
288  wxSizeEvent e;
289  Resize (e);
290 }
291 
293 {
294  m_imageLines=NULL;
295  m_img.Create(0,0,true);
296  m_edge.Create(0,0,true);
297  m_remapped_img.Create(0,0,true);
298 
299  wxSizeEvent e;
300  Resize(e);
301 };
302 
303 void LensCalImageCtrl::SetShowLines(bool showLines)
304 {
305  m_showLines=showLines;
306  // draw new view into offscreen buffer
307  DrawView();
308  // eventually update the view
309  Refresh(false);
310 };
311 
313 {
314  m_previewMode=newMode;
315  wxSizeEvent e;
316  Resize (e);
317  Refresh(true);
318 };
319 
320 void LensCalImageCtrl::SetLens(const HuginBase::SrcPanoImage::Projection newProjection,const double newFocallength, const double newCropfactor)
321 {
322  m_projection=newProjection;
323  m_focallength=newFocallength;
324  m_cropfactor=newCropfactor;
325 };
326 
327 void LensCalImageCtrl::SetLensDistortions(const double newA, const double newB, const double newC, const double newD, const double newE)
328 {
329  m_a=newA;
330  m_b=newB;
331  m_c=newC;
332  m_d=newD;
333  m_e=newE;
335  {
336  wxSizeEvent e;
337  Resize(e);
338  };
339 };
340 
341 vigra::RGBValue<vigra::UInt8> gray2RGB(vigra::UInt8 const& v)
342 {
343  return vigra::RGBValue<vigra::UInt8>(v,v,v);
344 }
345 
347 {
348  vigra::BImage* edgeImage=m_imageLines->GetEdgeImage();
349  if(edgeImage->width()>0 && edgeImage->height()>0)
350  {
351  // we need to convert to RGB
352  m_edgeImage.resize(edgeImage->width(),edgeImage->height());
354  m_edge.SetData((unsigned char*)m_edgeImage.data(),m_edgeImage.width(),m_edgeImage.height(),true);
355  }
356  else
357  {
358  m_edgeImage.resize(0,0);
359  m_edge.Create(0,0,true);
360  };
361  wxSizeEvent e;
362  Resize(e);
363 };
364 
365 void LensCalImageCtrl::GenerateRemappedImage(const unsigned int newWidth,const unsigned int newHeight)
366 {
368  //generate SrcPanoImage with current settings
370  m_panoimage.setProjection(m_projection);
371  m_panoimage.setExifFocalLength(m_focallength);
372  m_panoimage.setCropFactor(m_cropfactor);
373  m_panoimage.setExposureValue(0);
374  m_panoimage.setVar("a",m_a);
375  m_panoimage.setVar("b",m_b);
376  m_panoimage.setVar("c",m_c);
377  m_panoimage.setVar("d",m_d);
378  m_panoimage.setVar("e",m_e);
379  double hfov=HuginBase::SrcPanoImage::calcHFOV(m_panoimage.getProjection(),m_panoimage.getExifFocalLength(),m_panoimage.getCropFactor(),m_panoimage.getSize());
380  m_panoimage.setHFOV(hfov);
381 
382  std::string filename(m_imageLines->GetFilename().mb_str(HUGIN_CONV_FILENAME));
383  ImageCache::EntryPtr img = ImageCache::getInstance().getImage(filename);
384  //fill options with current settings
385  switch(m_projection)
386  {
389  break;
392  break;
396  break;
399  break;
402  break;
405  break;
408  break;
411  break;
412  };
413  m_opts.setHeight(newHeight);
414  m_opts.setWidth(newWidth,false);
415  m_opts.setHFOV(m_panoimage.getHFOV(),false);
416  m_opts.setROI(vigra::Rect2D(0,0,m_opts.getWidth(),m_opts.getHeight()));
417  //now remap image
419  remapped->remapImage(vigra::srcImageRange(*(img->get8BitImage())),vigra_ext::INTERP_CUBIC, wxGetApp().GetLensCalFrame());
420  m_remappedImage=remapped->m_image;
421  m_remapped_img.SetData((unsigned char*)m_remappedImage.data(),m_remappedImage.width(),m_remappedImage.height(),true);
422  // apply color profiles
423  if (!img->iccProfile->empty() || m_hasMonitorProfile)
424  {
426  }
427  delete remapped;
428 };
429 
431 
433 {
434  AddWindowStyles();
435 }
436 
438 {
439  XRC_MAKE_INSTANCE(cp, LensCalImageCtrl)
440  cp->Create(m_parentAsWindow, GetID(), GetPosition(), GetSize(), GetStyle(wxT("style")), GetName());
441  SetupWindow(cp);
442  return cp;
443 }
444 
446 {
447  return IsOfClass(node, wxT("LensCalCanvas"));
448 }
449 
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
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
LensCalImageCtrl()
constructor
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