diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2015-06-28 15:34:21 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2015-06-28 15:34:21 +0000 |
commit | 620ecbee2ed1cb478e0289722d86dd72717f1cb8 (patch) | |
tree | 7a427b24d86f6789706acee21a52dca15b88806b /analyzer | |
parent | 8c2dab4922b514045cbae8e71ba93aaf8c0fff48 (diff) | |
download | netpbm-mirror-620ecbee2ed1cb478e0289722d86dd72717f1cb8.tar.gz netpbm-mirror-620ecbee2ed1cb478e0289722d86dd72717f1cb8.tar.xz netpbm-mirror-620ecbee2ed1cb478e0289722d86dd72717f1cb8.zip |
Release 10.71.00
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@2588 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'analyzer')
-rw-r--r-- | analyzer/pamfile.c | 2 | ||||
-rw-r--r-- | analyzer/pnmpsnr.c | 417 |
2 files changed, 315 insertions, 104 deletions
diff --git a/analyzer/pamfile.c b/analyzer/pamfile.c index bb55ecce..a7c3c5ac 100644 --- a/analyzer/pamfile.c +++ b/analyzer/pamfile.c @@ -59,6 +59,8 @@ parseCommandLine(int argc, const char ** argv, cmdlineP->inputFilespec = (const char **)&argv[1]; cmdlineP->inputFileCount = argc - 1; + + free(option_def); } diff --git a/analyzer/pnmpsnr.c b/analyzer/pnmpsnr.c index b04316cf..af74e8c8 100644 --- a/analyzer/pnmpsnr.c +++ b/analyzer/pnmpsnr.c @@ -8,13 +8,71 @@ * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> */ +#include <assert.h> #include <string.h> #include <stdio.h> #include <math.h> #include "pm_c_util.h" +#include "mallocvar.h" #include "nstring.h" #include "pam.h" +#include "shhopt.h" + + + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFile1Name; /* Name of first input file */ + const char * inputFile2Name; /* Name of second input file */ + unsigned int rgb; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to as as the argv array. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "rgb", OPT_FLAG, NULL, &cmdlineP->rgb, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others */ + + if (argc-1 < 2) + pm_error("Takes two arguments: names of the two files to compare"); + else { + cmdlineP->inputFile1Name = argv[1]; + cmdlineP->inputFile2Name = argv[2]; + + if (argc-1 > 2) + pm_error("Too many arguments (%u). The only arguments are " + "the names of the two files to compare", argc-1); + } + + free(option_def); +} + + static int udiff(unsigned int const subtrahend, @@ -68,79 +126,266 @@ validateInput(struct pam const pam1, } +enum ColorSpaceId { + COLORSPACE_GRAYSCALE, + COLORSPACE_YCBCR, + COLORSPACE_RGB +}; -static void -psnrColor(tuple const tuple1, - tuple const tuple2, - double * const ySqDiffP, - double * const cbSqDiffP, - double * const crSqDiffP) { +typedef struct { + + enum ColorSpaceId id; + + unsigned int componentCt; + + const char * componentName[3]; + /* Only first 'componentCt' elements are valid */ + +} ColorSpace; + + +struct SqDiff { +/*---------------------------------------------------------------------------- + The square-differences of the components of two pixels, for some + component set. +-----------------------------------------------------------------------------*/ + double sqDiff[3]; +}; + + + +static struct SqDiff +zeroSqDiff() { + + struct SqDiff retval; + unsigned int i; + + for (i = 0; i < 3; ++i) + retval.sqDiff[i] = 0.0; + + return retval; +} + + + +static struct SqDiff +sqDiffSum(ColorSpace const colorSpace, + struct SqDiff const addend, + struct SqDiff const adder) { + + struct SqDiff retval; + unsigned int i; + + for (i = 0; i < colorSpace.componentCt; ++i) + retval.sqDiff[i] = addend.sqDiff[i] + adder.sqDiff[i]; + + return retval; +} + + + +#define Y_INDEX 0 +#define CB_INDEX 1 +#define CR_INDEX 2 + +static ColorSpace +yCbCrColorSpace() { + + ColorSpace retval; + + retval.id = COLORSPACE_YCBCR; + + retval.componentCt = 3; + + retval.componentName[Y_INDEX] = "Y"; + retval.componentName[CR_INDEX] = "CR"; + retval.componentName[CB_INDEX] = "CB"; + + return retval; +} + + + +static struct SqDiff +sqDiffYCbCr(tuple const tuple1, + tuple const tuple2) { + + struct SqDiff retval; double y1, y2, cb1, cb2, cr1, cr2; pnm_YCbCrtuple(tuple1, &y1, &cb1, &cr1); pnm_YCbCrtuple(tuple2, &y2, &cb2, &cr2); - *ySqDiffP = square(y1 - y2); - *cbSqDiffP = square(cb1 - cb2); - *crSqDiffP = square(cr1 - cr2); + retval.sqDiff[Y_INDEX] = square(y1 - y2); + retval.sqDiff[CB_INDEX] = square(cb1 - cb2); + retval.sqDiff[CR_INDEX] = square(cr1 - cr2); + + return retval; +} + + + +#define R_INDEX 0 +#define G_INDEX 1 +#define B_INDEX 2 + + + +static ColorSpace +rgbColorSpace() { + + ColorSpace retval; + + retval.id = COLORSPACE_RGB; + + retval.componentCt = 3; + + retval.componentName[R_INDEX] = "Red"; + retval.componentName[G_INDEX] = "Green"; + retval.componentName[B_INDEX] = "Blue"; + + return retval; +} + + + +static struct SqDiff +sqDiffRgb(tuple const tuple1, + tuple const tuple2) { + + struct SqDiff retval; + + retval.sqDiff[R_INDEX] = + square((int)tuple1[PAM_RED_PLANE] - (int)tuple2[PAM_RED_PLANE]); + retval.sqDiff[G_INDEX] = + square((int)tuple1[PAM_GRN_PLANE] - (int)tuple2[PAM_GRN_PLANE]); + retval.sqDiff[B_INDEX] = + square((int)tuple1[PAM_BLU_PLANE] - (int)tuple2[PAM_BLU_PLANE]); + + return retval; +} + + + +static ColorSpace +grayscaleColorSpace() { + + ColorSpace retval; + + retval.id = COLORSPACE_GRAYSCALE; + + retval.componentCt = 1; + + retval.componentName[Y_INDEX] = "luminance"; + + return retval; +} + + + +static struct SqDiff +sqDiffGrayscale(tuple const tuple1, + tuple const tuple2) { + + struct SqDiff sqDiff; + + sqDiff.sqDiff[Y_INDEX] = square(udiff(tuple1[0], tuple2[0])); + + return sqDiff; +} + + + +static struct SqDiff +sumSqDiffFromRaster(struct pam * const pam1P, + struct pam * const pam2P, + ColorSpace const colorSpace) { + + struct SqDiff sumSqDiff; + tuple *tuplerow1, *tuplerow2; /* malloc'ed */ + unsigned int row; + + tuplerow1 = pnm_allocpamrow(pam1P); + tuplerow2 = pnm_allocpamrow(pam2P); + + sumSqDiff = zeroSqDiff(); + + for (row = 0; row < pam1P->height; ++row) { + unsigned int col; + + pnm_readpamrow(pam1P, tuplerow1); + pnm_readpamrow(pam2P, tuplerow2); + + assert(pam1P->width == pam2P->width); + + for (col = 0; col < pam1P->width; ++col) { + struct SqDiff sqDiff; + + switch (colorSpace.id) { + case COLORSPACE_GRAYSCALE: + sqDiff = sqDiffGrayscale(tuplerow1[col], tuplerow2[col]); + break; + case COLORSPACE_YCBCR: + sqDiff = sqDiffYCbCr(tuplerow1[col], tuplerow2[col]); + break; + case COLORSPACE_RGB: + sqDiff = sqDiffRgb(tuplerow1[col], tuplerow2[col]); + break; + } + sumSqDiff = sqDiffSum(colorSpace, sumSqDiff, sqDiff); + } + } + + pnm_freepamrow(tuplerow1); + pnm_freepamrow(tuplerow2); + + return sumSqDiff; } static void -reportPsnr(struct pam const pam, - double const ySumSqDiff, - double const crSumSqDiff, - double const cbSumSqDiff, - char const filespec1[], - char const filespec2[]) { - - bool const color = streq(pam.tuple_type, PAM_PPM_TUPLETYPE); - - /* Maximum possible sum square difference, i.e. the sum of the squares of - the sample differences between an entirely white image and entirely - black image of the given dimensions. - */ +reportPsnr(struct pam const pam, + struct SqDiff const sumSqDiff, + ColorSpace const colorSpace, + const char * const fileName1, + const char * const fileName2) { + double const maxSumSqDiff = square(pam.maxval) * pam.width * pam.height; + /* Maximum possible sum square difference, i.e. the sum of the squares + of the sample differences between an entirely white image and + entirely black image of the given dimensions. + */ + + unsigned int i; + /* The PSNR is the ratio of the maximum possible mean square difference - to the actual mean square difference. + to the actual mean square difference, which is also the ratio of + the maximum possible sum square difference to the actual sum square + difference. Note that in the important special case that the images are identical, the sum square differences are identically 0.0. No precision error; no rounding error. */ - if (color) { - pm_message("PSNR between %s and %s:", filespec1, filespec2); + pm_message("PSNR between '%s' and '%s':", fileName1, fileName2); - if (ySumSqDiff > 0) - pm_message("Y color component: %.2f dB", - 10 * log10(maxSumSqDiff/ySumSqDiff) ); - else - pm_message("Y color component does not differ."); + for (i = 0; i < colorSpace.componentCt; ++i) { + const char * label; - if (cbSumSqDiff > 0) - pm_message("Cb color component: %.2f dB", - 10 * log10(maxSumSqDiff/cbSumSqDiff) ); - else - pm_message("Cb color component does not differ."); + pm_asprintf(&label, "%s:", colorSpace.componentName[i]); - if (crSumSqDiff > 0) - pm_message("Cr color component: %.2f dB", - 10 * log10(maxSumSqDiff/crSumSqDiff) ); + if (sumSqDiff.sqDiff[i] > 0) + pm_message(" %-6.6s %.2f dB", + label, + 10 * log10(maxSumSqDiff/sumSqDiff.sqDiff[i])); else - pm_message("Cr color component does not differ."); - - } else { - if (ySumSqDiff > 0) { - pm_message("PSNR between %s and %s: %.2f dB", - filespec1, filespec2, - 10 * log10(maxSumSqDiff/ySumSqDiff) ); - } else - pm_message("Images %s and %s don't differ.", - filespec1, filespec2); + pm_message(" %-6.6s no difference", label); + + pm_strfree(label); } } @@ -148,78 +393,42 @@ reportPsnr(struct pam const pam, int main (int argc, const char **argv) { - const char * fileName1; /* name of first file to compare */ - const char * fileName2; /* name of second file to compare */ FILE * if1P; FILE * if2P; struct pam pam1, pam2; - bool color; - /* It's a color image */ - double ySumSqDiff, crSumSqDiff, cbSumSqDiff; - tuple *tuplerow1, *tuplerow2; /* malloc'ed */ - int row; + ColorSpace colorSpace; + struct CmdlineInfo cmdline; + pm_proginit(&argc, argv); - if (argc-1 < 2) - pm_error("Takes two arguments: names of the two files to compare"); - else { - fileName1 = argv[1]; - fileName2 = argv[2]; + parseCommandLine(argc, argv, &cmdline); - if (argc-1 > 2) - pm_error("Too many arguments (%u). The only arguments are " - "the names of the two files to compare", argc-1); - } - - if1P = pm_openr(fileName1); - if2P = pm_openr(fileName2); + if1P = pm_openr(cmdline.inputFile1Name); + if2P = pm_openr(cmdline.inputFile2Name); pnm_readpaminit(if1P, &pam1, PAM_STRUCT_SIZE(tuple_type)); pnm_readpaminit(if2P, &pam2, PAM_STRUCT_SIZE(tuple_type)); validateInput(pam1, pam2); - if (streq(pam1.tuple_type, PAM_PPM_TUPLETYPE)) - color = TRUE; - else - color = FALSE; + if (streq(pam1.tuple_type, PAM_PPM_TUPLETYPE)) { + if (cmdline.rgb) + colorSpace = rgbColorSpace(); + else + colorSpace = yCbCrColorSpace(); + } else + colorSpace = grayscaleColorSpace(); - tuplerow1 = pnm_allocpamrow(&pam1); - tuplerow2 = pnm_allocpamrow(&pam2); - - ySumSqDiff = 0.0; - cbSumSqDiff = 0.0; - crSumSqDiff = 0.0; + { + struct SqDiff const sumSqDiff = + sumSqDiffFromRaster(&pam1, &pam2, colorSpace); - for (row = 0; row < pam1.height; ++row) { - int col; - - pnm_readpamrow(&pam1, tuplerow1); - pnm_readpamrow(&pam2, tuplerow2); - - for (col = 0; col < pam1.width; ++col) { - if (color) { - double ySqDiff, cbSqDiff, crSqDiff; - psnrColor(tuplerow1[col], tuplerow2[col], - &ySqDiff, &cbSqDiff, &crSqDiff); - ySumSqDiff += ySqDiff; - cbSumSqDiff += cbSqDiff; - crSumSqDiff += crSqDiff; - - } else { - unsigned int const yDiffSq = - square(udiff(tuplerow1[col][0], tuplerow2[col][0])); - ySumSqDiff += yDiffSq; - } - } + reportPsnr(pam1, sumSqDiff, colorSpace, + cmdline.inputFile1Name, cmdline.inputFile2Name); } - - reportPsnr(pam1, ySumSqDiff, crSumSqDiff, cbSumSqDiff, - fileName1, fileName2); - - pnm_freepamrow(tuplerow1); - pnm_freepamrow(tuplerow2); + pm_close(if2P); + pm_close(if1P); return 0; } |