00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <ReinhardGlobalOperator.h>
00022 #include <Exceptions.h>
00023 #include <math.h>
00024
00025 #define OPERATOR_NAME "Reinhard Global Operator"
00026
00027 Q_EXPORT_PLUGIN2(TT_ReinhardGlobalOperator, ReinhardGlobalOperatorFactory)
00028
00029
00038 ReinhardGlobalOperator::ReinhardGlobalOperator() :
00039 inputImage(NULL),
00040 outputImage(NULL),
00041 avLum(0.0),
00042 keyValue(0.18),
00043 burnOut(false),
00044 lumWhite2(1.0)
00045 {
00046
00047 }
00048
00049 void ReinhardGlobalOperator::setupUi(QWidget* parent)
00050 {
00051 ui.setupUi(parent);
00052
00053 connect(ui.keyValueSlider, SIGNAL(sliderReleased()), this, SLOT(toneMap()));
00054 connect(ui.keyValueSlider, SIGNAL(valueChanged(int)), this, SLOT(updateKeyValue(int)));
00055 connect(ui.burnOutGroupBox, SIGNAL(toggled(bool)), this, SLOT(updateBurnOut(bool)));
00056 connect(ui.whiteValueSpinBox, SIGNAL(editingFinished()), this, SLOT(updateLumWhite()));
00057 connect(ui.whiteValueOkButton, SIGNAL(clicked()), this, SLOT(toneMap()));
00058 }
00059
00063 QString ReinhardGlobalOperator::name() const
00064 {
00065 return tr(OPERATOR_NAME);
00066 }
00067
00068 const HdrImage* ReinhardGlobalOperator::getToneMappedImage() const
00069 {
00070 return outputImage;
00071 }
00072
00078 void ReinhardGlobalOperator::setImage(const HdrImage* image)
00079 {
00080 if (!image->hasY())
00081 throw Exception(tr("Image passed to %1 does not contains Y data. Cannot turn water into wine.").arg(name()));
00082
00083 QTime t;
00084 t.start();
00085
00086 inputImage = image;
00087 QSize size = inputImage->size();
00088 delete outputImage;
00089 outputImage = new HdrImage(*inputImage);
00090 const double delta = 0.0001;
00091
00092 float lumMax = 0.0;
00093 int Y = inputImage->YIndex();
00094 avLum = 0.0;
00095 for(int i=0; i<size.height(); ++i)
00096 for(int j=0; j<size.width(); ++j)
00097 {
00098 double lum = qMax(double((*inputImage)[i][j][Y]),0.0);
00099 avLum += log(delta + lum);
00100 lumMax = qMax(lumMax,float(lum));
00101 }
00102 avLum = exp(avLum/(double)(size.width()*size.height()));
00103
00104 ui.whiteValueSpinBox->setMaximum(qMin(lumMax,float(1e19)));
00105 ui.whiteValueSpinBox->setValue(qMin(lumMax,float(1e19)));
00106 ui.keyValueSlider->setValue(18);
00107 ui.burnOutGroupBox->setChecked(false);
00108
00109 msg = tr("Operator Init: %1 ms").arg(t.elapsed());
00110
00111 toneMap();
00112 }
00113
00119 void ReinhardGlobalOperator::toneMap()
00120 {
00121 if (inputImage)
00122 {
00123 QTime t;
00124 t.start();
00125
00126 QSize size = inputImage->size();
00127 int width = size.width();
00128 int height = size.height();
00129 int Y = inputImage->YIndex();
00130
00131 if(burnOut)
00132 for(int i=0; i<height; ++i)
00133 for(int j=0; j<width; ++j)
00134 {
00135 float lum = (*inputImage)[i][j][Y];
00136 lum = keyValue*lum/avLum;
00137 (*outputImage)[i][j][Y] = lum*(1.0+(lum/lumWhite2))/(1.0+lum);
00138
00139 }
00140 else
00141 for(int i=0; i<height; ++i)
00142 for(int j=0; j<width; ++j)
00143 {
00144 float lum = (*inputImage)[i][j][Y];
00145 lum = keyValue*lum/avLum;
00146 (*outputImage)[i][j][Y] = lum/(1.0+lum);
00147
00148 }
00149
00150 emit message(msg + tr(" Tone Mapping: %1 ms").arg(t.elapsed()));
00151
00152 emit imageUpdated();
00153 }
00154 }
00155
00161 void ReinhardGlobalOperator::updateKeyValue(int value)
00162 {
00163 keyValue = float(value)/100.0;
00164 ui.keyValue->setText(QString("%1").arg(keyValue, 0, 'f', 2));
00165 }
00166
00173 void ReinhardGlobalOperator::updateBurnOut(bool enabled)
00174 {
00175 burnOut = enabled;
00176 updateLumWhite();
00177 }
00178
00185 void ReinhardGlobalOperator::updateLumWhite()
00186 {
00187 float value = ui.whiteValueSpinBox->value();
00188 lumWhite2 = value*value;
00189 toneMap();
00190 }
00191
00192
00193
00204 ToneMappingOperatorPtr ReinhardGlobalOperatorFactory::createOperator() const
00205 {
00206 return ToneMappingOperatorPtr(new ReinhardGlobalOperator);
00207 }
00208
00212 QString ReinhardGlobalOperatorFactory::operatorName() const
00213 {
00214 return tr(OPERATOR_NAME);
00215 }