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 "tonemapperThread.h"
26
#include "../Common/config.h"
27
pfs::Frame* resizeFrame(pfs::Frame* inpfsframe, int _xSize);
28
void applyGammaFrame( pfs::Frame*, const float);
29
pfs::Frame* pfstmo_ashikhmin02 (pfs::Frame*,bool,float,int);
30
pfs::Frame* pfstmo_drago03 (pfs::Frame *, float);
31
pfs::Frame* pfstmo_fattal02 (pfs::Frame*,float,float,float,float,bool);
32
pfs::Frame* pfstmo_durand02 (pfs::Frame*,float,float,float);
33
pfs::Frame* pfstmo_pattanaik00 (pfs::Frame*,bool,float,float,float,bool);
34
pfs::Frame* pfstmo_reinhard02 (pfs::Frame*,float,float,int,int,int,bool);
35
pfs::Frame* pfstmo_reinhard05 (pfs::Frame *,float,float,float);
36
pfs::Frame* pfstmo_mantiuk06(pfs::Frame*,float,float,bool);
38
// width of the pfs:frame written on disk during resize operation, cannot be the 100% size: originalxsize, because i don't resize to 100% and write to disk.
39
int xsize=-1; //-1 means nothing has been computed yet
40
// gamma of the pfs:frame written on disk after resize
41
float pregamma=-1; //-1 means NOT VALID (size has changed/is changing)
42
//pregamma!=-1 means that the pregamma frame has the xsize as width
46
TonemapperThread::TonemapperThread(int xorigsize, const tonemapping_options opts) : QThread(0), originalxsize(xorigsize), settings("Qtpfsgui", "Qtpfsgui"), opts(opts) {
47
colorspaceconversion=false;
48
settings.beginGroup(GROUP_TONEMAPPING);
49
cachepath=settings.value(KEY_TEMP_RESULT_PATH,QDir::currentPath()).toString();
52
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
53
setTerminationEnabled(true);
54
forciblyTerminated=false;
57
TonemapperThread::~TonemapperThread() {
58
if (!forciblyTerminated) {
63
void TonemapperThread::fetch(QString filename) {
65
workingframe=pfsio.readFrame(cachepath+filename);
68
void TonemapperThread::swap(pfs::Frame *frame, QString filename) {
71
pfsio.writeFrame(frame,cachepath+filename);
74
void TonemapperThread::run() {
75
qDebug("TMthread::begin thread, size=%d, gamma=%f",xsize, pregamma);
77
if (opts.xsize==originalxsize && opts.pregamma==1.0f) {
78
//original goes into tone mapping
79
qDebug("TMthread::original goes into tone mapping");
80
fetch("/original.pfs");
82
colorspaceconversion=true;
83
emit setMaximumSteps(2);
84
} else if (opts.xsize==xsize && opts.pregamma==1.0f) {
85
//resized goes into tone mapping
86
qDebug("TMthread::resized goes into tone mapping");
87
fetch("/after_resize.pfs");
89
colorspaceconversion=true;
90
emit setMaximumSteps(2);
91
} else if ( (opts.xsize==xsize && opts.pregamma==pregamma) || (opts.xsize==originalxsize && xsize==-1 && opts.pregamma==pregamma) ) {
92
//after_pregamma goes into tone mapping
93
qDebug("TMthread::after_pregamma goes into tone mapping");
94
fetch("/after_pregamma.pfs");
96
emit setMaximumSteps(2);
97
} else if (opts.xsize==xsize) {
98
//resized goes into pregamma
99
qDebug("TMthread::resized goes into pregamma");
100
fetch("/after_resize.pfs");
101
status=from_pregamma;
102
emit setMaximumSteps(3);
103
} else if (opts.xsize==originalxsize) {
104
//original goes into pregamma
105
qDebug("TMthread::original goes into pregamma");
106
fetch("/original.pfs");
107
status=from_pregamma;
108
emit setMaximumSteps(3);
110
//original goes into resize
111
qDebug("TMthread::original goes into resize");
112
fetch("/original.pfs");
114
emit setMaximumSteps(4);
116
emit advanceCurrentProgress();
120
if (status==from_resize) {
121
assert(opts.xsize!=originalxsize);
122
qDebug("TMthread:: executing resize step");
123
pfs::Frame *resized=resizeFrame(workingframe, opts.xsize);
125
swap(resized,"/after_resize.pfs");
130
workingframe=resized;
131
status=from_pregamma;
132
emit advanceCurrentProgress();
134
if (status==from_pregamma) {
135
qDebug("TMthread:: executing pregamma step");
136
applyGammaFrame( workingframe, opts.pregamma );
138
swap(workingframe,"/after_pregamma.pfs");
139
pregamma=opts.pregamma;
140
if (opts.xsize==originalxsize)
146
emit advanceCurrentProgress();
148
if (status==from_tm) {
149
qDebug("TMthread:: executing tone mapping step");
150
if (colorspaceconversion)
151
workingframe->convertRGBChannelsToXYZ();
152
pfs::Frame *result=NULL;
153
switch (opts.tmoperator) {
155
result=pfstmo_mantiuk06(workingframe,
156
opts.operator_options.mantiukoptions.contrastfactor,
157
opts.operator_options.mantiukoptions.saturationfactor,
158
opts.operator_options.mantiukoptions.contrastequalization);
161
//fattal is NOT even reentrant! (problem in PDE solving)
162
//therefore I need to use a mutex here
164
result=pfstmo_fattal02(workingframe,
165
opts.operator_options.fattaloptions.alpha,
166
opts.operator_options.fattaloptions.beta,
167
opts.operator_options.fattaloptions.color,
168
opts.operator_options.fattaloptions.noiseredux,
169
opts.operator_options.fattaloptions.newfattal);
173
result=pfstmo_ashikhmin02(workingframe,
174
opts.operator_options.ashikhminoptions.simple,
175
opts.operator_options.ashikhminoptions.lct,
176
opts.operator_options.ashikhminoptions.eq2 ? 2 : 4);
179
//even durand seems to be not reentrant
181
result=pfstmo_durand02(workingframe,
182
opts.operator_options.durandoptions.spatial,
183
opts.operator_options.durandoptions.range,
184
opts.operator_options.durandoptions.base);
188
result=pfstmo_drago03(workingframe, opts.operator_options.dragooptions.bias);
191
result=pfstmo_pattanaik00(workingframe,
192
opts.operator_options.pattanaikoptions.local,
193
opts.operator_options.pattanaikoptions.multiplier,
194
opts.operator_options.pattanaikoptions.cone,
195
opts.operator_options.pattanaikoptions.rod,
196
opts.operator_options.pattanaikoptions.autolum);
199
result=pfstmo_reinhard02(workingframe,
200
opts.operator_options.reinhard02options.key,
201
opts.operator_options.reinhard02options.phi,
202
opts.operator_options.reinhard02options.range,
203
opts.operator_options.reinhard02options.lower,
204
opts.operator_options.reinhard02options.upper,
205
opts.operator_options.reinhard02options.scales);
208
result=pfstmo_reinhard05(workingframe,
209
opts.operator_options.reinhard05options.brightness,
210
opts.operator_options.reinhard05options.chromaticAdaptation,
211
opts.operator_options.reinhard05options.lightAdaptation);
213
} //switch (opts.tmoperator)
214
emit advanceCurrentProgress();
215
assert(result!=NULL);
217
const QImage& res=fromLDRPFStoQImage(result);
219
emit ImageComputed(res,&opts);
220
} //if (status==from_tm)
224
void TonemapperThread::terminateRequested() {
225
if (forciblyTerminated)
231
forciblyTerminated=true;
232
//HACK oddly enough for the other operators we cannot emit finished (it segfaults)
233
if (opts.tmoperator==mantiuk || opts.tmoperator==ashikhmin || opts.tmoperator==pattanaik )