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
37template <class PixelType>
38vigra::BasicImage<vigra::RGBValue<PixelType>> CreateBrightVersion(const vigra::BasicImage<vigra::RGBValue<PixelType>>& input, const double correction)
39{
41 srcImage.setSize(input.size());
42 // build inverse response transform
44 std::vector<PixelType> outLut;
45 vigra_ext::EMoR::createEMoRLUT(srcImage.getEMoRParams(), outLut);
47 invResponse.setOutput(1.0 / std::pow(2.0, srcImage.getExposureValue() - correction), outLut, 1);
48 // now do photometric transformation
49 vigra::BasicImage<vigra::RGBValue<PixelType>> output(input.size());
50 vigra_ext::transformImageSpatial(vigra::srcImageRange(input), vigra::destImage(output), invResponse, vigra::Diff2D(0, 0));
51 return output;
52}
53
55{
56 // load from xrc
57 wxXmlResource::Get()->LoadDialog(this, parent, "enfuse_create_file");
58 // get pointer to some controls
59 m_stepWidthChoice = XRCCTRL(*this, "create_bright_choice_step_width", wxChoice);
60 m_levelChoice = XRCCTRL(*this, "create_bright_choice_levels", wxChoice);
61 m_exposuresListBox = XRCCTRL(*this, "create_bright_listctrl", wxListCtrl);
62 m_exposuresListBox->InsertColumn(0, _("Exposure value (EV)"), wxLIST_FORMAT_LEFT, wxLIST_AUTOSIZE_USEHEADER);
63 m_exposuresListBox->EnableCheckBoxes(true);
64 m_previewBitmap = XRCCTRL(*this, "create_bright_preview", wxStaticBitmap);
65 // load image size and position
66 hugin_utils::RestoreFramePosition(this, "ToolboxFrame/CreateBrighterDarkerImageDialog");
67 // bind event handler
74 // fill initial values
75 wxCommandEvent e;
77}
78
80{
81 // save position and size
82 hugin_utils::StoreFramePosition(this, "ToolboxFrame/CreateBrighterDarkerImageDialog");
83}
84
86{
87 m_filename = filename;
88 const std::string filenameString(filename.mb_str(HUGIN_CONV_FILENAME));
89 vigra::ImageImportInfo info(filenameString.c_str());
90 const std::string pixeltype(info.getPixelType());
91 if (!(pixeltype == "UINT8" || pixeltype == "UINT16"))
92 {
93 errorMsg = _("The creation of brighter and darker images works only for 8 and 16 bit images.");
94 return false;
95 }
96 try
97 {
98 ImageCache::getInstance().softFlush();
99 m_image = ImageCache::getInstance().getImage(filenameString);
100 }
101 catch (std::exception& e)
102 {
103 // loading of image failed
104 errorMsg = wxString::Format(_("Could not load image %s"), filename.c_str());;
105 errorMsg.Append(" (");
106 errorMsg.Append(e.what());
107 errorMsg.Append(")");
108 return false;
109 }
110 SetLabel(GetLabel() + " " + filename);
111 Layout();
112 RescaleImage();
114 return true;
115}
116
121
122void CreateBrightImgDlg::OnOk(wxCommandEvent & e)
123{
125 {
128 wxGauge* progress = XRCCTRL(*this, "enfuse_create_file_progress", wxGauge);
129 progress->Show();
130 Layout();
131 progress->SetRange(GetCheckedItemCount() + 1);
132 for (long i = 0; i < m_exposuresListBox->GetItemCount(); ++i)
133 {
134 if (m_exposuresListBox->IsItemChecked(i))
135 {
136 wxFileName tempfile(wxFileName::CreateTempFileName(tempDir + "htb"));
138 {
139 m_tempFiles.Add(tempfile.GetFullPath());
140 };
141 };
142 progress->SetValue(progress->GetValue() + 1);
143 progress->Update();
144 wxTheApp->Yield();
145 };
146 progress->Hide();
147 Layout();
148 }
149 if (!m_tempFiles.empty())
150 {
152 }
153 else
154 {
155 hugin_utils::HuginMessageBox(_("You have not yet selected at least one exposure correction."), _("Hugin toolbox"), wxOK | wxICON_WARNING, this);
156 };
157}
158
160{
161 m_exposures.clear();
162 m_exposuresListBox->DeleteAllItems();
163 const double stepWidth = GetExposureStepWidth();
164 const int nrLevels = (m_levelChoice->GetSelection() + 1) * 2 + 1;
165 double exposure = -std::trunc(nrLevels / 2.0) * stepWidth;
166 // disable checkbox check for updating the list
168 for (int i = 0; i < nrLevels; ++i)
169 {
170 m_exposures.push_back(exposure);
171 long index = m_exposuresListBox->InsertItem(m_exposuresListBox->GetItemCount(), wxString::Format(_("EV %+.2f"), exposure));
172 // set checkbox, disable checkbox for uncorrected image
173 m_exposuresListBox->CheckItem(index, std::abs(exposure) > 0.05);
174 exposure = exposure + stepWidth;
175 };
177}
178
180{
181 long index = m_exposuresListBox->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
182 if (index != -1)
183 {
184 // remember exposure correction value
186 // apply exposure correction and update wxStaticBitmap
187 vigra::BRGBImage img = CreateBrightVersion(m_scaledImg, m_currentExposure);
188 CreatewxBitmap(img);
190 }
191 else
192 {
193 // no item selected, do no exposure correction
195 };
196}
197
199{
200 // prevent checking item for exposure correction 0
201 if (e.GetIndex() == m_exposuresListBox->GetItemCount() / 2)
202 {
203 m_exposuresListBox->CheckItem(e.GetIndex(), false);
204 };
205}
206
208{
209 Layout();
210 RescaleImage();
212 e.Skip();
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
252void CreateBrightImgDlg::CreatewxBitmap(const vigra::BRGBImage& img)
253{
255 resizedImage.SetData((unsigned char*)img.data(), img.width(), img.height(), true);
256 wxBitmap bitmap(m_previewBitmap->GetClientSize());
257 {
258 wxMemoryDC dc(bitmap);
259 dc.SetBackground(wxBrush(m_previewBitmap->GetParent()->GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
260 dc.Clear();
261 wxPoint offset;
262 offset.x = (bitmap.GetWidth() - resizedImage.GetWidth()) / 2;
263 offset.y = (bitmap.GetHeight() - resizedImage.GetHeight()) / 2;
264 // apply color profiles
265 if (!m_image->iccProfile->empty() || wxGetApp().GetToolboxFrame()->HasMonitorProfile())
266 {
267 // we need a copy of the image, otherwise the orignal data is changed
269 HuginBase::Color::CorrectImage(resizedImage2, *(m_image->iccProfile), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
270 dc.DrawBitmap(resizedImage2, offset);
271 }
272 else
273 {
274 dc.DrawBitmap(resizedImage, offset);
275 }
276 }
277 m_scaledwxBitmap = bitmap;
278}
279
281{
282 vigra::ImageExportInfo info(filename.mb_str(HUGIN_CONV_FILENAME));
283 info.setFileType("TIFF");
284 // embed icc profile
285 if (!m_image->iccProfile->empty())
286 {
287 info.setICCProfile(*m_image->iccProfile);
288 };
289 if (m_image->image16->size().area() > 0)
290 {
291 //process 16 bit image
292 info.setPixelType("UINT16");
293 vigra::UInt16RGBImage finalImg = CreateBrightVersion(*m_image->image16, correction);
294 try
295 {
296 if (m_image->mask->size().area() > 0)
297 {
298 vigra::exportImageAlpha(vigra::srcImageRange(finalImg), vigra::srcImage(*m_image->mask), info);
299 }
300 else
301 {
302 vigra::exportImage(vigra::srcImageRange(finalImg), info);
303 };
304 }
305 catch (...)
306 {
307 return false;
308 }
309
310 }
311 else
312 {
313 // process 8 bit image
314 vigra::BRGBImage finalImg = CreateBrightVersion(*m_image->image8, correction);
315 try
316 {
317 info.setPixelType("UINT8");
318 if (m_image->mask->size().area() > 0)
319 {
320 vigra::exportImageAlpha(vigra::srcImageRange(finalImg), vigra::srcImage(*m_image->mask), info);
321 }
322 else
323 {
324 vigra::exportImage(vigra::srcImageRange(finalImg), info);
325 };
326 }
327 catch (...)
328 {
329 return false;
330 };
331 };
332 // copy some basic Exif data
333 const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
335 exiftoolCmd.Append(" -overwrite_original -tagsfromfile " + HuginQueue::wxEscapeFilename(m_filename) + " -xresolution -yresolution -resolutionunit -xposition -yposition -imagefullwidth -imagefullheight -FNumber -ISO ");
336 // update the exposure time with the corrected one
337 exiftoolCmd.Append("-ExposureTime<${exposuretime#;$_*=" + wxString::FromCDouble(std::pow(2, correction)) + "} ");
340
341 return true;
342}
343
345{
346 int count = 0;
347 for (long i = 0; i < m_exposuresListBox->GetItemCount(); ++i)
348 {
349 if (m_exposuresListBox->IsItemChecked(i))
350 {
351 ++count;
352 };
353 }
354 return count;
355}
356
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