00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "tonemap.h"
00026 #include "mipmap.h"
00027
00028 class HighContrastOp : public ToneMap {
00029 public:
00030 void Map(const float *y,
00031 int xRes, int yRes,
00032 float maxDisplayY, float *scale) const;
00033 private:
00034
00035 static float C(float y) {
00036 if (y < 0.0034f)
00037 return y / 0.0014f;
00038 else if (y < 1)
00039 return 2.4483f + log10f(y/0.0034f)/0.4027f;
00040 else if (y < 7.2444f)
00041 return 16.563f + (y - 1)/0.4027f;
00042 else
00043 return 32.0693f + log10f(y / 7.2444f)/0.0556f;
00044 }
00045 static float T(float y, float CYmin, float CYmax,
00046 float maxDisplayY) {
00047 return maxDisplayY * (C(y) - CYmin) / (CYmax - CYmin);
00048 }
00049 };
00050
00051 void HighContrastOp::Map(const float *y, int xRes, int yRes,
00052 float maxDisplayY, float *scale) const {
00053
00054 float minY = y[0], maxY = y[0];
00055 for (int i = 0; i < xRes * yRes; ++i) {
00056 minY = min(minY, y[i]);
00057 maxY = max(maxY, y[i]);
00058 }
00059 float CYmin = C(minY), CYmax = C(maxY);
00060
00061 MIPMap<float> pyramid(xRes, yRes,
00062 y, false,
00063 4.f, TEXTURE_CLAMP);
00064
00065 ProgressReporter progress(xRes*yRes, "Tone Mapping");
00066 for (int y = 0; y < yRes; ++y) {
00067 float yc = (float(y) + .5f) / float(yRes);
00068 for (int x = 0; x < xRes; ++x) {
00069 float xc = (float(x) + .5f) / float(xRes);
00070
00071 float dwidth = 1.f / float(max(xRes, yRes));
00072 float maxWidth = 32.f / float(max(xRes, yRes));
00073 float width = dwidth, prevWidth = 0.f;
00074 float Yadapt;
00075 float prevlc = 0.f;
00076 const float maxLocalContrast = .5f;
00077 while (1) {
00078
00079 float b0 = pyramid.Lookup(xc, yc, width,
00080 0.f, 0.f, width);
00081 float b1 = pyramid.Lookup(xc, yc, 2.f*width,
00082 0.f, 0.f, 2.f*width);
00083 float lc = fabsf((b0 - b1) / b0);
00084
00085 if (lc > maxLocalContrast) {
00086 float t = (maxLocalContrast - prevlc) / (lc - prevlc);
00087 float w = Lerp(t, prevWidth, width);
00088 Yadapt = pyramid.Lookup(xc, yc, w,
00089 0.f, 0.f, w);
00090 break;
00091 }
00092
00093 prevlc = lc;
00094 prevWidth = width;
00095 width += dwidth;
00096 if (width >= maxWidth) {
00097 Yadapt = pyramid.Lookup(xc, yc, maxWidth,
00098 0.f, 0.f, maxWidth);
00099 break;
00100 }
00101 }
00102
00103 scale[x + y*xRes] = T(Yadapt, CYmin, CYmax, maxDisplayY) /
00104 Yadapt;
00105 }
00106 progress.Update(xRes);
00107 }
00108 progress.Done();
00109 }
00110 extern "C" DLLEXPORT ToneMap *CreateToneMap(const ParamSet &ps) {
00111 return new HighContrastOp;
00112 }