2
* This file is a part of Qtpfsgui package.
3
* ----------------------------------------------------------------------
4
* Copyright (C) 2006,2007 Giuseppe Rota
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* ----------------------------------------------------------------------
21
* @author Giuseppe Rota <grota@users.sourceforge.net>
24
#include <QStringList>
25
#include <QFileDialog>
27
#include <QMessageBox>
29
#include <QTextStream>
31
#if defined(__FreeBSD__) && __FreeBSD__ < 6
33
#include "../arch/freebsd/s_exp2f.c"
37
#include "newHdrWizard.h"
38
#include "editingTools.h"
39
#include "../Common/config.h"
41
HdrWizardForm::HdrWizardForm(QWidget *p, qtpfsgui_opts *options) : QDialog(p), opts(options), settings("Qtpfsgui", "Qtpfsgui"), hdrCreationManager(NULL), loadcurvefilename(""), savecurvefilename("") {
44
weights_in_gui[0]=TRIANGULAR;
45
weights_in_gui[1]=GAUSSIAN;
46
weights_in_gui[2]=PLATEAU;
47
responses_in_gui[0]=GAMMA;
48
responses_in_gui[1]=LINEAR;
49
responses_in_gui[2]=LOG10;
50
responses_in_gui[3]=FROM_ROBERTSON;
51
models_in_gui[0]=DEBEVEC;
52
models_in_gui[1]=ROBERTSON;
54
tableWidget->setHorizontalHeaderLabels(QStringList()<< tr("Image Filename") << tr("Exposure"));
55
tableWidget->resizeColumnsToContents();
56
EVgang = new Gang(EVSlider, ImageEVdsb,-10,10,0);
57
connect(EVgang, SIGNAL(finished()), this, SLOT(editingEVfinished()));
58
connect(tableWidget, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(inputHdrFileSelected(int)));
60
connect(NextFinishButton,SIGNAL(clicked()),this,SLOT(NextFinishButtonClicked()));
61
connect(cancelButton,SIGNAL(clicked()),this,SLOT(cancelButtonClicked()));
62
connect(pagestack,SIGNAL(currentChanged(int)),this,SLOT(currentPageChangedInto(int)));
64
connect(predefConfigsComboBox,SIGNAL(activated(int)),this,
65
SLOT(predefConfigsComboBoxActivated(int)));
66
connect(antighostRespCurveCombobox,SIGNAL(activated(int)),this,
67
SLOT(antighostRespCurveComboboxActivated(int)));
68
connect(customConfigCheckBox,SIGNAL(toggled(bool)),this,
69
SLOT(customConfigCheckBoxToggled(bool)));
70
connect(triGaussPlateauComboBox,SIGNAL(activated(int)),this,
71
SLOT(triGaussPlateauComboBoxActivated(int)));
72
connect(predefRespCurveRadioButton,SIGNAL(toggled(bool)),this,
73
SLOT(predefRespCurveRadioButtonToggled(bool)));
74
connect(gammaLinLogComboBox,SIGNAL(activated(int)),this,
75
SLOT(gammaLinLogComboBoxActivated(int)));
76
connect(loadRespCurveFromFileCheckbox,SIGNAL(toggled(bool)),this,
77
SLOT(loadRespCurveFromFileCheckboxToggled(bool)));
78
connect(loadRespCurveFileButton,SIGNAL(clicked()),this,
79
SLOT(loadRespCurveFileButtonClicked()));
80
connect(saveRespCurveToFileCheckbox,SIGNAL(toggled(bool)),this,
81
SLOT(saveRespCurveToFileCheckboxToggled(bool)));
82
connect(saveRespCurveFileButton,SIGNAL(clicked()),this,
83
SLOT(saveRespCurveFileButtonClicked()));
84
connect(modelComboBox,SIGNAL(activated(int)),this,
85
SLOT(modelComboBoxActivated(int)));
86
connect(RespCurveFileLoadedLineEdit,SIGNAL(textChanged(const QString&)),this,
87
SLOT(loadRespCurveFilename(const QString&)));
88
connect(loadImagesButton,SIGNAL(clicked()),this,SLOT(loadImagesButtonClicked()));
90
hdrCreationManager = new HdrCreationManager ( opts->num_threads, opts->tempfilespath, opts->dcraw_options );
91
connect(hdrCreationManager, SIGNAL(fileLoaded(int,QString,float)), this, SLOT(fileLoaded(int,QString,float)));
92
connect(hdrCreationManager,SIGNAL(finishedLoadingInputFiles(QStringList)),this, SLOT(finishedLoadingInputFiles(QStringList)));
93
connect(hdrCreationManager,SIGNAL(errorWhileLoading(QString)),this, SLOT(errorWhileLoading(QString)));
94
connect(hdrCreationManager,SIGNAL(expotimeValueChanged(float,int)),this, SLOT(updateGraphicalEVvalue(float,int)));
95
connect(hdrCreationManager, SIGNAL(finishedAligning()), this, SLOT(finishedAligning()));
96
connect(hdrCreationManager, SIGNAL(ais_failed(QProcess::ProcessError)), this, SLOT(ais_failed(QProcess::ProcessError)));
100
void HdrWizardForm::loadImagesButtonClicked() {
102
filetypes += tr("All formats (*.jpeg *.jpg *.tiff *.tif *.crw *.cr2 *.nef *.dng *.mrw *.orf *.kdc *.dcr *.arw *.raf *.ptx *.pef *.x3f *.raw);;");
103
filetypes += tr("JPEG (*.jpeg *.jpg);;");
104
filetypes += tr("TIFF Images (*.tiff *.tif);;");
105
filetypes += tr("RAW Images (*.crw *.cr2 *.nef *.dng *.mrw *.orf *.kdc *.dcr *.arw *.raf *.ptx *.pef *.x3f *.raw)");
107
QString RecentDirInputLDRs = settings.value(KEY_RECENT_PATH_LOAD_LDRs_FOR_HDR, QDir::currentPath()).toString();
109
QStringList files = QFileDialog::getOpenFileNames(this, tr("Select the input images"), RecentDirInputLDRs, filetypes );
111
if (!files.isEmpty() ) {
112
QFileInfo qfi(files.at(0));
113
// if the new dir, the one just chosen by the user, is different from the one stored in the settings, update the settings.
114
if (RecentDirInputLDRs != qfi.path()) {
115
// update internal field variable
116
RecentDirInputLDRs=qfi.path();
117
settings.setValue(KEY_RECENT_PATH_LOAD_LDRs_FOR_HDR, RecentDirInputLDRs);
120
tableWidget->setEnabled(false);
121
tableWidget->setRowCount(files.count());
122
progressBar->setMaximum(files.count());
123
progressBar->setValue(0);
125
hdrCreationManager->setFileList(files);
126
hdrCreationManager->loadInputFiles();
127
} //if (!files.isEmpty())
130
void HdrWizardForm::fileLoaded(int index, QString fname, float expotime) {
131
qDebug("WIZ: fileLoaded, expotimes[%d]=%f --- EV=%f",index,expotime,log2f(expotime));
132
updateGraphicalEVvalue(expotime,index);
133
//fill graphical list
134
QFileInfo qfi(fname);
135
tableWidget->setItem(index,0,new QTableWidgetItem(qfi.fileName()));
137
progressBar->setValue(progressBar->value()+1); // increment progressbar
140
void HdrWizardForm::finishedLoadingInputFiles(QStringList filesLackingExif) {
141
if (filesLackingExif.size()==0) {
142
NextFinishButton->setEnabled(TRUE);
143
confirmloadlabel->setText(tr("<center><font color=\"#008400\"><h3><b>Images Loaded.</b></h3></font></center>"));
145
QString warning_message=(QString(tr("<font color=\"#FF0000\"><h3><b>WARNING:</b></h3></font>\
146
Qtpfsgui was not able to find the relevant <i>EXIF</i> tags\nfor the following images:\n <ul>\
148
<hr>You can still proceed creating an Hdr. To do so you have to insert <b>manually</b> the EV (exposure values) or stop difference values.\
149
<hr>If you want Qtfsgui to do this <b>automatically</b>, you have to load images that have at least\nthe following exif data: \
150
<ul><li>Shutter Speed (seconds)</li>\
151
<li>Aperture (f-number)</li></ul>\
152
<hr><b>HINT:</b> Losing EXIF data usually happens when you preprocess your pictures.<br>\
153
You can perform a <b>one-to-one copy of the exif data</b> between two sets of images via the <i><b>\"Tools->Copy Exif Data...\"</b></i> menu item."))).arg(filesLackingExif.join(""));
154
QMessageBox::warning(this,tr("EXIF data not found"),warning_message);
155
confirmloadlabel->setText(QString(tr("<center><h3><b>To proceed you need to manually set the exposure values.<br><font color=\"#FF0000\">%1</font> values still required.</b></h3></center>")).arg(filesLackingExif.size()));
157
//do not load any more images
158
loadImagesButton->setEnabled(FALSE);
160
tableWidget->resizeColumnsToContents();
161
//enable user EV input
162
EVgroupBox->setEnabled(TRUE);
163
tableWidget->selectRow(0);
164
tableWidget->setEnabled(true);
166
//align_image_stack & mtb don't yet work with 16bit data
167
if (tableWidget->rowCount()>=2 && hdrCreationManager->inputImageType()==HdrCreationManager::LDR_INPUT_TYPE) {
168
alignCheckBox->setEnabled(TRUE);
169
alignGroupBox->setEnabled(TRUE);
173
void HdrWizardForm::errorWhileLoading(QString error) {
174
tableWidget->clear();
175
tableWidget->setRowCount(0);
176
tableWidget->setEnabled(true);
177
progressBar->setValue(0);
178
QMessageBox::critical(this,tr("Loading Error"), error);
179
hdrCreationManager->clearlists(true);
182
void HdrWizardForm::updateGraphicalEVvalue(float expotime, int index_in_table) {
183
qDebug("WIZ: updateGraphicalEVvalue EV[%d]=%f",index_in_table,log2f(expotime));
186
QTextStream ts(&EVdisplay);
187
ts.setRealNumberPrecision(2);
188
ts << right << forcesign << fixed << log2f(expotime) << " EV";
189
QTableWidgetItem *tableitem=new QTableWidgetItem(EVdisplay);
190
tableitem->setTextAlignment(Qt::AlignRight);
191
tableWidget->setItem(index_in_table,1,tableitem);
193
//if image doesn't contain (the required) exif tags
194
tableWidget->setItem(index_in_table,1,new QTableWidgetItem(tr("Unknown ")));
198
void HdrWizardForm::finishedAligning() {
199
QApplication::restoreOverrideCursor();
200
NextFinishButton->setEnabled(TRUE);
201
pagestack->setCurrentIndex(1);
204
void HdrWizardForm::ais_failed(QProcess::ProcessError e) {
206
case QProcess::FailedToStart:
207
QMessageBox::warning(this,tr("Error..."),tr("Failed to start external application \"<em>align_image_stack</em>\".<br>Please read \"Help -> Documentation... -> Hints and tips\" for more information."));
209
case QProcess::Crashed:
210
QMessageBox::warning(this,tr("Error..."),tr("The external application \"<em>align_image_stack</em>\" crashed..."));
212
case QProcess::Timedout:
213
case QProcess::ReadError:
214
case QProcess::WriteError:
215
case QProcess::UnknownError:
216
QMessageBox::warning(this,tr("Error..."),tr("An unknown error occurred while executing the \"<em>align_image_stack</em>\" application..."));
219
QApplication::restoreOverrideCursor();
220
NextFinishButton->setEnabled(TRUE);
221
if (pagestack->currentIndex()==0)
222
pagestack->setCurrentIndex(1);
225
void HdrWizardForm::customConfigCheckBoxToggled(bool want_custom) {
227
if (!antighostingCheckBox->isChecked()) {
228
label_RespCurve_Antighost->setDisabled(TRUE);
229
antighostRespCurveCombobox->setDisabled(TRUE);
230
label_Iterations->setDisabled(TRUE);
231
spinBoxIterations->setDisabled(TRUE);
232
//temporary disable anti-ghosting until it's fixed
233
antighostingCheckBox->setDisabled(TRUE);
236
label_predef_configs->setDisabled(TRUE);
237
predefConfigsComboBox->setDisabled(TRUE);
238
label_weights->setDisabled(TRUE);
239
lineEdit_showWeight->setDisabled(TRUE);
240
label_resp->setDisabled(TRUE);
241
lineEdit_show_resp->setDisabled(TRUE);
242
label_model->setDisabled(TRUE);
243
lineEdit_showmodel->setDisabled(TRUE);
245
predefConfigsComboBoxActivated(predefConfigsComboBox->currentIndex());
246
NextFinishButton->setText(tr("&Finish"));
248
NextFinishButton->setText(tr("&Next >"));
252
void HdrWizardForm::predefRespCurveRadioButtonToggled(bool want_predef_resp_curve) {
253
if (want_predef_resp_curve) {
254
//ENABLE load_curve_button and lineedit when "load from file" is checked.
255
if (!loadRespCurveFromFileCheckbox->isChecked()) {
256
loadRespCurveFileButton->setEnabled(FALSE);
257
RespCurveFileLoadedLineEdit->setEnabled(FALSE);
259
loadRespCurveFromFileCheckboxToggled(loadRespCurveFromFileCheckbox->isChecked());
260
} else { //want to recover response curve via robertson02
261
//update hdrCreationManager->chosen_config
262
hdrCreationManager->chosen_config.response_curve=FROM_ROBERTSON;
264
NextFinishButton->setEnabled(TRUE);
265
saveRespCurveToFileCheckboxToggled(saveRespCurveToFileCheckbox->isChecked());
269
void HdrWizardForm::loadRespCurveFromFileCheckboxToggled( bool checkedfile ) {
270
//if checkbox is checked AND we have a valid filename
271
if (checkedfile && loadcurvefilename != "") {
272
//update chosen config
273
hdrCreationManager->chosen_config.response_curve=FROM_FILE;
274
hdrCreationManager->chosen_config.LoadCurveFromFilename=loadcurvefilename;
275
//and ENABLE nextbutton
276
NextFinishButton->setEnabled(TRUE);
278
//if checkbox is checked AND no valid filename
279
else if (checkedfile && loadcurvefilename == "") {
280
// DISABLE nextbutton until situation is fixed
281
NextFinishButton->setEnabled(FALSE);
282
// qDebug("Load checkbox is checked AND no valid filename");
284
//checkbox not checked
286
// update chosen config
287
hdrCreationManager->chosen_config.response_curve=responses_in_gui[gammaLinLogComboBox->currentIndex()];
288
hdrCreationManager->chosen_config.LoadCurveFromFilename="";
289
//and ENABLE nextbutton
290
NextFinishButton->setEnabled(TRUE);
294
void HdrWizardForm::saveRespCurveToFileCheckboxToggled( bool checkedfile ) {
295
//if checkbox is checked AND we have a valid filename
296
if (checkedfile && savecurvefilename != "") {
297
hdrCreationManager->chosen_config.SaveCurveToFilename=savecurvefilename;
298
NextFinishButton->setEnabled(TRUE);
300
//if checkbox is checked AND no valid filename
301
else if (checkedfile && savecurvefilename == "") {
302
// DISABLE nextbutton until situation is fixed
303
NextFinishButton->setEnabled(FALSE);
305
//checkbox not checked
307
hdrCreationManager->chosen_config.SaveCurveToFilename="";
308
//and ENABLE nextbutton
309
NextFinishButton->setEnabled(TRUE);
313
void HdrWizardForm::NextFinishButtonClicked() {
314
int currentpage=pagestack->currentIndex();
315
switch (currentpage) {
317
//now align, if requested
318
if (alignCheckBox->isChecked()) {
319
QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
320
confirmloadlabel->setText("<center><h3><b>"+tr("Aligning...")+"</b></h3></center>");
321
NextFinishButton->setDisabled(TRUE);
322
alignGroupBox->setDisabled(TRUE);
323
EVgroupBox->setDisabled(TRUE);
324
tableWidget->setDisabled(TRUE);
325
switch (alignmentEngineCB->currentIndex()) {
326
case 0: //Hugin's align_image_stack
327
hdrCreationManager->align_with_ais();
330
// if (hdrCreationManager->inputImageType()==HdrCreationManager::MDR_INPUT_TYPE) {
331
// QMessageBox::warning(this,tr("Error..."),tr("MTB is not available with 16 bit input images."));
334
hdrCreationManager->align_with_mtb();
339
pagestack->setCurrentIndex(1);
342
if(!customConfigCheckBox->isChecked()) {
345
pagestack->setCurrentIndex(2);
349
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
350
PfsFrameHDR=hdrCreationManager->createHdr(antighostingCheckBox->isChecked(),spinBoxIterations->value());
351
QApplication::restoreOverrideCursor();
357
void HdrWizardForm::currentPageChangedInto(int newindex) {
358
//predefined configs page
360
hdrCreationManager->removeTempFiles();
361
NextFinishButton->setText(tr("&Finish"));
362
//when at least 2 LDR inputs perform Manual Alignment
363
int numldrs=hdrCreationManager->getLDRList().size();
364
if (hdrCreationManager->inputImageType()==HdrCreationManager::LDR_INPUT_TYPE && numldrs>=2) {
365
this->setDisabled(TRUE);
366
//fix for some platforms/Qt versions: makes sure LDR images have alpha channel
367
hdrCreationManager->makeSureLDRsHaveAlpha();
368
EditingTools *editingtools= new EditingTools(hdrCreationManager);
369
if (editingtools->exec() == QDialog::Accepted) {
370
this->setDisabled(FALSE);
377
else if (newindex==2) { //custom config
378
predefConfigsComboBoxActivated(1);
379
NextFinishButton->setText(tr("&Finish"));
384
void HdrWizardForm::antighostRespCurveComboboxActivated(int fromgui) {
385
gammaLinLogComboBoxActivated(fromgui);
388
void HdrWizardForm::loadRespCurveFileButtonClicked() {
389
loadcurvefilename = QFileDialog::getOpenFileName(
391
tr("Load a camera response curve file"),
393
tr("Camera response curve (*.m);;All Files (*)") );
394
if (!loadcurvefilename.isEmpty()) {
395
RespCurveFileLoadedLineEdit->setText(loadcurvefilename);
396
loadRespCurveFromFileCheckboxToggled(loadRespCurveFromFileCheckbox->isChecked());
400
void HdrWizardForm::saveRespCurveFileButtonClicked() {
401
savecurvefilename = QFileDialog::getSaveFileName(
403
tr("Save a camera response curve file"),
405
tr("Camera response curve (*.m);;All Files (*)") );
406
if (!savecurvefilename.isEmpty()) {
407
CurveFileNameSaveLineEdit->setText(savecurvefilename);
408
saveRespCurveToFileCheckboxToggled(saveRespCurveToFileCheckbox->isChecked());
412
void HdrWizardForm::predefConfigsComboBoxActivated( int index_from_gui ) {
413
hdrCreationManager->chosen_config=predef_confs[index_from_gui];
414
lineEdit_showWeight->setText(getQStringFromConfig(1));
415
lineEdit_show_resp->setText(getQStringFromConfig(2));
416
lineEdit_showmodel->setText(getQStringFromConfig(3));
419
void HdrWizardForm::triGaussPlateauComboBoxActivated(int from_gui) {
420
hdrCreationManager->chosen_config.weights=weights_in_gui[from_gui];
423
void HdrWizardForm::gammaLinLogComboBoxActivated(int from_gui) {
424
hdrCreationManager->chosen_config.response_curve=responses_in_gui[from_gui];
427
void HdrWizardForm::modelComboBoxActivated(int from_gui) {
428
hdrCreationManager->chosen_config.model=models_in_gui[from_gui];
431
void HdrWizardForm::loadRespCurveFilename( const QString & filename_from_gui) {
432
if (!filename_from_gui.isEmpty()) {
433
hdrCreationManager->chosen_config.response_curve=FROM_FILE;
434
hdrCreationManager->chosen_config.LoadCurveFromFilename=filename_from_gui;
438
QString HdrWizardForm::getCaptionTEXT() {
439
return tr("(*) Weights: ")+getQStringFromConfig(1) + tr(" - Response curve: ") + getQStringFromConfig(2) + tr(" - Model: ") + getQStringFromConfig(3);
442
QString HdrWizardForm::getQStringFromConfig( int type ) {
443
if (type==1) { //return String for weights
444
switch (hdrCreationManager->chosen_config.weights) {
446
return tr("Triangular");
448
return tr("Plateau");
450
return tr("Gaussian");
452
} else if (type==2) { //return String for response curve
453
switch (hdrCreationManager->chosen_config.response_curve) {
459
return tr("Logarithmic");
461
return tr("From Calibration");
463
return tr("From File");
465
} else if (type==3) { //return String for model
466
switch (hdrCreationManager->chosen_config.model) {
468
return tr("Debevec");
470
return tr("Robertson");
476
//triggered by user interaction
477
void HdrWizardForm::editingEVfinished() {
478
//transform from EV value to expotime value
479
hdrCreationManager->setEV(ImageEVdsb->value(),tableWidget->currentRow());
480
if (hdrCreationManager->getFilesLackingExif().size()==0) {
481
NextFinishButton->setEnabled(TRUE);
482
//give an offset to the EV values if they are outside of the -10..10 range.
483
hdrCreationManager->checkEVvalues();
484
confirmloadlabel->setText(tr("<center><font color=\"#008400\"><h3><b>All the EV values have been set.</b></h3></font></center>"));
486
confirmloadlabel->setText( QString(tr("<center><h3><b>To proceed you need to manually set the exposure values.<br><font color=\"#FF0000\">%1</font> values still required.</b></h3></center>")).arg(hdrCreationManager->getFilesLackingExif().size()) );
490
void HdrWizardForm::inputHdrFileSelected(int i) {
491
if (hdrCreationManager->isValidEV(i))
492
ImageEVdsb->setValue(hdrCreationManager->getEV(i));
493
if (hdrCreationManager->inputImageType()==HdrCreationManager::LDR_INPUT_TYPE) {
494
QImage *image=hdrCreationManager->getLDRList().at(i);
495
previewLabel->setPixmap(QPixmap::fromImage(image->scaled(previewLabel->size(), Qt::KeepAspectRatio)));
497
ImageEVdsb->setFocus();
500
void HdrWizardForm::resizeEvent ( QResizeEvent * ) {
501
//make sure we ask for a thumbnail only when we need it
502
if (pagestack->currentIndex()==0 && tableWidget->currentRow()!=-1 && hdrCreationManager->inputImageType()==HdrCreationManager::LDR_INPUT_TYPE) {
503
QImage *image=hdrCreationManager->getLDRList().at(tableWidget->currentRow());
504
previewLabel->setPixmap(QPixmap::fromImage(image->scaled(previewLabel->size(), Qt::KeepAspectRatio)));
508
HdrWizardForm::~HdrWizardForm() {
510
delete hdrCreationManager;
514
void HdrWizardForm::keyPressEvent(QKeyEvent *event) {
515
if (event->key() == Qt::Key_Enter || event->key()==Qt::Key_Return) {
516
tableWidget->selectRow(tableWidget->currentRow()==tableWidget->rowCount()-1 ? 0 : tableWidget->currentRow()+1);
517
} else if (event->key() == Qt::Key_Escape) {
522
void HdrWizardForm::cancelButtonClicked() {
523
hdrCreationManager->removeTempFiles();