[cairo-commit] 24 commits - test/buffer-diff.c test/buffer-diff.h
test/cairo-test.c test/caps-joins-ps-argb32-ref.png
test/caps-sub-paths-ps-argb32-ref.png
test/close-path-ps-argb32-ref.png
test/dash-offset-negative-ps-argb32-ref.png
test/fill-and-stroke-alpha-svg-ref.png
test/glyph-cache-pressure-ps-argb32-ref.png
test/glyph-cache-pressure-svg-ref.png
test/infinite-join-ps-argb32-ref.png
test/leaky-polygon-ps-argb32-ref.png
test/line-width-ps-argb32-ref.png test/Makefile.am
test/mask-ctm-svg-rgb24-ref.png
test/mask-surface-ctm-svg-rgb24-ref.png test/pdiff
test/push-group-svg-rgb24-ref.png
test/select-font-face-ps-argb32-ref.png
test/select-font-face-svg-ref.png test/set-source-svg-rgb24-ref.png
test/show-text-current-point-ps-argb32-ref.png
test/show-text-current-point-svg-ref.png
test/transforms-ps-argb32-ref.png test/trap-clip-svg-rgb24-ref.png
Carl Worth
cworth at kemper.freedesktop.org
Thu Dec 14 07:59:17 PST 2006
dev/null |binary
test/Makefile.am | 4
test/buffer-diff.c | 58 ++--
test/buffer-diff.h | 15 -
test/cairo-test.c | 12
test/caps-joins-ps-argb32-ref.png | 0
test/caps-sub-paths-ps-argb32-ref.png | 0
test/close-path-ps-argb32-ref.png | 0
test/dash-offset-negative-ps-argb32-ref.png | 0
test/fill-and-stroke-alpha-svg-ref.png | 0
test/glyph-cache-pressure-ps-argb32-ref.png | 0
test/glyph-cache-pressure-svg-ref.png | 0
test/infinite-join-ps-argb32-ref.png | 0
test/leaky-polygon-ps-argb32-ref.png | 0
test/line-width-ps-argb32-ref.png | 0
test/mask-ctm-svg-rgb24-ref.png | 0
test/mask-surface-ctm-svg-rgb24-ref.png | 0
test/pdiff/.gitignore | 1
test/pdiff/CompareArgs.cpp | 136 ---------
test/pdiff/CompareArgs.h | 44 ---
test/pdiff/LPyramid.cpp | 87 ------
test/pdiff/LPyramid.h | 38 --
test/pdiff/Makefile.am | 22 -
test/pdiff/Metric.cpp | 348 ------------------------
test/pdiff/Metric.h | 26 -
test/pdiff/PerceptualDiff.cpp | 45 ---
test/pdiff/README.txt | 4
test/pdiff/RGBAImage.cpp | 144 ---------
test/pdiff/RGBAImage.h | 57 ---
test/pdiff/args.c | 119 ++++++++
test/pdiff/args.h | 46 +++
test/pdiff/lpyramid.c | 111 +++++++
test/pdiff/lpyramid.h | 32 ++
test/pdiff/pdiff.c | 361 +++++++++++++++++++++++++
test/pdiff/pdiff.h | 40 ++
test/pdiff/perceptualdiff.c | 101 ++++++
test/push-group-svg-rgb24-ref.png | 0
test/select-font-face-ps-argb32-ref.png | 0
test/select-font-face-svg-ref.png | 0
test/set-source-svg-rgb24-ref.png | 0
test/show-text-current-point-ps-argb32-ref.png | 0
test/show-text-current-point-svg-ref.png | 0
test/transforms-ps-argb32-ref.png | 0
test/trap-clip-svg-rgb24-ref.png | 0
44 files changed, 882 insertions(+), 969 deletions(-)
New commits:
diff-tree 4888a02666972e9c09d9ffd9854538191cf59d77 (from 5e0818d79d13f5942485b411a04a4eebd56d36f8)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 04:56:19 2006 -0800
test: Remove ps-specific reference images no longer needed thanks to pdiff
diff --git a/test/caps-joins-ps-argb32-ref.png b/test/caps-joins-ps-argb32-ref.png
deleted file mode 100644
index c126d34..0000000
Binary files a/test/caps-joins-ps-argb32-ref.png and /dev/null differ
diff --git a/test/caps-sub-paths-ps-argb32-ref.png b/test/caps-sub-paths-ps-argb32-ref.png
deleted file mode 100644
index a53aad8..0000000
Binary files a/test/caps-sub-paths-ps-argb32-ref.png and /dev/null differ
diff --git a/test/close-path-ps-argb32-ref.png b/test/close-path-ps-argb32-ref.png
deleted file mode 100644
index 1f5790c..0000000
Binary files a/test/close-path-ps-argb32-ref.png and /dev/null differ
diff --git a/test/dash-offset-negative-ps-argb32-ref.png b/test/dash-offset-negative-ps-argb32-ref.png
deleted file mode 100644
index f1d56fe..0000000
Binary files a/test/dash-offset-negative-ps-argb32-ref.png and /dev/null differ
diff --git a/test/glyph-cache-pressure-ps-argb32-ref.png b/test/glyph-cache-pressure-ps-argb32-ref.png
deleted file mode 100644
index e51bca7..0000000
Binary files a/test/glyph-cache-pressure-ps-argb32-ref.png and /dev/null differ
diff --git a/test/infinite-join-ps-argb32-ref.png b/test/infinite-join-ps-argb32-ref.png
deleted file mode 100644
index 1db6622..0000000
Binary files a/test/infinite-join-ps-argb32-ref.png and /dev/null differ
diff --git a/test/leaky-polygon-ps-argb32-ref.png b/test/leaky-polygon-ps-argb32-ref.png
deleted file mode 100644
index a8ba771..0000000
Binary files a/test/leaky-polygon-ps-argb32-ref.png and /dev/null differ
diff --git a/test/line-width-ps-argb32-ref.png b/test/line-width-ps-argb32-ref.png
deleted file mode 100644
index 4c64e6c..0000000
Binary files a/test/line-width-ps-argb32-ref.png and /dev/null differ
diff --git a/test/select-font-face-ps-argb32-ref.png b/test/select-font-face-ps-argb32-ref.png
deleted file mode 100644
index d8d84a5..0000000
Binary files a/test/select-font-face-ps-argb32-ref.png and /dev/null differ
diff --git a/test/show-text-current-point-ps-argb32-ref.png b/test/show-text-current-point-ps-argb32-ref.png
deleted file mode 100644
index e3f7e7f..0000000
Binary files a/test/show-text-current-point-ps-argb32-ref.png and /dev/null differ
diff --git a/test/transforms-ps-argb32-ref.png b/test/transforms-ps-argb32-ref.png
deleted file mode 100644
index 5d5cfa9..0000000
Binary files a/test/transforms-ps-argb32-ref.png and /dev/null differ
diff-tree 5e0818d79d13f5942485b411a04a4eebd56d36f8 (from c426e71141d75dbfd39730bf9c4847309fcd9d9e)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 04:33:08 2006 -0800
test: Remove svg-specific reference images no longer needed thanks to pdiff
This doesn't get rid of all the SVG reference images, but it
does clean up quite a few.
diff --git a/test/fill-and-stroke-alpha-svg-ref.png b/test/fill-and-stroke-alpha-svg-ref.png
deleted file mode 100644
index 812c897..0000000
Binary files a/test/fill-and-stroke-alpha-svg-ref.png and /dev/null differ
diff --git a/test/glyph-cache-pressure-svg-ref.png b/test/glyph-cache-pressure-svg-ref.png
deleted file mode 100644
index 6f40d60..0000000
Binary files a/test/glyph-cache-pressure-svg-ref.png and /dev/null differ
diff --git a/test/mask-ctm-svg-rgb24-ref.png b/test/mask-ctm-svg-rgb24-ref.png
deleted file mode 100644
index 90628a6..0000000
Binary files a/test/mask-ctm-svg-rgb24-ref.png and /dev/null differ
diff --git a/test/mask-surface-ctm-svg-rgb24-ref.png b/test/mask-surface-ctm-svg-rgb24-ref.png
deleted file mode 100644
index 90628a6..0000000
Binary files a/test/mask-surface-ctm-svg-rgb24-ref.png and /dev/null differ
diff --git a/test/push-group-svg-rgb24-ref.png b/test/push-group-svg-rgb24-ref.png
deleted file mode 100644
index 5a0a59c..0000000
Binary files a/test/push-group-svg-rgb24-ref.png and /dev/null differ
diff --git a/test/select-font-face-svg-ref.png b/test/select-font-face-svg-ref.png
deleted file mode 100644
index e2e93b5..0000000
Binary files a/test/select-font-face-svg-ref.png and /dev/null differ
diff --git a/test/set-source-svg-rgb24-ref.png b/test/set-source-svg-rgb24-ref.png
deleted file mode 100644
index 802147f..0000000
Binary files a/test/set-source-svg-rgb24-ref.png and /dev/null differ
diff --git a/test/show-text-current-point-svg-ref.png b/test/show-text-current-point-svg-ref.png
deleted file mode 100644
index 2c4bcd7..0000000
Binary files a/test/show-text-current-point-svg-ref.png and /dev/null differ
diff --git a/test/trap-clip-svg-rgb24-ref.png b/test/trap-clip-svg-rgb24-ref.png
deleted file mode 100644
index 46a9200..0000000
Binary files a/test/trap-clip-svg-rgb24-ref.png and /dev/null differ
diff-tree c426e71141d75dbfd39730bf9c4847309fcd9d9e (from 305cbd8e71a2d21a2c71ed2c382daa5bfcec3992)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 04:17:07 2006 -0800
Hook up pdiff to the test suite now that its written in C
diff --git a/test/Makefile.am b/test/Makefile.am
index 26f28b5..11d414b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -392,6 +392,7 @@ SUPPORT_PROGS =
INCLUDES = \
-D_GNU_SOURCE \
-I$(srcdir) \
+ -I$(srcdir)/pdiff \
-I$(top_srcdir)/boilerplate \
-I$(top_srcdir)/pixman/src \
-I$(top_srcdir)/src \
@@ -407,6 +408,7 @@ libcairotest_la_SOURCES =\
cairo-test.h
LDADD = libcairotest.la \
+ $(top_builddir)/test/pdiff/libpdiff.la \
$(top_builddir)/boilerplate/libcairoboilerplate.la \
$(top_builddir)/src/libcairo.la
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index 99501bc..e4324ff 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -38,6 +38,7 @@
#include "cairo-test.h"
+#include "pdiff.h"
#include "buffer-diff.h"
#include "xmalloc.h"
@@ -122,6 +123,18 @@ compare_surfaces (cairo_surface_t *surfa
cairo_surface_t *surface_diff,
buffer_diff_result_t *result)
{
+ /* These default values were taken straight from the
+ * perceptualdiff program. We'll probably want to tune these as
+ * necessary. */
+ double gamma = 2.2;
+ double luminance = 100.0;
+ double field_of_view = 45.0;
+ int discernible_pixels_changed;
+
+ /* First, we run cairo's old buffer_diff algorithm which looks for
+ * pixel-perfect images, (we do this first since the test suite
+ * runs about 3x slower if we run pdiff_compare first).
+ */
buffer_diff_core (cairo_image_surface_get_data (surface_a),
cairo_image_surface_get_data (surface_b),
cairo_image_surface_get_data (surface_diff),
@@ -130,6 +143,23 @@ compare_surfaces (cairo_surface_t *surfa
cairo_image_surface_get_stride (surface_a),
0xffffffff,
result);
+ if (result->pixels_changed == 0)
+ return;
+
+ cairo_test_log ("%d pixels differ (with maximum difference of %d) from reference image\n",
+ result->pixels_changed, result->max_diff);
+
+ /* Then, if there are any different pixels, we give the pdiff code
+ * a crack at the images. If it decides that there are no visually
+ * discernible differences in any pixels, then we accept this
+ * result as good enough. */
+ discernible_pixels_changed = pdiff_compare (surface_a, surface_b,
+ gamma, luminance, field_of_view);
+ if (discernible_pixels_changed == 0) {
+ result->pixels_changed = 0;
+ cairo_test_log ("But perceptual diff finds no visually discernible difference.\n"
+ "Accepting result.\n");
+ }
}
void
diff --git a/test/cairo-test.c b/test/cairo-test.c
index ea8f2ac..498eb8e 100755
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -313,6 +313,8 @@ cairo_test_for_target (cairo_test_t *
goto UNWIND_CAIRO;
}
+ cairo_test_log ("Comparing result against reference image: %s\n", ref_name);
+
if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) {
diff_status= image_diff_flattened (png_name, ref_name, diff_name,
dev_offset, dev_offset, 0, 0, &result);
@@ -326,13 +328,9 @@ cairo_test_for_target (cairo_test_t *
ret = CAIRO_TEST_FAILURE;
goto UNWIND_CAIRO;
}
- if (result.pixels_changed) {
- cairo_test_log ("%d pixels differ (with maximum difference of %d) from reference image %s\n",
- result.pixels_changed, result.max_diff, ref_name);
- if (result.max_diff > target->error_tolerance) {
- ret = CAIRO_TEST_FAILURE;
- goto UNWIND_CAIRO;
- }
+ if (result.pixels_changed && result.max_diff > target->error_tolerance) {
+ ret = CAIRO_TEST_FAILURE;
+ goto UNWIND_CAIRO;
}
}
diff-tree 305cbd8e71a2d21a2c71ed2c382daa5bfcec3992 (from f175b23559f3ba759d222538fd28922c1cbe2196)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 04:14:24 2006 -0800
pdiff: Remove casts since we're out of the land of X++ where void* is stupidly broken
diff --git a/test/pdiff/lpyramid.c b/test/pdiff/lpyramid.c
index 92915ab..de72d8e 100644
--- a/test/pdiff/lpyramid.c
+++ b/test/pdiff/lpyramid.c
@@ -65,8 +65,7 @@ lpyramid_create (float *image, int width
lpyramid_t *pyramid;
int i;
- /* XXX: Remove stupid cast after finishing port to C */
- pyramid = (lpyramid_t *) malloc (sizeof (lpyramid_t));
+ pyramid = malloc (sizeof (lpyramid_t));
if (pyramid == NULL) {
fprintf (stderr, "Out of memory.\n");
exit (1);
@@ -77,8 +76,7 @@ lpyramid_create (float *image, int width
/* Make the Laplacian pyramid by successively
* copying the earlier levels and blurring them */
for (i=0; i<MAX_PYR_LEVELS; i++) {
- /* XXX: Remove stupid cast after finishing port to C */
- pyramid->levels[i] = (float *) malloc (width * height * sizeof (float));
+ pyramid->levels[i] = malloc (width * height * sizeof (float));
if (pyramid->levels[i] == NULL) {
fprintf (stderr, "Out of memory.\n");
exit (1);
diff-tree f175b23559f3ba759d222538fd28922c1cbe2196 (from 18a4fa448fcdb6a72f427e997ee2b234f96a56f7)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 03:49:31 2006 -0800
pdiff: Rename everything to .c and fix an last littele C++ isms.
The only things we had missed were a few new/delete pairs, and some
obvious header file fixups, (like not doing <string>).
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
deleted file mode 100644
index 3b58ff7..0000000
--- a/test/pdiff/CompareArgs.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- Comapre Args
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "CompareArgs.h"
-#include <stdio.h>
-
-static const char* copyright =
-"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
-PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
-This is free software, and you are welcome\n\
-to redistribute it under certain conditions;\n\
-See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n";
-
-static const char *usage =
-"PeceptualDiff image1.tif image2.tif\n\n\
- Compares image1.tif and image2.tif using a perceptually based image metric\n\
- Options:\n\
-\t-verbose : Turns on verbose mode\n\
-\t-fov deg : Field of view in degrees (0.1 to 89.9)\n\
-\t-threshold p : #pixels p below which differences are ignored\n\
-\t-gamma g : Value to convert rgb into linear space (default 2.2)\n\
-\t-luminance l : White luminance (default 100.0 cdm^-2)\n\
-\n\
-\n Note: Input files can also be in the PNG format\
-\n";
-
-CompareArgs::CompareArgs()
-{
- surface_a = NULL;
- surface_b = NULL;
- Verbose = false;
- FieldOfView = 45.0f;
- Gamma = 2.2f;
- ThresholdPixels = 100;
- Luminance = 100.0f;
-}
-
-CompareArgs::~CompareArgs()
-{
- cairo_surface_destroy (surface_a);
- cairo_surface_destroy (surface_b);
-}
-
-bool CompareArgs::Parse_Args(int argc, char **argv)
-{
- int i;
-
- if (argc < 3) {
- fprintf (stderr, "%s", copyright);
- fprintf (stderr, "%s", usage);
- return false;
- }
- for (i = 0; i < argc; i++) {
- if (i == 1) {
- surface_a = cairo_image_surface_create_from_png (argv[1]);
- if (cairo_surface_status (surface_a))
- {
- fprintf (stderr, "FAIL: Cannot open %s: %s\n",
- argv[1], cairo_status_to_string (cairo_surface_status (surface_a)));
- return false;
- }
- } else if (i == 2) {
- surface_b = cairo_image_surface_create_from_png (argv[2]);
- if (cairo_surface_status (surface_b))
- {
- fprintf (stderr, "FAIL: Cannot open %s: %s\n",
- argv[2], cairo_status_to_string (cairo_surface_status (surface_b)));
- return false;
- }
- } else {
- if (strstr(argv[i], "-fov")) {
- if (i + 1 < argc) {
- FieldOfView = (float) atof(argv[i + 1]);
- }
- } else if (strstr(argv[i], "-verbose")) {
- Verbose = true;
- } else if (strstr(argv[i], "-threshold")) {
- if (i + 1 < argc) {
- ThresholdPixels = atoi(argv[i + 1]);
- }
- } else if (strstr(argv[i], "-gamma")) {
- if (i + 1 < argc) {
- Gamma = (float) atof(argv[i + 1]);
- }
- }else if (strstr(argv[i], "-luminance")) {
- if (i + 1 < argc) {
- Luminance = (float) atof(argv[i + 1]);
- }
- }
- }
- } /* i */
- return true;
-}
-
-void CompareArgs::Print_Args()
-{
- printf("Field of view is %f degrees\n", FieldOfView);
- printf("Threshold pixels is %d pixels\n", ThresholdPixels);
- printf("The Gamma is %f\n", Gamma);
- printf("The Display's luminance is %f candela per meter squared\n", Luminance);
-}
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index f53c8d2..d72b273 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -5,12 +5,12 @@ libpdiff_la_SOURCES = \
pdiff.h \
lpyramid.c \
lpyramid.h \
- pdiff.cpp
+ pdiff.c
perceptualdiff_SOURCES = \
- args.cpp \
+ args.c \
args.h \
- PerceptualDiff.cpp
+ perceptualdiff.c
INCLUDES = -I$(top_srcdir)/src
LDADD = libpdiff.la $(top_builddir)/src/libcairo.la
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
deleted file mode 100644
index 1df3614..0000000
--- a/test/pdiff/PerceptualDiff.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- PerceptualDiff - a program that compares two images using a perceptual metric
- based on the paper :
- A perceptual metric for production testing. Journal of graphics tools, 9(4):33-40, 2004, Hector Yee
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <string>
-#include "lpyramid.h"
-#include "args.h"
-#include "pdiff.h"
-
-static bool Yee_Compare(args_t *args)
-{
- int width_a, height_a, stride_a;
- unsigned char *data_a, *row_a;
- uint32_t *pixel_a;
- int width_b, height_b, stride_b;
- unsigned char *data_b, *row_b;
- uint32_t *pixel_b;
- unsigned int x, y, dim, pixels_failed;
- bool identical = true;
-
- width_a = cairo_image_surface_get_width (args->surface_a);
- height_a = cairo_image_surface_get_height (args->surface_a);
- stride_a = cairo_image_surface_get_stride (args->surface_a);
- data_a = cairo_image_surface_get_data (args->surface_a);
-
- width_b = cairo_image_surface_get_width (args->surface_b);
- height_b = cairo_image_surface_get_height (args->surface_b);
- stride_b = cairo_image_surface_get_stride (args->surface_b);
- data_b = cairo_image_surface_get_data (args->surface_b);
-
- if ((width_a != width_b) || (height_a != height_b)) {
- printf ("FAIL: Image dimensions do not match\n");
- return false;
- }
-
- identical = true;
-
- for (y = 0; y < height_a; y++) {
- row_a = data_a + y * stride_a;
- row_b = data_b + y * stride_b;
- pixel_a = (uint32_t *) row_a;
- pixel_b = (uint32_t *) row_b;
- for (x = 0; x < width_a; x++) {
- if (*pixel_a != *pixel_b) {
- identical = false;
- }
- pixel_a++;
- pixel_b++;
- }
- }
- if (identical) {
- printf ("PASS: Images are binary identical\n");
- return true;
- }
-
- pixels_failed = pdiff_compare (args->surface_a, args->surface_b,
- args->Gamma, args->Luminance,
- args->FieldOfView);
-
- if (pixels_failed < args->ThresholdPixels) {
- printf ("PASS: Images are perceptually indistinguishable\n");
- return true;
- }
-
- printf("FAIL: Images are visibly different\n"
- "%d pixels are different\n", pixels_failed);
-
- return false;
-}
-
-int main(int argc, char **argv)
-{
- args_t args;
-
- args_init (&args);
-
- if (!args_parse (&args, argc, argv)) {
- return -1;
- } else {
- if (args.Verbose)
- args_print (&args);
- }
- return ! Yee_Compare(&args);
-}
diff --git a/test/pdiff/args.c b/test/pdiff/args.c
new file mode 100644
index 0000000..0dfbea5
--- /dev/null
+++ b/test/pdiff/args.c
@@ -0,0 +1,119 @@
+/*
+ Comapre Args
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "args.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char* copyright =
+"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
+PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
+This is free software, and you are welcome\n\
+to redistribute it under certain conditions;\n\
+See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n";
+
+static const char *usage =
+"PeceptualDiff image1.tif image2.tif\n\n\
+ Compares image1.tif and image2.tif using a perceptually based image metric\n\
+ Options:\n\
+\t-verbose : Turns on verbose mode\n\
+\t-fov deg : Field of view in degrees (0.1 to 89.9)\n\
+\t-threshold p : #pixels p below which differences are ignored\n\
+\t-gamma g : Value to convert rgb into linear space (default 2.2)\n\
+\t-luminance l : White luminance (default 100.0 cdm^-2)\n\
+\n\
+\n Note: Input files can also be in the PNG format\
+\n";
+
+void
+args_init (args_t *args)
+{
+ args->surface_a = NULL;
+ args->surface_b = NULL;
+ args->Verbose = false;
+ args->FieldOfView = 45.0f;
+ args->Gamma = 2.2f;
+ args->ThresholdPixels = 100;
+ args->Luminance = 100.0f;
+}
+
+void
+args_fini (args_t *args)
+{
+ cairo_surface_destroy (args->surface_a);
+ cairo_surface_destroy (args->surface_b);
+}
+
+bool
+args_parse (args_t *args, int argc, char **argv)
+{
+ int i;
+ if (argc < 3) {
+ fprintf (stderr, "%s", copyright);
+ fprintf (stderr, "%s", usage);
+ return false;
+ }
+ for (i = 0; i < argc; i++) {
+ if (i == 1) {
+ args->surface_a = cairo_image_surface_create_from_png (argv[1]);
+ if (cairo_surface_status (args->surface_a))
+ {
+ fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+ argv[1], cairo_status_to_string (cairo_surface_status (args->surface_a)));
+ return false;
+ }
+ } else if (i == 2) {
+ args->surface_b = cairo_image_surface_create_from_png (argv[2]);
+ if (cairo_surface_status (args->surface_b))
+ {
+ fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+ argv[2], cairo_status_to_string (cairo_surface_status (args->surface_b)));
+ return false;
+ }
+ } else {
+ if (strstr(argv[i], "-fov")) {
+ if (i + 1 < argc) {
+ args->FieldOfView = (float) atof(argv[i + 1]);
+ }
+ } else if (strstr(argv[i], "-verbose")) {
+ args->Verbose = true;
+ } else if (strstr(argv[i], "-threshold")) {
+ if (i + 1 < argc) {
+ args->ThresholdPixels = atoi(argv[i + 1]);
+ }
+ } else if (strstr(argv[i], "-gamma")) {
+ if (i + 1 < argc) {
+ args->Gamma = (float) atof(argv[i + 1]);
+ }
+ }else if (strstr(argv[i], "-luminance")) {
+ if (i + 1 < argc) {
+ args->Luminance = (float) atof(argv[i + 1]);
+ }
+ }
+ }
+ } /* i */
+ return true;
+}
+
+void
+args_print (args_t *args)
+{
+ printf("Field of view is %f degrees\n", args->FieldOfView);
+ printf("Threshold pixels is %d pixels\n", args->ThresholdPixels);
+ printf("The Gamma is %f\n", args->Gamma);
+ printf("The Display's luminance is %f candela per meter squared\n", args->Luminance);
+}
diff --git a/test/pdiff/args.cpp b/test/pdiff/args.cpp
deleted file mode 100644
index 9fbe23e..0000000
--- a/test/pdiff/args.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- Comapre Args
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "args.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static const char* copyright =
-"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
-PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
-This is free software, and you are welcome\n\
-to redistribute it under certain conditions;\n\
-See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n";
-
-static const char *usage =
-"PeceptualDiff image1.tif image2.tif\n\n\
- Compares image1.tif and image2.tif using a perceptually based image metric\n\
- Options:\n\
-\t-verbose : Turns on verbose mode\n\
-\t-fov deg : Field of view in degrees (0.1 to 89.9)\n\
-\t-threshold p : #pixels p below which differences are ignored\n\
-\t-gamma g : Value to convert rgb into linear space (default 2.2)\n\
-\t-luminance l : White luminance (default 100.0 cdm^-2)\n\
-\n\
-\n Note: Input files can also be in the PNG format\
-\n";
-
-void
-args_init (args_t *args)
-{
- args->surface_a = NULL;
- args->surface_b = NULL;
- args->Verbose = false;
- args->FieldOfView = 45.0f;
- args->Gamma = 2.2f;
- args->ThresholdPixels = 100;
- args->Luminance = 100.0f;
-}
-
-void
-args_fini (args_t *args)
-{
- cairo_surface_destroy (args->surface_a);
- cairo_surface_destroy (args->surface_b);
-}
-
-bool
-args_parse (args_t *args, int argc, char **argv)
-{
- if (argc < 3) {
- fprintf (stderr, "%s", copyright);
- fprintf (stderr, "%s", usage);
- return false;
- }
- for (int i = 0; i < argc; i++) {
- if (i == 1) {
- args->surface_a = cairo_image_surface_create_from_png (argv[1]);
- if (cairo_surface_status (args->surface_a))
- {
- fprintf (stderr, "FAIL: Cannot open %s: %s\n",
- argv[1], cairo_status_to_string (cairo_surface_status (args->surface_a)));
- return false;
- }
- } else if (i == 2) {
- args->surface_b = cairo_image_surface_create_from_png (argv[2]);
- if (cairo_surface_status (args->surface_b))
- {
- fprintf (stderr, "FAIL: Cannot open %s: %s\n",
- argv[2], cairo_status_to_string (cairo_surface_status (args->surface_b)));
- return false;
- }
- } else {
- if (strstr(argv[i], "-fov")) {
- if (i + 1 < argc) {
- args->FieldOfView = (float) atof(argv[i + 1]);
- }
- } else if (strstr(argv[i], "-verbose")) {
- args->Verbose = true;
- } else if (strstr(argv[i], "-threshold")) {
- if (i + 1 < argc) {
- args->ThresholdPixels = atoi(argv[i + 1]);
- }
- } else if (strstr(argv[i], "-gamma")) {
- if (i + 1 < argc) {
- args->Gamma = (float) atof(argv[i + 1]);
- }
- }else if (strstr(argv[i], "-luminance")) {
- if (i + 1 < argc) {
- args->Luminance = (float) atof(argv[i + 1]);
- }
- }
- }
- } /* i */
- return true;
-}
-
-void
-args_print (args_t *args)
-{
- printf("Field of view is %f degrees\n", args->FieldOfView);
- printf("Threshold pixels is %d pixels\n", args->ThresholdPixels);
- printf("The Gamma is %f\n", args->Gamma);
- printf("The Display's luminance is %f candela per meter squared\n", args->Luminance);
-}
diff --git a/test/pdiff/args.h b/test/pdiff/args.h
index 0197c90..aa6cf29 100644
--- a/test/pdiff/args.h
+++ b/test/pdiff/args.h
@@ -17,7 +17,7 @@
#ifndef _ARGS_H
#define _ARGS_H
-#include <cairo.h>
+#include "pdiff.h"
/* Args to pass into the comparison function */
typedef struct _args
diff --git a/test/pdiff/lpyramid.c b/test/pdiff/lpyramid.c
new file mode 100644
index 0000000..92915ab
--- /dev/null
+++ b/test/pdiff/lpyramid.c
@@ -0,0 +1,113 @@
+/*
+ Laplacian Pyramid
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "lpyramid.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct _lpyramid {
+ /* Succesively blurred versions of the original image */
+ float *levels[MAX_PYR_LEVELS];
+
+ int width;
+ int height;
+};
+
+static void
+convolve (lpyramid_t *pyramid, float *a, float *b)
+/* convolves image b with the filter kernel and stores it in a */
+{
+ int y,x,i,j,nx,ny;
+ const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
+ int width = pyramid->width;
+ int height = pyramid->height;
+
+ for (y=0; y<height; y++) {
+ for (x=0; x<width; x++) {
+ int index = y * width + x;
+ a[index] = 0.0f;
+ for (i=-2; i<=2; i++) {
+ for (j=-2; j<=2; j++) {
+ nx=x+i;
+ ny=y+j;
+ if (nx<0) nx=-nx;
+ if (ny<0) ny=-ny;
+ if (nx>=width) nx=2*(width-1)-nx;
+ if (ny>=height) ny=2*(height-1)-ny;
+ a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * width + nx];
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Construction/Destruction
+ */
+
+lpyramid_t *
+lpyramid_create (float *image, int width, int height)
+{
+ lpyramid_t *pyramid;
+ int i;
+
+ /* XXX: Remove stupid cast after finishing port to C */
+ pyramid = (lpyramid_t *) malloc (sizeof (lpyramid_t));
+ if (pyramid == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+ pyramid->width = width;
+ pyramid->height = height;
+
+ /* Make the Laplacian pyramid by successively
+ * copying the earlier levels and blurring them */
+ for (i=0; i<MAX_PYR_LEVELS; i++) {
+ /* XXX: Remove stupid cast after finishing port to C */
+ pyramid->levels[i] = (float *) malloc (width * height * sizeof (float));
+ if (pyramid->levels[i] == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+ if (i == 0) {
+ memcpy (pyramid->levels[i], image, width * height * sizeof (float));
+ } else {
+ convolve(pyramid, pyramid->levels[i], pyramid->levels[i - 1]);
+ }
+ }
+
+ return pyramid;
+}
+
+void
+lpyramid_destroy (lpyramid_t *pyramid)
+{
+ int i;
+
+ for (i=0; i<MAX_PYR_LEVELS; i++)
+ free (pyramid->levels[i]);
+}
+
+float
+lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level)
+{
+ int index = x + y * pyramid->width;
+ int l = level;
+ if (l > MAX_PYR_LEVELS)
+ l = MAX_PYR_LEVELS;
+ return pyramid->levels[level][index];
+}
diff --git a/test/pdiff/lpyramid.cpp b/test/pdiff/lpyramid.cpp
deleted file mode 100644
index 92915ab..0000000
--- a/test/pdiff/lpyramid.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- Laplacian Pyramid
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "lpyramid.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-struct _lpyramid {
- /* Succesively blurred versions of the original image */
- float *levels[MAX_PYR_LEVELS];
-
- int width;
- int height;
-};
-
-static void
-convolve (lpyramid_t *pyramid, float *a, float *b)
-/* convolves image b with the filter kernel and stores it in a */
-{
- int y,x,i,j,nx,ny;
- const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
- int width = pyramid->width;
- int height = pyramid->height;
-
- for (y=0; y<height; y++) {
- for (x=0; x<width; x++) {
- int index = y * width + x;
- a[index] = 0.0f;
- for (i=-2; i<=2; i++) {
- for (j=-2; j<=2; j++) {
- nx=x+i;
- ny=y+j;
- if (nx<0) nx=-nx;
- if (ny<0) ny=-ny;
- if (nx>=width) nx=2*(width-1)-nx;
- if (ny>=height) ny=2*(height-1)-ny;
- a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * width + nx];
- }
- }
- }
- }
-}
-
-/*
- * Construction/Destruction
- */
-
-lpyramid_t *
-lpyramid_create (float *image, int width, int height)
-{
- lpyramid_t *pyramid;
- int i;
-
- /* XXX: Remove stupid cast after finishing port to C */
- pyramid = (lpyramid_t *) malloc (sizeof (lpyramid_t));
- if (pyramid == NULL) {
- fprintf (stderr, "Out of memory.\n");
- exit (1);
- }
- pyramid->width = width;
- pyramid->height = height;
-
- /* Make the Laplacian pyramid by successively
- * copying the earlier levels and blurring them */
- for (i=0; i<MAX_PYR_LEVELS; i++) {
- /* XXX: Remove stupid cast after finishing port to C */
- pyramid->levels[i] = (float *) malloc (width * height * sizeof (float));
- if (pyramid->levels[i] == NULL) {
- fprintf (stderr, "Out of memory.\n");
- exit (1);
- }
- if (i == 0) {
- memcpy (pyramid->levels[i], image, width * height * sizeof (float));
- } else {
- convolve(pyramid, pyramid->levels[i], pyramid->levels[i - 1]);
- }
- }
-
- return pyramid;
-}
-
-void
-lpyramid_destroy (lpyramid_t *pyramid)
-{
- int i;
-
- for (i=0; i<MAX_PYR_LEVELS; i++)
- free (pyramid->levels[i]);
-}
-
-float
-lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level)
-{
- int index = x + y * pyramid->width;
- int l = level;
- if (l > MAX_PYR_LEVELS)
- l = MAX_PYR_LEVELS;
- return pyramid->levels[level][index];
-}
diff --git a/test/pdiff/pdiff.c b/test/pdiff/pdiff.c
new file mode 100644
index 0000000..1b73e79
--- /dev/null
+++ b/test/pdiff/pdiff.c
@@ -0,0 +1,361 @@
+/*
+ Metric
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "lpyramid.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "pdiff.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265f
+#endif
+
+/*
+ * Given the adaptation luminance, this function returns the
+ * threshold of visibility in cd per m^2
+ * TVI means Threshold vs Intensity function
+ * This version comes from Ward Larson Siggraph 1997
+ */
+static float
+tvi (float adaptation_luminance)
+{
+ /* returns the threshold luminance given the adaptation luminance
+ units are candelas per meter squared
+ */
+ float log_a, r, result;
+ log_a = log10f(adaptation_luminance);
+
+ if (log_a < -3.94f) {
+ r = -2.86f;
+ } else if (log_a < -1.44f) {
+ r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
+ } else if (log_a < -0.0184f) {
+ r = log_a - 0.395f;
+ } else if (log_a < 1.9f) {
+ r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
+ } else {
+ r = log_a - 1.255f;
+ }
+
+ result = powf(10.0f , r);
+
+ return result;
+}
+
+/* computes the contrast sensitivity function (Barten SPIE 1989)
+ * given the cycles per degree (cpd) and luminance (lum)
+ */
+static float
+csf (float cpd, float lum)
+{
+ float a, b, result;
+
+ a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
+ b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
+
+ result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
+
+ return result;
+}
+
+/*
+ * Visual Masking Function
+ * from Daly 1993
+ */
+static float
+mask (float contrast)
+{
+ float a, b, result;
+ a = powf(392.498f * contrast, 0.7f);
+ b = powf(0.0153f * a, 4.0f);
+ result = powf(1.0f + b, 0.25f);
+
+ return result;
+}
+
+/* convert Adobe RGB (1998) with reference white D65 to XYZ */
+static void
+AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z)
+{
+ /* matrix is from http://www.brucelindbloom.com/ */
+ *x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
+ *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
+ *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
+}
+
+static void
+XYZToLAB (float x, float y, float z, float *L, float *A, float *B)
+{
+ static float xw = -1;
+ static float yw;
+ static float zw;
+ const float epsilon = 216.0f / 24389.0f;
+ const float kappa = 24389.0f / 27.0f;
+ float f[3];
+ float r[3];
+ int i;
+
+ /* reference white */
+ if (xw < 0) {
+ AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw);
+ }
+ r[0] = x / xw;
+ r[1] = y / yw;
+ r[2] = z / zw;
+ for (i = 0; i < 3; i++) {
+ if (r[i] > epsilon) {
+ f[i] = powf(r[i], 1.0f / 3.0f);
+ } else {
+ f[i] = (kappa * r[i] + 16.0f) / 116.0f;
+ }
+ }
+ *L = 116.0f * f[1] - 16.0f;
+ *A = 500.0f * (f[0] - f[1]);
+ *B = 200.0f * (f[1] - f[2]);
+}
+
+static uint32_t
+_get_pixel (cairo_surface_t *surface, int i)
+{
+ uint32_t *data;
+
+ data = (uint32_t *) cairo_image_surface_get_data (surface);
+ return data[i];
+}
+
+static unsigned char
+_get_red (cairo_surface_t *surface, int i)
+{
+ uint32_t pixel;
+ uint8_t alpha;
+
+ pixel = _get_pixel (surface, i);
+
+ alpha = (pixel & 0xff000000) >> 24;
+
+ if (alpha == 0)
+ return 0;
+ else
+ return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
+}
+
+static unsigned char
+_get_green (cairo_surface_t *surface, int i)
+{
+ uint32_t pixel;
+ uint8_t alpha;
+
+ pixel = _get_pixel (surface, i);
+
+ alpha = (pixel & 0xff000000) >> 24;
+
+ if (alpha == 0)
+ return 0;
+ else
+ return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
+}
+
+static unsigned char
+_get_blue (cairo_surface_t *surface, int i)
+{
+ uint32_t pixel;
+ uint8_t alpha;
+
+ pixel = _get_pixel (surface, i);
+
+ alpha = (pixel & 0xff000000) >> 24;
+
+ if (alpha == 0)
+ return 0;
+ else
+ return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
+}
+
+static void *
+xmalloc (size_t size)
+{
+ void *buf;
+
+ buf = malloc (size);
+ if (buf == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+}
+
+int
+pdiff_compare (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ double gamma,
+ double luminance,
+ double field_of_view)
+{
+ unsigned int dim = (cairo_image_surface_get_width (surface_a)
+ * cairo_image_surface_get_height (surface_a));
+ unsigned int i;
+
+ /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
+ float *aX = xmalloc (dim * sizeof (float));
+ float *aY = xmalloc (dim * sizeof (float));
+ float *aZ = xmalloc (dim * sizeof (float));
+ float *bX = xmalloc (dim * sizeof (float));
+ float *bY = xmalloc (dim * sizeof (float));
+ float *bZ = xmalloc (dim * sizeof (float));
+ float *aLum = xmalloc (dim * sizeof (float));
+ float *bLum = xmalloc (dim * sizeof (float));
+
+ float *aA = xmalloc (dim * sizeof (float));
+ float *bA = xmalloc (dim * sizeof (float));
+ float *aB = xmalloc (dim * sizeof (float));
+ float *bB = xmalloc (dim * sizeof (float));
+
+ unsigned int x, y, w, h;
+
+ lpyramid_t *la, *lb;
+
+ float num_one_degree_pixels, pixels_per_degree, num_pixels;
+ unsigned int adaptation_level;
+
+ float cpd[MAX_PYR_LEVELS];
+ float F_freq[MAX_PYR_LEVELS - 2];
+ float csf_max;
+
+ unsigned int pixels_failed;
+
+ w = cairo_image_surface_get_width (surface_a);
+ h = cairo_image_surface_get_height (surface_a);
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ float r, g, b, l;
+ i = x + y * w;
+ r = powf(_get_red (surface_a, i) / 255.0f, gamma);
+ g = powf(_get_green (surface_a, i) / 255.0f, gamma);
+ b = powf(_get_blue (surface_a, i) / 255.0f, gamma);
+
+ AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
+ XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
+ r = powf(_get_red (surface_b, i) / 255.0f, gamma);
+ g = powf(_get_green (surface_b, i) / 255.0f, gamma);
+ b = powf(_get_blue (surface_b, i) / 255.0f, gamma);
+
+ AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
+ XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
+ aLum[i] = aY[i] * luminance;
+ bLum[i] = bY[i] * luminance;
+ }
+ }
+
+ la = lpyramid_create (aLum, w, h);
+ lb = lpyramid_create (bLum, w, h);
+
+ num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
+ pixels_per_degree = w / num_one_degree_pixels;
+
+ num_pixels = 1;
+ adaptation_level = 0;
+ for (i = 0; i < MAX_PYR_LEVELS; i++) {
+ adaptation_level = i;
+ if (num_pixels > num_one_degree_pixels) break;
+ num_pixels *= 2;
+ }
+
+ cpd[0] = 0.5f * pixels_per_degree;
+ for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
+ csf_max = csf(3.248f, 100.0f);
+
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
+
+ pixels_failed = 0;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ int index = x + y * w;
+ float contrast[MAX_PYR_LEVELS - 2];
+ float F_mask[MAX_PYR_LEVELS - 2];
+ float factor;
+ float delta;
+ bool pass;
+ float sum_contrast = 0;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
+ float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
+ float numerator = (n1 > n2) ? n1 : n2;
+ float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
+ float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
+ float denominator = (d1 > d2) ? d1 : d2;
+ if (denominator < 1e-5f) denominator = 1e-5f;
+ contrast[i] = numerator / denominator;
+ sum_contrast += contrast[i];
+ }
+ if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
+ float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
+ adapt *= 0.5f;
+ if (adapt < 1e-5) adapt = 1e-5f;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
+ }
+ factor = 0;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
+ }
+ if (factor < 1) factor = 1;
+ if (factor > 10) factor = 10;
+ delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
+ pass = true;
+ /* pure luminance test */
+ if (delta > factor * tvi(adapt)) {
+ pass = false;
+ } else {
+ /* CIE delta E test with modifications */
+ float color_scale = 1.0f;
+ float da = aA[index] - bA[index];
+ float db = aB[index] - bB[index];
+ float delta_e;
+ /* ramp down the color test in scotopic regions */
+ if (adapt < 10.0f) {
+ color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
+ color_scale = color_scale * color_scale;
+ }
+ da = da * da;
+ db = db * db;
+ delta_e = (da + db) * color_scale;
+ if (delta_e > factor) {
+ pass = false;
+ }
+ }
+ if (!pass)
+ pixels_failed++;
+ }
+ }
+
+ free (aX);
+ free (aY);
+ free (aZ);
+ free (bX);
+ free (bY);
+ free (bZ);
+ free (aLum);
+ free (bLum);
+ lpyramid_destroy (la);
+ lpyramid_destroy (lb);
+ free (aA);
+ free (bA);
+ free (aB);
+ free (bB);
+
+ return pixels_failed;
+}
diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
deleted file mode 100644
index 1609cda..0000000
--- a/test/pdiff/pdiff.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- Metric
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "lpyramid.h"
-#include <math.h>
-#include <stdint.h>
-#include "pdiff.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265f
-#endif
-
-/*
- * Given the adaptation luminance, this function returns the
- * threshold of visibility in cd per m^2
- * TVI means Threshold vs Intensity function
- * This version comes from Ward Larson Siggraph 1997
- */
-static float
-tvi (float adaptation_luminance)
-{
- /* returns the threshold luminance given the adaptation luminance
- units are candelas per meter squared
- */
- float log_a, r, result;
- log_a = log10f(adaptation_luminance);
-
- if (log_a < -3.94f) {
- r = -2.86f;
- } else if (log_a < -1.44f) {
- r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
- } else if (log_a < -0.0184f) {
- r = log_a - 0.395f;
- } else if (log_a < 1.9f) {
- r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
- } else {
- r = log_a - 1.255f;
- }
-
- result = powf(10.0f , r);
-
- return result;
-}
-
-/* computes the contrast sensitivity function (Barten SPIE 1989)
- * given the cycles per degree (cpd) and luminance (lum)
- */
-static float
-csf (float cpd, float lum)
-{
- float a, b, result;
-
- a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
- b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
-
- result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
-
- return result;
-}
-
-/*
- * Visual Masking Function
- * from Daly 1993
- */
-static float
-mask (float contrast)
-{
- float a, b, result;
- a = powf(392.498f * contrast, 0.7f);
- b = powf(0.0153f * a, 4.0f);
- result = powf(1.0f + b, 0.25f);
-
- return result;
-}
-
-/* convert Adobe RGB (1998) with reference white D65 to XYZ */
-static void
-AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z)
-{
- /* matrix is from http://www.brucelindbloom.com/ */
- *x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
- *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
- *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
-}
-
-static void
-XYZToLAB (float x, float y, float z, float *L, float *A, float *B)
-{
- static float xw = -1;
- static float yw;
- static float zw;
- const float epsilon = 216.0f / 24389.0f;
- const float kappa = 24389.0f / 27.0f;
- float f[3];
- float r[3];
- int i;
-
- /* reference white */
- if (xw < 0) {
- AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw);
- }
- r[0] = x / xw;
- r[1] = y / yw;
- r[2] = z / zw;
- for (i = 0; i < 3; i++) {
- if (r[i] > epsilon) {
- f[i] = powf(r[i], 1.0f / 3.0f);
- } else {
- f[i] = (kappa * r[i] + 16.0f) / 116.0f;
- }
- }
- *L = 116.0f * f[1] - 16.0f;
- *A = 500.0f * (f[0] - f[1]);
- *B = 200.0f * (f[1] - f[2]);
-}
-
-static uint32_t
-_get_pixel (cairo_surface_t *surface, int i)
-{
- uint32_t *data;
-
- data = (uint32_t *) cairo_image_surface_get_data (surface);
- return data[i];
-}
-
-static unsigned char
-_get_red (cairo_surface_t *surface, int i)
-{
- uint32_t pixel;
- uint8_t alpha;
-
- pixel = _get_pixel (surface, i);
-
- alpha = (pixel & 0xff000000) >> 24;
-
- if (alpha == 0)
- return 0;
- else
- return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
-}
-
-static unsigned char
-_get_green (cairo_surface_t *surface, int i)
-{
- uint32_t pixel;
- uint8_t alpha;
-
- pixel = _get_pixel (surface, i);
-
- alpha = (pixel & 0xff000000) >> 24;
-
- if (alpha == 0)
- return 0;
- else
- return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
-}
-
-static unsigned char
-_get_blue (cairo_surface_t *surface, int i)
-{
- uint32_t pixel;
- uint8_t alpha;
-
- pixel = _get_pixel (surface, i);
-
- alpha = (pixel & 0xff000000) >> 24;
-
- if (alpha == 0)
- return 0;
- else
- return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
-}
-
-int
-pdiff_compare (cairo_surface_t *surface_a,
- cairo_surface_t *surface_b,
- double gamma,
- double luminance,
- double field_of_view)
-{
- unsigned int dim = (cairo_image_surface_get_width (surface_a)
- * cairo_image_surface_get_height (surface_a));
- unsigned int i;
-
- /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
- float *aX = new float[dim];
- float *aY = new float[dim];
- float *aZ = new float[dim];
- float *bX = new float[dim];
- float *bY = new float[dim];
- float *bZ = new float[dim];
- float *aLum = new float[dim];
- float *bLum = new float[dim];
-
- float *aA = new float[dim];
- float *bA = new float[dim];
- float *aB = new float[dim];
- float *bB = new float[dim];
-
- unsigned int x, y, w, h;
-
- lpyramid_t *la, *lb;
-
- float num_one_degree_pixels, pixels_per_degree, num_pixels;
- unsigned int adaptation_level;
-
- float cpd[MAX_PYR_LEVELS];
- float F_freq[MAX_PYR_LEVELS - 2];
- float csf_max;
-
- unsigned int pixels_failed;
-
- w = cairo_image_surface_get_width (surface_a);
- h = cairo_image_surface_get_height (surface_a);
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- float r, g, b, l;
- i = x + y * w;
- r = powf(_get_red (surface_a, i) / 255.0f, gamma);
- g = powf(_get_green (surface_a, i) / 255.0f, gamma);
- b = powf(_get_blue (surface_a, i) / 255.0f, gamma);
-
- AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
- XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
- r = powf(_get_red (surface_b, i) / 255.0f, gamma);
- g = powf(_get_green (surface_b, i) / 255.0f, gamma);
- b = powf(_get_blue (surface_b, i) / 255.0f, gamma);
-
- AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
- XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
- aLum[i] = aY[i] * luminance;
- bLum[i] = bY[i] * luminance;
- }
- }
-
- la = lpyramid_create (aLum, w, h);
- lb = lpyramid_create (bLum, w, h);
-
- num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
- pixels_per_degree = w / num_one_degree_pixels;
-
- num_pixels = 1;
- adaptation_level = 0;
- for (i = 0; i < MAX_PYR_LEVELS; i++) {
- adaptation_level = i;
- if (num_pixels > num_one_degree_pixels) break;
- num_pixels *= 2;
- }
-
- cpd[0] = 0.5f * pixels_per_degree;
- for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
- csf_max = csf(3.248f, 100.0f);
-
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
-
- pixels_failed = 0;
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- int index = x + y * w;
- float contrast[MAX_PYR_LEVELS - 2];
- float F_mask[MAX_PYR_LEVELS - 2];
- float factor;
- float delta;
- bool pass;
- float sum_contrast = 0;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
- float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
- float numerator = (n1 > n2) ? n1 : n2;
- float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
- float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
- float denominator = (d1 > d2) ? d1 : d2;
- if (denominator < 1e-5f) denominator = 1e-5f;
- contrast[i] = numerator / denominator;
- sum_contrast += contrast[i];
- }
- if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
- float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
- adapt *= 0.5f;
- if (adapt < 1e-5) adapt = 1e-5f;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
- }
- factor = 0;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
- }
- if (factor < 1) factor = 1;
- if (factor > 10) factor = 10;
- delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
- pass = true;
- /* pure luminance test */
- if (delta > factor * tvi(adapt)) {
- pass = false;
- } else {
- /* CIE delta E test with modifications */
- float color_scale = 1.0f;
- float da = aA[index] - bA[index];
- float db = aB[index] - bB[index];
- float delta_e;
- /* ramp down the color test in scotopic regions */
- if (adapt < 10.0f) {
- color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
- color_scale = color_scale * color_scale;
- }
- da = da * da;
- db = db * db;
- delta_e = (da + db) * color_scale;
- if (delta_e > factor) {
- pass = false;
- }
- }
- if (!pass)
- pixels_failed++;
- }
- }
-
- if (aX) delete[] aX;
- if (aY) delete[] aY;
- if (aZ) delete[] aZ;
- if (bX) delete[] bX;
- if (bY) delete[] bY;
- if (bZ) delete[] bZ;
- if (aLum) delete[] aLum;
- if (bLum) delete[] bLum;
- lpyramid_destroy (la);
- lpyramid_destroy (lb);
- if (aA) delete aA;
- if (bA) delete bA;
- if (aB) delete aB;
- if (bB) delete bB;
-
- return pixels_failed;
-}
diff --git a/test/pdiff/pdiff.h b/test/pdiff/pdiff.h
index d20ae86..b398cc6 100644
--- a/test/pdiff/pdiff.h
+++ b/test/pdiff/pdiff.h
@@ -17,12 +17,16 @@
#ifndef _PDIFF_H
#define _PDIFF_H
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include <cairo.h>
+typedef int bool;
+#ifndef true
+#define true 1
+#endif
+#ifndef false
+#define false 0
+#endif
+
/* Image comparison metric using Yee's method (and a cairo interface)
* References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
*/
@@ -33,8 +37,4 @@ pdiff_compare (cairo_surface_t *surface_
double luminance,
double field_of_view);
-#ifdef __cplusplus
-}
-#endif
-
#endif
diff --git a/test/pdiff/perceptualdiff.c b/test/pdiff/perceptualdiff.c
new file mode 100644
index 0000000..953558e
--- /dev/null
+++ b/test/pdiff/perceptualdiff.c
@@ -0,0 +1,101 @@
+/*
+ PerceptualDiff - a program that compares two images using a perceptual metric
+ based on the paper :
+ A perceptual metric for production testing. Journal of graphics tools, 9(4):33-40, 2004, Hector Yee
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#include "lpyramid.h"
+#include "args.h"
+#include "pdiff.h"
+
+static bool Yee_Compare(args_t *args)
+{
+ int width_a, height_a, stride_a;
+ unsigned char *data_a, *row_a;
+ uint32_t *pixel_a;
+ int width_b, height_b, stride_b;
+ unsigned char *data_b, *row_b;
+ uint32_t *pixel_b;
+ unsigned int x, y, dim, pixels_failed;
+ bool identical = true;
+
+ width_a = cairo_image_surface_get_width (args->surface_a);
+ height_a = cairo_image_surface_get_height (args->surface_a);
+ stride_a = cairo_image_surface_get_stride (args->surface_a);
+ data_a = cairo_image_surface_get_data (args->surface_a);
+
+ width_b = cairo_image_surface_get_width (args->surface_b);
+ height_b = cairo_image_surface_get_height (args->surface_b);
+ stride_b = cairo_image_surface_get_stride (args->surface_b);
+ data_b = cairo_image_surface_get_data (args->surface_b);
+
+ if ((width_a != width_b) || (height_a != height_b)) {
+ printf ("FAIL: Image dimensions do not match\n");
+ return false;
+ }
+
+ identical = true;
+
+ for (y = 0; y < height_a; y++) {
+ row_a = data_a + y * stride_a;
+ row_b = data_b + y * stride_b;
+ pixel_a = (uint32_t *) row_a;
+ pixel_b = (uint32_t *) row_b;
+ for (x = 0; x < width_a; x++) {
+ if (*pixel_a != *pixel_b) {
+ identical = false;
+ }
+ pixel_a++;
+ pixel_b++;
+ }
+ }
+ if (identical) {
+ printf ("PASS: Images are binary identical\n");
+ return true;
+ }
+
+ pixels_failed = pdiff_compare (args->surface_a, args->surface_b,
+ args->Gamma, args->Luminance,
+ args->FieldOfView);
+
+ if (pixels_failed < args->ThresholdPixels) {
+ printf ("PASS: Images are perceptually indistinguishable\n");
+ return true;
+ }
+
+ printf("FAIL: Images are visibly different\n"
+ "%d pixels are different\n", pixels_failed);
+
+ return false;
+}
+
+int main(int argc, char **argv)
+{
+ args_t args;
+
+ args_init (&args);
+
+ if (!args_parse (&args, argc, argv)) {
+ return -1;
+ } else {
+ if (args.Verbose)
+ args_print (&args);
+ }
+ return ! Yee_Compare(&args);
+}
diff-tree 18a4fa448fcdb6a72f427e997ee2b234f96a56f7 (from 871aba6c80b8f3101eac51cc055ad9ca26770a95)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 03:25:51 2006 -0800
pdiff: Replace CompareArgs class with args_t struct
This gets rid of nearly the last vestiges of C++ from the pdiff code.
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index f33ba9f..3b58ff7 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -56,12 +56,14 @@ CompareArgs::~CompareArgs()
bool CompareArgs::Parse_Args(int argc, char **argv)
{
+ int i;
+
if (argc < 3) {
fprintf (stderr, "%s", copyright);
fprintf (stderr, "%s", usage);
return false;
}
- for (int i = 0; i < argc; i++) {
+ for (i = 0; i < argc; i++) {
if (i == 1) {
surface_a = cairo_image_surface_create_from_png (argv[1]);
if (cairo_surface_status (surface_a))
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
deleted file mode 100644
index 31cf059..0000000
--- a/test/pdiff/CompareArgs.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- Comapre Args
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _COMPAREARGS_H
-#define _COMPAREARGS_H
-
-#include <string>
-#include <cairo.h>
-
-/* Args to pass into the comparison function */
-class CompareArgs
-{
-public:
- CompareArgs();
- ~CompareArgs();
- bool Parse_Args(int argc, char **argv);
- void Print_Args();
-
- cairo_surface_t *surface_a; /* Image A */
- cairo_surface_t *surface_b; /* Image B */
- bool Verbose; /* Print lots of text or not */
- float FieldOfView; /* Field of view in degrees */
- float Gamma; /* The gamma to convert to linear color space */
- float Luminance; /* the display's luminance */
- unsigned int ThresholdPixels; /* How many pixels different to ignore */
-};
-
-#endif
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 4d46238..f53c8d2 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -8,8 +8,8 @@ libpdiff_la_SOURCES = \
pdiff.cpp
perceptualdiff_SOURCES = \
- CompareArgs.cpp \
- CompareArgs.h \
+ args.cpp \
+ args.h \
PerceptualDiff.cpp
INCLUDES = -I$(top_srcdir)/src
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 41aea79..1df3614 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -21,10 +21,10 @@
#include <math.h>
#include <string>
#include "lpyramid.h"
-#include "CompareArgs.h"
+#include "args.h"
#include "pdiff.h"
-static bool Yee_Compare(CompareArgs &args)
+static bool Yee_Compare(args_t *args)
{
int width_a, height_a, stride_a;
unsigned char *data_a, *row_a;
@@ -35,15 +35,15 @@ static bool Yee_Compare(CompareArgs &arg
unsigned int x, y, dim, pixels_failed;
bool identical = true;
- width_a = cairo_image_surface_get_width (args.surface_a);
- height_a = cairo_image_surface_get_height (args.surface_a);
- stride_a = cairo_image_surface_get_stride (args.surface_a);
- data_a = cairo_image_surface_get_data (args.surface_a);
-
- width_b = cairo_image_surface_get_width (args.surface_b);
- height_b = cairo_image_surface_get_height (args.surface_b);
- stride_b = cairo_image_surface_get_stride (args.surface_b);
- data_b = cairo_image_surface_get_data (args.surface_b);
+ width_a = cairo_image_surface_get_width (args->surface_a);
+ height_a = cairo_image_surface_get_height (args->surface_a);
+ stride_a = cairo_image_surface_get_stride (args->surface_a);
+ data_a = cairo_image_surface_get_data (args->surface_a);
+
+ width_b = cairo_image_surface_get_width (args->surface_b);
+ height_b = cairo_image_surface_get_height (args->surface_b);
+ stride_b = cairo_image_surface_get_stride (args->surface_b);
+ data_b = cairo_image_surface_get_data (args->surface_b);
if ((width_a != width_b) || (height_a != height_b)) {
printf ("FAIL: Image dimensions do not match\n");
@@ -70,11 +70,11 @@ static bool Yee_Compare(CompareArgs &arg
return true;
}
- pixels_failed = pdiff_compare (args.surface_a, args.surface_b,
- args.Gamma, args.Luminance,
- args.FieldOfView);
+ pixels_failed = pdiff_compare (args->surface_a, args->surface_b,
+ args->Gamma, args->Luminance,
+ args->FieldOfView);
- if (pixels_failed < args.ThresholdPixels) {
+ if (pixels_failed < args->ThresholdPixels) {
printf ("PASS: Images are perceptually indistinguishable\n");
return true;
}
@@ -87,12 +87,15 @@ static bool Yee_Compare(CompareArgs &arg
int main(int argc, char **argv)
{
- CompareArgs args;
+ args_t args;
- if (!args.Parse_Args(argc, argv)) {
+ args_init (&args);
+
+ if (!args_parse (&args, argc, argv)) {
return -1;
} else {
- if (args.Verbose) args.Print_Args();
+ if (args.Verbose)
+ args_print (&args);
}
- return ! Yee_Compare(args);
+ return ! Yee_Compare(&args);
}
diff --git a/test/pdiff/args.cpp b/test/pdiff/args.cpp
new file mode 100644
index 0000000..9fbe23e
--- /dev/null
+++ b/test/pdiff/args.cpp
@@ -0,0 +1,118 @@
+/*
+ Comapre Args
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "args.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char* copyright =
+"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
+PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
+This is free software, and you are welcome\n\
+to redistribute it under certain conditions;\n\
+See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n";
+
+static const char *usage =
+"PeceptualDiff image1.tif image2.tif\n\n\
+ Compares image1.tif and image2.tif using a perceptually based image metric\n\
+ Options:\n\
+\t-verbose : Turns on verbose mode\n\
+\t-fov deg : Field of view in degrees (0.1 to 89.9)\n\
+\t-threshold p : #pixels p below which differences are ignored\n\
+\t-gamma g : Value to convert rgb into linear space (default 2.2)\n\
+\t-luminance l : White luminance (default 100.0 cdm^-2)\n\
+\n\
+\n Note: Input files can also be in the PNG format\
+\n";
+
+void
+args_init (args_t *args)
+{
+ args->surface_a = NULL;
+ args->surface_b = NULL;
+ args->Verbose = false;
+ args->FieldOfView = 45.0f;
+ args->Gamma = 2.2f;
+ args->ThresholdPixels = 100;
+ args->Luminance = 100.0f;
+}
+
+void
+args_fini (args_t *args)
+{
+ cairo_surface_destroy (args->surface_a);
+ cairo_surface_destroy (args->surface_b);
+}
+
+bool
+args_parse (args_t *args, int argc, char **argv)
+{
+ if (argc < 3) {
+ fprintf (stderr, "%s", copyright);
+ fprintf (stderr, "%s", usage);
+ return false;
+ }
+ for (int i = 0; i < argc; i++) {
+ if (i == 1) {
+ args->surface_a = cairo_image_surface_create_from_png (argv[1]);
+ if (cairo_surface_status (args->surface_a))
+ {
+ fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+ argv[1], cairo_status_to_string (cairo_surface_status (args->surface_a)));
+ return false;
+ }
+ } else if (i == 2) {
+ args->surface_b = cairo_image_surface_create_from_png (argv[2]);
+ if (cairo_surface_status (args->surface_b))
+ {
+ fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+ argv[2], cairo_status_to_string (cairo_surface_status (args->surface_b)));
+ return false;
+ }
+ } else {
+ if (strstr(argv[i], "-fov")) {
+ if (i + 1 < argc) {
+ args->FieldOfView = (float) atof(argv[i + 1]);
+ }
+ } else if (strstr(argv[i], "-verbose")) {
+ args->Verbose = true;
+ } else if (strstr(argv[i], "-threshold")) {
+ if (i + 1 < argc) {
+ args->ThresholdPixels = atoi(argv[i + 1]);
+ }
+ } else if (strstr(argv[i], "-gamma")) {
+ if (i + 1 < argc) {
+ args->Gamma = (float) atof(argv[i + 1]);
+ }
+ }else if (strstr(argv[i], "-luminance")) {
+ if (i + 1 < argc) {
+ args->Luminance = (float) atof(argv[i + 1]);
+ }
+ }
+ }
+ } /* i */
+ return true;
+}
+
+void
+args_print (args_t *args)
+{
+ printf("Field of view is %f degrees\n", args->FieldOfView);
+ printf("Threshold pixels is %d pixels\n", args->ThresholdPixels);
+ printf("The Gamma is %f\n", args->Gamma);
+ printf("The Display's luminance is %f candela per meter squared\n", args->Luminance);
+}
diff --git a/test/pdiff/args.h b/test/pdiff/args.h
new file mode 100644
index 0000000..0197c90
--- /dev/null
+++ b/test/pdiff/args.h
@@ -0,0 +1,46 @@
+/*
+ Comapre Args
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _ARGS_H
+#define _ARGS_H
+
+#include <cairo.h>
+
+/* Args to pass into the comparison function */
+typedef struct _args
+{
+ cairo_surface_t *surface_a; /* Image A */
+ cairo_surface_t *surface_b; /* Image B */
+ bool Verbose; /* Print lots of text or not */
+ float FieldOfView; /* Field of view in degrees */
+ float Gamma; /* The gamma to convert to linear color space */
+ float Luminance; /* the display's luminance */
+ unsigned int ThresholdPixels; /* How many pixels different to ignore */
+} args_t;
+
+void
+args_init (args_t *args);
+
+void
+args_fini (args_t *args);
+
+bool
+args_parse (args_t *args, int argc, char **argv);
+
+void
+args_print (args_t *args);
+
+#endif
diff-tree 871aba6c80b8f3101eac51cc055ad9ca26770a95 (from 2174ee247554feef6a24792390d858b12fd44acd)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 03:16:18 2006 -0800
pdiff: Fix return value from perceptualdiff program
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 04b9e45..41aea79 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -94,6 +94,5 @@ int main(int argc, char **argv)
} else {
if (args.Verbose) args.Print_Args();
}
- int result = Yee_Compare(args) == true;
- return result;
+ return ! Yee_Compare(args);
}
diff-tree 2174ee247554feef6a24792390d858b12fd44acd (from 91b156b82e0219b2b851c218813f24024cad7c69)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 03:15:14 2006 -0800
pdiff: Remove all uses of std::string
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 265cfed..f33ba9f 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -57,8 +57,8 @@ CompareArgs::~CompareArgs()
bool CompareArgs::Parse_Args(int argc, char **argv)
{
if (argc < 3) {
- ErrorStr = copyright;
- ErrorStr += usage;
+ fprintf (stderr, "%s", copyright);
+ fprintf (stderr, "%s", usage);
return false;
}
for (int i = 0; i < argc; i++) {
@@ -66,22 +66,16 @@ bool CompareArgs::Parse_Args(int argc, c
surface_a = cairo_image_surface_create_from_png (argv[1]);
if (cairo_surface_status (surface_a))
{
- ErrorStr = "FAIL: Cannot open ";
- ErrorStr += argv[1];
- ErrorStr += " ";
- ErrorStr += cairo_status_to_string (cairo_surface_status (surface_a));
- ErrorStr += "\n";
+ fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+ argv[1], cairo_status_to_string (cairo_surface_status (surface_a)));
return false;
}
} else if (i == 2) {
surface_b = cairo_image_surface_create_from_png (argv[2]);
if (cairo_surface_status (surface_b))
{
- ErrorStr = "FAIL: Cannot open ";
- ErrorStr += argv[2];
- ErrorStr += " ";
- ErrorStr += cairo_status_to_string (cairo_surface_status (surface_b));
- ErrorStr += "\n";
+ fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+ argv[2], cairo_status_to_string (cairo_surface_status (surface_b)));
return false;
}
} else {
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index ac368d5..31cf059 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -36,7 +36,6 @@ public:
float Gamma; /* The gamma to convert to linear color space */
float Luminance; /* the display's luminance */
unsigned int ThresholdPixels; /* How many pixels different to ignore */
- std::string ErrorStr; /* Error string */
};
#endif
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 45ab7cb..04b9e45 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -32,6 +32,8 @@ static bool Yee_Compare(CompareArgs &arg
int width_b, height_b, stride_b;
unsigned char *data_b, *row_b;
uint32_t *pixel_b;
+ unsigned int x, y, dim, pixels_failed;
+ bool identical = true;
width_a = cairo_image_surface_get_width (args.surface_a);
height_a = cairo_image_surface_get_height (args.surface_a);
@@ -44,12 +46,11 @@ static bool Yee_Compare(CompareArgs &arg
data_b = cairo_image_surface_get_data (args.surface_b);
if ((width_a != width_b) || (height_a != height_b)) {
- args.ErrorStr = "Image dimensions do not match\n";
+ printf ("FAIL: Image dimensions do not match\n");
return false;
}
- unsigned int x, y, dim, pixels_failed;
- bool identical = true;
+ identical = true;
for (y = 0; y < height_a; y++) {
row_a = data_a + y * stride_a;
@@ -65,7 +66,7 @@ static bool Yee_Compare(CompareArgs &arg
}
}
if (identical) {
- args.ErrorStr = "Images are binary identical\n";
+ printf ("PASS: Images are binary identical\n");
return true;
}
@@ -74,15 +75,12 @@ static bool Yee_Compare(CompareArgs &arg
args.FieldOfView);
if (pixels_failed < args.ThresholdPixels) {
- args.ErrorStr = "Images are perceptually indistinguishable\n";
+ printf ("PASS: Images are perceptually indistinguishable\n");
return true;
}
- char different[100];
- sprintf(different, "%d pixels are different\n", pixels_failed);
-
- args.ErrorStr = "Images are visibly different\n";
- args.ErrorStr += different;
+ printf("FAIL: Images are visibly different\n"
+ "%d pixels are different\n", pixels_failed);
return false;
}
@@ -92,16 +90,10 @@ int main(int argc, char **argv)
CompareArgs args;
if (!args.Parse_Args(argc, argv)) {
- printf("%s", args.ErrorStr.c_str());
return -1;
} else {
if (args.Verbose) args.Print_Args();
}
int result = Yee_Compare(args) == true;
- if (result) {
- printf("PASS: %s\n", args.ErrorStr.c_str());
- } else {
- printf("FAIL: %s\n", args.ErrorStr.c_str());
- }
return result;
}
diff-tree 91b156b82e0219b2b851c218813f24024cad7c69 (from 4c812c38e4ec9885b9451185127e5c8877354d75)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 03:02:48 2006 -0800
pdiff: Remove RGBAImage classes now that we're just using cairo image surfaces
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 38ff1f6..265cfed 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -15,7 +15,6 @@
*/
#include "CompareArgs.h"
-#include "RGBAImage.h"
#include <stdio.h>
static const char* copyright =
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index ca51bf0..ac368d5 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -20,9 +20,6 @@
#include <string>
#include <cairo.h>
-class RGBAImage;
-class RGBACairoImage;
-
/* Args to pass into the comparison function */
class CompareArgs
{
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 67d13fb..4d46238 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -5,9 +5,7 @@ libpdiff_la_SOURCES = \
pdiff.h \
lpyramid.c \
lpyramid.h \
- pdiff.cpp \
- RGBAImage.cpp \
- RGBAImage.h
+ pdiff.cpp
perceptualdiff_SOURCES = \
CompareArgs.cpp \
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index eb89fbf..45ab7cb 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -21,7 +21,6 @@
#include <math.h>
#include <string>
#include "lpyramid.h"
-#include "RGBAImage.h"
#include "CompareArgs.h"
#include "pdiff.h"
diff --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp
deleted file mode 100644
index 2c38f9c..0000000
--- a/test/pdiff/RGBAImage.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- RGBAImage.cpp
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "RGBAImage.h"
-#include "png.h"
-
-#if HAVE_LIBTIFF
-#include "tiff.h"
-#include "tiffio.h"
-
-/* Reads Tiff Images */
-RGBAImage* RGBAImage::ReadTiff(char *filename)
-{
- RGBAImage *fimg = 0;
-
- TIFF* tif = TIFFOpen(filename, "r");
- char emsg[1024];
- emsg[0] = 0;
- if (tif) {
- TIFFRGBAImage img;
-
- if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
- size_t npixels;
- uint32* raster;
-
- npixels = img.width * img.height;
- raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
- if (raster != NULL) {
- if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
- /* result is in ABGR */
- fimg = new RGBAImage(img.width, img.height);
- for (int y = img.height - 1; y >= 0; y--) {
- for (int x = 0; x < (int) img.width; x++) {
- fimg->Set(x,img.height - (y+1), raster[x + y * img.width]);
- }
- }
- }
- _TIFFfree(raster);
- }
- }
- TIFFRGBAImageEnd(&img);
- }
- return fimg;
-}
-#endif /* HAVE_LIBTIFF */
-
-/* This portion was written by Scott Corley */
-RGBAImage* RGBAImage::ReadPNG(char *filename)
-{
- RGBAImage *fimg = 0;
- FILE *fp=fopen(filename, "rb");
- if (!fp)
- {
- return NULL;
- }
- png_byte header[8];
-
- fread(header, 1, 8, fp);
- bool is_png = !png_sig_cmp(header, 0, 8);
- if (!is_png)
- {
- return NULL;
- }
-
- png_structp png_ptr = png_create_read_struct
- (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
- NULL, NULL);
- if (!png_ptr)
- return (NULL);
-
- png_infop info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr)
- {
- png_destroy_read_struct(&png_ptr,
- (png_infopp)NULL, (png_infopp)NULL);
- return (NULL);
- }
-
- png_infop end_info = png_create_info_struct(png_ptr);
- if (!end_info)
- {
- png_destroy_read_struct(&png_ptr, &info_ptr,
- (png_infopp)NULL);
- return (NULL);
- }
-
- png_init_io(png_ptr, fp);
- png_set_sig_bytes(png_ptr, 8);
-
- png_read_png(png_ptr, info_ptr, 0, NULL);
-
- png_bytep *row_pointers;
- row_pointers = png_get_rows(png_ptr, info_ptr);
-
- fimg = new RGBAImage(png_ptr->width, png_ptr->height);
- for (int y = 0; y < (int) png_ptr->height; y++) {
- for (int x = 0; x < (int) png_ptr->width; x++) {
- uint32_t value = 0;
- if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
- value = ((uint32_t)row_pointers[y][x*4]) | (((uint32_t)row_pointers[y][x*4+1])<<8) | (((uint32_t)row_pointers[y][x*4+2])<<16) |(((uint32_t)row_pointers[y][x*4+3])<<24);
- else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
- value = ((uint32_t)row_pointers[y][x*3] /*B*/) | (((uint32_t)row_pointers[y][x*3+1] /*G*/)<<8) | (((uint32_t)row_pointers[y][x*3+2]/*R*/)<<16) | (0xFFUL << 24);
- fimg->Set(x,y, value);
- }
- }
-
- png_read_destroy(png_ptr, info_ptr, end_info);
- return fimg;
-}
-
-bool RGBAImage::WritePPM()
-{
- if (Width <= 0) return false;
- if (Height <=0 ) return false;
- FILE *out = fopen(Name.c_str(), "wb");
- if (!out) return false;
- fprintf(out, "P6\n%d %d 255\n", Width, Height);
- for (int y = 0; y < Height; y++) {
- for (int x = 0; x < Width; x++) {
- int i = x + y * Width;
- unsigned char r = Get_Red(i);
- unsigned char g = Get_Green(i);
- unsigned char b = Get_Blue(i);
- fwrite(&r, 1, 1, out);
- fwrite(&g, 1, 1, out);
- fwrite(&b, 1, 1, out);
- }
- }
- fclose(out);
- return true;
-}
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
deleted file mode 100644
index 710cabe..0000000
--- a/test/pdiff/RGBAImage.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- RGBAImage.h
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _RGBAIMAGE_H
-#define _RGBAIMAGE_H
-
-#include<string>
-#include<cairo.h>
-
-/* assumes data is in the ABGR format */
-class RGBAImage
-{
-public:
- RGBAImage() { Width = 0; Height = 0; Data = 0; }
- RGBAImage(int w, int h, const char *name = 0)
- {
- Width = w;
- Height = h;
- if (name) Name = name;
- Data = new unsigned int[w * h];
- };
- ~RGBAImage() { if (Data) delete[] Data; }
- virtual unsigned char Get_Red(unsigned int i) { return (Data[i] & 0xFF); }
- virtual unsigned char Get_Green(unsigned int i) { return ((Data[i]>>8) & 0xFF); }
- virtual unsigned char Get_Blue(unsigned int i) { return ((Data[i]>>16) & 0xFF); }
- virtual unsigned char Get_Alpha(unsigned int i) { return ((Data[i]>>24) & 0xFF); }
- virtual void Set(unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned int i)
- { Data[i] = r | (g << 8) | (b << 16) | (a << 24); }
- int Get_Width(void) const { return Width; }
- int Get_Height(void) const { return Height; }
- virtual void Set(int x, int y, unsigned int d) { Data[x + y * Width] = d; }
- virtual unsigned int Get(int x, int y) const { return Data[x + y * Width]; }
- virtual unsigned int Get(int i) const { return Data[i]; }
- const std::string &Get_Name(void) const { return Name; }
-
- bool WritePPM();
- static RGBAImage* ReadTiff(char *filename);
- static RGBAImage* ReadPNG(char *filename);
-protected:
- int Width;
- int Height;
- std::string Name;
- unsigned int *Data;
-};
-
-class RGBACairoImage : public RGBAImage
-{
-public:
- RGBACairoImage (cairo_surface_t *surface)
- {
- Width = cairo_image_surface_get_width (surface);
- Height = cairo_image_surface_get_height (surface);
- Data = (unsigned int *) cairo_image_surface_get_data (surface);
- if (cairo_image_surface_get_stride (surface) != 4 * Width) {
- fprintf (stderr, "Error: Currently only support images where stride == 4 * width\n");
- exit (1);
- }
- }
- ~RGBACairoImage() { }
-
- unsigned int ARGB_to_ABGR(unsigned int pixel) const {
- unsigned int new_pixel;
- new_pixel = pixel & 0xff00ff00;
- new_pixel |= (pixel & 0x00ff0000) >> 16;
- new_pixel |= (pixel & 0x000000ff) << 16;
- return new_pixel;
- }
- unsigned int Get_Unpremultiply(unsigned int i) const {
- uint32_t pixel;
- uint8_t alpha;
-
- pixel = Data[i];
-
- alpha = (pixel & 0xff000000) >> 24;
-
- if (alpha == 0)
- return 0;
-
- return (alpha << 24) |
- ((((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha) << 16 |
- ((((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha) << 8 |
- ((((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha) << 0;
- }
- unsigned char Get_Alpha(unsigned int i) { return (Get_Unpremultiply(i) & 0xff000000) >> 24;}
- unsigned char Get_Red(unsigned int i) { return (Get_Unpremultiply(i) & 0x00ff0000) >> 16;}
- unsigned char Get_Green(unsigned int i) { return (Get_Unpremultiply(i) & 0x0000ff00) >> 8;}
- unsigned char Get_Blue(unsigned int i) { return (Get_Unpremultiply(i) & 0x000000ff) >> 0;}
- unsigned int Get(int x, int y) const { return Get(Width * y + x); }
- unsigned int Get(int i) const { return ARGB_to_ABGR(Get_Unpremultiply(i)); }
-};
-
-#endif
diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
index ad8dd72..1609cda 100644
--- a/test/pdiff/pdiff.cpp
+++ b/test/pdiff/pdiff.cpp
@@ -14,10 +14,9 @@
if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "CompareArgs.h"
-#include "RGBAImage.h"
#include "lpyramid.h"
#include <math.h>
+#include <stdint.h>
#include "pdiff.h"
#ifndef M_PI
@@ -128,6 +127,63 @@ XYZToLAB (float x, float y, float z, flo
*B = 200.0f * (f[1] - f[2]);
}
+static uint32_t
+_get_pixel (cairo_surface_t *surface, int i)
+{
+ uint32_t *data;
+
+ data = (uint32_t *) cairo_image_surface_get_data (surface);
+ return data[i];
+}
+
+static unsigned char
+_get_red (cairo_surface_t *surface, int i)
+{
+ uint32_t pixel;
+ uint8_t alpha;
+
+ pixel = _get_pixel (surface, i);
+
+ alpha = (pixel & 0xff000000) >> 24;
+
+ if (alpha == 0)
+ return 0;
+ else
+ return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
+}
+
+static unsigned char
+_get_green (cairo_surface_t *surface, int i)
+{
+ uint32_t pixel;
+ uint8_t alpha;
+
+ pixel = _get_pixel (surface, i);
+
+ alpha = (pixel & 0xff000000) >> 24;
+
+ if (alpha == 0)
+ return 0;
+ else
+ return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
+}
+
+static unsigned char
+_get_blue (cairo_surface_t *surface, int i)
+{
+ uint32_t pixel;
+ uint8_t alpha;
+
+ pixel = _get_pixel (surface, i);
+
+ alpha = (pixel & 0xff000000) >> 24;
+
+ if (alpha == 0)
+ return 0;
+ else
+ return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
+}
+
int
pdiff_compare (cairo_surface_t *surface_a,
cairo_surface_t *surface_b,
@@ -135,7 +191,6 @@ pdiff_compare (cairo_surface_t *surface_
double luminance,
double field_of_view)
{
- RGBAImage *image_a, *image_b;
unsigned int dim = (cairo_image_surface_get_width (surface_a)
* cairo_image_surface_get_height (surface_a));
unsigned int i;
@@ -168,24 +223,21 @@ pdiff_compare (cairo_surface_t *surface_
unsigned int pixels_failed;
- image_a = new RGBACairoImage (surface_a);
- image_b = new RGBACairoImage (surface_b);
-
- w = image_a->Get_Width();
- h = image_a->Get_Height();
+ w = cairo_image_surface_get_width (surface_a);
+ h = cairo_image_surface_get_height (surface_a);
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
float r, g, b, l;
i = x + y * w;
- r = powf(image_a->Get_Red(i) / 255.0f, gamma);
- g = powf(image_a->Get_Green(i) / 255.0f, gamma);
- b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
+ r = powf(_get_red (surface_a, i) / 255.0f, gamma);
+ g = powf(_get_green (surface_a, i) / 255.0f, gamma);
+ b = powf(_get_blue (surface_a, i) / 255.0f, gamma);
AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
- r = powf(image_b->Get_Red(i) / 255.0f, gamma);
- g = powf(image_b->Get_Green(i) / 255.0f, gamma);
- b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
+ r = powf(_get_red (surface_b, i) / 255.0f, gamma);
+ g = powf(_get_green (surface_b, i) / 255.0f, gamma);
+ b = powf(_get_blue (surface_b, i) / 255.0f, gamma);
AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
diff --git a/test/pdiff/pdiff.h b/test/pdiff/pdiff.h
index 195a34c..d20ae86 100644
--- a/test/pdiff/pdiff.h
+++ b/test/pdiff/pdiff.h
@@ -21,6 +21,8 @@
extern "C" {
#endif
+#include <cairo.h>
+
/* Image comparison metric using Yee's method (and a cairo interface)
* References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
*/
diff-tree 4c812c38e4ec9885b9451185127e5c8877354d75 (from 2457756afd66b69840640eff3aaf72e7ea0f64e8)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 02:10:35 2006 -0800
pdiff: Remove hideous C++ reference passing
diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
index 2c11cc6..ad8dd72 100644
--- a/test/pdiff/pdiff.cpp
+++ b/test/pdiff/pdiff.cpp
@@ -89,16 +89,16 @@ mask (float contrast)
/* convert Adobe RGB (1998) with reference white D65 to XYZ */
static void
-AdobeRGBToXYZ (float r, float g, float b, float &x, float &y, float &z)
+AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z)
{
/* matrix is from http://www.brucelindbloom.com/ */
- x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
- y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
- z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
+ *x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
+ *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
+ *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
}
static void
-XYZToLAB (float x, float y, float z, float &L, float &A, float &B)
+XYZToLAB (float x, float y, float z, float *L, float *A, float *B)
{
static float xw = -1;
static float yw;
@@ -111,7 +111,7 @@ XYZToLAB (float x, float y, float z, flo
/* reference white */
if (xw < 0) {
- AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
+ AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw);
}
r[0] = x / xw;
r[1] = y / yw;
@@ -123,9 +123,9 @@ XYZToLAB (float x, float y, float z, flo
f[i] = (kappa * r[i] + 16.0f) / 116.0f;
}
}
- L = 116.0f * f[1] - 16.0f;
- A = 500.0f * (f[0] - f[1]);
- B = 200.0f * (f[1] - f[2]);
+ *L = 116.0f * f[1] - 16.0f;
+ *A = 500.0f * (f[0] - f[1]);
+ *B = 200.0f * (f[1] - f[2]);
}
int
@@ -181,14 +181,14 @@ pdiff_compare (cairo_surface_t *surface_
g = powf(image_a->Get_Green(i) / 255.0f, gamma);
b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
- AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]);
- XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]);
+ AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
+ XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
r = powf(image_b->Get_Red(i) / 255.0f, gamma);
g = powf(image_b->Get_Green(i) / 255.0f, gamma);
b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
- AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]);
- XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]);
+ AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
+ XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
aLum[i] = aY[i] * luminance;
bLum[i] = bY[i] * luminance;
}
diff-tree 2457756afd66b69840640eff3aaf72e7ea0f64e8 (from e947f5a4bdf4a4134faa8961406a10f32cf4e2d6)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 02:08:30 2006 -0800
pdiff: Remove intermingled statements and declarations
diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
index 12b055b..2c11cc6 100644
--- a/test/pdiff/pdiff.cpp
+++ b/test/pdiff/pdiff.cpp
@@ -36,7 +36,6 @@ tvi (float adaptation_luminance)
/* returns the threshold luminance given the adaptation luminance
units are candelas per meter squared
*/
-
float log_a, r, result;
log_a = log10f(adaptation_luminance);
@@ -55,7 +54,6 @@ tvi (float adaptation_luminance)
result = powf(10.0f , r);
return result;
-
}
/* computes the contrast sensitivity function (Barten SPIE 1989)
@@ -105,18 +103,20 @@ XYZToLAB (float x, float y, float z, flo
static float xw = -1;
static float yw;
static float zw;
- /* reference white */
- if (xw < 0) {
- AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
- }
const float epsilon = 216.0f / 24389.0f;
const float kappa = 24389.0f / 27.0f;
float f[3];
float r[3];
+ int i;
+
+ /* reference white */
+ if (xw < 0) {
+ AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
+ }
r[0] = x / xw;
r[1] = y / yw;
r[2] = z / zw;
- for (int i = 0; i < 3; i++) {
+ for (i = 0; i < 3; i++) {
if (r[i] > epsilon) {
f[i] = powf(r[i], 1.0f / 3.0f);
} else {
@@ -136,12 +136,9 @@ pdiff_compare (cairo_surface_t *surface_
double field_of_view)
{
RGBAImage *image_a, *image_b;
- unsigned int i, dim;
-
- image_a = new RGBACairoImage (surface_a);
- image_b = new RGBACairoImage (surface_b);
-
- dim = image_a->Get_Width() * image_a->Get_Height();
+ unsigned int dim = (cairo_image_surface_get_width (surface_a)
+ * cairo_image_surface_get_height (surface_a));
+ unsigned int i;
/* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
float *aX = new float[dim];
@@ -159,6 +156,21 @@ pdiff_compare (cairo_surface_t *surface_
float *bB = new float[dim];
unsigned int x, y, w, h;
+
+ lpyramid_t *la, *lb;
+
+ float num_one_degree_pixels, pixels_per_degree, num_pixels;
+ unsigned int adaptation_level;
+
+ float cpd[MAX_PYR_LEVELS];
+ float F_freq[MAX_PYR_LEVELS - 2];
+ float csf_max;
+
+ unsigned int pixels_failed;
+
+ image_a = new RGBACairoImage (surface_a);
+ image_b = new RGBACairoImage (surface_b);
+
w = image_a->Get_Width();
h = image_a->Get_Height();
for (y = 0; y < h; y++) {
@@ -182,33 +194,35 @@ pdiff_compare (cairo_surface_t *surface_
}
}
- lpyramid_t *la = lpyramid_create (aLum, w, h);
- lpyramid_t *lb = lpyramid_create (bLum, w, h);
+ la = lpyramid_create (aLum, w, h);
+ lb = lpyramid_create (bLum, w, h);
- float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
- float pixels_per_degree = w / num_one_degree_pixels;
+ num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
+ pixels_per_degree = w / num_one_degree_pixels;
- float num_pixels = 1;
- unsigned int adaptation_level = 0;
+ num_pixels = 1;
+ adaptation_level = 0;
for (i = 0; i < MAX_PYR_LEVELS; i++) {
adaptation_level = i;
if (num_pixels > num_one_degree_pixels) break;
num_pixels *= 2;
}
- float cpd[MAX_PYR_LEVELS];
cpd[0] = 0.5f * pixels_per_degree;
for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
- float csf_max = csf(3.248f, 100.0f);
+ csf_max = csf(3.248f, 100.0f);
- float F_freq[MAX_PYR_LEVELS - 2];
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
- unsigned int pixels_failed = 0;
+ pixels_failed = 0;
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
int index = x + y * w;
float contrast[MAX_PYR_LEVELS - 2];
+ float F_mask[MAX_PYR_LEVELS - 2];
+ float factor;
+ float delta;
+ bool pass;
float sum_contrast = 0;
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
@@ -222,37 +236,37 @@ pdiff_compare (cairo_surface_t *surface_
sum_contrast += contrast[i];
}
if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
- float F_mask[MAX_PYR_LEVELS - 2];
float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
adapt *= 0.5f;
if (adapt < 1e-5) adapt = 1e-5f;
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
}
- float factor = 0;
+ factor = 0;
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
}
if (factor < 1) factor = 1;
if (factor > 10) factor = 10;
- float delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
- bool pass = true;
+ delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
+ pass = true;
/* pure luminance test */
if (delta > factor * tvi(adapt)) {
pass = false;
} else {
/* CIE delta E test with modifications */
float color_scale = 1.0f;
+ float da = aA[index] - bA[index];
+ float db = aB[index] - bB[index];
+ float delta_e;
/* ramp down the color test in scotopic regions */
if (adapt < 10.0f) {
color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
color_scale = color_scale * color_scale;
}
- float da = aA[index] - bA[index];
- float db = aB[index] - bB[index];
da = da * da;
db = db * db;
- float delta_e = (da + db) * color_scale;
+ delta_e = (da + db) * color_scale;
if (delta_e > factor) {
pass = false;
}
diff-tree e947f5a4bdf4a4134faa8961406a10f32cf4e2d6 (from bb4d4dc77117ded253d1f507e771de7f98c69fb8)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 01:09:05 2006 -0800
pdiff: Add .gitignore for perceptualdiff binary
diff --git a/test/pdiff/.gitignore b/test/pdiff/.gitignore
new file mode 100644
index 0000000..d2e5a94
--- /dev/null
+++ b/test/pdiff/.gitignore
@@ -0,0 +1 @@
+perceptualdiff
diff-tree bb4d4dc77117ded253d1f507e771de7f98c69fb8 (from 53c3a2f75b7f065b4c769ad087bbc9aaaaf6d7ee)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 01:06:42 2006 -0800
pdiff: Remove old, unused Yee_Compare interface
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 5dd4003..67d13fb 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -5,7 +5,7 @@ libpdiff_la_SOURCES = \
pdiff.h \
lpyramid.c \
lpyramid.h \
- Metric.cpp \
+ pdiff.cpp \
RGBAImage.cpp \
RGBAImage.h
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
deleted file mode 100644
index d9e56ac..0000000
--- a/test/pdiff/Metric.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- Metric
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "CompareArgs.h"
-#include "RGBAImage.h"
-#include "lpyramid.h"
-#include <math.h>
-#include "pdiff.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265f
-#endif
-
-/*
- * Given the adaptation luminance, this function returns the
- * threshold of visibility in cd per m^2
- * TVI means Threshold vs Intensity function
- * This version comes from Ward Larson Siggraph 1997
- */
-
-float tvi(float adaptation_luminance)
-{
- /* returns the threshold luminance given the adaptation luminance
- units are candelas per meter squared
- */
-
- float log_a, r, result;
- log_a = log10f(adaptation_luminance);
-
- if (log_a < -3.94f) {
- r = -2.86f;
- } else if (log_a < -1.44f) {
- r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
- } else if (log_a < -0.0184f) {
- r = log_a - 0.395f;
- } else if (log_a < 1.9f) {
- r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
- } else {
- r = log_a - 1.255f;
- }
-
- result = powf(10.0f , r);
-
- return result;
-
-}
-
-/* computes the contrast sensitivity function (Barten SPIE 1989)
- * given the cycles per degree (cpd) and luminance (lum)
- */
-float csf(float cpd, float lum)
-{
- float a, b, result;
-
- a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
- b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
-
- result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
-
- return result;
-}
-
-/*
- * Visual Masking Function
- * from Daly 1993
- */
-float mask(float contrast)
-{
- float a, b, result;
- a = powf(392.498f * contrast, 0.7f);
- b = powf(0.0153f * a, 4.0f);
- result = powf(1.0f + b, 0.25f);
-
- return result;
-}
-
-/* convert Adobe RGB (1998) with reference white D65 to XYZ */
-void AdobeRGBToXYZ(float r, float g, float b, float &x, float &y, float &z)
-{
- /* matrix is from http://www.brucelindbloom.com/ */
- x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
- y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
- z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
-}
-
-void XYZToLAB(float x, float y, float z, float &L, float &A, float &B)
-{
- static float xw = -1;
- static float yw;
- static float zw;
- /* reference white */
- if (xw < 0) {
- AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
- }
- const float epsilon = 216.0f / 24389.0f;
- const float kappa = 24389.0f / 27.0f;
- float f[3];
- float r[3];
- r[0] = x / xw;
- r[1] = y / yw;
- r[2] = z / zw;
- for (int i = 0; i < 3; i++) {
- if (r[i] > epsilon) {
- f[i] = powf(r[i], 1.0f / 3.0f);
- } else {
- f[i] = (kappa * r[i] + 16.0f) / 116.0f;
- }
- }
- L = 116.0f * f[1] - 16.0f;
- A = 500.0f * (f[0] - f[1]);
- B = 200.0f * (f[1] - f[2]);
-}
-
-int Yee_Compare_Images(RGBAImage *image_a,
- RGBAImage *image_b,
- float gamma,
- float luminance,
- float field_of_view,
- bool verbose)
-{
- unsigned int i, dim;
- dim = image_a->Get_Width() * image_a->Get_Height();
-
- /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
- float *aX = new float[dim];
- float *aY = new float[dim];
- float *aZ = new float[dim];
- float *bX = new float[dim];
- float *bY = new float[dim];
- float *bZ = new float[dim];
- float *aLum = new float[dim];
- float *bLum = new float[dim];
-
- float *aA = new float[dim];
- float *bA = new float[dim];
- float *aB = new float[dim];
- float *bB = new float[dim];
-
- if (verbose) printf("Converting RGB to XYZ\n");
-
- unsigned int x, y, w, h;
- w = image_a->Get_Width();
- h = image_a->Get_Height();
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- float r, g, b, l;
- i = x + y * w;
- r = powf(image_a->Get_Red(i) / 255.0f, gamma);
- g = powf(image_a->Get_Green(i) / 255.0f, gamma);
- b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
-
- AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]);
- XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]);
- r = powf(image_b->Get_Red(i) / 255.0f, gamma);
- g = powf(image_b->Get_Green(i) / 255.0f, gamma);
- b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
-
- AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]);
- XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]);
- aLum[i] = aY[i] * luminance;
- bLum[i] = bY[i] * luminance;
- }
- }
-
- if (verbose) printf("Constructing Laplacian Pyramids\n");
-
- lpyramid_t *la = lpyramid_create (aLum, w, h);
- lpyramid_t *lb = lpyramid_create (bLum, w, h);
-
- float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
- float pixels_per_degree = w / num_one_degree_pixels;
-
- if (verbose) printf("Performing test\n");
-
- float num_pixels = 1;
- unsigned int adaptation_level = 0;
- for (i = 0; i < MAX_PYR_LEVELS; i++) {
- adaptation_level = i;
- if (num_pixels > num_one_degree_pixels) break;
- num_pixels *= 2;
- }
-
- float cpd[MAX_PYR_LEVELS];
- cpd[0] = 0.5f * pixels_per_degree;
- for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
- float csf_max = csf(3.248f, 100.0f);
-
- float F_freq[MAX_PYR_LEVELS - 2];
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
-
- unsigned int pixels_failed = 0;
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- int index = x + y * w;
- float contrast[MAX_PYR_LEVELS - 2];
- float sum_contrast = 0;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
- float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
- float numerator = (n1 > n2) ? n1 : n2;
- float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
- float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
- float denominator = (d1 > d2) ? d1 : d2;
- if (denominator < 1e-5f) denominator = 1e-5f;
- contrast[i] = numerator / denominator;
- sum_contrast += contrast[i];
- }
- if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
- float F_mask[MAX_PYR_LEVELS - 2];
- float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
- adapt *= 0.5f;
- if (adapt < 1e-5) adapt = 1e-5f;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
- }
- float factor = 0;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
- }
- if (factor < 1) factor = 1;
- if (factor > 10) factor = 10;
- float delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
- bool pass = true;
- /* pure luminance test */
- if (delta > factor * tvi(adapt)) {
- pass = false;
- } else {
- /* CIE delta E test with modifications */
- float color_scale = 1.0f;
- /* ramp down the color test in scotopic regions */
- if (adapt < 10.0f) {
- color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
- color_scale = color_scale * color_scale;
- }
- float da = aA[index] - bA[index];
- float db = aB[index] - bB[index];
- da = da * da;
- db = db * db;
- float delta_e = (da + db) * color_scale;
- if (delta_e > factor) {
- pass = false;
- }
- }
- if (!pass)
- pixels_failed++;
- }
- }
-
- if (aX) delete[] aX;
- if (aY) delete[] aY;
- if (aZ) delete[] aZ;
- if (bX) delete[] bX;
- if (bY) delete[] bY;
- if (bZ) delete[] bZ;
- if (aLum) delete[] aLum;
- if (bLum) delete[] bLum;
- lpyramid_destroy (la);
- lpyramid_destroy (lb);
- if (aA) delete aA;
- if (bA) delete bA;
- if (aB) delete aB;
- if (bB) delete bB;
-
- return pixels_failed;
-}
-
-int
-pdiff_compare (cairo_surface_t *surface_a,
- cairo_surface_t *surface_b,
- double gamma,
- double luminance,
- double field_of_view)
-{
- RGBAImage *image_a, *image_b;
-
- image_a = new RGBACairoImage (surface_a);
- image_b = new RGBACairoImage (surface_b);
-
- return Yee_Compare_Images (image_a, image_b,
- gamma, luminance,
- field_of_view, false);
-}
diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
new file mode 100644
index 0000000..12b055b
--- /dev/null
+++ b/test/pdiff/pdiff.cpp
@@ -0,0 +1,281 @@
+/*
+ Metric
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "CompareArgs.h"
+#include "RGBAImage.h"
+#include "lpyramid.h"
+#include <math.h>
+#include "pdiff.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265f
+#endif
+
+/*
+ * Given the adaptation luminance, this function returns the
+ * threshold of visibility in cd per m^2
+ * TVI means Threshold vs Intensity function
+ * This version comes from Ward Larson Siggraph 1997
+ */
+static float
+tvi (float adaptation_luminance)
+{
+ /* returns the threshold luminance given the adaptation luminance
+ units are candelas per meter squared
+ */
+
+ float log_a, r, result;
+ log_a = log10f(adaptation_luminance);
+
+ if (log_a < -3.94f) {
+ r = -2.86f;
+ } else if (log_a < -1.44f) {
+ r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
+ } else if (log_a < -0.0184f) {
+ r = log_a - 0.395f;
+ } else if (log_a < 1.9f) {
+ r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
+ } else {
+ r = log_a - 1.255f;
+ }
+
+ result = powf(10.0f , r);
+
+ return result;
+
+}
+
+/* computes the contrast sensitivity function (Barten SPIE 1989)
+ * given the cycles per degree (cpd) and luminance (lum)
+ */
+static float
+csf (float cpd, float lum)
+{
+ float a, b, result;
+
+ a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
+ b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
+
+ result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
+
+ return result;
+}
+
+/*
+ * Visual Masking Function
+ * from Daly 1993
+ */
+static float
+mask (float contrast)
+{
+ float a, b, result;
+ a = powf(392.498f * contrast, 0.7f);
+ b = powf(0.0153f * a, 4.0f);
+ result = powf(1.0f + b, 0.25f);
+
+ return result;
+}
+
+/* convert Adobe RGB (1998) with reference white D65 to XYZ */
+static void
+AdobeRGBToXYZ (float r, float g, float b, float &x, float &y, float &z)
+{
+ /* matrix is from http://www.brucelindbloom.com/ */
+ x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
+ y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
+ z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
+}
+
+static void
+XYZToLAB (float x, float y, float z, float &L, float &A, float &B)
+{
+ static float xw = -1;
+ static float yw;
+ static float zw;
+ /* reference white */
+ if (xw < 0) {
+ AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
+ }
+ const float epsilon = 216.0f / 24389.0f;
+ const float kappa = 24389.0f / 27.0f;
+ float f[3];
+ float r[3];
+ r[0] = x / xw;
+ r[1] = y / yw;
+ r[2] = z / zw;
+ for (int i = 0; i < 3; i++) {
+ if (r[i] > epsilon) {
+ f[i] = powf(r[i], 1.0f / 3.0f);
+ } else {
+ f[i] = (kappa * r[i] + 16.0f) / 116.0f;
+ }
+ }
+ L = 116.0f * f[1] - 16.0f;
+ A = 500.0f * (f[0] - f[1]);
+ B = 200.0f * (f[1] - f[2]);
+}
+
+int
+pdiff_compare (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ double gamma,
+ double luminance,
+ double field_of_view)
+{
+ RGBAImage *image_a, *image_b;
+ unsigned int i, dim;
+
+ image_a = new RGBACairoImage (surface_a);
+ image_b = new RGBACairoImage (surface_b);
+
+ dim = image_a->Get_Width() * image_a->Get_Height();
+
+ /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
+ float *aX = new float[dim];
+ float *aY = new float[dim];
+ float *aZ = new float[dim];
+ float *bX = new float[dim];
+ float *bY = new float[dim];
+ float *bZ = new float[dim];
+ float *aLum = new float[dim];
+ float *bLum = new float[dim];
+
+ float *aA = new float[dim];
+ float *bA = new float[dim];
+ float *aB = new float[dim];
+ float *bB = new float[dim];
+
+ unsigned int x, y, w, h;
+ w = image_a->Get_Width();
+ h = image_a->Get_Height();
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ float r, g, b, l;
+ i = x + y * w;
+ r = powf(image_a->Get_Red(i) / 255.0f, gamma);
+ g = powf(image_a->Get_Green(i) / 255.0f, gamma);
+ b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
+
+ AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]);
+ XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]);
+ r = powf(image_b->Get_Red(i) / 255.0f, gamma);
+ g = powf(image_b->Get_Green(i) / 255.0f, gamma);
+ b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
+
+ AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]);
+ XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]);
+ aLum[i] = aY[i] * luminance;
+ bLum[i] = bY[i] * luminance;
+ }
+ }
+
+ lpyramid_t *la = lpyramid_create (aLum, w, h);
+ lpyramid_t *lb = lpyramid_create (bLum, w, h);
+
+ float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
+ float pixels_per_degree = w / num_one_degree_pixels;
+
+ float num_pixels = 1;
+ unsigned int adaptation_level = 0;
+ for (i = 0; i < MAX_PYR_LEVELS; i++) {
+ adaptation_level = i;
+ if (num_pixels > num_one_degree_pixels) break;
+ num_pixels *= 2;
+ }
+
+ float cpd[MAX_PYR_LEVELS];
+ cpd[0] = 0.5f * pixels_per_degree;
+ for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
+ float csf_max = csf(3.248f, 100.0f);
+
+ float F_freq[MAX_PYR_LEVELS - 2];
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
+
+ unsigned int pixels_failed = 0;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ int index = x + y * w;
+ float contrast[MAX_PYR_LEVELS - 2];
+ float sum_contrast = 0;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
+ float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
+ float numerator = (n1 > n2) ? n1 : n2;
+ float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
+ float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
+ float denominator = (d1 > d2) ? d1 : d2;
+ if (denominator < 1e-5f) denominator = 1e-5f;
+ contrast[i] = numerator / denominator;
+ sum_contrast += contrast[i];
+ }
+ if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
+ float F_mask[MAX_PYR_LEVELS - 2];
+ float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
+ adapt *= 0.5f;
+ if (adapt < 1e-5) adapt = 1e-5f;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
+ }
+ float factor = 0;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
+ }
+ if (factor < 1) factor = 1;
+ if (factor > 10) factor = 10;
+ float delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
+ bool pass = true;
+ /* pure luminance test */
+ if (delta > factor * tvi(adapt)) {
+ pass = false;
+ } else {
+ /* CIE delta E test with modifications */
+ float color_scale = 1.0f;
+ /* ramp down the color test in scotopic regions */
+ if (adapt < 10.0f) {
+ color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
+ color_scale = color_scale * color_scale;
+ }
+ float da = aA[index] - bA[index];
+ float db = aB[index] - bB[index];
+ da = da * da;
+ db = db * db;
+ float delta_e = (da + db) * color_scale;
+ if (delta_e > factor) {
+ pass = false;
+ }
+ }
+ if (!pass)
+ pixels_failed++;
+ }
+ }
+
+ if (aX) delete[] aX;
+ if (aY) delete[] aY;
+ if (aZ) delete[] aZ;
+ if (bX) delete[] bX;
+ if (bY) delete[] bY;
+ if (bZ) delete[] bZ;
+ if (aLum) delete[] aLum;
+ if (bLum) delete[] bLum;
+ lpyramid_destroy (la);
+ lpyramid_destroy (lb);
+ if (aA) delete aA;
+ if (bA) delete bA;
+ if (aB) delete aB;
+ if (bB) delete bB;
+
+ return pixels_failed;
+}
diff-tree 53c3a2f75b7f065b4c769ad087bbc9aaaaf6d7ee (from 358645d6eb68b4eaf79159e7aefa01bca4cb0acf)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 01:00:43 2006 -0800
pdiff: Rewrite main program to use cairo-based pdiff_compare interface
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 0f9cb0f..38ff1f6 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -40,8 +40,8 @@ static const char *usage =
CompareArgs::CompareArgs()
{
- ImgA = NULL;
- ImgB = NULL;
+ surface_a = NULL;
+ surface_b = NULL;
Verbose = false;
FieldOfView = 45.0f;
Gamma = 2.2f;
@@ -51,13 +51,12 @@ CompareArgs::CompareArgs()
CompareArgs::~CompareArgs()
{
- if (ImgA) delete ImgA;
- if (ImgB) delete ImgB;
+ cairo_surface_destroy (surface_a);
+ cairo_surface_destroy (surface_b);
}
bool CompareArgs::Parse_Args(int argc, char **argv)
{
- cairo_surface_t *surface;
if (argc < 3) {
ErrorStr = copyright;
ErrorStr += usage;
@@ -65,29 +64,27 @@ bool CompareArgs::Parse_Args(int argc, c
}
for (int i = 0; i < argc; i++) {
if (i == 1) {
- surface = cairo_image_surface_create_from_png (argv[1]);
- if (cairo_surface_status (surface))
+ surface_a = cairo_image_surface_create_from_png (argv[1]);
+ if (cairo_surface_status (surface_a))
{
ErrorStr = "FAIL: Cannot open ";
ErrorStr += argv[1];
ErrorStr += " ";
- ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+ ErrorStr += cairo_status_to_string (cairo_surface_status (surface_a));
ErrorStr += "\n";
return false;
}
- ImgA = new RGBACairoImage (surface);
} else if (i == 2) {
- surface = cairo_image_surface_create_from_png (argv[2]);
- if (cairo_surface_status (surface))
+ surface_b = cairo_image_surface_create_from_png (argv[2]);
+ if (cairo_surface_status (surface_b))
{
ErrorStr = "FAIL: Cannot open ";
ErrorStr += argv[2];
ErrorStr += " ";
- ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+ ErrorStr += cairo_status_to_string (cairo_surface_status (surface_b));
ErrorStr += "\n";
return false;
}
- ImgB = new RGBACairoImage (surface);
} else {
if (strstr(argv[i], "-fov")) {
if (i + 1 < argc) {
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index 1cab0da..ca51bf0 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -18,6 +18,7 @@
#define _COMPAREARGS_H
#include <string>
+#include <cairo.h>
class RGBAImage;
class RGBACairoImage;
@@ -31,8 +32,8 @@ public:
bool Parse_Args(int argc, char **argv);
void Print_Args();
- RGBAImage *ImgA; /* Image A */
- RGBAImage *ImgB; /* Image B */
+ cairo_surface_t *surface_a; /* Image A */
+ cairo_surface_t *surface_b; /* Image B */
bool Verbose; /* Print lots of text or not */
float FieldOfView; /* Field of view in degrees */
float Gamma; /* The gamma to convert to linear color space */
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 0179f05..5dd4003 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -6,7 +6,6 @@ libpdiff_la_SOURCES = \
lpyramid.c \
lpyramid.h \
Metric.cpp \
- Metric.h \
RGBAImage.cpp \
RGBAImage.h
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index 44a704d..d9e56ac 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -14,7 +14,6 @@
if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "Metric.h"
#include "CompareArgs.h"
#include "RGBAImage.h"
#include "lpyramid.h"
@@ -125,23 +124,6 @@ void XYZToLAB(float x, float y, float z,
B = 200.0f * (f[1] - f[2]);
}
-int
-pdiff_compare (cairo_surface_t *surface_a,
- cairo_surface_t *surface_b,
- double gamma,
- double luminance,
- double field_of_view)
-{
- RGBAImage *image_a, *image_b;
-
- image_a = new RGBACairoImage (surface_a);
- image_b = new RGBACairoImage (surface_b);
-
- return Yee_Compare_Images (image_a, image_b,
- gamma, luminance,
- field_of_view, false);
-}
-
int Yee_Compare_Images(RGBAImage *image_a,
RGBAImage *image_b,
float gamma,
@@ -294,3 +276,20 @@ int Yee_Compare_Images(RGBAImage *image_
return pixels_failed;
}
+
+int
+pdiff_compare (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ double gamma,
+ double luminance,
+ double field_of_view)
+{
+ RGBAImage *image_a, *image_b;
+
+ image_a = new RGBACairoImage (surface_a);
+ image_b = new RGBACairoImage (surface_b);
+
+ return Yee_Compare_Images (image_a, image_b,
+ gamma, luminance,
+ field_of_view, false);
+}
diff --git a/test/pdiff/Metric.h b/test/pdiff/Metric.h
deleted file mode 100644
index 8235a0e..0000000
--- a/test/pdiff/Metric.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-Metric
-Copyright (C) 2006 Yangli Hector Yee
-
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _METRIC_H
-#define _METRIC_H
-
-#include "RGBAImage.h"
-
-/* Image comparison metric using Yee's method
- * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
- */
-int Yee_Compare_Images(RGBAImage *image_a,
- RGBAImage *image_b,
- float gamma,
- float luminance,
- float field_of_view,
- bool verbose);
-
-#endif
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 3affa16..eb89fbf 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -23,23 +23,46 @@
#include "lpyramid.h"
#include "RGBAImage.h"
#include "CompareArgs.h"
-#include "Metric.h"
+#include "pdiff.h"
static bool Yee_Compare(CompareArgs &args)
{
- if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
- (args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
+ int width_a, height_a, stride_a;
+ unsigned char *data_a, *row_a;
+ uint32_t *pixel_a;
+ int width_b, height_b, stride_b;
+ unsigned char *data_b, *row_b;
+ uint32_t *pixel_b;
+
+ width_a = cairo_image_surface_get_width (args.surface_a);
+ height_a = cairo_image_surface_get_height (args.surface_a);
+ stride_a = cairo_image_surface_get_stride (args.surface_a);
+ data_a = cairo_image_surface_get_data (args.surface_a);
+
+ width_b = cairo_image_surface_get_width (args.surface_b);
+ height_b = cairo_image_surface_get_height (args.surface_b);
+ stride_b = cairo_image_surface_get_stride (args.surface_b);
+ data_b = cairo_image_surface_get_data (args.surface_b);
+
+ if ((width_a != width_b) || (height_a != height_b)) {
args.ErrorStr = "Image dimensions do not match\n";
return false;
}
- unsigned int i, dim, pixels_failed;
- dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
+ unsigned int x, y, dim, pixels_failed;
bool identical = true;
- for (i = 0; i < dim; i++) {
- if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
- identical = false;
- break;
+
+ for (y = 0; y < height_a; y++) {
+ row_a = data_a + y * stride_a;
+ row_b = data_b + y * stride_b;
+ pixel_a = (uint32_t *) row_a;
+ pixel_b = (uint32_t *) row_b;
+ for (x = 0; x < width_a; x++) {
+ if (*pixel_a != *pixel_b) {
+ identical = false;
+ }
+ pixel_a++;
+ pixel_b++;
}
}
if (identical) {
@@ -47,9 +70,9 @@ static bool Yee_Compare(CompareArgs &arg
return true;
}
- pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
- args.Gamma, args.Luminance,
- args.FieldOfView, args.Verbose);
+ pixels_failed = pdiff_compare (args.surface_a, args.surface_b,
+ args.Gamma, args.Luminance,
+ args.FieldOfView);
if (pixels_failed < args.ThresholdPixels) {
args.ErrorStr = "Images are perceptually indistinguishable\n";
diff-tree 358645d6eb68b4eaf79159e7aefa01bca4cb0acf (from 4438fb6dca1b4b6c0a30d66508339c3997ee94a4)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 00:42:52 2006 -0800
pdiff: Rip out unused ImgDiff code, (dropping -output option)
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 716f79e..0f9cb0f 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -34,7 +34,6 @@ static const char *usage =
\t-threshold p : #pixels p below which differences are ignored\n\
\t-gamma g : Value to convert rgb into linear space (default 2.2)\n\
\t-luminance l : White luminance (default 100.0 cdm^-2)\n\
-\t-output o.ppm : Write difference to the file o.ppm\n\
\n\
\n Note: Input files can also be in the PNG format\
\n";
@@ -43,7 +42,6 @@ CompareArgs::CompareArgs()
{
ImgA = NULL;
ImgB = NULL;
- ImgDiff = NULL;
Verbose = false;
FieldOfView = 45.0f;
Gamma = 2.2f;
@@ -55,7 +53,6 @@ CompareArgs::~CompareArgs()
{
if (ImgA) delete ImgA;
if (ImgB) delete ImgB;
- if (ImgDiff) delete ImgDiff;
}
bool CompareArgs::Parse_Args(int argc, char **argv)
@@ -110,10 +107,6 @@ bool CompareArgs::Parse_Args(int argc, c
if (i + 1 < argc) {
Luminance = (float) atof(argv[i + 1]);
}
- }else if (strstr(argv[i], "-output")) {
- if (i + 1 < argc) {
- ImgDiff = new RGBAImage(ImgA->Get_Width(), ImgA->Get_Height(), argv[i+1]);
- }
}
}
} /* i */
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index 85f0174..1cab0da 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -33,7 +33,6 @@ public:
RGBAImage *ImgA; /* Image A */
RGBAImage *ImgB; /* Image B */
- RGBAImage *ImgDiff; /* Diff image */
bool Verbose; /* Print lots of text or not */
float FieldOfView; /* Field of view in degrees */
float Gamma; /* The gamma to convert to linear color space */
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index c1a8b99..44a704d 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -274,17 +274,6 @@ int Yee_Compare_Images(RGBAImage *image_
}
if (!pass)
pixels_failed++;
-#if IMAGE_DIFF_ENABLED
- if (!pass) {
- if (args.ImgDiff) {
- args.ImgDiff->Set(255, 0, 0, 255, index);
- }
- } else {
- if (args.ImgDiff) {
- args.ImgDiff->Set(0, 0, 0, 255, index);
- }
- }
-#endif
}
}
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 6e098ed..3affa16 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -62,20 +62,6 @@ static bool Yee_Compare(CompareArgs &arg
args.ErrorStr = "Images are visibly different\n";
args.ErrorStr += different;
- if (args.ImgDiff) {
-#if IMAGE_DIFF_CODE_ENABLED
- if (args.ImgDiff->WritePPM()) {
- args.ErrorStr += "Wrote difference image to ";
- args.ErrorStr+= args.ImgDiff->Get_Name();
- args.ErrorStr += "\n";
- } else {
- args.ErrorStr += "Could not write difference image to ";
- args.ErrorStr+= args.ImgDiff->Get_Name();
- args.ErrorStr += "\n";
- }
-#endif
- args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
- }
return false;
}
diff --git a/test/pdiff/README.txt b/test/pdiff/README.txt
index a873f3c..922ddaf 100644
--- a/test/pdiff/README.txt
+++ b/test/pdiff/README.txt
@@ -36,10 +36,10 @@ a theatre has a field of view of around
-gamma g : The gamma to use to convert to RGB linear space. Default is 2.2
-luminance l: The luminance of the display the observer is seeing. Default
is 100 candela per meter squared
--output foo.ppm : Saves the difference image to foo.ppm
Credits
Hector Yee, project administrator and originator - hectorgon.blogspot.com
Scott Corley, for png file IO code
-Mick Weiss, Linux build and release & QA
\ No newline at end of file
+Mick Weiss, Linux build and release & QA
+Carl Worth, Rewrite as library, depend on cairo, and port to C
\ No newline at end of file
diff-tree 4438fb6dca1b4b6c0a30d66508339c3997ee94a4 (from c7379fcea478fbd3fc5e09a10828586e641e2375)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 00:38:39 2006 -0800
pdiff: Move function that depends on command-line argument class to same file as main
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index 5bb90ce..c1a8b99 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -125,67 +125,6 @@ void XYZToLAB(float x, float y, float z,
B = 200.0f * (f[1] - f[2]);
}
-int Yee_Compare_Images(RGBAImage *image_a,
- RGBAImage *image_b,
- float gamma,
- float luminance,
- float field_of_view,
- bool verbose);
-
-bool Yee_Compare(CompareArgs &args)
-{
- if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
- (args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
- args.ErrorStr = "Image dimensions do not match\n";
- return false;
- }
-
- unsigned int i, dim, pixels_failed;
- dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
- bool identical = true;
- for (i = 0; i < dim; i++) {
- if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
- identical = false;
- break;
- }
- }
- if (identical) {
- args.ErrorStr = "Images are binary identical\n";
- return true;
- }
-
- pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
- args.Gamma, args.Luminance,
- args.FieldOfView, args.Verbose);
-
- if (pixels_failed < args.ThresholdPixels) {
- args.ErrorStr = "Images are perceptually indistinguishable\n";
- return true;
- }
-
- char different[100];
- sprintf(different, "%d pixels are different\n", pixels_failed);
-
- args.ErrorStr = "Images are visibly different\n";
- args.ErrorStr += different;
-
- if (args.ImgDiff) {
-#if IMAGE_DIFF_CODE_ENABLED
- if (args.ImgDiff->WritePPM()) {
- args.ErrorStr += "Wrote difference image to ";
- args.ErrorStr+= args.ImgDiff->Get_Name();
- args.ErrorStr += "\n";
- } else {
- args.ErrorStr += "Could not write difference image to ";
- args.ErrorStr+= args.ImgDiff->Get_Name();
- args.ErrorStr += "\n";
- }
-#endif
- args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
- }
- return false;
-}
-
int
pdiff_compare (cairo_surface_t *surface_a,
cairo_surface_t *surface_b,
diff --git a/test/pdiff/Metric.h b/test/pdiff/Metric.h
index 4801f86..8235a0e 100644
--- a/test/pdiff/Metric.h
+++ b/test/pdiff/Metric.h
@@ -17,11 +17,16 @@ if not, write to the Free Software Found
#ifndef _METRIC_H
#define _METRIC_H
-class CompareArgs;
+#include "RGBAImage.h"
/* Image comparison metric using Yee's method
* References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
*/
-bool Yee_Compare(CompareArgs &args);
+int Yee_Compare_Images(RGBAImage *image_a,
+ RGBAImage *image_b,
+ float gamma,
+ float luminance,
+ float field_of_view,
+ bool verbose);
#endif
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 7f2229d..6e098ed 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -25,6 +25,60 @@
#include "CompareArgs.h"
#include "Metric.h"
+static bool Yee_Compare(CompareArgs &args)
+{
+ if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
+ (args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
+ args.ErrorStr = "Image dimensions do not match\n";
+ return false;
+ }
+
+ unsigned int i, dim, pixels_failed;
+ dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
+ bool identical = true;
+ for (i = 0; i < dim; i++) {
+ if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
+ identical = false;
+ break;
+ }
+ }
+ if (identical) {
+ args.ErrorStr = "Images are binary identical\n";
+ return true;
+ }
+
+ pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
+ args.Gamma, args.Luminance,
+ args.FieldOfView, args.Verbose);
+
+ if (pixels_failed < args.ThresholdPixels) {
+ args.ErrorStr = "Images are perceptually indistinguishable\n";
+ return true;
+ }
+
+ char different[100];
+ sprintf(different, "%d pixels are different\n", pixels_failed);
+
+ args.ErrorStr = "Images are visibly different\n";
+ args.ErrorStr += different;
+
+ if (args.ImgDiff) {
+#if IMAGE_DIFF_CODE_ENABLED
+ if (args.ImgDiff->WritePPM()) {
+ args.ErrorStr += "Wrote difference image to ";
+ args.ErrorStr+= args.ImgDiff->Get_Name();
+ args.ErrorStr += "\n";
+ } else {
+ args.ErrorStr += "Could not write difference image to ";
+ args.ErrorStr+= args.ImgDiff->Get_Name();
+ args.ErrorStr += "\n";
+ }
+#endif
+ args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
+ }
+ return false;
+}
+
int main(int argc, char **argv)
{
CompareArgs args;
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index ec33d22..710cabe 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -14,7 +14,7 @@
if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef _RGAIMAGE_H
+#ifndef _RGBAIMAGE_H
#define _RGBAIMAGE_H
#include<string>
diff-tree c7379fcea478fbd3fc5e09a10828586e641e2375 (from 29456d38658b8ba7267fadeac9820a68227df787)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 00:30:54 2006 -0800
pdiff: Rewrite Laplacian pyramid code from C++ to C
diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
deleted file mode 100644
index 5b69a8e..0000000
--- a/test/pdiff/LPyramid.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- Laplacian Pyramid
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "LPyramid.h"
-
-
-/*
- * Construction/Destruction
- */
-
-LPyramid::LPyramid(float *image, int width, int height) :
- Width(width),
- Height(height)
-{
- /* Make the Laplacian pyramid by successively
- * copying the earlier levels and blurring them */
- for (int i=0; i<MAX_PYR_LEVELS; i++) {
- if (i == 0) {
- Levels[i] = Copy(image);
- } else {
- Levels[i] = new float[Width * Height];
- Convolve(Levels[i], Levels[i - 1]);
- }
- }
-}
-
-LPyramid::~LPyramid()
-{
- for (int i=0; i<MAX_PYR_LEVELS; i++) {
- if (Levels[i]) delete Levels[i];
- }
-}
-
-float *LPyramid::Copy(float *img)
-{
- int max = Width * Height;
- float *out = new float[max];
- for (int i = 0; i < max; i++) out[i] = img[i];
-
- return out;
-}
-
-void LPyramid::Convolve(float *a, float *b)
-/* convolves image b with the filter kernel and stores it in a */
-{
- int y,x,i,j,nx,ny;
- const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
-
- for (y=0; y<Height; y++) {
- for (x=0; x<Width; x++) {
- int index = y * Width + x;
- a[index] = 0.0f;
- for (i=-2; i<=2; i++) {
- for (j=-2; j<=2; j++) {
- nx=x+i;
- ny=y+j;
- if (nx<0) nx=-nx;
- if (ny<0) ny=-ny;
- if (nx>=Width) nx=2*(Width-1)-nx;
- if (ny>=Height) ny=2*(Height-1)-ny;
- a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * Width + nx];
- }
- }
- }
- }
-}
-
-float LPyramid::Get_Value(int x, int y, int level)
-{
- int index = x + y * Width;
- int l = level;
- if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
- return Levels[level][index];
-}
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
deleted file mode 100644
index d558616..0000000
--- a/test/pdiff/LPyramid.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Laplacian Pyramid
- Copyright (C) 2006 Yangli Hector Yee
-
- This program is free software; you can redistribute it and/or modify it under the terms of the
- GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with this program;
- if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifndef _LPYRAMID_H
-#define _LPYRAMID_H
-
-#define MAX_PYR_LEVELS 8
-
-class LPyramid
-{
-public:
- LPyramid(float *image, int width, int height);
- virtual ~LPyramid();
- float Get_Value(int x, int y, int level);
-protected:
- float *Copy(float *img);
- void Convolve(float *a, float *b);
-
- /* Succesively blurred versions of the original image */
- float *Levels[MAX_PYR_LEVELS];
-
- int Width;
- int Height;
-};
-
-#endif /* _LPYRAMID_H */
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 6443269..0179f05 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -3,8 +3,8 @@ EXTRA_PROGRAMS = perceptualdiff
noinst_LTLIBRARIES = libpdiff.la
libpdiff_la_SOURCES = \
pdiff.h \
- LPyramid.cpp \
- LPyramid.h \
+ lpyramid.c \
+ lpyramid.h \
Metric.cpp \
Metric.h \
RGBAImage.cpp \
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index 2f19ef9..5bb90ce 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -17,7 +17,7 @@
#include "Metric.h"
#include "CompareArgs.h"
#include "RGBAImage.h"
-#include "LPyramid.h"
+#include "lpyramid.h"
#include <math.h>
#include "pdiff.h"
@@ -256,8 +256,8 @@ int Yee_Compare_Images(RGBAImage *image_
if (verbose) printf("Constructing Laplacian Pyramids\n");
- LPyramid *la = new LPyramid(aLum, w, h);
- LPyramid *lb = new LPyramid(bLum, w, h);
+ lpyramid_t *la = lpyramid_create (aLum, w, h);
+ lpyramid_t *lb = lpyramid_create (bLum, w, h);
float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
float pixels_per_degree = w / num_one_degree_pixels;
@@ -287,11 +287,11 @@ int Yee_Compare_Images(RGBAImage *image_
float contrast[MAX_PYR_LEVELS - 2];
float sum_contrast = 0;
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- float n1 = fabsf(la->Get_Value(x,y,i) - la->Get_Value(x,y,i + 1));
- float n2 = fabsf(lb->Get_Value(x,y,i) - lb->Get_Value(x,y,i + 1));
+ float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
+ float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
float numerator = (n1 > n2) ? n1 : n2;
- float d1 = fabsf(la->Get_Value(x,y,i+2));
- float d2 = fabsf(lb->Get_Value(x,y,i+2));
+ float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
+ float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
float denominator = (d1 > d2) ? d1 : d2;
if (denominator < 1e-5f) denominator = 1e-5f;
contrast[i] = numerator / denominator;
@@ -299,7 +299,7 @@ int Yee_Compare_Images(RGBAImage *image_
}
if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
float F_mask[MAX_PYR_LEVELS - 2];
- float adapt = la->Get_Value(x,y,adaptation_level) + lb->Get_Value(x,y,adaptation_level);
+ float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
adapt *= 0.5f;
if (adapt < 1e-5) adapt = 1e-5f;
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
@@ -311,7 +311,7 @@ int Yee_Compare_Images(RGBAImage *image_
}
if (factor < 1) factor = 1;
if (factor > 10) factor = 10;
- float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(x,y,0));
+ float delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
bool pass = true;
/* pure luminance test */
if (delta > factor * tvi(adapt)) {
@@ -357,8 +357,8 @@ int Yee_Compare_Images(RGBAImage *image_
if (bZ) delete[] bZ;
if (aLum) delete[] aLum;
if (bLum) delete[] bLum;
- if (la) delete la;
- if (lb) delete lb;
+ lpyramid_destroy (la);
+ lpyramid_destroy (lb);
if (aA) delete aA;
if (bA) delete bA;
if (aB) delete aB;
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 1fd66b9..7f2229d 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -20,7 +20,7 @@
#include <string.h>
#include <math.h>
#include <string>
-#include "LPyramid.h"
+#include "lpyramid.h"
#include "RGBAImage.h"
#include "CompareArgs.h"
#include "Metric.h"
diff --git a/test/pdiff/lpyramid.cpp b/test/pdiff/lpyramid.cpp
new file mode 100644
index 0000000..92915ab
--- /dev/null
+++ b/test/pdiff/lpyramid.cpp
@@ -0,0 +1,113 @@
+/*
+ Laplacian Pyramid
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "lpyramid.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct _lpyramid {
+ /* Succesively blurred versions of the original image */
+ float *levels[MAX_PYR_LEVELS];
+
+ int width;
+ int height;
+};
+
+static void
+convolve (lpyramid_t *pyramid, float *a, float *b)
+/* convolves image b with the filter kernel and stores it in a */
+{
+ int y,x,i,j,nx,ny;
+ const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
+ int width = pyramid->width;
+ int height = pyramid->height;
+
+ for (y=0; y<height; y++) {
+ for (x=0; x<width; x++) {
+ int index = y * width + x;
+ a[index] = 0.0f;
+ for (i=-2; i<=2; i++) {
+ for (j=-2; j<=2; j++) {
+ nx=x+i;
+ ny=y+j;
+ if (nx<0) nx=-nx;
+ if (ny<0) ny=-ny;
+ if (nx>=width) nx=2*(width-1)-nx;
+ if (ny>=height) ny=2*(height-1)-ny;
+ a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * width + nx];
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Construction/Destruction
+ */
+
+lpyramid_t *
+lpyramid_create (float *image, int width, int height)
+{
+ lpyramid_t *pyramid;
+ int i;
+
+ /* XXX: Remove stupid cast after finishing port to C */
+ pyramid = (lpyramid_t *) malloc (sizeof (lpyramid_t));
+ if (pyramid == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+ pyramid->width = width;
+ pyramid->height = height;
+
+ /* Make the Laplacian pyramid by successively
+ * copying the earlier levels and blurring them */
+ for (i=0; i<MAX_PYR_LEVELS; i++) {
+ /* XXX: Remove stupid cast after finishing port to C */
+ pyramid->levels[i] = (float *) malloc (width * height * sizeof (float));
+ if (pyramid->levels[i] == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+ if (i == 0) {
+ memcpy (pyramid->levels[i], image, width * height * sizeof (float));
+ } else {
+ convolve(pyramid, pyramid->levels[i], pyramid->levels[i - 1]);
+ }
+ }
+
+ return pyramid;
+}
+
+void
+lpyramid_destroy (lpyramid_t *pyramid)
+{
+ int i;
+
+ for (i=0; i<MAX_PYR_LEVELS; i++)
+ free (pyramid->levels[i]);
+}
+
+float
+lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level)
+{
+ int index = x + y * pyramid->width;
+ int l = level;
+ if (l > MAX_PYR_LEVELS)
+ l = MAX_PYR_LEVELS;
+ return pyramid->levels[level][index];
+}
diff --git a/test/pdiff/lpyramid.h b/test/pdiff/lpyramid.h
new file mode 100644
index 0000000..ab1235c
--- /dev/null
+++ b/test/pdiff/lpyramid.h
@@ -0,0 +1,32 @@
+/*
+ Laplacian Pyramid
+ Copyright (C) 2006 Yangli Hector Yee
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef _LPYRAMID_H
+#define _LPYRAMID_H
+
+#define MAX_PYR_LEVELS 8
+
+typedef struct _lpyramid lpyramid_t;
+
+lpyramid_t *
+lpyramid_create (float *image, int width, int height);
+
+void
+lpyramid_destroy (lpyramid_t *pyramid);
+
+float
+lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level);
+
+#endif /* _LPYRAMID_H */
diff-tree 29456d38658b8ba7267fadeac9820a68227df787 (from 34a6af3c55cf8bba292cec8dc42fdc1917759a08)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Dec 14 00:13:23 2006 -0800
pdiff: Convert C++-style comments to good old-fashioned C-style comments
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 6b8fe8a..716f79e 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -116,7 +116,7 @@ bool CompareArgs::Parse_Args(int argc, c
}
}
}
- } // i
+ } /* i */
return true;
}
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index ab2a251..85f0174 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -22,7 +22,7 @@
class RGBAImage;
class RGBACairoImage;
-// Args to pass into the comparison function
+/* Args to pass into the comparison function */
class CompareArgs
{
public:
@@ -31,15 +31,15 @@ public:
bool Parse_Args(int argc, char **argv);
void Print_Args();
- RGBAImage *ImgA; // Image A
- RGBAImage *ImgB; // Image B
- RGBAImage *ImgDiff; // Diff image
- bool Verbose; // Print lots of text or not
- float FieldOfView; // Field of view in degrees
- float Gamma; // The gamma to convert to linear color space
- float Luminance; // the display's luminance
- unsigned int ThresholdPixels; // How many pixels different to ignore
- std::string ErrorStr; // Error string
+ RGBAImage *ImgA; /* Image A */
+ RGBAImage *ImgB; /* Image B */
+ RGBAImage *ImgDiff; /* Diff image */
+ bool Verbose; /* Print lots of text or not */
+ float FieldOfView; /* Field of view in degrees */
+ float Gamma; /* The gamma to convert to linear color space */
+ float Luminance; /* the display's luminance */
+ unsigned int ThresholdPixels; /* How many pixels different to ignore */
+ std::string ErrorStr; /* Error string */
};
#endif
diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
index 104179d..5b69a8e 100644
--- a/test/pdiff/LPyramid.cpp
+++ b/test/pdiff/LPyramid.cpp
@@ -17,16 +17,16 @@
#include "LPyramid.h"
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
+/*
+ * Construction/Destruction
+ */
LPyramid::LPyramid(float *image, int width, int height) :
Width(width),
Height(height)
{
- // Make the Laplacian pyramid by successively
- // copying the earlier levels and blurring them
+ /* Make the Laplacian pyramid by successively
+ * copying the earlier levels and blurring them */
for (int i=0; i<MAX_PYR_LEVELS; i++) {
if (i == 0) {
Levels[i] = Copy(image);
@@ -54,7 +54,7 @@ float *LPyramid::Copy(float *img)
}
void LPyramid::Convolve(float *a, float *b)
-// convolves image b with the filter kernel and stores it in a
+/* convolves image b with the filter kernel and stores it in a */
{
int y,x,i,j,nx,ny;
const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
index 27e041b..d558616 100644
--- a/test/pdiff/LPyramid.h
+++ b/test/pdiff/LPyramid.h
@@ -28,11 +28,11 @@ protected:
float *Copy(float *img);
void Convolve(float *a, float *b);
- // Succesively blurred versions of the original image
+ /* Succesively blurred versions of the original image */
float *Levels[MAX_PYR_LEVELS];
int Width;
int Height;
};
-#endif // _LPYRAMID_H
+#endif /* _LPYRAMID_H */
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index dde17c0..2f19ef9 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -34,8 +34,9 @@
float tvi(float adaptation_luminance)
{
- // returns the threshold luminance given the adaptation luminance
- // units are candelas per meter squared
+ /* returns the threshold luminance given the adaptation luminance
+ units are candelas per meter squared
+ */
float log_a, r, result;
log_a = log10f(adaptation_luminance);
@@ -58,8 +59,9 @@ float tvi(float adaptation_luminance)
}
-// computes the contrast sensitivity function (Barten SPIE 1989)
-// given the cycles per degree (cpd) and luminance (lum)
+/* computes the contrast sensitivity function (Barten SPIE 1989)
+ * given the cycles per degree (cpd) and luminance (lum)
+ */
float csf(float cpd, float lum)
{
float a, b, result;
@@ -86,10 +88,10 @@ float mask(float contrast)
return result;
}
-// convert Adobe RGB (1998) with reference white D65 to XYZ
+/* convert Adobe RGB (1998) with reference white D65 to XYZ */
void AdobeRGBToXYZ(float r, float g, float b, float &x, float &y, float &z)
{
- // matrix is from http://www.brucelindbloom.com/
+ /* matrix is from http://www.brucelindbloom.com/ */
x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
@@ -100,7 +102,7 @@ void XYZToLAB(float x, float y, float z,
static float xw = -1;
static float yw;
static float zw;
- // reference white
+ /* reference white */
if (xw < 0) {
AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
}
@@ -211,7 +213,7 @@ int Yee_Compare_Images(RGBAImage *image_
unsigned int i, dim;
dim = image_a->Get_Width() * image_a->Get_Height();
- // assuming colorspaces are in Adobe RGB (1998) convert to XYZ
+ /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
float *aX = new float[dim];
float *aY = new float[dim];
float *aZ = new float[dim];
@@ -311,13 +313,13 @@ int Yee_Compare_Images(RGBAImage *image_
if (factor > 10) factor = 10;
float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(x,y,0));
bool pass = true;
- // pure luminance test
+ /* pure luminance test */
if (delta > factor * tvi(adapt)) {
pass = false;
} else {
- // CIE delta E test with modifications
+ /* CIE delta E test with modifications */
float color_scale = 1.0f;
- // ramp down the color test in scotopic regions
+ /* ramp down the color test in scotopic regions */
if (adapt < 10.0f) {
color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
color_scale = color_scale * color_scale;
diff --git a/test/pdiff/Metric.h b/test/pdiff/Metric.h
index a6b234e..4801f86 100644
--- a/test/pdiff/Metric.h
+++ b/test/pdiff/Metric.h
@@ -19,8 +19,9 @@ if not, write to the Free Software Found
class CompareArgs;
-// Image comparison metric using Yee's method
-// References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
+/* Image comparison metric using Yee's method
+ * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
+ */
bool Yee_Compare(CompareArgs &args);
#endif
diff --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp
index 08e5cd9..2c38f9c 100644
--- a/test/pdiff/RGBAImage.cpp
+++ b/test/pdiff/RGBAImage.cpp
@@ -21,7 +21,7 @@
#include "tiff.h"
#include "tiffio.h"
-// Reads Tiff Images
+/* Reads Tiff Images */
RGBAImage* RGBAImage::ReadTiff(char *filename)
{
RGBAImage *fimg = 0;
@@ -40,7 +40,7 @@ RGBAImage* RGBAImage::ReadTiff(char *fil
raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
if (raster != NULL) {
if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
- // result is in ABGR
+ /* result is in ABGR */
fimg = new RGBAImage(img.width, img.height);
for (int y = img.height - 1; y >= 0; y--) {
for (int x = 0; x < (int) img.width; x++) {
@@ -57,7 +57,7 @@ RGBAImage* RGBAImage::ReadTiff(char *fil
}
#endif /* HAVE_LIBTIFF */
-// This portion was written by Scott Corley
+/* This portion was written by Scott Corley */
RGBAImage* RGBAImage::ReadPNG(char *filename)
{
RGBAImage *fimg = 0;
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index 5f662bb..ec33d22 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -20,7 +20,7 @@
#include<string>
#include<cairo.h>
-// assumes data is in the ABGR format
+/* assumes data is in the ABGR format */
class RGBAImage
{
public:
diff-tree 34a6af3c55cf8bba292cec8dc42fdc1917759a08 (from d421a856d08fba2fa0fdbd362d947497a952b347)
Author: Carl Worth <cworth at cworth.org>
Date: Wed Dec 13 18:10:21 2006 -0800
pdiff: Delete all trailing whitespace.
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 2c5e5d4..6b8fe8a 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -18,7 +18,7 @@
#include "RGBAImage.h"
#include <stdio.h>
-static const char* copyright =
+static const char* copyright =
"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
This is free software, and you are welcome\n\
@@ -79,7 +79,7 @@ bool CompareArgs::Parse_Args(int argc, c
return false;
}
ImgA = new RGBACairoImage (surface);
- } else if (i == 2) {
+ } else if (i == 2) {
surface = cairo_image_surface_create_from_png (argv[2]);
if (cairo_surface_status (surface))
{
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index fb5fc9d..ab2a251 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -28,9 +28,9 @@ class CompareArgs
public:
CompareArgs();
~CompareArgs();
- bool Parse_Args(int argc, char **argv);
+ bool Parse_Args(int argc, char **argv);
void Print_Args();
-
+
RGBAImage *ImgA; // Image A
RGBAImage *ImgB; // Image B
RGBAImage *ImgDiff; // Diff image
diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
index cefd24b..104179d 100644
--- a/test/pdiff/LPyramid.cpp
+++ b/test/pdiff/LPyramid.cpp
@@ -49,7 +49,7 @@ float *LPyramid::Copy(float *img)
int max = Width * Height;
float *out = new float[max];
for (int i = 0; i < max; i++) out[i] = img[i];
-
+
return out;
}
@@ -72,7 +72,7 @@ void LPyramid::Convolve(float *a, float
if (nx>=Width) nx=2*(Width-1)-nx;
if (ny>=Height) ny=2*(Height-1)-ny;
a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * Width + nx];
- }
+ }
}
}
}
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
index bb9777a..27e041b 100644
--- a/test/pdiff/LPyramid.h
+++ b/test/pdiff/LPyramid.h
@@ -20,14 +20,14 @@
class LPyramid
{
-public:
+public:
LPyramid(float *image, int width, int height);
virtual ~LPyramid();
float Get_Value(int x, int y, int level);
protected:
float *Copy(float *img);
void Convolve(float *a, float *b);
-
+
// Succesively blurred versions of the original image
float *Levels[MAX_PYR_LEVELS];
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index b92dd5c..dde17c0 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -30,14 +30,14 @@
* threshold of visibility in cd per m^2
* TVI means Threshold vs Intensity function
* This version comes from Ward Larson Siggraph 1997
- */
+ */
float tvi(float adaptation_luminance)
{
// returns the threshold luminance given the adaptation luminance
// units are candelas per meter squared
- float log_a, r, result;
+ float log_a, r, result;
log_a = log10f(adaptation_luminance);
if (log_a < -3.94f) {
@@ -52,24 +52,24 @@ float tvi(float adaptation_luminance)
r = log_a - 1.255f;
}
- result = powf(10.0f , r);
+ result = powf(10.0f , r);
return result;
-}
+}
// computes the contrast sensitivity function (Barten SPIE 1989)
// given the cycles per degree (cpd) and luminance (lum)
float csf(float cpd, float lum)
{
- float a, b, result;
-
+ float a, b, result;
+
a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
-
- result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
-
- return result;
+
+ result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
+
+ return result;
}
/*
@@ -81,10 +81,10 @@ float mask(float contrast)
float a, b, result;
a = powf(392.498f * contrast, 0.7f);
b = powf(0.0153f * a, 4.0f);
- result = powf(1.0f + b, 0.25f);
+ result = powf(1.0f + b, 0.25f);
return result;
-}
+}
// convert Adobe RGB (1998) with reference white D65 to XYZ
void AdobeRGBToXYZ(float r, float g, float b, float &x, float &y, float &z)
@@ -137,7 +137,7 @@ bool Yee_Compare(CompareArgs &args)
args.ErrorStr = "Image dimensions do not match\n";
return false;
}
-
+
unsigned int i, dim, pixels_failed;
dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
bool identical = true;
@@ -160,7 +160,7 @@ bool Yee_Compare(CompareArgs &args)
args.ErrorStr = "Images are perceptually indistinguishable\n";
return true;
}
-
+
char different[100];
sprintf(different, "%d pixels are different\n", pixels_failed);
@@ -220,14 +220,14 @@ int Yee_Compare_Images(RGBAImage *image_
float *bZ = new float[dim];
float *aLum = new float[dim];
float *bLum = new float[dim];
-
+
float *aA = new float[dim];
float *bA = new float[dim];
float *aB = new float[dim];
float *bB = new float[dim];
if (verbose) printf("Converting RGB to XYZ\n");
-
+
unsigned int x, y, w, h;
w = image_a->Get_Width();
h = image_a->Get_Height();
@@ -251,17 +251,17 @@ int Yee_Compare_Images(RGBAImage *image_
bLum[i] = bY[i] * luminance;
}
}
-
+
if (verbose) printf("Constructing Laplacian Pyramids\n");
-
+
LPyramid *la = new LPyramid(aLum, w, h);
LPyramid *lb = new LPyramid(bLum, w, h);
-
+
float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
float pixels_per_degree = w / num_one_degree_pixels;
-
+
if (verbose) printf("Performing test\n");
-
+
float num_pixels = 1;
unsigned int adaptation_level = 0;
for (i = 0; i < MAX_PYR_LEVELS; i++) {
@@ -269,15 +269,15 @@ int Yee_Compare_Images(RGBAImage *image_
if (num_pixels > num_one_degree_pixels) break;
num_pixels *= 2;
}
-
+
float cpd[MAX_PYR_LEVELS];
cpd[0] = 0.5f * pixels_per_degree;
for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
float csf_max = csf(3.248f, 100.0f);
-
+
float F_freq[MAX_PYR_LEVELS - 2];
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
-
+
unsigned int pixels_failed = 0;
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
@@ -301,7 +301,7 @@ int Yee_Compare_Images(RGBAImage *image_
adapt *= 0.5f;
if (adapt < 1e-5) adapt = 1e-5f;
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
+ F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
}
float factor = 0;
for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
@@ -346,7 +346,7 @@ int Yee_Compare_Images(RGBAImage *image_
#endif
}
}
-
+
if (aX) delete[] aX;
if (aY) delete[] aY;
if (aZ) delete[] aZ;
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 70c6e12..1fd66b9 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -28,7 +28,7 @@
int main(int argc, char **argv)
{
CompareArgs args;
-
+
if (!args.Parse_Args(argc, argv)) {
printf("%s", args.ErrorStr.c_str());
return -1;
diff --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp
index 0b540d2..08e5cd9 100644
--- a/test/pdiff/RGBAImage.cpp
+++ b/test/pdiff/RGBAImage.cpp
@@ -25,13 +25,13 @@
RGBAImage* RGBAImage::ReadTiff(char *filename)
{
RGBAImage *fimg = 0;
-
+
TIFF* tif = TIFFOpen(filename, "r");
char emsg[1024];
emsg[0] = 0;
if (tif) {
TIFFRGBAImage img;
-
+
if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
size_t npixels;
uint32* raster;
@@ -120,9 +120,9 @@ RGBAImage* RGBAImage::ReadPNG(char *file
png_read_destroy(png_ptr, info_ptr, end_info);
return fimg;
}
-
+
bool RGBAImage::WritePPM()
-{
+{
if (Width <= 0) return false;
if (Height <=0 ) return false;
FILE *out = fopen(Name.c_str(), "wb");
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index 31727fa..5f662bb 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -45,7 +45,7 @@ public:
virtual unsigned int Get(int x, int y) const { return Data[x + y * Width]; }
virtual unsigned int Get(int i) const { return Data[i]; }
const std::string &Get_Name(void) const { return Name; }
-
+
bool WritePPM();
static RGBAImage* ReadTiff(char *filename);
static RGBAImage* ReadPNG(char *filename);
diff-tree d421a856d08fba2fa0fdbd362d947497a952b347 (from 4f6611ef6cac3928427b6fc28dab40829ef0d748)
Author: Carl Worth <cworth at cworth.org>
Date: Wed Dec 13 18:08:25 2006 -0800
pdiff: Re-indent all code
I've given up on trying to preserve the old code formatting
for compatibility. We're not planning on augmenting the algorithm
itself, just integrating it into cairo. So I don't expect to
make changes that we'll be all that interested in pushing
upstream.
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 60520b0..2c5e5d4 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -1,17 +1,17 @@
/*
-Comapre Args
-Copyright (C) 2006 Yangli Hector Yee
+ Comapre Args
+ Copyright (C) 2006 Yangli Hector Yee
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "CompareArgs.h"
@@ -41,89 +41,89 @@ static const char *usage =
CompareArgs::CompareArgs()
{
- ImgA = NULL;
- ImgB = NULL;
- ImgDiff = NULL;
- Verbose = false;
- FieldOfView = 45.0f;
- Gamma = 2.2f;
- ThresholdPixels = 100;
- Luminance = 100.0f;
+ ImgA = NULL;
+ ImgB = NULL;
+ ImgDiff = NULL;
+ Verbose = false;
+ FieldOfView = 45.0f;
+ Gamma = 2.2f;
+ ThresholdPixels = 100;
+ Luminance = 100.0f;
}
CompareArgs::~CompareArgs()
{
- if (ImgA) delete ImgA;
- if (ImgB) delete ImgB;
- if (ImgDiff) delete ImgDiff;
+ if (ImgA) delete ImgA;
+ if (ImgB) delete ImgB;
+ if (ImgDiff) delete ImgDiff;
}
bool CompareArgs::Parse_Args(int argc, char **argv)
{
- cairo_surface_t *surface;
- if (argc < 3) {
- ErrorStr = copyright;
- ErrorStr += usage;
+ cairo_surface_t *surface;
+ if (argc < 3) {
+ ErrorStr = copyright;
+ ErrorStr += usage;
+ return false;
+ }
+ for (int i = 0; i < argc; i++) {
+ if (i == 1) {
+ surface = cairo_image_surface_create_from_png (argv[1]);
+ if (cairo_surface_status (surface))
+ {
+ ErrorStr = "FAIL: Cannot open ";
+ ErrorStr += argv[1];
+ ErrorStr += " ";
+ ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+ ErrorStr += "\n";
return false;
- }
- for (int i = 0; i < argc; i++) {
- if (i == 1) {
- surface = cairo_image_surface_create_from_png (argv[1]);
- if (cairo_surface_status (surface))
- {
- ErrorStr = "FAIL: Cannot open ";
- ErrorStr += argv[1];
- ErrorStr += " ";
- ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
- ErrorStr += "\n";
- return false;
- }
- ImgA = new RGBACairoImage (surface);
- } else if (i == 2) {
- surface = cairo_image_surface_create_from_png (argv[2]);
- if (cairo_surface_status (surface))
- {
- ErrorStr = "FAIL: Cannot open ";
- ErrorStr += argv[2];
- ErrorStr += " ";
- ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
- ErrorStr += "\n";
- return false;
- }
- ImgB = new RGBACairoImage (surface);
- } else {
- if (strstr(argv[i], "-fov")) {
- if (i + 1 < argc) {
- FieldOfView = (float) atof(argv[i + 1]);
- }
- } else if (strstr(argv[i], "-verbose")) {
- Verbose = true;
- } else if (strstr(argv[i], "-threshold")) {
- if (i + 1 < argc) {
- ThresholdPixels = atoi(argv[i + 1]);
- }
- } else if (strstr(argv[i], "-gamma")) {
- if (i + 1 < argc) {
- Gamma = (float) atof(argv[i + 1]);
- }
- }else if (strstr(argv[i], "-luminance")) {
- if (i + 1 < argc) {
- Luminance = (float) atof(argv[i + 1]);
- }
- }else if (strstr(argv[i], "-output")) {
- if (i + 1 < argc) {
- ImgDiff = new RGBAImage(ImgA->Get_Width(), ImgA->Get_Height(), argv[i+1]);
- }
- }
+ }
+ ImgA = new RGBACairoImage (surface);
+ } else if (i == 2) {
+ surface = cairo_image_surface_create_from_png (argv[2]);
+ if (cairo_surface_status (surface))
+ {
+ ErrorStr = "FAIL: Cannot open ";
+ ErrorStr += argv[2];
+ ErrorStr += " ";
+ ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+ ErrorStr += "\n";
+ return false;
+ }
+ ImgB = new RGBACairoImage (surface);
+ } else {
+ if (strstr(argv[i], "-fov")) {
+ if (i + 1 < argc) {
+ FieldOfView = (float) atof(argv[i + 1]);
+ }
+ } else if (strstr(argv[i], "-verbose")) {
+ Verbose = true;
+ } else if (strstr(argv[i], "-threshold")) {
+ if (i + 1 < argc) {
+ ThresholdPixels = atoi(argv[i + 1]);
+ }
+ } else if (strstr(argv[i], "-gamma")) {
+ if (i + 1 < argc) {
+ Gamma = (float) atof(argv[i + 1]);
}
- } // i
- return true;
+ }else if (strstr(argv[i], "-luminance")) {
+ if (i + 1 < argc) {
+ Luminance = (float) atof(argv[i + 1]);
+ }
+ }else if (strstr(argv[i], "-output")) {
+ if (i + 1 < argc) {
+ ImgDiff = new RGBAImage(ImgA->Get_Width(), ImgA->Get_Height(), argv[i+1]);
+ }
+ }
+ }
+ } // i
+ return true;
}
void CompareArgs::Print_Args()
{
- printf("Field of view is %f degrees\n", FieldOfView);
- printf("Threshold pixels is %d pixels\n", ThresholdPixels);
- printf("The Gamma is %f\n", Gamma);
- printf("The Display's luminance is %f candela per meter squared\n", Luminance);
+ printf("Field of view is %f degrees\n", FieldOfView);
+ printf("Threshold pixels is %d pixels\n", ThresholdPixels);
+ printf("The Gamma is %f\n", Gamma);
+ printf("The Display's luminance is %f candela per meter squared\n", Luminance);
}
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index fc6993f..fb5fc9d 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -1,17 +1,17 @@
/*
-Comapre Args
-Copyright (C) 2006 Yangli Hector Yee
+ Comapre Args
+ Copyright (C) 2006 Yangli Hector Yee
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _COMPAREARGS_H
@@ -26,20 +26,20 @@ class RGBACairoImage;
class CompareArgs
{
public:
- CompareArgs();
- ~CompareArgs();
- bool Parse_Args(int argc, char **argv);
- void Print_Args();
+ CompareArgs();
+ ~CompareArgs();
+ bool Parse_Args(int argc, char **argv);
+ void Print_Args();
- RGBAImage *ImgA; // Image A
- RGBAImage *ImgB; // Image B
- RGBAImage *ImgDiff; // Diff image
- bool Verbose; // Print lots of text or not
- float FieldOfView; // Field of view in degrees
- float Gamma; // The gamma to convert to linear color space
- float Luminance; // the display's luminance
- unsigned int ThresholdPixels; // How many pixels different to ignore
- std::string ErrorStr; // Error string
+ RGBAImage *ImgA; // Image A
+ RGBAImage *ImgB; // Image B
+ RGBAImage *ImgDiff; // Diff image
+ bool Verbose; // Print lots of text or not
+ float FieldOfView; // Field of view in degrees
+ float Gamma; // The gamma to convert to linear color space
+ float Luminance; // the display's luminance
+ unsigned int ThresholdPixels; // How many pixels different to ignore
+ std::string ErrorStr; // Error string
};
#endif
diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
index be0daa5..cefd24b 100644
--- a/test/pdiff/LPyramid.cpp
+++ b/test/pdiff/LPyramid.cpp
@@ -1,17 +1,17 @@
/*
-Laplacian Pyramid
-Copyright (C) 2006 Yangli Hector Yee
+ Laplacian Pyramid
+ Copyright (C) 2006 Yangli Hector Yee
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "LPyramid.h"
@@ -22,66 +22,66 @@ if not, write to the Free Software Found
//////////////////////////////////////////////////////////////////////
LPyramid::LPyramid(float *image, int width, int height) :
- Width(width),
- Height(height)
+ Width(width),
+ Height(height)
{
- // Make the Laplacian pyramid by successively
- // copying the earlier levels and blurring them
- for (int i=0; i<MAX_PYR_LEVELS; i++) {
- if (i == 0) {
- Levels[i] = Copy(image);
- } else {
- Levels[i] = new float[Width * Height];
- Convolve(Levels[i], Levels[i - 1]);
- }
+ // Make the Laplacian pyramid by successively
+ // copying the earlier levels and blurring them
+ for (int i=0; i<MAX_PYR_LEVELS; i++) {
+ if (i == 0) {
+ Levels[i] = Copy(image);
+ } else {
+ Levels[i] = new float[Width * Height];
+ Convolve(Levels[i], Levels[i - 1]);
}
+ }
}
LPyramid::~LPyramid()
{
- for (int i=0; i<MAX_PYR_LEVELS; i++) {
- if (Levels[i]) delete Levels[i];
- }
+ for (int i=0; i<MAX_PYR_LEVELS; i++) {
+ if (Levels[i]) delete Levels[i];
+ }
}
float *LPyramid::Copy(float *img)
{
- int max = Width * Height;
- float *out = new float[max];
- for (int i = 0; i < max; i++) out[i] = img[i];
+ int max = Width * Height;
+ float *out = new float[max];
+ for (int i = 0; i < max; i++) out[i] = img[i];
- return out;
+ return out;
}
void LPyramid::Convolve(float *a, float *b)
// convolves image b with the filter kernel and stores it in a
{
- int y,x,i,j,nx,ny;
- const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
+ int y,x,i,j,nx,ny;
+ const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
- for (y=0; y<Height; y++) {
- for (x=0; x<Width; x++) {
- int index = y * Width + x;
- a[index] = 0.0f;
- for (i=-2; i<=2; i++) {
- for (j=-2; j<=2; j++) {
- nx=x+i;
- ny=y+j;
- if (nx<0) nx=-nx;
- if (ny<0) ny=-ny;
- if (nx>=Width) nx=2*(Width-1)-nx;
- if (ny>=Height) ny=2*(Height-1)-ny;
- a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * Width + nx];
- }
- }
- }
+ for (y=0; y<Height; y++) {
+ for (x=0; x<Width; x++) {
+ int index = y * Width + x;
+ a[index] = 0.0f;
+ for (i=-2; i<=2; i++) {
+ for (j=-2; j<=2; j++) {
+ nx=x+i;
+ ny=y+j;
+ if (nx<0) nx=-nx;
+ if (ny<0) ny=-ny;
+ if (nx>=Width) nx=2*(Width-1)-nx;
+ if (ny>=Height) ny=2*(Height-1)-ny;
+ a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * Width + nx];
+ }
+ }
}
+ }
}
float LPyramid::Get_Value(int x, int y, int level)
{
- int index = x + y * Width;
- int l = level;
- if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
- return Levels[level][index];
+ int index = x + y * Width;
+ int l = level;
+ if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
+ return Levels[level][index];
}
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
index 162d464..bb9777a 100644
--- a/test/pdiff/LPyramid.h
+++ b/test/pdiff/LPyramid.h
@@ -1,17 +1,17 @@
/*
-Laplacian Pyramid
-Copyright (C) 2006 Yangli Hector Yee
+ Laplacian Pyramid
+ Copyright (C) 2006 Yangli Hector Yee
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LPYRAMID_H
#define _LPYRAMID_H
@@ -21,18 +21,18 @@ if not, write to the Free Software Found
class LPyramid
{
public:
- LPyramid(float *image, int width, int height);
- virtual ~LPyramid();
- float Get_Value(int x, int y, int level);
+ LPyramid(float *image, int width, int height);
+ virtual ~LPyramid();
+ float Get_Value(int x, int y, int level);
protected:
- float *Copy(float *img);
- void Convolve(float *a, float *b);
+ float *Copy(float *img);
+ void Convolve(float *a, float *b);
- // Succesively blurred versions of the original image
- float *Levels[MAX_PYR_LEVELS];
+ // Succesively blurred versions of the original image
+ float *Levels[MAX_PYR_LEVELS];
- int Width;
- int Height;
+ int Width;
+ int Height;
};
#endif // _LPYRAMID_H
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index ded0afc..b92dd5c 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -1,17 +1,17 @@
/*
-Metric
-Copyright (C) 2006 Yangli Hector Yee
+ Metric
+ Copyright (C) 2006 Yangli Hector Yee
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Metric.h"
@@ -26,35 +26,35 @@ if not, write to the Free Software Found
#endif
/*
-* Given the adaptation luminance, this function returns the
-* threshold of visibility in cd per m^2
-* TVI means Threshold vs Intensity function
-* This version comes from Ward Larson Siggraph 1997
-*/
+ * Given the adaptation luminance, this function returns the
+ * threshold of visibility in cd per m^2
+ * TVI means Threshold vs Intensity function
+ * This version comes from Ward Larson Siggraph 1997
+ */
float tvi(float adaptation_luminance)
{
- // returns the threshold luminance given the adaptation luminance
- // units are candelas per meter squared
+ // returns the threshold luminance given the adaptation luminance
+ // units are candelas per meter squared
- float log_a, r, result;
- log_a = log10f(adaptation_luminance);
+ float log_a, r, result;
+ log_a = log10f(adaptation_luminance);
- if (log_a < -3.94f) {
- r = -2.86f;
- } else if (log_a < -1.44f) {
- r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
- } else if (log_a < -0.0184f) {
- r = log_a - 0.395f;
- } else if (log_a < 1.9f) {
- r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
- } else {
- r = log_a - 1.255f;
- }
+ if (log_a < -3.94f) {
+ r = -2.86f;
+ } else if (log_a < -1.44f) {
+ r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
+ } else if (log_a < -0.0184f) {
+ r = log_a - 0.395f;
+ } else if (log_a < 1.9f) {
+ r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
+ } else {
+ r = log_a - 1.255f;
+ }
- result = powf(10.0f , r);
+ result = powf(10.0f , r);
- return result;
+ return result;
}
@@ -62,65 +62,65 @@ float tvi(float adaptation_luminance)
// given the cycles per degree (cpd) and luminance (lum)
float csf(float cpd, float lum)
{
- float a, b, result;
+ float a, b, result;
- a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
- b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
+ a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
+ b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
- result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
+ result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
- return result;
+ return result;
}
/*
-* Visual Masking Function
-* from Daly 1993
-*/
+ * Visual Masking Function
+ * from Daly 1993
+ */
float mask(float contrast)
{
- float a, b, result;
- a = powf(392.498f * contrast, 0.7f);
- b = powf(0.0153f * a, 4.0f);
- result = powf(1.0f + b, 0.25f);
+ float a, b, result;
+ a = powf(392.498f * contrast, 0.7f);
+ b = powf(0.0153f * a, 4.0f);
+ result = powf(1.0f + b, 0.25f);
- return result;
+ return result;
}
// convert Adobe RGB (1998) with reference white D65 to XYZ
void AdobeRGBToXYZ(float r, float g, float b, float &x, float &y, float &z)
{
- // matrix is from http://www.brucelindbloom.com/
- x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
- y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
- z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
+ // matrix is from http://www.brucelindbloom.com/
+ x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
+ y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
+ z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
}
void XYZToLAB(float x, float y, float z, float &L, float &A, float &B)
{
- static float xw = -1;
- static float yw;
- static float zw;
- // reference white
- if (xw < 0) {
- AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
- }
- const float epsilon = 216.0f / 24389.0f;
- const float kappa = 24389.0f / 27.0f;
- float f[3];
- float r[3];
- r[0] = x / xw;
- r[1] = y / yw;
- r[2] = z / zw;
- for (int i = 0; i < 3; i++) {
- if (r[i] > epsilon) {
- f[i] = powf(r[i], 1.0f / 3.0f);
- } else {
- f[i] = (kappa * r[i] + 16.0f) / 116.0f;
- }
+ static float xw = -1;
+ static float yw;
+ static float zw;
+ // reference white
+ if (xw < 0) {
+ AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
+ }
+ const float epsilon = 216.0f / 24389.0f;
+ const float kappa = 24389.0f / 27.0f;
+ float f[3];
+ float r[3];
+ r[0] = x / xw;
+ r[1] = y / yw;
+ r[2] = z / zw;
+ for (int i = 0; i < 3; i++) {
+ if (r[i] > epsilon) {
+ f[i] = powf(r[i], 1.0f / 3.0f);
+ } else {
+ f[i] = (kappa * r[i] + 16.0f) / 116.0f;
}
- L = 116.0f * f[1] - 16.0f;
- A = 500.0f * (f[0] - f[1]);
- B = 200.0f * (f[1] - f[2]);
+ }
+ L = 116.0f * f[1] - 16.0f;
+ A = 500.0f * (f[0] - f[1]);
+ B = 200.0f * (f[1] - f[2]);
}
int Yee_Compare_Images(RGBAImage *image_a,
@@ -132,56 +132,56 @@ int Yee_Compare_Images(RGBAImage *image_
bool Yee_Compare(CompareArgs &args)
{
- if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
- (args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
- args.ErrorStr = "Image dimensions do not match\n";
- return false;
- }
+ if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
+ (args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
+ args.ErrorStr = "Image dimensions do not match\n";
+ return false;
+ }
- unsigned int i, dim, pixels_failed;
- dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
- bool identical = true;
- for (i = 0; i < dim; i++) {
- if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
- identical = false;
- break;
- }
- }
- if (identical) {
- args.ErrorStr = "Images are binary identical\n";
- return true;
- }
-
- pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
- args.Gamma, args.Luminance,
- args.FieldOfView, args.Verbose);
-
- if (pixels_failed < args.ThresholdPixels) {
- args.ErrorStr = "Images are perceptually indistinguishable\n";
- return true;
+ unsigned int i, dim, pixels_failed;
+ dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
+ bool identical = true;
+ for (i = 0; i < dim; i++) {
+ if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
+ identical = false;
+ break;
}
+ }
+ if (identical) {
+ args.ErrorStr = "Images are binary identical\n";
+ return true;
+ }
+
+ pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
+ args.Gamma, args.Luminance,
+ args.FieldOfView, args.Verbose);
+
+ if (pixels_failed < args.ThresholdPixels) {
+ args.ErrorStr = "Images are perceptually indistinguishable\n";
+ return true;
+ }
- char different[100];
- sprintf(different, "%d pixels are different\n", pixels_failed);
+ char different[100];
+ sprintf(different, "%d pixels are different\n", pixels_failed);
- args.ErrorStr = "Images are visibly different\n";
- args.ErrorStr += different;
+ args.ErrorStr = "Images are visibly different\n";
+ args.ErrorStr += different;
- if (args.ImgDiff) {
+ if (args.ImgDiff) {
#if IMAGE_DIFF_CODE_ENABLED
- if (args.ImgDiff->WritePPM()) {
- args.ErrorStr += "Wrote difference image to ";
- args.ErrorStr+= args.ImgDiff->Get_Name();
- args.ErrorStr += "\n";
- } else {
- args.ErrorStr += "Could not write difference image to ";
- args.ErrorStr+= args.ImgDiff->Get_Name();
- args.ErrorStr += "\n";
- }
-#endif
- args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
+ if (args.ImgDiff->WritePPM()) {
+ args.ErrorStr += "Wrote difference image to ";
+ args.ErrorStr+= args.ImgDiff->Get_Name();
+ args.ErrorStr += "\n";
+ } else {
+ args.ErrorStr += "Could not write difference image to ";
+ args.ErrorStr+= args.ImgDiff->Get_Name();
+ args.ErrorStr += "\n";
}
- return false;
+#endif
+ args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
+ }
+ return false;
}
int
@@ -191,14 +191,14 @@ pdiff_compare (cairo_surface_t *surface_
double luminance,
double field_of_view)
{
- RGBAImage *image_a, *image_b;
+ RGBAImage *image_a, *image_b;
- image_a = new RGBACairoImage (surface_a);
- image_b = new RGBACairoImage (surface_b);
+ image_a = new RGBACairoImage (surface_a);
+ image_b = new RGBACairoImage (surface_b);
- return Yee_Compare_Images (image_a, image_b,
- gamma, luminance,
- field_of_view, false);
+ return Yee_Compare_Images (image_a, image_b,
+ gamma, luminance,
+ field_of_view, false);
}
int Yee_Compare_Images(RGBAImage *image_a,
@@ -208,159 +208,159 @@ int Yee_Compare_Images(RGBAImage *image_
float field_of_view,
bool verbose)
{
- unsigned int i, dim;
- dim = image_a->Get_Width() * image_a->Get_Height();
+ unsigned int i, dim;
+ dim = image_a->Get_Width() * image_a->Get_Height();
- // assuming colorspaces are in Adobe RGB (1998) convert to XYZ
- float *aX = new float[dim];
- float *aY = new float[dim];
- float *aZ = new float[dim];
- float *bX = new float[dim];
- float *bY = new float[dim];
- float *bZ = new float[dim];
- float *aLum = new float[dim];
- float *bLum = new float[dim];
-
- float *aA = new float[dim];
- float *bA = new float[dim];
- float *aB = new float[dim];
- float *bB = new float[dim];
-
- if (verbose) printf("Converting RGB to XYZ\n");
-
- unsigned int x, y, w, h;
- w = image_a->Get_Width();
- h = image_a->Get_Height();
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- float r, g, b, l;
- i = x + y * w;
- r = powf(image_a->Get_Red(i) / 255.0f, gamma);
- g = powf(image_a->Get_Green(i) / 255.0f, gamma);
- b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
-
- AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]);
- XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]);
- r = powf(image_b->Get_Red(i) / 255.0f, gamma);
- g = powf(image_b->Get_Green(i) / 255.0f, gamma);
- b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
-
- AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]);
- XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]);
- aLum[i] = aY[i] * luminance;
- bLum[i] = bY[i] * luminance;
- }
+ // assuming colorspaces are in Adobe RGB (1998) convert to XYZ
+ float *aX = new float[dim];
+ float *aY = new float[dim];
+ float *aZ = new float[dim];
+ float *bX = new float[dim];
+ float *bY = new float[dim];
+ float *bZ = new float[dim];
+ float *aLum = new float[dim];
+ float *bLum = new float[dim];
+
+ float *aA = new float[dim];
+ float *bA = new float[dim];
+ float *aB = new float[dim];
+ float *bB = new float[dim];
+
+ if (verbose) printf("Converting RGB to XYZ\n");
+
+ unsigned int x, y, w, h;
+ w = image_a->Get_Width();
+ h = image_a->Get_Height();
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ float r, g, b, l;
+ i = x + y * w;
+ r = powf(image_a->Get_Red(i) / 255.0f, gamma);
+ g = powf(image_a->Get_Green(i) / 255.0f, gamma);
+ b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
+
+ AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]);
+ XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]);
+ r = powf(image_b->Get_Red(i) / 255.0f, gamma);
+ g = powf(image_b->Get_Green(i) / 255.0f, gamma);
+ b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
+
+ AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]);
+ XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]);
+ aLum[i] = aY[i] * luminance;
+ bLum[i] = bY[i] * luminance;
}
+ }
- if (verbose) printf("Constructing Laplacian Pyramids\n");
-
- LPyramid *la = new LPyramid(aLum, w, h);
- LPyramid *lb = new LPyramid(bLum, w, h);
+ if (verbose) printf("Constructing Laplacian Pyramids\n");
- float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
- float pixels_per_degree = w / num_one_degree_pixels;
+ LPyramid *la = new LPyramid(aLum, w, h);
+ LPyramid *lb = new LPyramid(bLum, w, h);
- if (verbose) printf("Performing test\n");
-
- float num_pixels = 1;
- unsigned int adaptation_level = 0;
- for (i = 0; i < MAX_PYR_LEVELS; i++) {
- adaptation_level = i;
- if (num_pixels > num_one_degree_pixels) break;
- num_pixels *= 2;
- }
-
- float cpd[MAX_PYR_LEVELS];
- cpd[0] = 0.5f * pixels_per_degree;
- for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
- float csf_max = csf(3.248f, 100.0f);
-
- float F_freq[MAX_PYR_LEVELS - 2];
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
-
- unsigned int pixels_failed = 0;
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- int index = x + y * w;
- float contrast[MAX_PYR_LEVELS - 2];
- float sum_contrast = 0;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- float n1 = fabsf(la->Get_Value(x,y,i) - la->Get_Value(x,y,i + 1));
- float n2 = fabsf(lb->Get_Value(x,y,i) - lb->Get_Value(x,y,i + 1));
- float numerator = (n1 > n2) ? n1 : n2;
- float d1 = fabsf(la->Get_Value(x,y,i+2));
- float d2 = fabsf(lb->Get_Value(x,y,i+2));
- float denominator = (d1 > d2) ? d1 : d2;
- if (denominator < 1e-5f) denominator = 1e-5f;
- contrast[i] = numerator / denominator;
- sum_contrast += contrast[i];
- }
- if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
- float F_mask[MAX_PYR_LEVELS - 2];
- float adapt = la->Get_Value(x,y,adaptation_level) + lb->Get_Value(x,y,adaptation_level);
- adapt *= 0.5f;
- if (adapt < 1e-5) adapt = 1e-5f;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
+ float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
+ float pixels_per_degree = w / num_one_degree_pixels;
+
+ if (verbose) printf("Performing test\n");
+
+ float num_pixels = 1;
+ unsigned int adaptation_level = 0;
+ for (i = 0; i < MAX_PYR_LEVELS; i++) {
+ adaptation_level = i;
+ if (num_pixels > num_one_degree_pixels) break;
+ num_pixels *= 2;
+ }
+
+ float cpd[MAX_PYR_LEVELS];
+ cpd[0] = 0.5f * pixels_per_degree;
+ for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
+ float csf_max = csf(3.248f, 100.0f);
+
+ float F_freq[MAX_PYR_LEVELS - 2];
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
+
+ unsigned int pixels_failed = 0;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ int index = x + y * w;
+ float contrast[MAX_PYR_LEVELS - 2];
+ float sum_contrast = 0;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ float n1 = fabsf(la->Get_Value(x,y,i) - la->Get_Value(x,y,i + 1));
+ float n2 = fabsf(lb->Get_Value(x,y,i) - lb->Get_Value(x,y,i + 1));
+ float numerator = (n1 > n2) ? n1 : n2;
+ float d1 = fabsf(la->Get_Value(x,y,i+2));
+ float d2 = fabsf(lb->Get_Value(x,y,i+2));
+ float denominator = (d1 > d2) ? d1 : d2;
+ if (denominator < 1e-5f) denominator = 1e-5f;
+ contrast[i] = numerator / denominator;
+ sum_contrast += contrast[i];
+ }
+ if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
+ float F_mask[MAX_PYR_LEVELS - 2];
+ float adapt = la->Get_Value(x,y,adaptation_level) + lb->Get_Value(x,y,adaptation_level);
+ adapt *= 0.5f;
+ if (adapt < 1e-5) adapt = 1e-5f;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
+ }
+ float factor = 0;
+ for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+ factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
+ }
+ if (factor < 1) factor = 1;
+ if (factor > 10) factor = 10;
+ float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(x,y,0));
+ bool pass = true;
+ // pure luminance test
+ if (delta > factor * tvi(adapt)) {
+ pass = false;
+ } else {
+ // CIE delta E test with modifications
+ float color_scale = 1.0f;
+ // ramp down the color test in scotopic regions
+ if (adapt < 10.0f) {
+ color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
+ color_scale = color_scale * color_scale;
}
- float factor = 0;
- for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
- factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
+ float da = aA[index] - bA[index];
+ float db = aB[index] - bB[index];
+ da = da * da;
+ db = db * db;
+ float delta_e = (da + db) * color_scale;
+ if (delta_e > factor) {
+ pass = false;
}
- if (factor < 1) factor = 1;
- if (factor > 10) factor = 10;
- float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(x,y,0));
- bool pass = true;
- // pure luminance test
- if (delta > factor * tvi(adapt)) {
- pass = false;
- } else {
- // CIE delta E test with modifications
- float color_scale = 1.0f;
- // ramp down the color test in scotopic regions
- if (adapt < 10.0f) {
- color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
- color_scale = color_scale * color_scale;
- }
- float da = aA[index] - bA[index];
- float db = aB[index] - bB[index];
- da = da * da;
- db = db * db;
- float delta_e = (da + db) * color_scale;
- if (delta_e > factor) {
- pass = false;
- }
- }
- if (!pass)
- pixels_failed++;
+ }
+ if (!pass)
+ pixels_failed++;
#if IMAGE_DIFF_ENABLED
- if (!pass) {
- if (args.ImgDiff) {
- args.ImgDiff->Set(255, 0, 0, 255, index);
- }
- } else {
- if (args.ImgDiff) {
- args.ImgDiff->Set(0, 0, 0, 255, index);
- }
+ if (!pass) {
+ if (args.ImgDiff) {
+ args.ImgDiff->Set(255, 0, 0, 255, index);
+ }
+ } else {
+ if (args.ImgDiff) {
+ args.ImgDiff->Set(0, 0, 0, 255, index);
}
+ }
#endif
- }
}
+ }
- if (aX) delete[] aX;
- if (aY) delete[] aY;
- if (aZ) delete[] aZ;
- if (bX) delete[] bX;
- if (bY) delete[] bY;
- if (bZ) delete[] bZ;
- if (aLum) delete[] aLum;
- if (bLum) delete[] bLum;
- if (la) delete la;
- if (lb) delete lb;
- if (aA) delete aA;
- if (bA) delete bA;
- if (aB) delete aB;
- if (bB) delete bB;
+ if (aX) delete[] aX;
+ if (aY) delete[] aY;
+ if (aZ) delete[] aZ;
+ if (bX) delete[] bX;
+ if (bY) delete[] bY;
+ if (bZ) delete[] bZ;
+ if (aLum) delete[] aLum;
+ if (bLum) delete[] bLum;
+ if (la) delete la;
+ if (lb) delete lb;
+ if (aA) delete aA;
+ if (bA) delete bA;
+ if (aB) delete aB;
+ if (bB) delete bB;
- return pixels_failed;
+ return pixels_failed;
}
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index ee79666..70c6e12 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -1,19 +1,19 @@
/*
-PerceptualDiff - a program that compares two images using a perceptual metric
-based on the paper :
-A perceptual metric for production testing. Journal of graphics tools, 9(4):33-40, 2004, Hector Yee
-Copyright (C) 2006 Yangli Hector Yee
+ PerceptualDiff - a program that compares two images using a perceptual metric
+ based on the paper :
+ A perceptual metric for production testing. Journal of graphics tools, 9(4):33-40, 2004, Hector Yee
+ Copyright (C) 2006 Yangli Hector Yee
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
@@ -27,19 +27,19 @@ if not, write to the Free Software Found
int main(int argc, char **argv)
{
- CompareArgs args;
+ CompareArgs args;
- if (!args.Parse_Args(argc, argv)) {
- printf("%s", args.ErrorStr.c_str());
- return -1;
- } else {
- if (args.Verbose) args.Print_Args();
- }
- int result = Yee_Compare(args) == true;
- if (result) {
- printf("PASS: %s\n", args.ErrorStr.c_str());
- } else {
- printf("FAIL: %s\n", args.ErrorStr.c_str());
- }
- return result;
+ if (!args.Parse_Args(argc, argv)) {
+ printf("%s", args.ErrorStr.c_str());
+ return -1;
+ } else {
+ if (args.Verbose) args.Print_Args();
+ }
+ int result = Yee_Compare(args) == true;
+ if (result) {
+ printf("PASS: %s\n", args.ErrorStr.c_str());
+ } else {
+ printf("FAIL: %s\n", args.ErrorStr.c_str());
+ }
+ return result;
}
diff --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp
index a39195f..0b540d2 100644
--- a/test/pdiff/RGBAImage.cpp
+++ b/test/pdiff/RGBAImage.cpp
@@ -1,17 +1,17 @@
/*
-RGBAImage.cpp
-Copyright (C) 2006 Yangli Hector Yee
+ RGBAImage.cpp
+ Copyright (C) 2006 Yangli Hector Yee
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "RGBAImage.h"
@@ -24,60 +24,60 @@ if not, write to the Free Software Found
// Reads Tiff Images
RGBAImage* RGBAImage::ReadTiff(char *filename)
{
- RGBAImage *fimg = 0;
+ RGBAImage *fimg = 0;
TIFF* tif = TIFFOpen(filename, "r");
- char emsg[1024];
- emsg[0] = 0;
+ char emsg[1024];
+ emsg[0] = 0;
if (tif) {
- TIFFRGBAImage img;
+ TIFFRGBAImage img;
- if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
- size_t npixels;
- uint32* raster;
-
- npixels = img.width * img.height;
- raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
- if (raster != NULL) {
- if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
- // result is in ABGR
- fimg = new RGBAImage(img.width, img.height);
- for (int y = img.height - 1; y >= 0; y--) {
- for (int x = 0; x < (int) img.width; x++) {
- fimg->Set(x,img.height - (y+1), raster[x + y * img.width]);
- }
- }
- }
- _TIFFfree(raster);
+ if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
+ size_t npixels;
+ uint32* raster;
+
+ npixels = img.width * img.height;
+ raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
+ if (raster != NULL) {
+ if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
+ // result is in ABGR
+ fimg = new RGBAImage(img.width, img.height);
+ for (int y = img.height - 1; y >= 0; y--) {
+ for (int x = 0; x < (int) img.width; x++) {
+ fimg->Set(x,img.height - (y+1), raster[x + y * img.width]);
}
+ }
+ }
+ _TIFFfree(raster);
}
- TIFFRGBAImageEnd(&img);
}
- return fimg;
+ TIFFRGBAImageEnd(&img);
+ }
+ return fimg;
}
#endif /* HAVE_LIBTIFF */
// This portion was written by Scott Corley
RGBAImage* RGBAImage::ReadPNG(char *filename)
{
- RGBAImage *fimg = 0;
- FILE *fp=fopen(filename, "rb");
- if (!fp)
- {
- return NULL;
- }
- png_byte header[8];
+ RGBAImage *fimg = 0;
+ FILE *fp=fopen(filename, "rb");
+ if (!fp)
+ {
+ return NULL;
+ }
+ png_byte header[8];
- fread(header, 1, 8, fp);
- bool is_png = !png_sig_cmp(header, 0, 8);
- if (!is_png)
- {
- return NULL;
- }
+ fread(header, 1, 8, fp);
+ bool is_png = !png_sig_cmp(header, 0, 8);
+ if (!is_png)
+ {
+ return NULL;
+ }
png_structp png_ptr = png_create_read_struct
- (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
- NULL, NULL);
+ (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ NULL, NULL);
if (!png_ptr)
return (NULL);
@@ -85,7 +85,7 @@ RGBAImage* RGBAImage::ReadPNG(char *file
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr,
- (png_infopp)NULL, (png_infopp)NULL);
+ (png_infopp)NULL, (png_infopp)NULL);
return (NULL);
}
@@ -93,52 +93,52 @@ RGBAImage* RGBAImage::ReadPNG(char *file
if (!end_info)
{
png_destroy_read_struct(&png_ptr, &info_ptr,
- (png_infopp)NULL);
+ (png_infopp)NULL);
return (NULL);
}
- png_init_io(png_ptr, fp);
- png_set_sig_bytes(png_ptr, 8);
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, 8);
- png_read_png(png_ptr, info_ptr, 0, NULL);
+ png_read_png(png_ptr, info_ptr, 0, NULL);
- png_bytep *row_pointers;
- row_pointers = png_get_rows(png_ptr, info_ptr);
+ png_bytep *row_pointers;
+ row_pointers = png_get_rows(png_ptr, info_ptr);
- fimg = new RGBAImage(png_ptr->width, png_ptr->height);
- for (int y = 0; y < (int) png_ptr->height; y++) {
- for (int x = 0; x < (int) png_ptr->width; x++) {
- uint32_t value = 0;
- if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
- value = ((uint32_t)row_pointers[y][x*4]) | (((uint32_t)row_pointers[y][x*4+1])<<8) | (((uint32_t)row_pointers[y][x*4+2])<<16) |(((uint32_t)row_pointers[y][x*4+3])<<24);
- else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
- value = ((uint32_t)row_pointers[y][x*3] /*B*/) | (((uint32_t)row_pointers[y][x*3+1] /*G*/)<<8) | (((uint32_t)row_pointers[y][x*3+2]/*R*/)<<16) | (0xFFUL << 24);
- fimg->Set(x,y, value);
- }
+ fimg = new RGBAImage(png_ptr->width, png_ptr->height);
+ for (int y = 0; y < (int) png_ptr->height; y++) {
+ for (int x = 0; x < (int) png_ptr->width; x++) {
+ uint32_t value = 0;
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ value = ((uint32_t)row_pointers[y][x*4]) | (((uint32_t)row_pointers[y][x*4+1])<<8) | (((uint32_t)row_pointers[y][x*4+2])<<16) |(((uint32_t)row_pointers[y][x*4+3])<<24);
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ value = ((uint32_t)row_pointers[y][x*3] /*B*/) | (((uint32_t)row_pointers[y][x*3+1] /*G*/)<<8) | (((uint32_t)row_pointers[y][x*3+2]/*R*/)<<16) | (0xFFUL << 24);
+ fimg->Set(x,y, value);
}
+ }
- png_read_destroy(png_ptr, info_ptr, end_info);
- return fimg;
+ png_read_destroy(png_ptr, info_ptr, end_info);
+ return fimg;
}
bool RGBAImage::WritePPM()
{
- if (Width <= 0) return false;
- if (Height <=0 ) return false;
- FILE *out = fopen(Name.c_str(), "wb");
- if (!out) return false;
- fprintf(out, "P6\n%d %d 255\n", Width, Height);
- for (int y = 0; y < Height; y++) {
- for (int x = 0; x < Width; x++) {
- int i = x + y * Width;
- unsigned char r = Get_Red(i);
- unsigned char g = Get_Green(i);
- unsigned char b = Get_Blue(i);
- fwrite(&r, 1, 1, out);
- fwrite(&g, 1, 1, out);
- fwrite(&b, 1, 1, out);
- }
+ if (Width <= 0) return false;
+ if (Height <=0 ) return false;
+ FILE *out = fopen(Name.c_str(), "wb");
+ if (!out) return false;
+ fprintf(out, "P6\n%d %d 255\n", Width, Height);
+ for (int y = 0; y < Height; y++) {
+ for (int x = 0; x < Width; x++) {
+ int i = x + y * Width;
+ unsigned char r = Get_Red(i);
+ unsigned char g = Get_Green(i);
+ unsigned char b = Get_Blue(i);
+ fwrite(&r, 1, 1, out);
+ fwrite(&g, 1, 1, out);
+ fwrite(&b, 1, 1, out);
}
- fclose(out);
- return true;
+ }
+ fclose(out);
+ return true;
}
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index f5d27c5..31727fa 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -1,17 +1,17 @@
/*
-RGBAImage.h
-Copyright (C) 2006 Yangli Hector Yee
+ RGBAImage.h
+ Copyright (C) 2006 Yangli Hector Yee
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _RGAIMAGE_H
@@ -24,51 +24,51 @@ if not, write to the Free Software Found
class RGBAImage
{
public:
- RGBAImage() { Width = 0; Height = 0; Data = 0; }
- RGBAImage(int w, int h, const char *name = 0)
+ RGBAImage() { Width = 0; Height = 0; Data = 0; }
+ RGBAImage(int w, int h, const char *name = 0)
{
- Width = w;
- Height = h;
- if (name) Name = name;
- Data = new unsigned int[w * h];
+ Width = w;
+ Height = h;
+ if (name) Name = name;
+ Data = new unsigned int[w * h];
};
- ~RGBAImage() { if (Data) delete[] Data; }
- virtual unsigned char Get_Red(unsigned int i) { return (Data[i] & 0xFF); }
- virtual unsigned char Get_Green(unsigned int i) { return ((Data[i]>>8) & 0xFF); }
- virtual unsigned char Get_Blue(unsigned int i) { return ((Data[i]>>16) & 0xFF); }
- virtual unsigned char Get_Alpha(unsigned int i) { return ((Data[i]>>24) & 0xFF); }
- virtual void Set(unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned int i)
+ ~RGBAImage() { if (Data) delete[] Data; }
+ virtual unsigned char Get_Red(unsigned int i) { return (Data[i] & 0xFF); }
+ virtual unsigned char Get_Green(unsigned int i) { return ((Data[i]>>8) & 0xFF); }
+ virtual unsigned char Get_Blue(unsigned int i) { return ((Data[i]>>16) & 0xFF); }
+ virtual unsigned char Get_Alpha(unsigned int i) { return ((Data[i]>>24) & 0xFF); }
+ virtual void Set(unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned int i)
{ Data[i] = r | (g << 8) | (b << 16) | (a << 24); }
- int Get_Width(void) const { return Width; }
- int Get_Height(void) const { return Height; }
- virtual void Set(int x, int y, unsigned int d) { Data[x + y * Width] = d; }
- virtual unsigned int Get(int x, int y) const { return Data[x + y * Width]; }
- virtual unsigned int Get(int i) const { return Data[i]; }
- const std::string &Get_Name(void) const { return Name; }
+ int Get_Width(void) const { return Width; }
+ int Get_Height(void) const { return Height; }
+ virtual void Set(int x, int y, unsigned int d) { Data[x + y * Width] = d; }
+ virtual unsigned int Get(int x, int y) const { return Data[x + y * Width]; }
+ virtual unsigned int Get(int i) const { return Data[i]; }
+ const std::string &Get_Name(void) const { return Name; }
- bool WritePPM();
- static RGBAImage* ReadTiff(char *filename);
- static RGBAImage* ReadPNG(char *filename);
+ bool WritePPM();
+ static RGBAImage* ReadTiff(char *filename);
+ static RGBAImage* ReadPNG(char *filename);
protected:
- int Width;
- int Height;
- std::string Name;
- unsigned int *Data;
+ int Width;
+ int Height;
+ std::string Name;
+ unsigned int *Data;
};
class RGBACairoImage : public RGBAImage
{
public:
RGBACairoImage (cairo_surface_t *surface)
- {
- Width = cairo_image_surface_get_width (surface);
- Height = cairo_image_surface_get_height (surface);
- Data = (unsigned int *) cairo_image_surface_get_data (surface);
- if (cairo_image_surface_get_stride (surface) != 4 * Width) {
- fprintf (stderr, "Error: Currently only support images where stride == 4 * width\n");
- exit (1);
+ {
+ Width = cairo_image_surface_get_width (surface);
+ Height = cairo_image_surface_get_height (surface);
+ Data = (unsigned int *) cairo_image_surface_get_data (surface);
+ if (cairo_image_surface_get_stride (surface) != 4 * Width) {
+ fprintf (stderr, "Error: Currently only support images where stride == 4 * width\n");
+ exit (1);
+ }
}
- }
~RGBACairoImage() { }
unsigned int ARGB_to_ABGR(unsigned int pixel) const {
diff --git a/test/pdiff/pdiff.h b/test/pdiff/pdiff.h
index 7c2c401..195a34c 100644
--- a/test/pdiff/pdiff.h
+++ b/test/pdiff/pdiff.h
@@ -1,17 +1,17 @@
/*
-Copyright (C) 2006 Yangli Hector Yee
-Copyright (C) 2006 Red Hat, Inc.
+ Copyright (C) 2006 Yangli Hector Yee
+ Copyright (C) 2006 Red Hat, Inc.
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ You should have received a copy of the GNU General Public License along with this program;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _PDIFF_H
diff-tree 4f6611ef6cac3928427b6fc28dab40829ef0d748 (from ccb3a6c4deadeaecf133dce6f1b152507ab5a14f)
Author: Carl Worth <cworth at cworth.org>
Date: Wed Dec 13 17:40:59 2006 -0800
pdiff: Fix line endings
diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
index 0e8d68a..be0daa5 100644
--- a/test/pdiff/LPyramid.cpp
+++ b/test/pdiff/LPyramid.cpp
@@ -1,87 +1,87 @@
-/*
-Laplacian Pyramid
-Copyright (C) 2006 Yangli Hector Yee
-
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "LPyramid.h"
-
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
-LPyramid::LPyramid(float *image, int width, int height) :
- Width(width),
- Height(height)
-{
- // Make the Laplacian pyramid by successively
- // copying the earlier levels and blurring them
- for (int i=0; i<MAX_PYR_LEVELS; i++) {
- if (i == 0) {
- Levels[i] = Copy(image);
- } else {
- Levels[i] = new float[Width * Height];
- Convolve(Levels[i], Levels[i - 1]);
- }
- }
-}
-
-LPyramid::~LPyramid()
-{
- for (int i=0; i<MAX_PYR_LEVELS; i++) {
- if (Levels[i]) delete Levels[i];
- }
-}
-
-float *LPyramid::Copy(float *img)
-{
- int max = Width * Height;
- float *out = new float[max];
- for (int i = 0; i < max; i++) out[i] = img[i];
-
- return out;
-}
-
-void LPyramid::Convolve(float *a, float *b)
-// convolves image b with the filter kernel and stores it in a
-{
- int y,x,i,j,nx,ny;
- const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
-
- for (y=0; y<Height; y++) {
- for (x=0; x<Width; x++) {
- int index = y * Width + x;
- a[index] = 0.0f;
- for (i=-2; i<=2; i++) {
- for (j=-2; j<=2; j++) {
- nx=x+i;
- ny=y+j;
- if (nx<0) nx=-nx;
- if (ny<0) ny=-ny;
- if (nx>=Width) nx=2*(Width-1)-nx;
- if (ny>=Height) ny=2*(Height-1)-ny;
- a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * Width + nx];
- }
- }
- }
- }
-}
-
-float LPyramid::Get_Value(int x, int y, int level)
-{
- int index = x + y * Width;
- int l = level;
- if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
- return Levels[level][index];
-}
+/*
+Laplacian Pyramid
+Copyright (C) 2006 Yangli Hector Yee
+
+This program is free software; you can redistribute it and/or modify it under the terms of the
+GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with this program;
+if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "LPyramid.h"
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+LPyramid::LPyramid(float *image, int width, int height) :
+ Width(width),
+ Height(height)
+{
+ // Make the Laplacian pyramid by successively
+ // copying the earlier levels and blurring them
+ for (int i=0; i<MAX_PYR_LEVELS; i++) {
+ if (i == 0) {
+ Levels[i] = Copy(image);
+ } else {
+ Levels[i] = new float[Width * Height];
+ Convolve(Levels[i], Levels[i - 1]);
+ }
+ }
+}
+
+LPyramid::~LPyramid()
+{
+ for (int i=0; i<MAX_PYR_LEVELS; i++) {
+ if (Levels[i]) delete Levels[i];
+ }
+}
+
+float *LPyramid::Copy(float *img)
+{
+ int max = Width * Height;
+ float *out = new float[max];
+ for (int i = 0; i < max; i++) out[i] = img[i];
+
+ return out;
+}
+
+void LPyramid::Convolve(float *a, float *b)
+// convolves image b with the filter kernel and stores it in a
+{
+ int y,x,i,j,nx,ny;
+ const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
+
+ for (y=0; y<Height; y++) {
+ for (x=0; x<Width; x++) {
+ int index = y * Width + x;
+ a[index] = 0.0f;
+ for (i=-2; i<=2; i++) {
+ for (j=-2; j<=2; j++) {
+ nx=x+i;
+ ny=y+j;
+ if (nx<0) nx=-nx;
+ if (ny<0) ny=-ny;
+ if (nx>=Width) nx=2*(Width-1)-nx;
+ if (ny>=Height) ny=2*(Height-1)-ny;
+ a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * Width + nx];
+ }
+ }
+ }
+ }
+}
+
+float LPyramid::Get_Value(int x, int y, int level)
+{
+ int index = x + y * Width;
+ int l = level;
+ if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
+ return Levels[level][index];
+}
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
index b53f3ef..162d464 100644
--- a/test/pdiff/LPyramid.h
+++ b/test/pdiff/LPyramid.h
@@ -1,38 +1,38 @@
-/*
-Laplacian Pyramid
-Copyright (C) 2006 Yangli Hector Yee
-
-This program is free software; you can redistribute it and/or modify it under the terms of the
-GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with this program;
-if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifndef _LPYRAMID_H
-#define _LPYRAMID_H
-
-#define MAX_PYR_LEVELS 8
-
-class LPyramid
-{
-public:
- LPyramid(float *image, int width, int height);
- virtual ~LPyramid();
- float Get_Value(int x, int y, int level);
-protected:
- float *Copy(float *img);
- void Convolve(float *a, float *b);
-
- // Succesively blurred versions of the original image
- float *Levels[MAX_PYR_LEVELS];
-
- int Width;
- int Height;
-};
-
-#endif // _LPYRAMID_H
+/*
+Laplacian Pyramid
+Copyright (C) 2006 Yangli Hector Yee
+
+This program is free software; you can redistribute it and/or modify it under the terms of the
+GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with this program;
+if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef _LPYRAMID_H
+#define _LPYRAMID_H
+
+#define MAX_PYR_LEVELS 8
+
+class LPyramid
+{
+public:
+ LPyramid(float *image, int width, int height);
+ virtual ~LPyramid();
+ float Get_Value(int x, int y, int level);
+protected:
+ float *Copy(float *img);
+ void Convolve(float *a, float *b);
+
+ // Succesively blurred versions of the original image
+ float *Levels[MAX_PYR_LEVELS];
+
+ int Width;
+ int Height;
+};
+
+#endif // _LPYRAMID_H
diff-tree ccb3a6c4deadeaecf133dce6f1b152507ab5a14f (from 55f776876d231a035cdc5da9bb90cbba14f19248)
Author: Carl Worth <cworth at cworth.org>
Date: Tue Dec 12 16:49:27 2006 -0800
pdiff: Compile pdiff algorithm as a libtool convenience library
The convenience library provides a pdiff_compare function with a
cairo interface into the perceptual diff algorithm.
diff --git a/test/Makefile.am b/test/Makefile.am
index 65325f1..26f28b5 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,4 +1,4 @@
-DIST_SUBDIRS=pdiff
+SUBDIRS=pdiff .
# Here are all the tests that are run unconditionally
TESTS = \
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 9f441b9..6443269 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -1,15 +1,19 @@
EXTRA_PROGRAMS = perceptualdiff
-perceptualdiff_SOURCES = \
- CompareArgs.cpp \
- CompareArgs.h \
+noinst_LTLIBRARIES = libpdiff.la
+libpdiff_la_SOURCES = \
+ pdiff.h \
LPyramid.cpp \
LPyramid.h \
Metric.cpp \
Metric.h \
- PerceptualDiff.cpp \
RGBAImage.cpp \
RGBAImage.h
+perceptualdiff_SOURCES = \
+ CompareArgs.cpp \
+ CompareArgs.h \
+ PerceptualDiff.cpp
+
INCLUDES = -I$(top_srcdir)/src
-LDADD = $(top_builddir)/src/libcairo.la
+LDADD = libpdiff.la $(top_builddir)/src/libcairo.la
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index 7974fa5..ded0afc 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -19,6 +19,7 @@ if not, write to the Free Software Found
#include "RGBAImage.h"
#include "LPyramid.h"
#include <math.h>
+#include "pdiff.h"
#ifndef M_PI
#define M_PI 3.14159265f
@@ -183,6 +184,23 @@ bool Yee_Compare(CompareArgs &args)
return false;
}
+int
+pdiff_compare (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ double gamma,
+ double luminance,
+ double field_of_view)
+{
+ RGBAImage *image_a, *image_b;
+
+ image_a = new RGBACairoImage (surface_a);
+ image_b = new RGBACairoImage (surface_b);
+
+ return Yee_Compare_Images (image_a, image_b,
+ gamma, luminance,
+ field_of_view, false);
+}
+
int Yee_Compare_Images(RGBAImage *image_a,
RGBAImage *image_b,
float gamma,
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index 6aa5ff9..f5d27c5 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -99,7 +99,7 @@ public:
unsigned char Get_Green(unsigned int i) { return (Get_Unpremultiply(i) & 0x0000ff00) >> 8;}
unsigned char Get_Blue(unsigned int i) { return (Get_Unpremultiply(i) & 0x000000ff) >> 0;}
unsigned int Get(int x, int y) const { return Get(Width * y + x); }
- unsigned int Get(int i) const { return ARGB_to_ABGR(Get_Pixel_Unpremultiply(i)); }
+ unsigned int Get(int i) const { return ARGB_to_ABGR(Get_Unpremultiply(i)); }
};
#endif
diff --git a/test/pdiff/pdiff.h b/test/pdiff/pdiff.h
new file mode 100644
index 0000000..7c2c401
--- /dev/null
+++ b/test/pdiff/pdiff.h
@@ -0,0 +1,38 @@
+/*
+Copyright (C) 2006 Yangli Hector Yee
+Copyright (C) 2006 Red Hat, Inc.
+
+This program is free software; you can redistribute it and/or modify it under the terms of the
+GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with this program;
+if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _PDIFF_H
+#define _PDIFF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Image comparison metric using Yee's method (and a cairo interface)
+ * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
+ */
+int
+pdiff_compare (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ double gamma,
+ double luminance,
+ double field_of_view);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff-tree 55f776876d231a035cdc5da9bb90cbba14f19248 (from 0d7870b6bf13edfe513e2de25a5814a0a1b78c79)
Author: Carl Worth <cworth at cworth.org>
Date: Tue Dec 12 16:37:35 2006 -0800
test: Rework buffer_diff interface as new compare_surfaces
This is a slightly kinder interface that accepts cairo_image_surface_t
pointers rather than pointers to the raw image data and width, height,
stride. This brings us closer to hooking up the pdiff code.
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index 819ba16..99501bc 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -117,17 +117,19 @@ buffer_diff_core (unsigned char *_buf_a,
}
void
-buffer_diff (unsigned char *buf_a,
- unsigned char *buf_b,
- unsigned char *buf_diff,
- int width,
- int height,
- int stride,
- buffer_diff_result_t *result)
-{
- buffer_diff_core(buf_a, buf_b, buf_diff,
- width, height, stride, 0xffffffff,
- result);
+compare_surfaces (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ cairo_surface_t *surface_diff,
+ buffer_diff_result_t *result)
+{
+ buffer_diff_core (cairo_image_surface_get_data (surface_a),
+ cairo_image_surface_get_data (surface_b),
+ cairo_image_surface_get_data (surface_diff),
+ cairo_image_surface_get_width (surface_a),
+ cairo_image_surface_get_height (surface_a),
+ cairo_image_surface_get_stride (surface_a),
+ 0xffffffff,
+ result);
}
void
@@ -304,11 +306,7 @@ image_diff_core (const char *filename_a,
surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
width_a, height_a);
- buffer_diff (cairo_image_surface_get_data (surface_a),
- cairo_image_surface_get_data (surface_b),
- cairo_image_surface_get_data (surface_diff),
- width_a, height_a, stride_a,
- result);
+ compare_surfaces (surface_a, surface_b, surface_diff, result);
if (result->pixels_changed) {
FILE *png_file;
diff --git a/test/buffer-diff.h b/test/buffer-diff.h
index d95c213..cd35345 100644
--- a/test/buffer-diff.h
+++ b/test/buffer-diff.h
@@ -36,22 +36,19 @@ typedef struct _buffer_diff_result {
unsigned int max_diff;
} buffer_diff_result_t;
-/* Compares two image buffers.
+/* Compares two image surfaces
*
* Provides number of pixels changed and maximum single-channel
* difference in result.
*
- * Also fills in a "diff" buffer intended to visually show where the
+ * Also fills in a "diff" surface intended to visually show where the
* images differ.
*/
void
-buffer_diff (unsigned char *buf_a,
- unsigned char *buf_b,
- unsigned char *buf_diff,
- int width,
- int height,
- int stride,
- buffer_diff_result_t *result);
+compare_surfaces (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ cairo_surface_t *surface_diff,
+ buffer_diff_result_t *result);
/* Compares two image buffers ignoring the alpha channel.
*
diff-tree 0d7870b6bf13edfe513e2de25a5814a0a1b78c79 (from a87f494d4b91f3acc78d6d7dd737939633f28d71)
Author: Carl Worth <cworth at cworth.org>
Date: Tue Dec 12 16:15:08 2006 -0800
pdiff: Teach pdiff code to accept cairo image surfaces
This is a second small step in enabling cairo's test suite and the
pdiff code to start working together.
diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index aa69a7d..60520b0 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -60,6 +60,7 @@ CompareArgs::~CompareArgs()
bool CompareArgs::Parse_Args(int argc, char **argv)
{
+ cairo_surface_t *surface;
if (argc < 3) {
ErrorStr = copyright;
ErrorStr += usage;
@@ -67,37 +68,29 @@ bool CompareArgs::Parse_Args(int argc, c
}
for (int i = 0; i < argc; i++) {
if (i == 1) {
-#if HAVE_LIBTIFF
- ImgA = RGBAImage::ReadTiff(argv[1]);
- if (!ImgA) {
-#endif /* HAVE_LIBTIFF */
- ImgA = RGBAImage::ReadPNG(argv[1]);
- if (!ImgA)
- {
- ErrorStr = "FAIL: Cannot open ";
- ErrorStr += argv[1];
- ErrorStr += "\n";
- return false;
- }
-#if HAVE_LIBTIFF
+ surface = cairo_image_surface_create_from_png (argv[1]);
+ if (cairo_surface_status (surface))
+ {
+ ErrorStr = "FAIL: Cannot open ";
+ ErrorStr += argv[1];
+ ErrorStr += " ";
+ ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+ ErrorStr += "\n";
+ return false;
}
-#endif /* HAVE_LIBTIFF */
+ ImgA = new RGBACairoImage (surface);
} else if (i == 2) {
-#if HAVE_LIBTIFF
- ImgB = RGBAImage::ReadTiff(argv[2]);
- if (!ImgB) {
-#endif /* HAVE_LIBTIFF */
- ImgB = RGBAImage::ReadPNG(argv[2]);
- if (!ImgB)
- {
- ErrorStr = "FAIL: Cannot open ";
- ErrorStr += argv[2];
- ErrorStr += "\n";
- return false;
- }
-#if HAVE_LIBTIFF
+ surface = cairo_image_surface_create_from_png (argv[2]);
+ if (cairo_surface_status (surface))
+ {
+ ErrorStr = "FAIL: Cannot open ";
+ ErrorStr += argv[2];
+ ErrorStr += " ";
+ ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+ ErrorStr += "\n";
+ return false;
}
-#endif /* HAVE_LIBTIFF */
+ ImgB = new RGBACairoImage (surface);
} else {
if (strstr(argv[i], "-fov")) {
if (i + 1 < argc) {
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index a4a1ddd..fc6993f 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -20,6 +20,7 @@ if not, write to the Free Software Found
#include <string>
class RGBAImage;
+class RGBACairoImage;
// Args to pass into the comparison function
class CompareArgs
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 36bebd0..9f441b9 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -11,4 +11,5 @@ perceptualdiff_SOURCES = \
RGBAImage.cpp \
RGBAImage.h
+INCLUDES = -I$(top_srcdir)/src
LDADD = $(top_builddir)/src/libcairo.la
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index 65802f9..6aa5ff9 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -18,11 +18,13 @@ if not, write to the Free Software Found
#define _RGBAIMAGE_H
#include<string>
+#include<cairo.h>
// assumes data is in the ABGR format
class RGBAImage
{
public:
+ RGBAImage() { Width = 0; Height = 0; Data = 0; }
RGBAImage(int w, int h, const char *name = 0)
{
Width = w;
@@ -31,17 +33,17 @@ public:
Data = new unsigned int[w * h];
};
~RGBAImage() { if (Data) delete[] Data; }
- unsigned char Get_Red(unsigned int i) { return (Data[i] & 0xFF); }
- unsigned char Get_Green(unsigned int i) { return ((Data[i]>>8) & 0xFF); }
- unsigned char Get_Blue(unsigned int i) { return ((Data[i]>>16) & 0xFF); }
- unsigned char Get_Alpha(unsigned int i) { return ((Data[i]>>24) & 0xFF); }
- void Set(unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned int i)
+ virtual unsigned char Get_Red(unsigned int i) { return (Data[i] & 0xFF); }
+ virtual unsigned char Get_Green(unsigned int i) { return ((Data[i]>>8) & 0xFF); }
+ virtual unsigned char Get_Blue(unsigned int i) { return ((Data[i]>>16) & 0xFF); }
+ virtual unsigned char Get_Alpha(unsigned int i) { return ((Data[i]>>24) & 0xFF); }
+ virtual void Set(unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned int i)
{ Data[i] = r | (g << 8) | (b << 16) | (a << 24); }
int Get_Width(void) const { return Width; }
int Get_Height(void) const { return Height; }
- void Set(int x, int y, unsigned int d) { Data[x + y * Width] = d; }
- unsigned int Get(int x, int y) const { return Data[x + y * Width]; }
- unsigned int Get(int i) const { return Data[i]; }
+ virtual void Set(int x, int y, unsigned int d) { Data[x + y * Width] = d; }
+ virtual unsigned int Get(int x, int y) const { return Data[x + y * Width]; }
+ virtual unsigned int Get(int i) const { return Data[i]; }
const std::string &Get_Name(void) const { return Name; }
bool WritePPM();
@@ -54,4 +56,50 @@ protected:
unsigned int *Data;
};
+class RGBACairoImage : public RGBAImage
+{
+public:
+ RGBACairoImage (cairo_surface_t *surface)
+ {
+ Width = cairo_image_surface_get_width (surface);
+ Height = cairo_image_surface_get_height (surface);
+ Data = (unsigned int *) cairo_image_surface_get_data (surface);
+ if (cairo_image_surface_get_stride (surface) != 4 * Width) {
+ fprintf (stderr, "Error: Currently only support images where stride == 4 * width\n");
+ exit (1);
+ }
+ }
+ ~RGBACairoImage() { }
+
+ unsigned int ARGB_to_ABGR(unsigned int pixel) const {
+ unsigned int new_pixel;
+ new_pixel = pixel & 0xff00ff00;
+ new_pixel |= (pixel & 0x00ff0000) >> 16;
+ new_pixel |= (pixel & 0x000000ff) << 16;
+ return new_pixel;
+ }
+ unsigned int Get_Unpremultiply(unsigned int i) const {
+ uint32_t pixel;
+ uint8_t alpha;
+
+ pixel = Data[i];
+
+ alpha = (pixel & 0xff000000) >> 24;
+
+ if (alpha == 0)
+ return 0;
+
+ return (alpha << 24) |
+ ((((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha) << 16 |
+ ((((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha) << 8 |
+ ((((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha) << 0;
+ }
+ unsigned char Get_Alpha(unsigned int i) { return (Get_Unpremultiply(i) & 0xff000000) >> 24;}
+ unsigned char Get_Red(unsigned int i) { return (Get_Unpremultiply(i) & 0x00ff0000) >> 16;}
+ unsigned char Get_Green(unsigned int i) { return (Get_Unpremultiply(i) & 0x0000ff00) >> 8;}
+ unsigned char Get_Blue(unsigned int i) { return (Get_Unpremultiply(i) & 0x000000ff) >> 0;}
+ unsigned int Get(int x, int y) const { return Get(Width * y + x); }
+ unsigned int Get(int i) const { return ARGB_to_ABGR(Get_Pixel_Unpremultiply(i)); }
+};
+
#endif
More information about the cairo-commit
mailing list