[Pixman] [PATCH 07/14] pixman-image: Added enable-gnuplot config to view filters in gnuplot
Bill Spitzak
spitzak at gmail.com
Tue Apr 12 20:11:30 UTC 2016
On Mon, Apr 11, 2016 at 7:36 PM, Søren Sandmann Pedersen <
soren.sandmann at gmail.com> wrote:
> From: Bill Spitzak <spitzak at gmail.com>
>
> If enable-gnuplot is configured, then you can pipe the output of a
> pixman-using program to gnuplot and get a continuously-updated plot of
> the horizontal filter. This works well with demos/scale to test the
> filter generation.
>
> The plot is all the different subposition filters shuffled
> together. This is misleading in a few cases:
>
> IMPULSE.BOX - goes up and down as the subfilters have different
> numbers of non-zero samples
>
> IMPULSE.TRIANGLE - somewhat crooked for the same reason
>
> 1-wide filters - looks triangular, but a 1-wide box would be more
> accurate
>
Because you are not plotting the two dummy points at (0,±width/2), a 1-wide
filter is actually just a single point.
You may be right that leaving the dummy points off the plot may make it
easier to figure out what is going on.
> Changes by Søren: Rewrote the pixman-filter.c part to
> - make it generate correct coordinates
> - add a comment on how coordinates are generated
> - in rounding.txt, add a ceil() variant of the first-sample
> formula
> - make the gnuplot output slightly prettier
>
> v7: First time this ability was included
>
> v8: Use config option
> Moved code to the filter generator
> Modified scale demo to not call filter generator a second time.
>
> v10: Only print if successful generation of plots
> Use #ifdef, not #if
>
> v11: small whitespace fixes
>
> Signed-off-by: Bill Spitzak <spitzak at gmail.com>
> Signed-off-by: Søren Sandmann <soren.sandmann at gmail.com>
> ---
> configure.ac | 13 ++++++
> pixman/pixman-filter.c | 115
> +++++++++++++++++++++++++++++++++++++++++++++++++
> pixman/rounding.txt | 1 +
> 3 files changed, 129 insertions(+)
>
> diff --git a/configure.ac b/configure.ac
> index 6b2134e..e833e45 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -834,6 +834,19 @@ fi
> AC_SUBST(PIXMAN_TIMERS)
>
> dnl ===================================
> +dnl gnuplot
> +
> +AC_ARG_ENABLE(gnuplot,
> + [AC_HELP_STRING([--enable-gnuplot],
> + [enable output of filters that can be piped to gnuplot
> [default=no]])],
> + [enable_gnuplot=$enableval], [enable_gnuplot=no])
> +
> +if test $enable_gnuplot = yes ; then
> + AC_DEFINE(PIXMAN_GNUPLOT, 1, [enable output that can be piped to
> gnuplot])
> +fi
> +AC_SUBST(PIXMAN_GNUPLOT)
> +
> +dnl ===================================
> dnl GTK+
>
> AC_ARG_ENABLE(gtk,
> diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
> index b2bf53f..af46a43 100644
> --- a/pixman/pixman-filter.c
> +++ b/pixman/pixman-filter.c
> @@ -297,6 +297,117 @@ create_1d_filter (int *width,
> return params;
> }
>
> +#ifdef PIXMAN_GNUPLOT
> +
> +/* If enable-gnuplot is configured, then you can pipe the output of a
> + * pixman-using program to gnuplot and get a continuously-updated plot
> + * of the horizontal filter. This works well with demos/scale to test
> + * the filter generation.
> + *
> + * The plot is all the different subposition filters shuffled
> + * together. This is misleading in a few cases:
> + *
> + * IMPULSE.BOX - goes up and down as the subfilters have different
> + * numbers of non-zero samples
> + * IMPULSE.TRIANGLE - somewhat crooked for the same reason
> + * 1-wide filters - looks triangular, but a 1-wide box would be more
> + * accurate
> + */
> +static void
> +gnuplot_filter (int width, int n_phases, const pixman_fixed_t* p)
> +{
> + double step;
> + int i, j;
> + int first;
> +
> + step = 1.0 / n_phases;
> +
> + printf ("set style line 1 lc rgb '#0060ad' lt 1 lw 0.5 pt 7 pi 1 ps
> 0.5\n");
> + printf ("plot '-' with linespoints ls 1\n");
> +
> + /* The position of the first sample of the phase corresponding to
> + * frac is given by:
> + *
> + * ceil (frac - width / 2.0 - 0.5) + 0.5 - frac
> + *
> + * We have to find the frac that minimizes this expression.
> + *
> + * For odd widths, we have
> + *
> + * ceil (frac - width / 2.0 - 0.5) + 0.5 - frac
> + * = ceil (frac) + K - frac
> + * = 1 + K - frac
> + *
> + * for some K, so this is minimized when frac is maximized and
> + * strictly growing with frac. So for odd widths, we can simply
> + * start at the last phase and go backwards.
> + *
> + * For even widths, we have
> + *
> + * ceil (frac - width / 2.0 - 0.5) + 0.5 - frac
> + * = ceil (frac - 0.5) + K - frac
> + *
> + * The graph for this function (ignoring K) looks like this:
> + *
> + * 0.5
> + * | |\
> + * | | \
> + * | | \
> + * 0 | | \
> + * |\ |
> + * | \ |
> + * | \ |
> + * -0.5 | \|
> + * ---------------------------------
> + * 0 0.5 1
> + *
> + * So in this case we need to start with the phase whose frac is
> + * less than, but as close as possible to 0.5, then go backwards
> + * until we hit the first phase, then wrap around to the last
> + * phase and continue backwards.
> + *
> + * Which phase is as close as possible 0.5? The locations of the
> + * sampling point corresponding to the kth phase is given by
> + * 1/(2 * n_phases) + k / n_phases:
> + *
> + * 1/(2 * n_phases) + k / n_phases = 0.5
> + *
> + * from which it follows that
> + *
> + * k = (n_phases - 1) / 2
> + *
> + * rounded down is the phase in question.
> + */
> + if (width & 1)
> + first = n_phases - 1;
> + else
> + first = (n_phases - 1) / 2;
>
My version printed an extra point at 0,-width/2 here. Not sure if that is
an improvement or a bug, you might want to try it just to get your opinion.
> +
> + for (j = 0; j < width; ++j)
> + {
> + for (i = 0; i < n_phases; ++i)
> + {
> + int phase = first - i;
> + double frac, pos;
> +
> + if (phase < 0)
> + phase = n_phases + phase;
> +
> + frac = step / 2.0 + phase * step;
> + pos = ceil (frac - width / 2.0 - 0.5) + 0.5 - frac + j;
>
See below I think this has to be changed to the floor() version.
> +
> + printf ("%g %g\n",
> + pos,
> + pixman_fixed_to_double (*(p + phase * width + j)));
> + }
> + }
>
My version printed an extra point at 0,width/2 here.
> +
> + printf ("e\n");
> + fflush (stdout);
> +}
> +
> +#endif
> +
> /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
> * with the given kernels and scale parameters
> */
> @@ -346,5 +457,9 @@ out:
> free (horz);
> free (vert);
>
> +#ifdef PIXMAN_GNUPLOT
> + gnuplot_filter(width, subsample_x, params + 4);
> +#endif
> +
> return params;
> }
> diff --git a/pixman/rounding.txt b/pixman/rounding.txt
> index b52b084..1c00019 100644
> --- a/pixman/rounding.txt
> +++ b/pixman/rounding.txt
> @@ -160,6 +160,7 @@ which means the contents of the matrix corresponding
> to (frac) should
> contain width samplings of the function, with the first sample at:
>
> floor (frac - (width - 1) / 2.0 - e) + 0.5 - frac
> + = ceil (frac - width / 2.0 - 0.5) + 0.5 - frac
>
Unfortunately this produces numbers that don't agree with the filter
generator or filtering code.
For a width==4 filter with n_phases==1, the generator seems to produce
values at -1, 0, 1, 2, so the first sample is at -1. It also appears the
filtering sampler is using the same rule, otherwise these filters would
produce an obvious shift in the image.
frac = step/2 = .5
width = 3
floor (frac - (width - 1) / 2.0) + 0.5 - frac = floor(.5 - 1.5) +
0.5-0.5 = floor(-1) = -1.
ceil (frac - width / 2.0 - 0.5) + 0.5 - frac = ceil(.5 - 2.5) + 0.5-0.5
= ceil(-2) = -2
Whether by accident or not it looks like the correct formula is the floor
one with the epsilon (e) removed, in disagreement with your rounding.txt
document. I would recommend using that rather than changing the
interpretation of the filter matrix.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/pixman/attachments/20160412/613f374b/attachment-0001.html>
More information about the Pixman
mailing list