Hugin trunk 0.1
Loading...
Searching...
No Matches
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
38template <class PixelType>
39vigra::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 (EV)"), 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 hugin_utils::RestoreFramePosition(this, "ToolboxFrame/CreateBrighterDarkerImageDialog");
68 // bind event handler
75 // fill initial values
76 wxCommandEvent e;
78}
79
81{
82 // save position and size
83 hugin_utils::StoreFramePosition(this, "ToolboxFrame/CreateBrighterDarkerImageDialog");
84}
85
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();
115 return true;
116}
117
122
123void CreateBrightImgDlg::OnOk(wxCommandEvent & e)
124{
126 {
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"));
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 {
153 }
154 else
155 {
156 hugin_utils::HuginMessageBox(_("You have not yet selected at least one exposure correction."), _("Hugin toolbox"), wxOK | wxICON_WARNING, this);
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
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 };
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);
191 }
192 else
193 {
194 // no item selected, do no exposure correction
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
209{
210 Layout();
211 RescaleImage();
213 e.Skip();
214}
215
217{
218 if (m_stepWidthChoice->GetSelection() == 0)
219 {
220 return 0.6667;
221 }
222 else
223 {
224 if (m_stepWidthChoice->GetSelection() == 2)
225 {
226 return 1.3333;
227 };
228 };
229 return 1.0;
230}
231
233{
234 wxSize previewSize = m_previewBitmap->GetClientSize();
235 const long imageWidth = m_image->image16->size().area() > 0 ? m_image->image16->width() : m_image->image8->width();
236 const long imageHeight = m_image->image16->size().area() > 0 ? m_image->image16->height() : m_image->image8->height();
237 const double scaleFactor = std::min<double>((double)previewSize.GetWidth() / imageWidth, (double)previewSize.GetHeight() / imageHeight);
238 m_scaledImg.resize(scaleFactor * imageWidth, scaleFactor * imageHeight);
239 vigra::resizeImageLinearInterpolation(vigra::srcImageRange(*m_image->get8BitImage()), vigra::destImageRange(m_scaledImg));
240 if (m_currentExposure > -0.01 && m_currentExposure < 0.01)
241 {
242 // no exposure correction, directly transform m_scaledImg to wxBitmap
244 }
245 else
246 {
247 // apply exposure correction and convert to wxBitmap
248 vigra::BRGBImage img = CreateBrightVersion(m_scaledImg, m_currentExposure);
249 CreatewxBitmap(img);
250 };
251}
252
253void CreateBrightImgDlg::CreatewxBitmap(const vigra::BRGBImage& img)
254{
256 resizedImage.SetData((unsigned char*)img.data(), img.width(), img.height(), true);
257 wxBitmap bitmap(m_previewBitmap->GetClientSize());
258 {
259 wxMemoryDC dc(bitmap);
260 dc.SetBackground(wxBrush(m_previewBitmap->GetParent()->GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
261 dc.Clear();
262 wxPoint offset;
263 offset.x = (bitmap.GetWidth() - resizedImage.GetWidth()) / 2;
264 offset.y = (bitmap.GetHeight() - resizedImage.GetHeight()) / 2;
265 // apply color profiles
266 if (!m_image->iccProfile->empty() || wxGetApp().GetToolboxFrame()->HasMonitorProfile())
267 {
268 // we need a copy of the image, otherwise the orignal data is changed
270 HuginBase::Color::CorrectImage(resizedImage2, *(m_image->iccProfile), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
271 dc.DrawBitmap(resizedImage2, offset);
272 }
273 else
274 {
275 dc.DrawBitmap(resizedImage, offset);
276 }
277 }
278 m_scaledwxBitmap = bitmap;
279}
280
282{
283 vigra::ImageExportInfo info(filename.mb_str(HUGIN_CONV_FILENAME));
284 info.setFileType("TIFF");
285 // embed icc profile
286 if (!m_image->iccProfile->empty())
287 {
288 info.setICCProfile(*m_image->iccProfile);
289 };
290 if (m_image->image16->size().area() > 0)
291 {
292 //process 16 bit image
293 info.setPixelType("UINT16");
294 vigra::UInt16RGBImage finalImg = CreateBrightVersion(*m_image->image16, correction);
295 try
296 {
297 if (m_image->mask->size().area() > 0)
298 {
299 vigra::exportImageAlpha(vigra::srcImageRange(finalImg), vigra::srcImage(*m_image->mask), info);
300 }
301 else
302 {
303 vigra::exportImage(vigra::srcImageRange(finalImg), info);
304 };
305 }
306 catch (...)
307 {
308 return false;
309 }
310
311 }
312 else
313 {
314 // process 8 bit image
315 vigra::BRGBImage finalImg = CreateBrightVersion(*m_image->image8, correction);
316 try
317 {
318 info.setPixelType("UINT8");
319 if (m_image->mask->size().area() > 0)
320 {
321 vigra::exportImageAlpha(vigra::srcImageRange(finalImg), vigra::srcImage(*m_image->mask), info);
322 }
323 else
324 {
325 vigra::exportImage(vigra::srcImageRange(finalImg), info);
326 };
327 }
328 catch (...)
329 {
330 return false;
331 };
332 };
333 // copy some basic Exif data
334 const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
336 exiftoolCmd.Append(" -overwrite_original -tagsfromfile " + HuginQueue::wxEscapeFilename(m_filename) + " -xresolution -yresolution -resolutionunit -xposition -yposition -imagefullwidth -imagefullheight -FNumber -ISO ");
337 // update the exposure time with the corrected one
338 exiftoolCmd.Append("-ExposureTime<${exposuretime#;$_*=" + wxString::FromCDouble(std::pow(2, correction)) + "} ");
341
342 return true;
343}
344
346{
347 int count = 0;
348 for (long i = 0; i < m_exposuresListBox->GetItemCount(); ++i)
349 {
350 if (m_exposuresListBox->IsItemChecked(i))
351 {
352 ++count;
353 };
354 }
355 return count;
356}
357
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
Definition of dialog class to create brighter/darker versions of the image.
basic classes and function for queuing commands in wxWidgets
CreateBrightImgDlg(wxWindow *parent)
Constructor, read from xrc ressource; restore position.
void OnSize(wxSizeEvent &e)
handler called when size of control was changed
wxStaticBitmap * m_previewBitmap
long GetCheckedItemCount()
return the number of checked exposures
wxArrayString m_tempFiles
bool CreateAndSaveExposureCorrectedImage(const wxString &filename, const double correction)
create the exposure corrected image and save it to the file
std::vector< double > m_exposures
~CreateBrightImgDlg()
destructor, save position
void OnOk(wxCommandEvent &e)
process all images
void OnCreateExposureLevels(wxCommandEvent &e)
update listbox with new exposure values
void CreatewxBitmap(const vigra::BRGBImage &img)
create the wxBitmap version and apply color profiles
void OnExposureChecked(wxListEvent &e)
prevent checking of exposure value 0
void OnExposureSelected(wxListEvent &e)
one exposure selected
ImageCache::EntryPtr m_image
image cache entry for current image
void RescaleImage()
create rescaled image
bool SetImage(const wxString &filename, wxString &errorMsg)
load the image, return true on success, otherwise false, error cause is in errorMsg
double GetExposureStepWidth() const
returns the current selected exposure step width
wxBitmap m_scaledwxBitmap
current image as wxBitmap
wxArrayString GetTempFiles() const
wxListCtrl * m_exposuresListBox
vigra::BRGBImage m_scaledImg
current image as vigra::RGBImage
radiometric transformation, includes exposure, vignetting and white balance
All variables of a source image.
class AlphaIterator class AlphaAccessor inline void exportImageAlpha(ImageIterator image_upper_left, ImageIterator image_lower_right, ImageAccessor image_accessor, AlphaIterator alpha_upper_left, AlphaAccessor alpha_accessor, const ImageExportInfo &export_info)
implementation of huginApp Class
#define HUGIN_CONV_FILENAME
Definition platform.h:40
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
str wxEscapeFilename(const str &arg)
special escaping routine for CommandQueues
Definition Executor.h:79
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
const wxString GetConfigTempDir(const wxConfigBase *config)
return the temp dir from the preferences, ensure that it ends with path separator
Definition Executor.cpp:302
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:176
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:106
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:67
void createEMoRLUT(const std::vector< float > &params, VECTOR &lut)
Definition emor.h:44
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
void enforceMonotonicity(LUT &lut)
enforce monotonicity of an array (mostly used for lookup tables)
Definition lut.h:87
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