42 #define DISPLAY_SCALING     255 
   47 #define MSSIM_C1            (MSSIM_K1*MSSIM_K1) 
   48 #define MSSIM_C2            (MSSIM_K2*MSSIM_K2) 
   80     int Width, 
int Height, 
int NumChannels, 
float D);
 
   81 void BasicMetrics(
float *Max, 
float *Mse, 
const float *A, 
const float *B,
 
   82     int Width, 
int Height, 
int NumChannels, 
int Pad);
 
   84     int Width, 
int Height, 
int NumChannels, 
int Pad);
 
   90     puts(
"Image difference calculator, P. Getreuer 2010-2011\n");
 
   91     puts(
"Usage: imdiff [options] <exact file> <distorted file>\n" 
   94     puts(
"   -m <metric>  Metric to use for comparison, choices are");
 
   95     puts(
"        max     Maximum absolute difference, max_n |A_n - B_n|");
 
   96     puts(
"        mse     Mean squared error, 1/N sum |A_n - B_n|^2");
 
   97     puts(
"        rmse    Root mean squared error, (MSE)^1/2");
 
   98     puts(
"        psnr    Peak signal-to-noise ratio, -10 log10(MSE/255^2)");
 
   99     puts(
"        mssim   Mean structural similarity index\n");
 
  100     puts(
"   -s           Compute metric separately for each channel");
 
  101     puts(
"   -p <pad>     Remove a margin of <pad> pixels before comparison");
 
  102     puts(
"   -D <number>  D parameter for difference image\n");
 
  104     puts(
"   -q <number>   Quality for saving JPEG images (0 to 100)\n");
 
  106     puts(
"Alternatively, a difference image is generated by the syntax\n" 
  107     "   imdiff [-D <number>] <exact file> <distorted file> <output file>\n");
 
  108     puts(
"The difference image is computed as\n" 
  109            "   D_n = 255/D (A_n - B_n) + 255/2.\n" 
  110            "Values outside of the range [0,255] are saturated.\n");
 
  113         "   imdiff -mpsnr frog-exact.png frog-4x.png");
 
  115         "   imdiff -mpsnr frog-exact.bmp frog-4x.bmp");
 
  120 int main(
int argc, 
char *argv[])
 
  127     } A = {NULL, 0, 0}, B = {NULL, 0, 0};
 
  130     float Max, MaxC[3], Mse, MseC[3], Mssim;
 
  131     int Channel, Status = 1;
 
  138     if(!(A.Data = (
float *)
ReadImage(&A.Width, &A.Height, Param.
FileA,
 
  143     if(!(B.Data = (
float *)
ReadImage(&B.Width, &B.Height, Param.
FileB,
 
  147     if(A.Width != B.Width || A.Height != B.Height)
 
  149         ErrorMessage(
"Image sizes don't match, %dx%d vs. %dx%d.\n",
 
  150             A.Width, A.Height, B.Width, B.Height);
 
  153     else if(A.Width <= 2*Param.
Pad || A.Height <= 2*Param.
Pad)
 
  156             "Removal of %d-pixel padding removes entire %dx%d image.\n",
 
  157             Param.
Pad, A.Width, A.Height);
 
  174         for(Channel = 0; Channel < 3; Channel++)
 
  177                     A.Data + Channel*A.Width*A.Height,
 
  178                     B.Data + Channel*B.Width*B.Height,
 
  179                     A.Width, A.Height, 1, Param.
Pad);
 
  181             if(MaxC[Channel] > Max)
 
  184             Mse += MseC[Channel];
 
  195                     printf(
"Peak signal-to-noise ratio:   %.4f\n", -10*log10(Mse));
 
  199                     printf(
"Maximum absolute difference:  %g %g %g\n",
 
  202                     printf(
"Peak signal-to-noise ratio:   %.4f %.4f %.4f\n",
 
  203                         -10*log10(MseC[0]), -10*log10(MseC[1]), -10*log10(MseC[2]));
 
  206                 if(A.Width <= 2*(5 + Param.
Pad)
 
  207                     || A.Height <= 2*(5 + Param.
Pad))
 
  208                     printf(
"Image size is too small to compute MSSIM.\n");
 
  213                             A.Width, A.Height, 3, Param.
Pad);
 
  216                         printf(
"Mean structural similarity:   %.4f\n", Mssim);
 
  230                     printf(
"%.4f %.4f %.4f\n",
 
  239                     printf(
"%.4f %.4f %.4f\n",
 
  246                     printf(
"%.4f\n", -10*log10(Mse));
 
  248                 printf(
"%.4f %.4f %.4f\n",
 
  249                     -10*log10(MseC[0]), -10*log10(MseC[1]), -10*log10(MseC[2]));
 
  252                 if(A.Width <= 2*(5 + Param.
Pad)
 
  253                     || A.Height <= 2*(5 + Param.
Pad))
 
  254                     printf(
"Image size is too small to compute MSSIM.\n");
 
  258                             A.Width, A.Height, 3, Param.
Pad);
 
  263                         printf(
"%.4f\n", Mssim);
 
  279     int Width, 
int Height, 
int NumChannels, 
float D)
 
  281     const int NumEl = NumChannels*Width*Height;
 
  286     for(n = 0; n < NumEl; n++)
 
  287         A[n] = (A[n] - B[n])/D + (float)0.5;
 
  292 void BasicMetrics(
float *Max, 
float *Mse, 
const float *A, 
const float *B,
 
  293     int Width, 
int Height, 
int NumChannels, 
int Pad)
 
  295     float Diff, CurMax = 0;
 
  297     int x, y, Channel, n;
 
  300     for(Channel = 0; Channel < NumChannels; Channel++)
 
  301         for(y = Pad; y < Height - Pad; y++)
 
  302             for(x = Pad; x < Width - Pad; x++)
 
  304                 n = x + Width*(y + Height*Channel);
 
  305                 Diff = (float)fabs(A[n] - B[n]);
 
  310                 AccumMse += Diff*Diff;
 
  314     *Mse = (float)(AccumMse / (NumChannels*(Width - 2*Pad)*(Height - 2*Pad)));
 
  320     int Width, 
int Height, 
int NumChannels, 
int Pad)
 
  328     const int NumPixels = Width*Height;
 
  329     const int NumEl = NumChannels*NumPixels;
 
  330     float *Buffer = NULL, *MuA = NULL, *MuB = NULL,
 
  331         *MuAA = NULL, *MuBB = NULL, *MuAB = NULL;
 
  332     double MuASqr, MuBSqr, MuAMuB,
 
  333         SigmaASqr, SigmaBSqr, SigmaAB, Mssim = -1;
 
  338         || !(Buffer = (
float *)
Malloc(
sizeof(
float)*NumPixels))
 
  339         || !(MuA = (
float *)
Malloc(
sizeof(
float)*NumEl))
 
  340         || !(MuB = (
float *)
Malloc(
sizeof(
float)*NumEl))
 
  341         || !(MuAA = (
float *)
Malloc(
sizeof(
float)*NumEl))
 
  342         || !(MuBB = (
float *)
Malloc(
sizeof(
float)*NumEl))
 
  343         || !(MuAB = (
float *)
Malloc(
sizeof(
float)*NumEl)))
 
  347         Boundary, Width, Height, NumChannels);
 
  349         Boundary, Width, Height, NumChannels);
 
  351     for(n = 0; n < NumEl; n++)
 
  359         Boundary, Width, Height, NumChannels);
 
  361         Boundary, Width, Height, NumChannels);
 
  363         Boundary, Width, Height, NumChannels);
 
  368     for(c = 0; c < NumChannels; c++)
 
  369         for(y = Pad; y < Height - Pad; y++)
 
  370             for(x = Pad; x < Width - Pad; x++)
 
  372                 n = x + Width*(y + Height*c);
 
  373                 MuASqr = MuA[n]*MuA[n];
 
  374                 MuBSqr = MuB[n]*MuB[n];
 
  375                 MuAMuB = MuA[n]*MuB[n];
 
  376                 SigmaASqr = MuAA[n] - MuASqr;
 
  377                 SigmaBSqr = MuBB[n] - MuBSqr;
 
  378                 SigmaAB = MuAB[n] - MuAMuB;
 
  382                         *(SigmaASqr + SigmaBSqr + 
MSSIM_C2));
 
  385     Mssim /= NumChannels*(Width - 2*Pad)*(Height - 2*Pad);
 
  424     for(i = 1; i < argc;)
 
  426         if(argv[i] && argv[i][0] == 
'-')
 
  428             if((OptionChar = argv[i][1]) == 0)
 
  435                 OptionString = &argv[i][2];
 
  437                 OptionString = argv[i];
 
  447                 Param->
Pad = atoi(OptionString);
 
  460                 Param->
D = (float)atof(OptionString);
 
  469                 if(!strcmp(OptionString, 
"max"))
 
  471                 else if(!strcmp(OptionString, 
"mse"))
 
  473                 else if(!strcmp(OptionString, 
"rmse"))
 
  475                 else if(!strcmp(OptionString, 
"psnr"))
 
  477                 else if(!strcmp(OptionString, 
"mssim"))
 
  489                     ErrorMessage(
"JPEG quality must be between 0 and 100.\n");
 
  498                 if(isprint(OptionChar))
 
  511                 Param->
FileA = argv[i];
 
  512             else if(!Param->
FileB)
 
  513                 Param->
FileB = argv[i];