media/libyuv/util/psnr_main.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  *  Copyright 2013 The LibYuv Project Authors. All rights reserved.
     3  *
     4  *  Use of this source code is governed by a BSD-style license
     5  *  that can be found in the LICENSE file in the root of the source
     6  *  tree. An additional intellectual property rights grant can be found
     7  *  in the file PATENTS. All contributing project authors may
     8  *  be found in the AUTHORS file in the root of the source tree.
     9  */
    11 // Get PSNR or SSIM for video sequence. Assuming RAW 4:2:0 Y:Cb:Cr format
    12 // To build: g++ -O3 -o psnr psnr.cc ssim.cc psnr_main.cc
    13 // or VisualC: cl /Ox psnr.cc ssim.cc psnr_main.cc
    14 //
    15 // To enable OpenMP and SSE2
    16 // gcc: g++ -msse2 -O3 -fopenmp -o psnr psnr.cc ssim.cc psnr_main.cc
    17 // vc:  cl /arch:SSE2 /Ox /openmp psnr.cc ssim.cc psnr_main.cc
    18 //
    19 // Usage: psnr org_seq rec_seq -s width height [-skip skip_org skip_rec]
    21 #ifndef _CRT_SECURE_NO_WARNINGS
    22 #define _CRT_SECURE_NO_WARNINGS
    23 #endif
    25 #include <stddef.h>
    26 #include <stdio.h>
    27 #include <stdlib.h>
    28 #include <string.h>
    29 #ifdef _OPENMP
    30 #include <omp.h>
    31 #endif
    33 #include "./psnr.h"
    34 #include "./ssim.h"
    36 struct metric {
    37   double y, u, v, all;
    38   double min_y, min_u, min_v, min_all;
    39   double global_y, global_u, global_v, global_all;
    40   int min_frame;
    41 };
    43 // options
    44 bool verbose = false;
    45 bool quiet = false;
    46 bool show_name = false;
    47 bool do_swap_uv = false;
    48 bool do_psnr = false;
    49 bool do_ssim = false;
    50 bool do_mse = false;
    51 bool do_lssim = false;
    52 int image_width = 0, image_height = 0;
    53 int fileindex_org = 0;  // argv argument contains the source file name.
    54 int fileindex_rec = 0;  // argv argument contains the destination file name.
    55 int num_rec = 0;
    56 int num_skip_org = 0;
    57 int num_skip_rec = 0;
    58 int num_frames = 0;
    59 #ifdef _OPENMP
    60 int num_threads = 0;
    61 #endif
    63 // Parse PYUV format. ie name.1920x800_24Hz_P420.yuv
    64 bool ExtractResolutionFromFilename(const char* name,
    65                                    int* width_ptr,
    66                                    int* height_ptr) {
    67   // Isolate the .width_height. section of the filename by searching for a
    68   // dot or underscore followed by a digit.
    69   for (int i = 0; name[i]; ++i) {
    70     if ((name[i] == '.' || name[i] == '_') &&
    71         name[i + 1] >= '0' && name[i + 1] <= '9') {
    72       int n = sscanf(name + i + 1, "%dx%d", width_ptr, height_ptr);  // NOLINT
    73       if (2 == n) {
    74         return true;
    75       }
    76     }
    77   }
    78   return false;
    79 }
    81 // Scale Y channel from 16..240 to 0..255.
    82 // This can be useful when comparing codecs that are inconsistant about Y
    83 uint8 ScaleY(uint8 y) {
    84   int ny = (y - 16) * 256 / 224;
    85   if (ny < 0) ny = 0;
    86   if (ny > 255) ny = 255;
    87   return static_cast<uint8>(ny);
    88 }
    90 // MSE = Mean Square Error
    91 double GetMSE(double sse, double size) {
    92   return sse / size;
    93 }
    95 void PrintHelp(const char * program) {
    96   printf("%s [-options] org_seq rec_seq [rec_seq2.. etc]\n", program);
    97   printf("options:\n");
    98   printf(" -s <width> <height> .... specify YUV size, mandatory if none of the "
    99          "sequences have the\n");
   100   printf("                          resolution embedded in their filename (ie. "
   101          "name.1920x800_24Hz_P420.yuv)\n");
   102   printf(" -psnr .................. compute PSNR (default)\n");
   103   printf(" -ssim .................. compute SSIM\n");
   104   printf(" -mse ................... compute MSE\n");
   105   printf(" -swap .................. Swap U and V plane\n");
   106   printf(" -skip <org> <rec> ...... Number of frame to skip of org and rec\n");
   107   printf(" -frames <num> .......... Number of frames to compare\n");
   108 #ifdef _OPENMP
   109   printf(" -t <num> ............... Number of threads\n");
   110 #endif
   111   printf(" -n ..................... Show file name\n");
   112   printf(" -v ..................... verbose++\n");
   113   printf(" -q ..................... quiet\n");
   114   printf(" -h ..................... this help\n");
   115   exit(0);
   116 }
   118 void ParseOptions(int argc, const char* argv[]) {
   119   if (argc <= 1) PrintHelp(argv[0]);
   120   for (int c = 1; c < argc; ++c) {
   121     if (!strcmp(argv[c], "-v")) {
   122       verbose = true;
   123     } else if (!strcmp(argv[c], "-q")) {
   124       quiet = true;
   125     } else if (!strcmp(argv[c], "-n")) {
   126       show_name = true;
   127     } else if (!strcmp(argv[c], "-psnr")) {
   128       do_psnr = true;
   129     } else if (!strcmp(argv[c], "-mse")) {
   130       do_mse = true;
   131     } else if (!strcmp(argv[c], "-ssim")) {
   132       do_ssim = true;
   133     } else if (!strcmp(argv[c], "-lssim")) {
   134       do_ssim = true;
   135       do_lssim = true;
   136     } else if (!strcmp(argv[c], "-swap")) {
   137       do_swap_uv = true;
   138     } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
   139       PrintHelp(argv[0]);
   140     } else if (!strcmp(argv[c], "-s") && c + 2 < argc) {
   141       image_width = atoi(argv[++c]);    // NOLINT
   142       image_height = atoi(argv[++c]);   // NOLINT
   143     } else if (!strcmp(argv[c], "-skip") && c + 2 < argc) {
   144       num_skip_org = atoi(argv[++c]);   // NOLINT
   145       num_skip_rec = atoi(argv[++c]);   // NOLINT
   146     } else if (!strcmp(argv[c], "-frames") && c + 1 < argc) {
   147       num_frames = atoi(argv[++c]);     // NOLINT
   148 #ifdef _OPENMP
   149     } else if (!strcmp(argv[c], "-t") && c + 1 < argc) {
   150       num_threads = atoi(argv[++c]);    // NOLINT
   151 #endif
   152     } else if (argv[c][0] == '-') {
   153       fprintf(stderr, "Unknown option. %s\n", argv[c]);
   154     } else if (fileindex_org == 0) {
   155       fileindex_org = c;
   156     } else if (fileindex_rec == 0) {
   157       fileindex_rec = c;
   158       num_rec = 1;
   159     } else {
   160       ++num_rec;
   161     }
   162   }
   163   if (fileindex_org == 0 || fileindex_rec == 0) {
   164     fprintf(stderr, "Missing filenames\n");
   165     PrintHelp(argv[0]);
   166   }
   167   if (num_skip_org < 0 || num_skip_rec < 0) {
   168     fprintf(stderr, "Skipped frames incorrect\n");
   169     PrintHelp(argv[0]);
   170   }
   171   if (num_frames < 0) {
   172     fprintf(stderr, "Number of frames incorrect\n");
   173     PrintHelp(argv[0]);
   174   }
   175   if (image_width == 0 || image_height == 0) {
   176     int org_width, org_height;
   177     int rec_width, rec_height;
   178     bool org_res_avail = ExtractResolutionFromFilename(argv[fileindex_org],
   179                                                        &org_width,
   180                                                        &org_height);
   181     bool rec_res_avail = ExtractResolutionFromFilename(argv[fileindex_rec],
   182                                                        &rec_width,
   183                                                        &rec_height);
   184     if (org_res_avail) {
   185       if (rec_res_avail) {
   186         if ((org_width == rec_width) && (org_height == rec_height)) {
   187           image_width = org_width;
   188           image_height = org_height;
   189         } else {
   190           fprintf(stderr, "Sequences have different resolutions.\n");
   191           PrintHelp(argv[0]);
   192         }
   193       } else {
   194         image_width = org_width;
   195         image_height = org_height;
   196       }
   197     } else if (rec_res_avail) {
   198       image_width = rec_width;
   199       image_height = rec_height;
   200     } else {
   201       fprintf(stderr, "Missing dimensions.\n");
   202       PrintHelp(argv[0]);
   203     }
   204   }
   205 }
   207 bool UpdateMetrics(uint8* ch_org, uint8* ch_rec,
   208                    const int y_size, const int uv_size, const size_t total_size,
   209                    int number_of_frames,
   210                    metric* cur_distortion_psnr,
   211                    metric* distorted_frame, bool do_psnr) {
   212   const int uv_offset = (do_swap_uv ? uv_size : 0);
   213   const uint8* const u_org = ch_org + y_size + uv_offset;
   214   const uint8* const u_rec = ch_rec + y_size;
   215   const uint8* const v_org = ch_org + y_size + (uv_size - uv_offset);
   216   const uint8* const v_rec = ch_rec + y_size + uv_size;
   217   if (do_psnr) {
   218     double y_err = ComputeSumSquareError(ch_org, ch_rec, y_size);
   219     double u_err = ComputeSumSquareError(u_org, u_rec, uv_size);
   220     double v_err = ComputeSumSquareError(v_org, v_rec, uv_size);
   221     const double total_err = y_err + u_err + v_err;
   222     cur_distortion_psnr->global_y += y_err;
   223     cur_distortion_psnr->global_u += u_err;
   224     cur_distortion_psnr->global_v += v_err;
   225     cur_distortion_psnr->global_all += total_err;
   226     distorted_frame->y = ComputePSNR(y_err, static_cast<double>(y_size));
   227     distorted_frame->u = ComputePSNR(u_err, static_cast<double>(uv_size));
   228     distorted_frame->v = ComputePSNR(v_err, static_cast<double>(uv_size));
   229     distorted_frame->all = ComputePSNR(total_err,
   230                                        static_cast<double>(total_size));
   231   } else {
   232     distorted_frame->y = CalcSSIM(ch_org, ch_rec, image_width, image_height);
   233     distorted_frame->u = CalcSSIM(u_org, u_rec, image_width / 2,
   234                                  image_height / 2);
   235     distorted_frame->v = CalcSSIM(v_org, v_rec, image_width / 2,
   236                                  image_height / 2);
   237     distorted_frame->all =
   238       (distorted_frame->y + distorted_frame->u + distorted_frame->v)
   239         / total_size;
   240     distorted_frame->y /= y_size;
   241     distorted_frame->u /= uv_size;
   242     distorted_frame->v /= uv_size;
   244     if (do_lssim) {
   245       distorted_frame->all = CalcLSSIM(distorted_frame->all);
   246       distorted_frame->y = CalcLSSIM(distorted_frame->y);
   247       distorted_frame->u = CalcLSSIM(distorted_frame->u);
   248       distorted_frame->v = CalcLSSIM(distorted_frame->v);
   249     }
   250   }
   252   cur_distortion_psnr->y += distorted_frame->y;
   253   cur_distortion_psnr->u += distorted_frame->u;
   254   cur_distortion_psnr->v += distorted_frame->v;
   255   cur_distortion_psnr->all += distorted_frame->all;
   257   bool ismin = false;
   258   if (distorted_frame->y < cur_distortion_psnr->min_y)
   259     cur_distortion_psnr->min_y = distorted_frame->y;
   260   if (distorted_frame->u < cur_distortion_psnr->min_u)
   261     cur_distortion_psnr->min_u = distorted_frame->u;
   262   if (distorted_frame->v < cur_distortion_psnr->min_v)
   263     cur_distortion_psnr->min_v = distorted_frame->v;
   264   if (distorted_frame->all < cur_distortion_psnr->min_all) {
   265     cur_distortion_psnr->min_all = distorted_frame->all;
   266     cur_distortion_psnr->min_frame = number_of_frames;
   267     ismin = true;
   268   }
   269   return ismin;
   270 }
   272 int main(int argc, const char* argv[]) {
   273   ParseOptions(argc, argv);
   274   if (!do_psnr && !do_ssim) {
   275     do_psnr = true;
   276   }
   278 #ifdef _OPENMP
   279   if (num_threads) {
   280     omp_set_num_threads(num_threads);
   281   }
   282   if (verbose) {
   283     printf("OpenMP %d procs\n", omp_get_num_procs());
   284   }
   285 #endif
   286   // Open original file (first file argument)
   287   FILE* const file_org = fopen(argv[fileindex_org], "rb");
   288   if (file_org == NULL) {
   289     fprintf(stderr, "Cannot open %s\n", argv[fileindex_org]);
   290     exit(1);
   291   }
   293   // Open all files to compare to
   294   FILE** file_rec = new FILE* [num_rec];
   295   memset(file_rec, 0, num_rec * sizeof(FILE*)); // NOLINT
   296   for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   297     file_rec[cur_rec] = fopen(argv[fileindex_rec + cur_rec], "rb");
   298     if (file_rec[cur_rec] == NULL) {
   299       fprintf(stderr, "Cannot open %s\n", argv[fileindex_rec + cur_rec]);
   300       fclose(file_org);
   301       for (int i = 0; i < cur_rec; ++i) {
   302         fclose(file_rec[i]);
   303       }
   304       delete[] file_rec;
   305       exit(1);
   306     }
   307   }
   309   const int y_size = image_width * image_height;
   310   const int uv_size = ((image_width + 1) / 2) * ((image_height + 1) / 2);
   311   const size_t total_size = y_size + 2 * uv_size;    // NOLINT
   312 #if defined(_MSC_VER)
   313   _fseeki64(file_org,
   314             static_cast<__int64>(num_skip_org) *
   315             static_cast<__int64>(total_size), SEEK_SET);
   316 #else
   317   fseek(file_org, num_skip_org * total_size, SEEK_SET);
   318 #endif
   319   for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   320 #if defined(_MSC_VER)
   321     _fseeki64(file_rec[cur_rec],
   322               static_cast<__int64>(num_skip_rec) *
   323               static_cast<__int64>(total_size),
   324               SEEK_SET);
   325 #else
   326     fseek(file_rec[cur_rec], num_skip_rec * total_size, SEEK_SET);
   327 #endif
   328   }
   330   uint8* const ch_org = new uint8[total_size];
   331   uint8* const ch_rec = new uint8[total_size];
   332   if (ch_org == NULL || ch_rec == NULL) {
   333     fprintf(stderr, "No memory available\n");
   334     fclose(file_org);
   335     for (int i = 0; i < num_rec; ++i) {
   336       fclose(file_rec[i]);
   337     }
   338     delete[] ch_org;
   339     delete[] ch_rec;
   340     delete[] file_rec;
   341     exit(1);
   342   }
   344   metric* const distortion_psnr = new metric[num_rec];
   345   metric* const distortion_ssim = new metric[num_rec];
   346   for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   347     metric* cur_distortion_psnr = &distortion_psnr[cur_rec];
   348     cur_distortion_psnr->y = 0.0;
   349     cur_distortion_psnr->u = 0.0;
   350     cur_distortion_psnr->v = 0.0;
   351     cur_distortion_psnr->all = 0.0;
   352     cur_distortion_psnr->min_y = kMaxPSNR;
   353     cur_distortion_psnr->min_u = kMaxPSNR;
   354     cur_distortion_psnr->min_v = kMaxPSNR;
   355     cur_distortion_psnr->min_all = kMaxPSNR;
   356     cur_distortion_psnr->min_frame = 0;
   357     cur_distortion_psnr->global_y = 0.0;
   358     cur_distortion_psnr->global_u = 0.0;
   359     cur_distortion_psnr->global_v = 0.0;
   360     cur_distortion_psnr->global_all = 0.0;
   361     distortion_ssim[cur_rec] = cur_distortion_psnr[cur_rec];
   362   }
   364   if (verbose) {
   365     printf("Size: %dx%d\n", image_width, image_height);
   366   }
   368   if (!quiet) {
   369     printf("Frame");
   370     if (do_psnr) {
   371       printf("\t PSNR-Y \t PSNR-U \t PSNR-V \t PSNR-All \t Frame");
   372     }
   373     if (do_ssim) {
   374       printf("\t  SSIM-Y\t  SSIM-U\t  SSIM-V\t  SSIM-All\t Frame");
   375     }
   376     if (show_name) {
   377       printf("\tName\n");
   378     } else {
   379       printf("\n");
   380     }
   381   }
   383   int number_of_frames;
   384   for (number_of_frames = 0; ; ++number_of_frames) {
   385     if (num_frames && number_of_frames >= num_frames)
   386       break;
   388     size_t bytes_org = fread(ch_org, sizeof(uint8), total_size, file_org);
   389     if (bytes_org < total_size)
   390       break;
   392     for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   393       size_t bytes_rec = fread(ch_rec, sizeof(uint8),
   394                                total_size, file_rec[cur_rec]);
   395       if (bytes_rec < total_size)
   396         break;
   398       if (verbose) {
   399         printf("%5d", number_of_frames);
   400       }
   401       if (do_psnr) {
   402         metric distorted_frame;
   403         metric* cur_distortion_psnr = &distortion_psnr[cur_rec];
   404         bool ismin = UpdateMetrics(ch_org, ch_rec,
   405                                    y_size, uv_size, total_size,
   406                                    number_of_frames,
   407                                    cur_distortion_psnr,
   408                                    &distorted_frame, true);
   409         if (verbose) {
   410           printf("\t%10.6f", distorted_frame.y);
   411           printf("\t%10.6f", distorted_frame.u);
   412           printf("\t%10.6f", distorted_frame.v);
   413           printf("\t%10.6f", distorted_frame.all);
   414           printf("\t%5s", ismin ? "min" : "");
   415         }
   416       }
   417       if (do_ssim) {
   418         metric distorted_frame;
   419         metric* cur_distortion_ssim = &distortion_ssim[cur_rec];
   420         bool ismin = UpdateMetrics(ch_org, ch_rec,
   421                                    y_size, uv_size, total_size,
   422                                    number_of_frames,
   423                                    cur_distortion_ssim,
   424                                    &distorted_frame, false);
   425         if (verbose) {
   426           printf("\t%10.6f", distorted_frame.y);
   427           printf("\t%10.6f", distorted_frame.u);
   428           printf("\t%10.6f", distorted_frame.v);
   429           printf("\t%10.6f", distorted_frame.all);
   430           printf("\t%5s", ismin ? "min" : "");
   431         }
   432       }
   433       if (verbose) {
   434         if (show_name) {
   435           printf("\t%s", argv[fileindex_rec + cur_rec]);
   436         }
   437         printf("\n");
   438       }
   439     }
   440   }
   442   // Final PSNR computation.
   443   for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   444     metric* cur_distortion_psnr = &distortion_psnr[cur_rec];
   445     metric* cur_distortion_ssim = &distortion_ssim[cur_rec];
   446     if (number_of_frames > 0) {
   447       const double norm = 1. / static_cast<double>(number_of_frames);
   448       cur_distortion_psnr->y *= norm;
   449       cur_distortion_psnr->u *= norm;
   450       cur_distortion_psnr->v *= norm;
   451       cur_distortion_psnr->all *= norm;
   452       cur_distortion_ssim->y *= norm;
   453       cur_distortion_ssim->u *= norm;
   454       cur_distortion_ssim->v *= norm;
   455       cur_distortion_ssim->all *= norm;
   456     }
   458     if (do_psnr) {
   459       const double global_psnr_y = ComputePSNR(
   460           cur_distortion_psnr->global_y,
   461           static_cast<double>(y_size) * number_of_frames);
   462       const double global_psnr_u = ComputePSNR(
   463           cur_distortion_psnr->global_u,
   464           static_cast<double>(uv_size) * number_of_frames);
   465       const double global_psnr_v = ComputePSNR(
   466           cur_distortion_psnr->global_v,
   467           static_cast<double>(uv_size) * number_of_frames);
   468       const double global_psnr_all = ComputePSNR(
   469           cur_distortion_psnr->global_all,
   470           static_cast<double>(total_size) * number_of_frames);
   471       printf("Global:\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
   472           global_psnr_y,
   473           global_psnr_u,
   474           global_psnr_v,
   475           global_psnr_all,
   476           number_of_frames);
   477       if (show_name) {
   478         printf("\t%s", argv[fileindex_rec + cur_rec]);
   479       }
   480       printf("\n");
   481     }
   483     if (!quiet) {
   484       printf("Avg:");
   485       if (do_psnr) {
   486         printf("\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
   487              cur_distortion_psnr->y,
   488              cur_distortion_psnr->u,
   489              cur_distortion_psnr->v,
   490              cur_distortion_psnr->all,
   491              number_of_frames);
   492       }
   493       if (do_ssim) {
   494         printf("\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
   495              cur_distortion_ssim->y,
   496              cur_distortion_ssim->u,
   497              cur_distortion_ssim->v,
   498              cur_distortion_ssim->all,
   499              number_of_frames);
   500       }
   501       if (show_name) {
   502         printf("\t%s", argv[fileindex_rec + cur_rec]);
   503       }
   504       printf("\n");
   505     }
   506     if (!quiet) {
   507       printf("Min:");
   508       if (do_psnr) {
   509         printf("\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
   510             cur_distortion_psnr->min_y,
   511             cur_distortion_psnr->min_u,
   512             cur_distortion_psnr->min_v,
   513             cur_distortion_psnr->min_all,
   514             cur_distortion_psnr->min_frame);
   515       }
   516       if (do_ssim) {
   517         printf("\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
   518             cur_distortion_ssim->min_y,
   519             cur_distortion_ssim->min_u,
   520             cur_distortion_ssim->min_v,
   521             cur_distortion_ssim->min_all,
   522             cur_distortion_ssim->min_frame);
   523       }
   524       if (show_name) {
   525         printf("\t%s", argv[fileindex_rec + cur_rec]);
   526       }
   527       printf("\n");
   528     }
   530     if (do_mse) {
   531       double global_mse_y = GetMSE(cur_distortion_psnr->global_y,
   532         static_cast<double>(y_size) * number_of_frames);
   533       double global_mse_u = GetMSE(cur_distortion_psnr->global_u,
   534         static_cast<double>(uv_size) * number_of_frames);
   535       double global_mse_v = GetMSE(cur_distortion_psnr->global_v,
   536         static_cast<double>(uv_size) * number_of_frames);
   537       double global_mse_all = GetMSE(cur_distortion_psnr->global_all,
   538         static_cast<double>(total_size) * number_of_frames);
   539       printf("MSE:\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%5d",
   540           global_mse_y,
   541           global_mse_u,
   542           global_mse_v,
   543           global_mse_all,
   544           number_of_frames);
   545       if (show_name) {
   546         printf("\t%s", argv[fileindex_rec + cur_rec]);
   547       }
   548       printf("\n");
   549     }
   550   }
   551   fclose(file_org);
   552   for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   553     fclose(file_rec[cur_rec]);
   554   }
   555   delete[] distortion_psnr;
   556   delete[] distortion_ssim;
   557   delete[] ch_org;
   558   delete[] ch_rec;
   559   delete[] file_rec;
   560   return 0;
   561 }

mercurial