00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "image.h"
00025 #include "error.h"
00026
00027 using namespace lux;
00028
00029
00030 ImageFilm::ImageFilm(int xres, int yres,
00031 Filter *filt, const float crop[4],
00032 const string &fn, bool premult, int wf, int wfs)
00033 : Film(xres, yres) {
00034 filter = filt;
00035 memcpy(cropWindow, crop, 4 * sizeof(float));
00036 filename = fn;
00037 premultiplyAlpha = premult;
00038 writeFrequency = sampleCount = wf;
00039 writeFrequencySeconds = wfs;
00040
00041 xPixelStart = Ceil2Int(xResolution * cropWindow[0]);
00042 xPixelCount =
00043 max(1, Ceil2Int(xResolution * cropWindow[1]) - xPixelStart);
00044 yPixelStart =
00045 Ceil2Int(yResolution * cropWindow[2]);
00046 yPixelCount =
00047 max(1, Ceil2Int(yResolution * cropWindow[3]) - yPixelStart);
00048
00049 pixels = new BlockedArray<Pixel>(xPixelCount, yPixelCount);
00050
00051 #define FILTER_TABLE_SIZE 16
00052 filterTable =
00053 new float[FILTER_TABLE_SIZE * FILTER_TABLE_SIZE];
00054 float *ftp = filterTable;
00055 for (int y = 0; y < FILTER_TABLE_SIZE; ++y) {
00056 float fy = ((float)y + .5f) * filter->yWidth /
00057 FILTER_TABLE_SIZE;
00058 for (int x = 0; x < FILTER_TABLE_SIZE; ++x) {
00059 float fx = ((float)x + .5f) * filter->xWidth /
00060 FILTER_TABLE_SIZE;
00061 *ftp++ = filter->Evaluate(fx, fy);
00062 }
00063 }
00064 }
00065 void ImageFilm::AddSample(float sX, float sY,
00066 const Spectrum &L, float alpha) {
00067
00068
00069 if (L.IsNaN()) {
00070
00071
00072
00073
00074 return;
00075 }
00076 else if (L.y() < -1e-5) {
00077
00078
00079
00080
00081 return;
00082 }
00083 else if (isinf(L.y())) {
00084
00085
00086 return;
00087 }
00088
00089
00090 float dImageX = sX - 0.5f;
00091 float dImageY = sY - 0.5f;
00092 int x0 = Ceil2Int (dImageX - filter->xWidth);
00093 int x1 = Floor2Int(dImageX + filter->xWidth);
00094 int y0 = Ceil2Int (dImageY - filter->yWidth);
00095 int y1 = Floor2Int(dImageY + filter->yWidth);
00096 x0 = max(x0, xPixelStart);
00097 x1 = min(x1, xPixelStart + xPixelCount - 1);
00098 y0 = max(y0, yPixelStart);
00099 y1 = min(y1, yPixelStart + yPixelCount - 1);
00100 if ((x1-x0) < 0 || (y1-y0) < 0) return;
00101
00102
00103 int *ifx = (int *)alloca((x1-x0+1) * sizeof(int));
00104 for (int x = x0; x <= x1; ++x) {
00105 float fx = fabsf((x - dImageX) *
00106 filter->invXWidth * FILTER_TABLE_SIZE);
00107 ifx[x-x0] = min(Floor2Int(fx), FILTER_TABLE_SIZE-1);
00108 }
00109 int *ify = (int *)alloca((y1-y0+1) * sizeof(int));
00110 for (int y = y0; y <= y1; ++y) {
00111 float fy = fabsf((y - dImageY) *
00112 filter->invYWidth * FILTER_TABLE_SIZE);
00113 ify[y-y0] = min(Floor2Int(fy), FILTER_TABLE_SIZE-1);
00114 }
00115 for (int y = y0; y <= y1; ++y)
00116 for (int x = x0; x <= x1; ++x) {
00117
00118 int offset = ify[y-y0]*FILTER_TABLE_SIZE + ifx[x-x0];
00119 float filterWt = filterTable[offset];
00120
00121 Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart);
00122 pixel.L.AddWeighted(filterWt, L);
00123 pixel.alpha += alpha * filterWt;
00124 pixel.weightSum += filterWt;
00125 }
00126
00127
00128 if (writeFrequency == -1) {
00129
00130 if( Floor2Int(Timer.elapsed()) > writeFrequencySeconds ) {
00131 Timer.restart();
00132 WriteImage();
00133 }
00134 } else {
00135
00136 if (--sampleCount == 0) {
00137 WriteImage();
00138 sampleCount = writeFrequency;
00139 }
00140 }
00141 }
00142 void ImageFilm::GetSampleExtent(int *xstart,
00143 int *xend, int *ystart, int *yend) const {
00144 *xstart = Floor2Int(xPixelStart + .5f - filter->xWidth);
00145 *xend = Floor2Int(xPixelStart + .5f + xPixelCount +
00146 filter->xWidth);
00147 *ystart = Floor2Int(yPixelStart + .5f - filter->yWidth);
00148 *yend = Floor2Int(yPixelStart + .5f + yPixelCount +
00149 filter->yWidth);
00150 }
00151 void ImageFilm::WriteImage() {
00152
00153 int nPix = xPixelCount * yPixelCount;
00154 float *rgb = new float[3*nPix], *alpha = new float[nPix];
00155 int offset = 0;
00156 for (int y = 0; y < yPixelCount; ++y) {
00157 for (int x = 0; x < xPixelCount; ++x) {
00158
00159 float xyz[3];
00160 (*pixels)(x, y).L.XYZ(xyz);
00161 const float
00162 rWeight[3] = { 3.240479f, -1.537150f, -0.498535f };
00163 const float
00164 gWeight[3] = {-0.969256f, 1.875991f, 0.041556f };
00165 const float
00166 bWeight[3] = { 0.055648f, -0.204043f, 1.057311f };
00167 rgb[3*offset ] = rWeight[0]*xyz[0] +
00168 rWeight[1]*xyz[1] +
00169 rWeight[2]*xyz[2];
00170 rgb[3*offset+1] = gWeight[0]*xyz[0] +
00171 gWeight[1]*xyz[1] +
00172 gWeight[2]*xyz[2];
00173 rgb[3*offset+2] = bWeight[0]*xyz[0] +
00174 bWeight[1]*xyz[1] +
00175 bWeight[2]*xyz[2];
00176 alpha[offset] = (*pixels)(x, y).alpha;
00177
00178 float weightSum = (*pixels)(x, y).weightSum;
00179 if (weightSum != 0.f) {
00180 float invWt = 1.f / weightSum;
00181 rgb[3*offset ] =
00182 Clamp(rgb[3*offset ] * invWt, 0.f, INFINITY);
00183 rgb[3*offset+1] =
00184 Clamp(rgb[3*offset+1] * invWt, 0.f, INFINITY);
00185 rgb[3*offset+2] =
00186 Clamp(rgb[3*offset+2] * invWt, 0.f, INFINITY);
00187
00188
00189 }
00190
00191 if (premultiplyAlpha) {
00192 rgb[3*offset ] *= alpha[offset];
00193 rgb[3*offset+1] *= alpha[offset];
00194 rgb[3*offset+2] *= alpha[offset];
00195 }
00196 ++offset;
00197 }
00198 }
00199
00200
00201 luxError(LUX_NOERROR, LUX_INFO, (std::string("Writing OpenEXR(RGBA) image to file ")+filename).c_str());
00202 WriteRGBAImage(filename, rgb, alpha,
00203 xPixelCount, yPixelCount,
00204 xResolution, yResolution,
00205 xPixelStart, yPixelStart);
00206
00207
00208 delete[] alpha;
00209 delete[] rgb;
00210 }
00211 Film* ImageFilm::CreateFilm(const ParamSet ¶ms, Filter *filter)
00212 {
00213 string filename = params.FindOneString("filename", "lux.exr");
00214 bool premultiplyAlpha = params.FindOneBool("premultiplyalpha", true);
00215
00216 int xres = params.FindOneInt("xresolution", 640);
00217 int yres = params.FindOneInt("yresolution", 480);
00218 float crop[4] = { 0, 1, 0, 1 };
00219 int cwi;
00220 const float *cr = params.FindFloat("cropwindow", &cwi);
00221 if (cr && cwi == 4) {
00222 crop[0] = Clamp(min(cr[0], cr[1]), 0., 1.);
00223 crop[1] = Clamp(max(cr[0], cr[1]), 0., 1.);
00224 crop[2] = Clamp(min(cr[2], cr[3]), 0., 1.);
00225 crop[3] = Clamp(max(cr[2], cr[3]), 0., 1.);
00226 }
00227 int writeFrequency = params.FindOneInt("writefrequency", -1);
00228 int writeFrequencySeconds = params.FindOneInt("writefrequencyseconds", 20);
00229 return new ImageFilm(xres, yres, filter, crop,
00230 filename, premultiplyAlpha, writeFrequency, writeFrequencySeconds);
00231 }