2020#include < list>
2121#include < vector>
2222
23+ #include < cmath>
2324#include < math.h>
2425#include < stdlib.h>
2526#include < string.h>
@@ -91,6 +92,11 @@ usageMessage (ostream& stream, const char* program_name, bool verbose = false)
9192 " --csv print output in csv mode. If passes>1, show median timing\n "
9293 " default is JSON mode\n "
9394 " --passes num write and re-read file num times (default 1)\n "
95+ " --mse compute MSE per part, comparing original vs. re-read after compression.\n "
96+ " Parts must have uniform channel types. Half and float channels use\n "
97+ " signed log-space MSE (reported as \" log_mse\" ), skipping non-finite\n "
98+ " original samples; non-finite re-read samples produce NaN. Uint\n "
99+ " channels use linear MSE (reported as \" mse\" ).\n "
94100 " \n "
95101 " -h, --help print this message\n "
96102 " -v output progress messages\n "
@@ -121,6 +127,7 @@ struct options
121127 bool outputPartSizeOnDisk = false ;
122128 bool verbose = false ;
123129 bool csv = false ;
130+ bool computeMSE = false ;
124131 std::vector<PixelMode> pixelModes;
125132 std::vector<OPENEXR_IMF_NAMESPACE ::Compression> compressions;
126133
@@ -259,7 +266,8 @@ jsonStats (
259266 int timing,
260267 bool partSize,
261268 bool raw,
262- bool stats)
269+ bool stats,
270+ bool computeMSE)
263271{
264272
265273 static const char * lastFileName = nullptr ;
@@ -386,25 +394,37 @@ jsonStats (
386394 printPartStats (
387395 out, run.metrics .totalStats , " " , timing,false , raw, stats);
388396 }
389- if (timing && run.metrics .stats .size () > 1 )
397+ if (timing && run.metrics .stats .size () > 1 || computeMSE )
390398 {
391399 out << " ,\n " ;
392400 out << " \" parts\" :\n " ;
393401 out << " [\n " ;
394- // first print total statistics, then print all part data, unless there's only one part
395402 for (size_t part = 0 ; part < run.metrics .stats .size (); ++part)
396403 {
397404 out << " {\n " ;
398- out << " \" part\" : " << part << " ,\n " ;
399-
400- printPartStats (
401- out,
402- run.metrics .stats [part],
403- " " ,
404- timing,
405- partSize,
406- raw,
407- stats);
405+ out << " \" part\" : " << part;
406+ if (computeMSE)
407+ {
408+ out << " ,\n " ;
409+ const char * mseKey =
410+ run.metrics .stats [part].mseKind != MSE_LOG_INT
411+ ? " log_mse"
412+ : " mse" ;
413+ out << " \" " << mseKey
414+ << " \" : " << run.metrics .stats [part].mse ;
415+ }
416+ if (timing)
417+ {
418+ out << " ,\n " ;
419+ printPartStats (
420+ out,
421+ run.metrics .stats [part],
422+ " " ,
423+ timing,
424+ partSize,
425+ raw,
426+ stats);
427+ }
408428 out << " \n }" ;
409429 if (part < run.metrics .stats .size () - 1 ) { out << ' ,' ; }
410430 out << endl;
@@ -425,7 +445,7 @@ jsonStats (
425445}
426446
427447void
428- csvStats (ostream& out, list<runData>& data, bool outputSizeData, int timing)
448+ csvStats (ostream& out, list<runData>& data, bool outputSizeData, int timing, bool computeMSE )
429449{
430450 out << " file name" ;
431451 if (outputSizeData)
@@ -434,6 +454,7 @@ csvStats (ostream& out, list<runData>& data, bool outputSizeData, int timing)
434454 }
435455 out << " ,compression,pixel mode" ;
436456 if (outputSizeData) { out << " ,output size" ; }
457+ if (computeMSE) { out << " ,mse" ; }
437458 if (timing & options::TIME_READ )
438459 {
439460 out << " ,count read time" ;
@@ -470,6 +491,23 @@ csvStats (ostream& out, list<runData>& data, bool outputSizeData, int timing)
470491 out << ' ,' << compName << ' ,' << modeName (run.mode );
471492
472493 if (outputSizeData) { out << ' ,' << run.metrics .outputFileSize ; }
494+ if (computeMSE)
495+ out << ' ,' ;
496+ for (size_t p = 0 ; p < run.metrics .stats .size (); ++p)
497+ {
498+ if (p > 0 ) { out << ' |' ; }
499+ switch (run.metrics .stats [p].mseKind ) {
500+ case MSE_LOG_INT :
501+ out << " mse:" << run.metrics .stats [p].mse ;
502+ break ;
503+ case MSE_LOG_HALF :
504+ case MSE_LOG_FLOAT :
505+ out << " log_mse:" << run.metrics .stats [p].mse ;
506+ break ;
507+ default :
508+ out << " ---" ;
509+ }
510+ }
473511 if (timing & options::TIME_READ )
474512 {
475513 if (run.metrics .totalStats .sizeData .isDeep )
@@ -545,10 +583,13 @@ main (int argc, char** argv)
545583 opts.level ,
546584 opts.passes ,
547585 opts.outFile || opts.outputSizeData ||
548- opts.timing & options::TIME_WRITE ,
549- opts.timing & options::TIME_REREAD ,
586+ opts.timing & options::TIME_WRITE ||
587+ opts.computeMSE ,
588+ opts.timing & options::TIME_REREAD ||
589+ opts.computeMSE ,
550590 mode,
551- opts.verbose );
591+ opts.verbose ,
592+ opts.computeMSE );
552593 data.push_back (d);
553594 }
554595 }
@@ -571,12 +612,12 @@ main (int argc, char** argv)
571612
572613 if (opts.csv )
573614 {
574- csvStats (cout, data, opts.outputSizeData , opts.timing );
615+ csvStats (cout, data, opts.outputSizeData , opts.timing , opts. computeMSE );
575616 }
576617 else
577618 {
578619 jsonStats (
579- cout, data, opts.outputSizeData , opts.timing ,showPartSizeOnDisk, true , true );
620+ cout, data, opts.outputSizeData , opts.timing , showPartSizeOnDisk, true , true , opts. computeMSE );
580621 }
581622 }
582623
@@ -905,6 +946,10 @@ options::parse (int argc, char* argv[])
905946 }
906947
907948 outputPartSizeOnDisk = true ;
949+ }
950+ else if (!strcmp (argv[i], " --mse" ))
951+ {
952+ computeMSE = true ;
908953 i += 1 ;
909954 }
910955 else if (!strcmp (argv[i], " -i" ))
0 commit comments