00001
00002
00003
00004 #include <stdio.h>
00005 #include <stdlib.h>
00006 #include <ImfInputFile.h>
00007 #include <ImfChannelList.h>
00008 #include <ImfFrameBuffer.h>
00009 #include <ImfRgbaFile.h>
00010 #include <half.h>
00011 #include <assert.h>
00012
00013 using namespace Imf;
00014 using namespace Imath;
00015
00016 static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha);
00017 static void WriteEXR(const char *name, float *pixels, int xRes, int yRes);
00018
00019 static void usage() {
00020 fprintf(stderr, "usage: exrdiff [-o difffile.exr] [-d diff tolerance %%] <foo.exr> <bar.exr>\n");
00021 exit(1);
00022 }
00023
00024 int main(int argc, char *argv[])
00025 {
00026 const char *outfile = NULL;
00027 const char *imageFile1 = NULL, *imageFile2 = NULL;
00028 float tol = 0.f;
00029
00030 if (argc == 1) usage();
00031 for (int i = 1; i < argc; ++i) {
00032 if (!strcmp(argv[i], "-o")) {
00033 if (!argv[i+1]) usage();
00034 outfile = argv[i+1];
00035 ++i;
00036 }
00037 else if (!strcmp(argv[i], "-d")) {
00038 if (!argv[i+1]) usage();
00039 tol = atof(argv[i+1]);
00040 ++i;
00041 }
00042 else if (!imageFile1)
00043 imageFile1 = argv[i];
00044 else if (!imageFile2)
00045 imageFile2 = argv[i];
00046 else
00047 usage();
00048 }
00049
00050 float *im1, *im2;
00051 int r1[2], r2[2];
00052 bool hasAlpha;
00053 if (!ReadEXR(imageFile1, im1, r1[0], r1[1], hasAlpha)) {
00054 printf("couldn't read image %s\n", imageFile1);
00055 return 1;
00056 }
00057 assert(hasAlpha);
00058 if (!ReadEXR(imageFile2, im2, r2[0], r2[1], hasAlpha)) {
00059 printf("couldn't read image %s\n", imageFile2);
00060 return 1;
00061 }
00062 assert(hasAlpha);
00063 if (r1[0] != r2[0] || r1[1] != r2[1]) {
00064 printf("%s/%s:\n\tresolutions don't match! (%d,%d) vs (%d,%d)\n",
00065 imageFile1, imageFile2, r1[0], r1[1], r2[0], r2[1]);
00066 return 1;
00067 }
00068
00069 float *diffImage = NULL;
00070 if (outfile != NULL)
00071 diffImage = new float[4 * r1[0] * r1[1]];
00072
00073 double sum1 = 0.f, sum2 = 0.f;
00074 int smallDiff = 0, bigDiff = 0;
00075 double mse = 0.f;
00076 for (int i = 0; i < 4*r1[0]*r1[1]; ++i) {
00077 if (diffImage) diffImage[i] = fabsf(im1[i] - im2[i]);
00078 if (im1[i] == 0 && im2[i] == 0)
00079 continue;
00080 if ((i % 4) == 0)
00081 continue;
00082
00083 sum1 += im1[i];
00084 sum2 += im2[i];
00085 float d = fabsf(im1[i] - im2[i]) / im1[i];
00086 mse += (im1[i] - im2[i]) * (im1[i] - im2[i]);
00087 if (d > .005) ++smallDiff;
00088 if (d > .05) ++bigDiff;
00089 }
00090 double avg1 = sum1 / (3. * r1[0] * r1[1]);
00091 double avg2 = sum2 / (3. * r1[0] * r1[1]);
00092 double avgDelta = (avg1-avg2) / std::min(avg1, avg2);
00093 if ((tol == 0. && (bigDiff > 0 || smallDiff > 0)) ||
00094 (tol > 0. && 100.f * fabs(avgDelta) > tol)) {
00095 printf("%s %s\n\tImages differ: %d big (%.2f%%), %d small (%.2f%%)\n"
00096 "\tavg 1 = %g, avg2 = %g (%f%% delta)\n"
00097 "\tMSE = %g\n",
00098 imageFile1, imageFile2,
00099 bigDiff, 100.f * float(bigDiff) / (3 * r1[0] * r1[1]),
00100 smallDiff, 100.f * float(smallDiff) / (3 * r1[0] * r1[1]),
00101 avg1, avg2, 100. * avgDelta,
00102 mse / (3. * r1[0] * r1[1]));
00103 if (outfile)
00104 WriteEXR(outfile, diffImage, r1[0], r1[1]);
00105 return 1;
00106 }
00107
00108 return 0;
00109 }
00110
00111 static bool ReadEXR(const char *name, float *&rgba, int &xRes, int &yRes, bool &hasAlpha)
00112 {
00113 try {
00114 InputFile file(name);
00115 Box2i dw = file.header().dataWindow();
00116 xRes = dw.max.x - dw.min.x + 1;
00117 yRes = dw.max.y - dw.min.y + 1;
00118
00119 half *hrgba = new half[4 * xRes * yRes];
00120
00121
00122 hasAlpha = true;
00123 int nChannels = 4;
00124
00125 hrgba -= 4 * (dw.min.x + dw.min.y * xRes);
00126 FrameBuffer frameBuffer;
00127 frameBuffer.insert("R", Slice(HALF, (char *)hrgba,
00128 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0));
00129 frameBuffer.insert("G", Slice(HALF, (char *)hrgba+sizeof(half),
00130 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0));
00131 frameBuffer.insert("B", Slice(HALF, (char *)hrgba+2*sizeof(half),
00132 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 0.0));
00133 frameBuffer.insert("A", Slice(HALF, (char *)hrgba+3*sizeof(half),
00134 4*sizeof(half), xRes * 4 * sizeof(half), 1, 1, 1.0));
00135
00136 file.setFrameBuffer(frameBuffer);
00137 file.readPixels(dw.min.y, dw.max.y);
00138
00139 hrgba += 4 * (dw.min.x + dw.min.y * xRes);
00140 rgba = new float[nChannels * xRes * yRes];
00141 for (int i = 0; i < nChannels * xRes * yRes; ++i)
00142 rgba[i] = hrgba[i];
00143 delete[] hrgba;
00144 } catch (const std::exception &e) {
00145 fprintf(stderr, "Unable to read image file \"%s\": %s", name, e.what());
00146 return NULL;
00147 }
00148
00149 return rgba;
00150 }
00151
00152 static void WriteEXR(const char *name, float *pixels, int xRes, int yRes) {
00153 Rgba *hrgba = new Rgba[xRes * yRes];
00154 for (int i = 0; i < xRes * yRes; ++i)
00155 hrgba[i] = Rgba(pixels[4*i], pixels[4*i+1], pixels[4*i+2], 1.);
00156
00157 Box2i displayWindow(V2i(0,0), V2i(xRes-1, yRes-1));
00158 Box2i dataWindow = displayWindow;
00159
00160 RgbaOutputFile file(name, displayWindow, dataWindow, WRITE_RGBA);
00161 file.setFrameBuffer(hrgba, 1, xRes);
00162 try {
00163 file.writePixels(yRes);
00164 }
00165 catch (const std::exception &e) {
00166 fprintf(stderr, "Unable to write image file \"%s\": %s", name,
00167 e.what());
00168 }
00169
00170 delete[] hrgba;
00171 }