Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CreateBrightImgDlg.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
10 /* This is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This software is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public
21  * License along with this software. If not, see
22  * <http://www.gnu.org/licenses/>.
23  *
24  */
25 
26 #include "CreateBrightImgDlg.h"
27 #include "ToolboxApp.h"
28 #include <vigra/impex.hxx>
29 #include <wx/busyinfo.h>
30 #include <wx/stdpaths.h>
31 #include "base_wx/wxutils.h"
32 #include "base_wx/platform.h"
33 #include "base_wx/wxcms.h"
34 #include "base_wx/Executor.h"
35 #include "ToolboxApp.h"
36 
38 template <class PixelType>
39 vigra::BasicImage<vigra::RGBValue<PixelType>> CreateBrightVersion(const vigra::BasicImage<vigra::RGBValue<PixelType>>& input, const double correction)
40 {
42  srcImage.setSize(input.size());
43  // build inverse response transform
45  std::vector<PixelType> outLut;
46  vigra_ext::EMoR::createEMoRLUT(srcImage.getEMoRParams(), outLut);
48  invResponse.setOutput(1.0 / std::pow(2.0, srcImage.getExposureValue() - correction), outLut, 1);
49  // now do photometric transformation
50  vigra::BasicImage<vigra::RGBValue<PixelType>> output(input.size());
51  vigra_ext::transformImageSpatial(vigra::srcImageRange(input), vigra::destImage(output), invResponse, vigra::Diff2D(0, 0));
52  return output;
53 }
54 
56 {
57  // load from xrc
58  wxXmlResource::Get()->LoadDialog(this, parent, "enfuse_create_file");
59  // get pointer to some controls
60  m_stepWidthChoice = XRCCTRL(*this, "create_bright_choice_step_width", wxChoice);
61  m_levelChoice = XRCCTRL(*this, "create_bright_choice_levels", wxChoice);
62  m_exposuresListBox = XRCCTRL(*this, "create_bright_listctrl", wxListCtrl);
63  m_exposuresListBox->InsertColumn(0, _("Exposure value (Eev)"), wxLIST_FORMAT_LEFT, wxLIST_AUTOSIZE_USEHEADER);
64  m_exposuresListBox->EnableCheckBoxes(true);
65  m_previewBitmap = XRCCTRL(*this, "create_bright_preview", wxStaticBitmap);
66  // load image size and position
67  RestoreFramePosition(this, "CreateBrighterDarkerImageDialog");
68  // bind event handler
69  Bind(wxEVT_BUTTON, &CreateBrightImgDlg::OnOk, this, wxID_OK);
72  m_exposuresListBox->Bind(wxEVT_LIST_ITEM_SELECTED, &CreateBrightImgDlg::OnExposureSelected, this);
73  m_exposuresListBox->Bind(wxEVT_LIST_ITEM_CHECKED, &CreateBrightImgDlg::OnExposureChecked, this);
74  Bind(wxEVT_SIZE, &CreateBrightImgDlg::OnSize, this);
75  // fill initial values
76  wxCommandEvent e;
78 }
79 
81 {
82  // save position and size
83  StoreFramePosition(this, "CreateBrighterDarkerImageDialog");
84 }
85 
86 bool CreateBrightImgDlg::SetImage(const wxString& filename, wxString& errorMsg)
87 {
88  m_filename = filename;
89  const std::string filenameString(filename.mb_str(HUGIN_CONV_FILENAME));
90  vigra::ImageImportInfo info(filenameString.c_str());
91  const std::string pixeltype(info.getPixelType());
92  if (!(pixeltype == "UINT8" || pixeltype == "UINT16"))
93  {
94  errorMsg = _("The creation of brighter and darker images works only for 8 and 16 bit images.");
95  return false;
96  }
97  try
98  {
99  ImageCache::getInstance().softFlush();
100  m_image = ImageCache::getInstance().getImage(filenameString);
101  }
102  catch (std::exception& e)
103  {
104  // loading of image failed
105  errorMsg = wxString::Format(_("Could not load image %s"), filename.c_str());;
106  errorMsg.Append(" (");
107  errorMsg.Append(e.what());
108  errorMsg.Append(")");
109  return false;
110  }
111  SetLabel(GetLabel() + " " + filename);
112  Layout();
113  RescaleImage();
114  m_previewBitmap->SetBitmap(m_scaledwxBitmap);
115  return true;
116 }
117 
118 wxArrayString CreateBrightImgDlg::GetTempFiles() const
119 {
120  return m_tempFiles;
121 }
122 
123 void CreateBrightImgDlg::OnOk(wxCommandEvent & e)
124 {
125  wxString tempDir = HuginQueue::GetConfigTempDir(wxConfig::Get());
126  {
127  wxWindowDisabler disableAll;
128  wxBusyCursor busyCursor;
129  wxGauge* progress = XRCCTRL(*this, "enfuse_create_file_progress", wxGauge);
130  progress->Show();
131  Layout();
132  progress->SetRange(GetCheckedItemCount() + 1);
133  for (long i = 0; i < m_exposuresListBox->GetItemCount(); ++i)
134  {
135  if (m_exposuresListBox->IsItemChecked(i))
136  {
137  wxFileName tempfile(wxFileName::CreateTempFileName(tempDir + "htb"));
138  if (CreateAndSaveExposureCorrectedImage(tempfile.GetFullPath(), m_exposures[i]))
139  {
140  m_tempFiles.Add(tempfile.GetFullPath());
141  };
142  };
143  progress->SetValue(progress->GetValue() + 1);
144  progress->Update();
145  wxTheApp->Yield();
146  };
147  progress->Hide();
148  Layout();
149  }
150  if (!m_tempFiles.empty())
151  {
152  EndModal(wxID_OK);
153  }
154  else
155  {
156  wxMessageBox(_("You have not yet selected at least one exposure correction."), _("Hugin toolbox"), wxOK | wxICON_WARNING);
157  };
158 }
159 
161 {
162  m_exposures.clear();
163  m_exposuresListBox->DeleteAllItems();
164  const double stepWidth = GetExposureStepWidth();
165  const int nrLevels = (m_levelChoice->GetSelection() + 1) * 2 + 1;
166  double exposure = -std::trunc(nrLevels / 2.0) * stepWidth;
167  // disable checkbox check for updating the list
168  m_exposuresListBox->Unbind(wxEVT_LIST_ITEM_CHECKED, &CreateBrightImgDlg::OnExposureChecked, this);
169  for (int i = 0; i < nrLevels; ++i)
170  {
171  m_exposures.push_back(exposure);
172  long index = m_exposuresListBox->InsertItem(m_exposuresListBox->GetItemCount(), wxString::Format(_("Ev %+.2f"), exposure));
173  // set checkbox, disable checkbox for uncorrected image
174  m_exposuresListBox->CheckItem(index, std::abs(exposure) > 0.05);
175  exposure = exposure + stepWidth;
176  };
177  m_exposuresListBox->Bind(wxEVT_LIST_ITEM_CHECKED, &CreateBrightImgDlg::OnExposureChecked, this);
178 }
179 
181 {
182  long index = m_exposuresListBox->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
183  if (index != -1)
184  {
185  // remember exposure correction value
187  // apply exposure correction and update wxStaticBitmap
188  vigra::BRGBImage img = CreateBrightVersion(m_scaledImg, m_currentExposure);
189  CreatewxBitmap(img);
190  m_previewBitmap->SetBitmap(m_scaledwxBitmap);
191  }
192  else
193  {
194  // no item selected, do no exposure correction
195  m_currentExposure = 0;
196  };
197 }
198 
200 {
201  // prevent checking item for exposure correction 0
202  if (e.GetIndex() == m_exposuresListBox->GetItemCount() / 2)
203  {
204  m_exposuresListBox->CheckItem(e.GetIndex(), false);
205  };
206 }
207 
208 void CreateBrightImgDlg::OnSize(wxSizeEvent& e)
209 {
210  Layout();
211  RescaleImage();
212  m_previewBitmap->SetBitmap(m_scaledwxBitmap);
213 }
214 
216 {
217  if (m_stepWidthChoice->GetSelection() == 0)
218  {
219  return 0.6667;
220  }
221  else
222  {
223  if (m_stepWidthChoice->GetSelection() == 2)
224  {
225  return 1.3333;
226  };
227  };
228  return 1.0;
229 }
230 
232 {
233  wxSize previewSize = m_previewBitmap->GetClientSize();
234  const long imageWidth = m_image->image16->size().area() > 0 ? m_image->image16->width() : m_image->image8->width();
235  const long imageHeight = m_image->image16->size().area() > 0 ? m_image->image16->height() : m_image->image8->height();
236  const double scaleFactor = std::min<double>((double)previewSize.GetWidth() / imageWidth, (double)previewSize.GetHeight() / imageHeight);
237  m_scaledImg.resize(scaleFactor * imageWidth, scaleFactor * imageHeight);
238  vigra::resizeImageLinearInterpolation(vigra::srcImageRange(*m_image->get8BitImage()), vigra::destImageRange(m_scaledImg));
239  if (m_currentExposure > -0.01 && m_currentExposure < 0.01)
240  {
241  // no exposure correction, directly transform m_scaledImg to wxBitmap
243  }
244  else
245  {
246  // apply exposure correction and convert to wxBitmap
247  vigra::BRGBImage img = CreateBrightVersion(m_scaledImg, m_currentExposure);
248  CreatewxBitmap(img);
249  };
250 }
251 
252 void CreateBrightImgDlg::CreatewxBitmap(const vigra::BRGBImage& img)
253 {
254  wxImage resizedImage;
255  resizedImage.SetData((unsigned char*)img.data(), img.width(), img.height(), true);
256  // apply color profiles
257  if (!m_image->iccProfile->empty() || wxGetApp().GetToolboxFrame()->HasMonitorProfile())
258  {
259  HuginBase::Color::CorrectImage(resizedImage, *(m_image->iccProfile), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
260  };
261  wxBitmap bitmap(m_previewBitmap->GetClientSize());
262  {
263  wxMemoryDC dc(bitmap);
264  dc.SetBackground(wxBrush(m_previewBitmap->GetParent()->GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
265  dc.Clear();
266  wxPoint offset;
267  offset.x = (bitmap.GetWidth() - resizedImage.GetWidth()) / 2;
268  offset.y = (bitmap.GetHeight() - resizedImage.GetHeight()) / 2;
269  dc.DrawBitmap(resizedImage, offset);
270  }
271  m_scaledwxBitmap = bitmap; // xBitmap(resizedImage);
272 }
273 
274 bool CreateBrightImgDlg::CreateAndSaveExposureCorrectedImage(const wxString& filename, const double correction)
275 {
276  vigra::ImageExportInfo info(filename.mb_str(HUGIN_CONV_FILENAME));
277  info.setFileType("TIFF");
278  if (m_image->image16->size().area() > 0)
279  {
280  //process 16 bit image
281  vigra::UInt16RGBImage finalImg = CreateBrightVersion(*m_image->image16, correction);
282  try
283  {
284  if (m_image->mask->size().area() > 0)
285  {
287  }
288  else
289  {
290  vigra::exportImage(vigra::srcImageRange(finalImg), info);
291  };
292  }
293  catch (...)
294  {
295  return false;
296  }
297 
298  }
299  else
300  {
301  // process 8 bit image
302  vigra::BRGBImage finalImg = CreateBrightVersion(*m_image->image8, correction);
303  try
304  {
305  if (m_image->mask->size().area() > 0)
306  {
308  }
309  else
310  {
311  vigra::exportImage(vigra::srcImageRange(finalImg), info);
312  };
313  }
314  catch (...)
315  {
316  return false;
317  };
318  };
319  // copy some basic Exif data
320  const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
321  wxString exiftoolCmd(HuginQueue::GetExternalProgram(wxConfig::Get(), exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), "exiftool"));
322  exiftoolCmd.Append(" -overwrite_original -tagsfromfile " + HuginQueue::wxEscapeFilename(m_filename) + " -FNumber -ISO ");
323  // update the exposure time with the corrected one
324  exiftoolCmd.Append("-ExposureTime<${exposuretime#;$_*=" + wxString::FromCDouble(std::pow(2, correction)) + "} ");
325  exiftoolCmd.Append(HuginQueue::wxEscapeFilename(filename));
326  wxExecute(exiftoolCmd, wxEXEC_SYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_NODISABLE | wxEXEC_MAKE_GROUP_LEADER);
327 
328  return true;
329 }
330 
332 {
333  int count = 0;
334  for (long i = 0; i < m_exposuresListBox->GetItemCount(); ++i)
335  {
336  if (m_exposuresListBox->IsItemChecked(i))
337  {
338  ++count;
339  };
340  }
341  return count;
342 }
343 
void transformImageSpatial(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor sa, DestImageIterator dest_upperleft, DestAccessor da, Functor const &f, vigra::Diff2D ul)
Definition: utils.h:725
implementation of huginApp Class
const wxString GetConfigTempDir(const wxConfigBase *config)
return the temp dir from the preferences, ensure that it ends with path separator ...
Definition: Executor.cpp:302
wxChoice * m_stepWidthChoice
bool CreateAndSaveExposureCorrectedImage(const wxString &filename, const double correction)
create the exposure corrected image and save it to the file
wxBitmap m_scaledwxBitmap
current image as wxBitmap
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
radiometric transformation, includes exposure, vignetting and white balance
std::vector< double > m_exposures
void enforceMonotonicity(LUT &lut)
enforce monotonicity of an array (mostly used for lookup tables)
Definition: lut.h:87
CreateBrightImgDlg(wxWindow *parent)
Constructor, read from xrc ressource; restore position.
void OnSize(wxSizeEvent &e)
handler called when size of control was changed
void exportImageAlpha(ImageIterator image_upper_left, ImageIterator image_lower_right, ImageAccessor image_accessor, AlphaIterator alpha_upper_left, AlphaAccessor alpha_accessor, const ImageExportInfo &export_info)
Write the image and its alpha channel to a file.
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
Definition: ROIImage.h:300
void GetMonitorProfile(wxString &profileName, cmsHPROFILE &profile)
Definition: wxcms.cpp:195
basic classes and function for queuing commands in wxWidgets
~CreateBrightImgDlg()
destructor, save position
bool SetImage(const wxString &filename, wxString &errorMsg)
load the image, return true on success, otherwise false, error cause is in errorMsg ...
wxStaticBitmap * m_previewBitmap
void OnCreateExposureLevels(wxCommandEvent &e)
update listbox with new exposure values
void RescaleImage()
create rescaled image
wxListCtrl * m_exposuresListBox
void OnExposureChecked(wxListEvent &e)
prevent checking of exposure value 0
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
float pow(float a, double b)
Definition: utils.h:181
Definition of dialog class to create brighter/darker versions of the image.
void OnExposureSelected(wxListEvent &e)
one exposure selected
vigra::BasicImage< vigra::RGBValue< PixelType > > CreateBrightVersion(const vigra::BasicImage< vigra::RGBValue< PixelType >> &input, const double correction)
creates a brighter or darker version of the input image using HuginBase::Photometric::InvResponse ...
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
Definition: wxutils.cpp:133
vigra::BRGBImage m_scaledImg
current image as vigra::RGBImage
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
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
ImageCache::EntryPtr m_image
image cache entry for current image
void createEMoRLUT(const std::vector< float > &params, VECTOR &lut)
Definition: emor.h:44
void CreatewxBitmap(const vigra::BRGBImage &img)
create the wxBitmap version and apply color profiles
double GetExposureStepWidth() const
returns the current selected exposure step width
str wxEscapeFilename(const str &arg)
special escaping routine for CommandQueues
Definition: Executor.h:79
void setSize(vigra::Size2D val)
Set the image size in pixels.
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
static void info(const char *fmt,...)
Definition: svm.cpp:95
void OnOk(wxCommandEvent &e)
process all images
All variables of a source image.
Definition: SrcPanoImage.h:194
long GetCheckedItemCount()
return the number of checked exposures
wxString GetExternalProgram(wxConfigBase *config, const wxString &bindir, const wxString &name)
return path and name of external program, which can be overwritten by the user
Definition: Executor.cpp:148
void setOutput(double destExposure, const LUTD &destLut, double scale, double rangeCompression=0.0)
output lut
wxArrayString m_tempFiles
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Restore window size and position from configfile/registry.
Definition: wxutils.cpp:65
wxArrayString GetTempFiles() const