summaryrefslogtreecommitdiff
path: root/gs/jasper/src/appl/imgcmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/jasper/src/appl/imgcmp.c')
-rw-r--r--gs/jasper/src/appl/imgcmp.c577
1 files changed, 577 insertions, 0 deletions
diff --git a/gs/jasper/src/appl/imgcmp.c b/gs/jasper/src/appl/imgcmp.c
new file mode 100644
index 000000000..dc3b58714
--- /dev/null
+++ b/gs/jasper/src/appl/imgcmp.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (c) 2001-2003 Michael David Adams.
+ * All rights reserved.
+ */
+
+/* __START_OF_JASPER_LICENSE__
+ *
+ * JasPer License Version 2.0
+ *
+ * Copyright (c) 1999-2000 Image Power, Inc.
+ * Copyright (c) 1999-2000 The University of British Columbia
+ * Copyright (c) 2001-2003 Michael David Adams
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person (the
+ * "User") obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * 1. The above copyright notices and this permission notice (which
+ * includes the disclaimer below) shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * 2. The name of a copyright holder shall not be used to endorse or
+ * promote products derived from the Software without specific prior
+ * written permission.
+ *
+ * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
+ * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+ * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
+ * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE
+ * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
+ * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
+ * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
+ * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
+ * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS
+ * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
+ * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE
+ * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
+ * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
+ * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
+ * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
+ * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
+ * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
+ * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
+ * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
+ *
+ * __END_OF_JASPER_LICENSE__
+ */
+
+/*
+ * Image Comparison Program
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+#include <assert.h>
+
+#include <jasper/jasper.h>
+
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+typedef enum {
+ OPT_HELP,
+ OPT_VERSION,
+ OPT_VERBOSE,
+ OPT_ORIG,
+ OPT_RECON,
+ OPT_METRIC,
+ OPT_MAXONLY,
+ OPT_MINONLY,
+ OPT_DIFFIMAGE
+} optid_t;
+
+typedef enum {
+ metricid_none = 0,
+ metricid_equal,
+ metricid_psnr,
+ metricid_mse,
+ metricid_rmse,
+ metricid_pae,
+ metricid_mae
+} metricid_t;
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+double getdistortion(jas_matrix_t *orig, jas_matrix_t *recon, int depth, int metric);
+double pae(jas_matrix_t *x, jas_matrix_t *y);
+double msen(jas_matrix_t *x, jas_matrix_t *y, int n);
+double psnr(jas_matrix_t *x, jas_matrix_t *y, int depth);
+jas_image_t *makediffimage(jas_matrix_t *origdata, jas_matrix_t *recondata);
+void usage(void);
+void cmdinfo(void);
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+static jas_taginfo_t metrictab[] = {
+ {metricid_mse, "mse"},
+ {metricid_pae, "pae"},
+ {metricid_rmse, "rmse"},
+ {metricid_psnr, "psnr"},
+ {metricid_mae, "mae"},
+ {metricid_equal, "equal"},
+ {-1, 0}
+};
+
+static jas_opt_t opts[] = {
+ {OPT_HELP, "help", 0},
+ {OPT_VERSION, "version", 0},
+ {OPT_VERBOSE, "verbose", 0},
+ {OPT_ORIG, "f", JAS_OPT_HASARG},
+ {OPT_RECON, "F", JAS_OPT_HASARG},
+ {OPT_METRIC, "m", JAS_OPT_HASARG},
+ {OPT_MAXONLY, "max", 0},
+ {OPT_MINONLY, "min", 0},
+ {OPT_DIFFIMAGE, "d", JAS_OPT_HASARG},
+ {-1, 0, 0}
+};
+
+static char *cmdname = 0;
+
+/******************************************************************************\
+* Main program.
+\******************************************************************************/
+
+int main(int argc, char **argv)
+{
+ char *origpath;
+ char *reconpath;
+ int verbose;
+ char *metricname;
+ int metric;
+
+ int id;
+ jas_image_t *origimage;
+ jas_image_t *reconimage;
+ jas_matrix_t *origdata;
+ jas_matrix_t *recondata;
+ jas_image_t *diffimage;
+ jas_stream_t *diffstream;
+ int width;
+ int height;
+ int depth;
+ int numcomps;
+ double d;
+ double maxdist;
+ double mindist;
+ int compno;
+ jas_stream_t *origstream;
+ jas_stream_t *reconstream;
+ char *diffpath;
+ int maxonly;
+ int minonly;
+ int fmtid;
+
+ verbose = 0;
+ origpath = 0;
+ reconpath = 0;
+ metricname = 0;
+ metric = metricid_none;
+ diffpath = 0;
+ maxonly = 0;
+ minonly = 0;
+
+ if (jas_init()) {
+ abort();
+ }
+
+ cmdname = argv[0];
+
+ /* Parse the command line options. */
+ while ((id = jas_getopt(argc, argv, opts)) >= 0) {
+ switch (id) {
+ case OPT_MAXONLY:
+ maxonly = 1;
+ break;
+ case OPT_MINONLY:
+ minonly = 1;
+ break;
+ case OPT_METRIC:
+ metricname = jas_optarg;
+ break;
+ case OPT_ORIG:
+ origpath = jas_optarg;
+ break;
+ case OPT_RECON:
+ reconpath = jas_optarg;
+ break;
+ case OPT_VERBOSE:
+ verbose = 1;
+ break;
+ case OPT_DIFFIMAGE:
+ diffpath = jas_optarg;
+ break;
+ case OPT_VERSION:
+ printf("%s\n", JAS_VERSION);
+ exit(EXIT_SUCCESS);
+ break;
+ case OPT_HELP:
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (verbose) {
+ cmdinfo();
+ }
+
+ /* Ensure that files are given for both the original and reconstructed
+ images. */
+ if (!origpath || !reconpath) {
+ usage();
+ }
+
+ /* If a metric was specified, process it. */
+ if (metricname) {
+ if ((metric = (jas_taginfo_nonull(jas_taginfos_lookup(metrictab,
+ metricname))->id)) < 0) {
+ usage();
+ }
+ }
+
+ /* Open the original image file. */
+ if (!(origstream = jas_stream_fopen(origpath, "rb"))) {
+ jas_eprintf("cannot open %s\n", origpath);
+ return EXIT_FAILURE;
+ }
+
+ /* Open the reconstructed image file. */
+ if (!(reconstream = jas_stream_fopen(reconpath, "rb"))) {
+ jas_eprintf("cannot open %s\n", reconpath);
+ return EXIT_FAILURE;
+ }
+
+ /* Decode the original image. */
+ if (!(origimage = jas_image_decode(origstream, -1, 0))) {
+ jas_eprintf("cannot load original image\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Decoder the reconstructed image. */
+ if (!(reconimage = jas_image_decode(reconstream, -1, 0))) {
+ jas_eprintf("cannot load reconstructed image\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Close the original image file. */
+ jas_stream_close(origstream);
+
+ /* Close the reconstructed image file. */
+ jas_stream_close(reconstream);
+
+ /* Ensure that both images have the same number of components. */
+ numcomps = jas_image_numcmpts(origimage);
+ if (jas_image_numcmpts(reconimage) != numcomps) {
+ jas_eprintf("number of components differ\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Compute the difference for each component. */
+ maxdist = 0;
+ mindist = FLT_MAX;
+ for (compno = 0; compno < numcomps; ++compno) {
+ width = jas_image_cmptwidth(origimage, compno);
+ height = jas_image_cmptheight(origimage, compno);
+ depth = jas_image_cmptprec(origimage, compno);
+ if (jas_image_cmptwidth(reconimage, compno) != width ||
+ jas_image_cmptheight(reconimage, compno) != height) {
+ jas_eprintf("image dimensions differ\n");
+ return EXIT_FAILURE;
+ }
+ if (jas_image_cmptprec(reconimage, compno) != depth) {
+ jas_eprintf("precisions differ\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!(origdata = jas_matrix_create(height, width))) {
+ jas_eprintf("internal error\n");
+ return EXIT_FAILURE;
+ }
+ if (!(recondata = jas_matrix_create(height, width))) {
+ jas_eprintf("internal error\n");
+ return EXIT_FAILURE;
+ }
+ if (jas_image_readcmpt(origimage, compno, 0, 0, width, height,
+ origdata)) {
+ jas_eprintf("cannot read component data\n");
+ return EXIT_FAILURE;
+ }
+ if (jas_image_readcmpt(reconimage, compno, 0, 0, width, height,
+ recondata)) {
+ jas_eprintf("cannot read component data\n");
+ return EXIT_FAILURE;
+ }
+
+ if (diffpath) {
+ if (!(diffstream = jas_stream_fopen(diffpath, "rwb"))) {
+ jas_eprintf("cannot open diff stream\n");
+ return EXIT_FAILURE;
+ }
+ if (!(diffimage = makediffimage(origdata, recondata))) {
+ jas_eprintf("cannot make diff image\n");
+ return EXIT_FAILURE;
+ }
+ fmtid = jas_image_strtofmt("pnm");
+ if (jas_image_encode(diffimage, diffstream, fmtid, 0)) {
+ jas_eprintf("cannot save\n");
+ return EXIT_FAILURE;
+ }
+ jas_stream_close(diffstream);
+ jas_image_destroy(diffimage);
+ }
+
+ if (metric != metricid_none) {
+ d = getdistortion(origdata, recondata, depth, metric);
+ if (d > maxdist) {
+ maxdist = d;
+ }
+ if (d < mindist) {
+ mindist = d;
+ }
+ if (!maxonly && !minonly) {
+ if (metric == metricid_pae || metric == metricid_equal) {
+ printf("%ld\n", (long) ceil(d));
+ } else {
+ printf("%f\n", d);
+ }
+ }
+ }
+ jas_matrix_destroy(origdata);
+ jas_matrix_destroy(recondata);
+ }
+
+ if (metric != metricid_none && (maxonly || minonly)) {
+ if (maxonly) {
+ d = maxdist;
+ } else if (minonly) {
+ d = mindist;
+ } else {
+ abort();
+ }
+
+ if (metric == metricid_pae || metric == metricid_equal) {
+ jas_eprintf("%ld\n", (long) ceil(d));
+ } else {
+ jas_eprintf("%f\n", d);
+ }
+ }
+
+ jas_image_destroy(origimage);
+ jas_image_destroy(reconimage);
+ jas_image_clearfmts();
+
+ return EXIT_SUCCESS;
+}
+
+/******************************************************************************\
+* Distortion metric computation functions.
+\******************************************************************************/
+
+double getdistortion(jas_matrix_t *orig, jas_matrix_t *recon, int depth, int metric)
+{
+ double d;
+
+ switch (metric) {
+ case metricid_psnr:
+ default:
+ d = psnr(orig, recon, depth);
+ break;
+ case metricid_mae:
+ d = msen(orig, recon, 1);
+ break;
+ case metricid_mse:
+ d = msen(orig, recon, 2);
+ break;
+ case metricid_rmse:
+ d = sqrt(msen(orig, recon, 2));
+ break;
+ case metricid_pae:
+ d = pae(orig, recon);
+ break;
+ case metricid_equal:
+ d = (pae(orig, recon) == 0) ? 0 : 1;
+ break;
+ }
+ return d;
+}
+
+/* Compute peak absolute error. */
+
+double pae(jas_matrix_t *x, jas_matrix_t *y)
+{
+ double s;
+ double d;
+ int i;
+ int j;
+
+ s = 0.0;
+ for (i = 0; i < jas_matrix_numrows(x); i++) {
+ for (j = 0; j < jas_matrix_numcols(x); j++) {
+ d = abs(jas_matrix_get(y, i, j) - jas_matrix_get(x, i, j));
+ if (d > s) {
+ s = d;
+ }
+ }
+ }
+
+ return s;
+}
+
+/* Compute either mean-squared error or mean-absolute error. */
+
+double msen(jas_matrix_t *x, jas_matrix_t *y, int n)
+{
+ double s;
+ double d;
+ int i;
+ int j;
+
+ s = 0.0;
+ for (i = 0; i < jas_matrix_numrows(x); i++) {
+ for (j = 0; j < jas_matrix_numcols(x); j++) {
+ d = jas_matrix_get(y, i, j) - jas_matrix_get(x, i, j);
+ if (n == 1) {
+ s += fabs(d);
+ } else if (n == 2) {
+ s += d * d;
+ } else {
+ abort();
+ }
+ }
+ }
+
+ return s / ((double) jas_matrix_numrows(x) * jas_matrix_numcols(x));
+}
+
+/* Compute peak signal-to-noise ratio. */
+
+double psnr(jas_matrix_t *x, jas_matrix_t *y, int depth)
+{
+ double m;
+ double p;
+ m = msen(x, y, 2);
+ p = ((1 << depth) - 1);
+ return 20.0 * log10(p / sqrt(m));
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+jas_image_t *makediffimage(jas_matrix_t *origdata, jas_matrix_t *recondata)
+{
+ jas_image_t *diffimage;
+ jas_matrix_t *diffdata[3];
+ int width;
+ int height;
+ int i;
+ int j;
+ int k;
+ jas_image_cmptparm_t compparms[3];
+ jas_seqent_t a;
+ jas_seqent_t b;
+
+ width = jas_matrix_numcols(origdata);
+ height = jas_matrix_numrows(origdata);
+
+ for (i = 0; i < 3; ++i) {
+ compparms[i].tlx = 0;
+ compparms[i].tly = 0;
+ compparms[i].hstep = 1;
+ compparms[i].vstep = 1;
+ compparms[i].width = width;
+ compparms[i].height = height;
+ compparms[i].prec = 8;
+ compparms[i].sgnd = jas_false;
+ }
+ if (!(diffimage = jas_image_create(3, compparms, JAS_CLRSPC_SRGB))) {
+ abort();
+ }
+
+ for (i = 0; i < 3; ++i) {
+ if (!(diffdata[i] = jas_matrix_create(height, width))) {
+ jas_eprintf("internal error\n");
+ return 0;
+ }
+ }
+
+ for (j = 0; j < height; ++j) {
+ for (k = 0; k < width; ++k) {
+ a = jas_matrix_get(origdata, j, k);
+ b = jas_matrix_get(recondata, j, k);
+ if (a > b) {
+ jas_matrix_set(diffdata[0], j, k, 255);
+ jas_matrix_set(diffdata[1], j, k, 0);
+ jas_matrix_set(diffdata[2], j, k, 0);
+ } else if (a < b) {
+ jas_matrix_set(diffdata[0], j, k, 0);
+ jas_matrix_set(diffdata[1], j, k, 255);
+ jas_matrix_set(diffdata[2], j, k, 0);
+ } else {
+ jas_matrix_set(diffdata[0], j, k, a);
+ jas_matrix_set(diffdata[1], j, k, a);
+ jas_matrix_set(diffdata[2], j, k, a);
+ }
+ }
+ }
+
+ for (i = 0; i < 3; ++i) {
+ if (jas_image_writecmpt(diffimage, i, 0, 0, width, height, diffdata[i])) {
+ return 0;
+ }
+ }
+
+ return diffimage;
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+void cmdinfo()
+{
+ jas_eprintf("Image Comparison Utility (Version %s).\n",
+ JAS_VERSION);
+ jas_eprintf(
+ "Copyright (c) 2001 Michael David Adams.\n"
+ "All rights reserved.\n"
+ );
+}
+
+void usage()
+{
+ cmdinfo();
+ jas_eprintf("usage:\n");
+ jas_eprintf("%s ", cmdname);
+ jas_eprintf(
+ "-f reference_image_file -F other_image_file [-m metric]\n"
+ );
+ jas_eprintf(
+ "The metric argument may assume one of the following values:\n"
+ " psnr .... peak signal to noise ratio\n"
+ " mse ..... mean squared error\n"
+ " rmse .... root mean squared error\n"
+ " pae ..... peak absolute error\n"
+ " mae ..... mean absolute error\n"
+ " equal ... equality (boolean)\n"
+ );
+ exit(EXIT_FAILURE);
+}