/* * edd error diffusion displacement * Copyright (c) 2008 Sam Hocevar * All Rights Reserved * * $Id$ * * This program is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ /* This program computes the Floyd-Steinberg error diffusion algorithm's * displacement on the given input image. Error diffusion displacement is * introduced in the paper "Reinstating Floyd-Steinberg: Improved Metrics * for Quality Assessment of Error Diffusion Algorithms.", ICISP 2008 * Proceedings. Lecture Notes in Computer Science 5099 Springer 2008, ISBN * 978-3-540-69904-0. * * The resulting dx/dy values are usually around 0.16/0.26 for images that * are not entirely black and white. */ #include "config.h" #include #include #include #include #define Z 3 int main(int argc, char *argv[]) { double sigma = 1.2, precision = 0.001, step = 2.; double best = 1., fx = -1., fy = -1., bfx = 0., bfy = 0.; double e, e0, e1; pipi_image_t *img, *kernel, *gauss, *dither, *tmp; int dx, dy; if(argc < 2) { fprintf(stderr, "%s: too few arguments\n", argv[0]); fprintf(stderr, "Usage: %s \n", argv[0]); return EXIT_FAILURE; } /* Load image, convert it to grayscale, dither it with Floyd-Steinberg */ img = pipi_load(argv[1]); pipi_set_colorspace(img, PIPI_PIXELS_Y_F32); gauss = pipi_gaussian_blur(img, sigma); kernel = pipi_load("ediff:fs"); dither = pipi_dither_ediff(img, kernel, PIPI_SCAN_RASTER); pipi_free(kernel); pipi_free(img); /* Compute the standard error */ tmp = pipi_gaussian_blur(dither, sigma); e0 = pipi_measure_msd(gauss, tmp); pipi_free(tmp); /* Compute the fast error */ tmp = pipi_gaussian_blur_ext(dither, sigma, sigma, 0.0, 0.16, 0.26); e1 = pipi_measure_msd(gauss, tmp); pipi_free(tmp); /* Compute displacement */ while(step > precision) { for(dy = 0; dy <= Z; dy++) for(dx = 0; dx <= Z; dx++) { tmp = pipi_gaussian_blur_ext(dither, sigma, sigma, 0.0, fx + step * dx / Z, fy + step * dy / Z); e = pipi_measure_msd(gauss, tmp); pipi_free(tmp); if(e < best) { best = e; bfx = fx + step * dx / Z; bfy = fy + step * dy / Z; } } fx = bfx - step / Z; fy = bfy - step / Z; step = step * 2 / Z; } printf("E: %g E_fast: %g E_min: %g dx: %g dy: %g\n", e0, e1, best, fx, fy); pipi_free(dither); pipi_free(gauss); return 0; }