[gegl/samplers] Added nohalo sampler (VSQBS).
- From: Adam Turcotte <aturcotte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/samplers] Added nohalo sampler (VSQBS).
- Date: Mon, 1 Aug 2011 00:33:34 +0000 (UTC)
commit cfbbf7a2b2e81fe76c20e72a0a32921c4d1b4092
Author: Adam Turcotte <aturcotte src gnome org>
Date: Sun Jul 31 20:33:28 2011 -0400
Added nohalo sampler (VSQBS).
gegl/buffer/Makefile.am | 2 +
gegl/buffer/gegl-buffer-access.c | 1 +
gegl/buffer/gegl-buffer.c | 1 +
gegl/buffer/gegl-buffer.h | 3 +-
gegl/buffer/gegl-sampler-nohalo.c | 628 +++++++++++++++++++++++++++++++++++++
gegl/buffer/gegl-sampler-nohalo.h | 48 +++
gegl/buffer/gegl-sampler.c | 6 +
operations/affine/affine.c | 2 +-
8 files changed, 689 insertions(+), 2 deletions(-)
---
diff --git a/gegl/buffer/Makefile.am b/gegl/buffer/Makefile.am
index 72f3e43..b813ca4 100644
--- a/gegl/buffer/Makefile.am
+++ b/gegl/buffer/Makefile.am
@@ -28,6 +28,7 @@ libbuffer_la_SOURCES = \
gegl-sampler-linear.c \
gegl-sampler-nearest.c \
gegl-sampler-lohalo.c \
+ gegl-sampler-nohalo.c \
gegl-region-generic.c \
gegl-tile.c \
gegl-tile-source.c \
@@ -56,6 +57,7 @@ libbuffer_la_SOURCES = \
gegl-sampler-linear.h \
gegl-sampler-nearest.h \
gegl-sampler-lohalo.h \
+ gegl-sampler-nohalo.h \
gegl-region.h \
gegl-region-generic.h \
gegl-tile.h \
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 50b301e..d5dfb57 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -36,6 +36,7 @@
#include "gegl-sampler-cubic.h"
#include "gegl-sampler-lanczos.h"
#include "gegl-sampler-lohalo.h"
+#include "gegl-sampler-nohalo.h"
#include "gegl-buffer-index.h"
#include "gegl-tile-backend.h"
#include "gegl-buffer-iterator.h"
diff --git a/gegl/buffer/gegl-buffer.c b/gegl/buffer/gegl-buffer.c
index 08056bb..0b15602 100644
--- a/gegl/buffer/gegl-buffer.c
+++ b/gegl/buffer/gegl-buffer.c
@@ -63,6 +63,7 @@
#include "gegl-sampler-cubic.h"
#include "gegl-sampler-lanczos.h"
#include "gegl-sampler-lohalo.h"
+#include "gegl-sampler-nohalo.h"
#include "gegl-types-internal.h"
#include "gegl-utils.h"
#include "gegl-id-pool.h"
diff --git a/gegl/buffer/gegl-buffer.h b/gegl/buffer/gegl-buffer.h
index f303f52..7043b5d 100644
--- a/gegl/buffer/gegl-buffer.h
+++ b/gegl/buffer/gegl-buffer.h
@@ -312,7 +312,8 @@ typedef enum {
GEGL_INTERPOLATION_LINEAR,
GEGL_INTERPOLATION_CUBIC,
GEGL_INTERPOLATION_LANCZOS,
- GEGL_INTERPOLATION_LOHALO
+ GEGL_INTERPOLATION_LOHALO,
+ GEGL_INTERPOLATION_NOHALO
} GeglInterpolation;
/**
diff --git a/gegl/buffer/gegl-sampler-nohalo.c b/gegl/buffer/gegl-sampler-nohalo.c
new file mode 100644
index 0000000..740e408
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-nohalo.c
@@ -0,0 +1,628 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GEGL 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 Lesser General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 2009 (c) Nicolas Robidoux, Chantal Racette, Adam Turcotte, Ãyvind
+ * KolÃs, Eric Daoust and Geert Jordaens.
+ */
+
+/*
+ * ================
+ * NOHALO SAMPLER
+ * ================
+ *
+ * Vertex-Split Quadratic B-Splines (VSQBS) is a brand new method
+ * which consists of vertex-split subdivision, a subdivision method
+ * with the (as yet unknown?) property that data which is (locally)
+ * constant on diagonals is subdivided into data which is (locally)
+ * constant on diagonals, followed by quadratic B-Spline smoothing.
+ * Because both methods are linear, their combination can be
+ * implemented as if there is no subdivision.
+ *
+ * At high enlargement ratios, VSQBS is very effective at "masking"
+ * that that the original has pixels uniformly distributed on a
+ * grid. In particular, VSQBS produces resamples with only very mild
+ * staircasing. Like cubic B-Spline smoothing, however, VSQBS is not
+ * an interpolatory method. For example, using VSQBS to perform the
+ * identity geometric transformation (enlargement by a scaling factor
+ * equal to 1) on an image does not return the original: VSQBS
+ * effectively smooths out the image with the convolution mask
+ *
+ * 1/8
+ * 1/8 1/2 1/8
+ * 1/8
+ *
+ * which is a fairly moderate blur (although the checkerboard mode is
+ * in its nullspace).
+ *
+ * In the nohalo sampler, VSQBS is blended with bilinear when all
+ * the singular values of the Jacobian matrix of the transformation
+ * which calls the sampler are in the interval (-1/2,2).
+ *
+ * Blending VSQBS with an interpolatory method (here, bilinear) in a
+ * Jacobian adaptive way ensures that resampling is interpolatory for
+ * rotations (that is, the above blur is not active when the
+ * transformation is a rotation). In particular, resampling for the
+ * identity geometric transformation is equivalent to the
+ * identity.
+ *
+ * An article on VSQBS is forthcoming.
+ */
+
+/*
+ * Acknowledgements: Adam Turcotte and Eric Daoust's Snohalo
+ * programming funded by Google Summer of Code 2009. Nicolas
+ * Robidoux's research on Nohalo funded in part by an NSERC (National
+ * Science and Engineering Research Council of Canada) Discovery
+ * Grant.
+ *
+ * Nicolas Robidoux thanks Minglun Gong, Ralf Meyer, John Cupitt and
+ * Sven Neumann for useful comments and code.
+ */
+
+#include "config.h"
+#include "math.h"
+#include "gegl-matrix.h"
+#include <glib-object.h>
+
+#include "gegl.h"
+#include "gegl-types-internal.h"
+#include "gegl-buffer-private.h"
+
+#include "gegl-sampler-nohalo.h"
+
+/*
+ * FAST_PSEUDO_FLOOR is a floor replacement which has been found to be
+ * faster. It returns the floor of its argument unless the argument is
+ * a negative integer, in which case it returns one less than the
+ * floor. For example:
+ *
+ * FAST_PSEUDO_FLOOR(0.5) = 0
+ *
+ * FAST_PSEUDO_FLOOR(0.) = 0
+ *
+ * FAST_PSEUDO_FLOOR(-.5) = -1
+ *
+ * as expected, but
+ *
+ * FAST_PSEUDO_FLOOR(-1.) = -2
+ *
+ * The discontinuities of FAST_PSEUDO_FLOOR are on the right of
+ * negative numbers instead of on the left as is the case for floor.
+ */
+#define FAST_PSEUDO_FLOOR(x) ( (gint)(x) - ( (x) < 0. ) )
+
+/*
+ * Hack to get the restrict C99 keyword going at least some of the
+ * time:
+ */
+#ifndef restrict
+#ifdef __restrict
+#define restrict __restrict
+#else
+#ifdef __restrict__
+#define restrict __restrict__
+#else
+#define restrict
+#endif
+#endif
+#endif
+
+enum
+{
+ PROP_0,
+ PROP_LAST
+};
+
+static void gegl_sampler_nohalo_get ( GeglSampler* restrict self,
+ const gdouble absolute_x,
+ const gdouble absolute_y,
+ void* restrict output);
+
+static void set_property ( GObject* gobject,
+ guint property_id,
+ const GValue* value,
+ GParamSpec* pspec);
+
+static void get_property (GObject* gobject,
+ guint property_id,
+ GValue* value,
+ GParamSpec* pspec);
+
+G_DEFINE_TYPE (GeglSamplerNohalo, gegl_sampler_nohalo, GEGL_TYPE_SAMPLER)
+
+static void
+gegl_sampler_nohalo_class_init (GeglSamplerNohaloClass *klass)
+{
+ GeglSamplerClass *sampler_class = GEGL_SAMPLER_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ sampler_class->get = gegl_sampler_nohalo_get;
+}
+
+static void
+gegl_sampler_nohalo_init (GeglSamplerNohalo *self)
+{
+ GEGL_SAMPLER (self)->context_rect.x = -1;
+ GEGL_SAMPLER (self)->context_rect.y = -1;
+ GEGL_SAMPLER (self)->context_rect.width = 3;
+ GEGL_SAMPLER (self)->context_rect.height = 3;
+ GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
+}
+
+/*
+ * THE STENCIL OF INPUT VALUES:
+ *
+ * Pointer arithmetic is used to implicitly reflect the input stencil
+ * about dos_two---assumed closer to the sampling location than other
+ * pixels (ties are OK)---in such a way that after reflection the
+ * sampling point is to the bottom right of dos_two.
+ *
+ * The following code and picture assumes that the stencil reflexion
+ * has already been performed. (X is the sampling location.)
+ *
+ *
+ * (ix,iy-1) (ix+1,iy-1)
+ * = uno_two = uno_thr
+ *
+ *
+ *
+ * (ix-1,iy) (ix,iy) (ix+1,iy)
+ * = dos_one = dos_two = dos_thr
+ * X
+ *
+ *
+ * (ix-1,iy+1) (ix,iy+1) (ix+1,iy+1)
+ * = tre_one = tre_two = tre_thr
+ *
+ *
+ * The above input pixel values are the ones needed in order to
+ * IMPLICITLY make available the following values, needed by quadratic
+ * B-Splines, which is performed on (shifted) double density data:
+ *
+ *
+ * uno_one_1 = uno_two_1 = uno_thr_1 =
+ * (ix-1/4,iy-1/4) (ix+1/4,iy-1/4) (ix+3/4,iy-1/4)
+ *
+ *
+ *
+ * X or X
+ * dos_one_1 = dos_two_1 = dos_thr_1 =
+ * (ix-1/4,iy+1/4) (ix+1/4,iy+1/4) (ix+3/4,iy+1/4)
+ * or X or X
+ *
+ *
+ *
+ * tre_one_1 = tre_two_1 = tre_thr_1 =
+ * (ix-1/4,iy+3/4) (ix+1/4,iy+3/4) (ix+3/4,iy+3/4)
+ *
+ *
+ * In the coefficient computations, we fix things so that coordinates
+ * are relative to dos_two_1, and so that distances are rescaled so
+ * that double density pixel locations are at a distance of 1.
+ *
+ * As far as the bilinear component of the sampler is concerned, the
+ * sampling position is normalized so that X is in the convex hull of
+ * dos_two, dos_thr, tre_two and tre_thr.
+ */
+
+static inline gfloat
+vsqbs_bilinear_mix (const gdouble four_c_uno_two,
+ const gdouble four_c_uno_thr,
+ const gdouble four_c_dos_one,
+ const gdouble four_c_dos_two,
+ const gdouble four_c_dos_thr,
+ const gdouble four_c_tre_one,
+ const gdouble four_c_tre_two,
+ const gdouble four_c_tre_thr,
+ const gdouble c_bot_rite,
+ const gdouble c_bot_left,
+ const gdouble c_top_left,
+ const gdouble c_top_rite,
+ const gdouble theta,
+ const gdouble uno_two,
+ const gdouble uno_thr,
+ const gdouble dos_one,
+ const gdouble dos_two,
+ const gdouble dos_thr,
+ const gdouble tre_one,
+ const gdouble tre_two,
+ const gdouble tre_thr)
+{
+ const gdouble vsqbs = ( four_c_uno_two * uno_two +
+ four_c_uno_thr * uno_thr +
+ four_c_dos_one * dos_one +
+ four_c_dos_two * dos_two +
+ four_c_dos_thr * dos_thr +
+ four_c_tre_one * tre_one +
+ four_c_tre_two * tre_two +
+ four_c_tre_thr * tre_thr ) * 0.25;
+
+ const gdouble bilinear = c_bot_rite * tre_thr +
+ c_bot_left * tre_two +
+ c_top_rite * dos_thr +
+ c_top_left * dos_two;
+
+ const gfloat newval = bilinear + theta * ( vsqbs - bilinear );
+
+ return newval;
+}
+
+static void
+gegl_sampler_nohalo_get ( GeglSampler* restrict self,
+ const gdouble absolute_x,
+ const gdouble absolute_y,
+ void* restrict output)
+{
+ /*
+ * Needed constants related to the input pixel value pointer
+ * provided by gegl_sampler_get_ptr (self, ix, iy). pixels_per_row
+ * corresponds to fetch_rectangle.width in gegl_sampler_get_ptr.
+ */
+ const gint channels = 4;
+ const gint pixels_per_row = 64;
+ const gint row_skip = channels * pixels_per_row;
+
+ /*
+ * epsilon determines how far from 1 the singular values can be
+ * before we switch out of pure bilinear. It should be strictly
+ * positive but reasonably close to 0. 3/255 ensures that using
+ * bilinear when, in theory, we should not, leads to pixel value
+ * differences of at most 1 when dealing with 8 bit images. (Some
+ * differences of 1 are unavoidable because of rounding.)
+ */
+ const gdouble epsilon = 3./255.;
+
+ /*
+ * The newval array will contain one computed resampled value per
+ * channel:
+ */
+ gfloat newval[channels];
+
+ /*
+ * Calculate the blending parameter from the squares of the singular
+ * values of the inverse Jacobian matrix:
+ */
+ GeglMatrix2* const inverse_jacobian = self->inverse_jacobian;
+
+ const gdouble Jinv_11 = *inverse_jacobian[0][0];
+ const gdouble Jinv_12 = *inverse_jacobian[0][1];
+ const gdouble Jinv_21 = *inverse_jacobian[1][0];
+ const gdouble Jinv_22 = *inverse_jacobian[1][1];
+
+ const gdouble Jinv_11_sq = Jinv_11 * Jinv_11;
+ const gdouble Jinv_12_sq = Jinv_12 * Jinv_12;
+ const gdouble Jinv_21_sq = Jinv_21 * Jinv_21;
+ const gdouble Jinv_22_sq = Jinv_22 * Jinv_22;
+
+ const gdouble sum_all_sq = Jinv_11_sq + Jinv_12_sq + Jinv_21_sq + Jinv_22_sq;
+ const gdouble det = Jinv_11 * Jinv_22 - Jinv_12 * Jinv_21;
+ const gdouble twice_det = det + det;
+
+ const gdouble discr_prod_1 = sum_all_sq + twice_det;
+ const gdouble discr_prod_2 = sum_all_sq - twice_det;
+ const gdouble discr = discr_prod_1 * discr_prod_2;
+ const gdouble discr_sqrt = sqrt (discr);
+
+ const gdouble sigma1_sq = ( sum_all_sq + discr_sqrt ) * 0.5;
+ const gdouble twice_sigma2_sq = sum_all_sq - discr_sqrt;
+ const gdouble one_over_sigma2_sq = 2. / twice_sigma2_sq;
+
+ /*
+ * Take the largest of the two singular values and their two
+ * reciprocals:
+ */
+ const gdouble t =
+ ( sigma1_sq>=one_over_sigma2_sq ? sigma1_sq : one_over_sigma2_sq );
+
+ if ( t <= 1. + epsilon ) /* Pure bilinear */
+ {
+ const gint ix = FAST_PSEUDO_FLOOR (absolute_x);
+ const gint iy = FAST_PSEUDO_FLOOR (absolute_y);
+
+ const gfloat* restrict input_bptr =
+ (gfloat*) gegl_sampler_get_ptr (self, ix, iy);
+
+ const gfloat x = absolute_x - ix;
+ const gfloat y = absolute_y - iy;
+
+ /*
+ * Bilinear weights (Note: w = 1-x and z = 1-y):
+ */
+ const gfloat x_times_y = x * y;
+ const gfloat w_times_y = y - x_times_y;
+ const gfloat x_times_z = x - x_times_y;
+ const gfloat w_times_z = 1.f - ( x + w_times_y );
+
+ gfloat newval0, newval1, newval2, newval3;
+ gfloat newval0i, newval1i, newval2i, newval3i;
+
+ newval0 = *input_bptr++;
+ newval1 = *input_bptr++;
+ newval2 = *input_bptr++;
+ newval3 = *input_bptr++;
+
+ newval0i = *input_bptr++;
+ newval1i = *input_bptr++;
+ newval2i = *input_bptr++;
+ newval3i = *input_bptr;
+
+ input_bptr += 1 + row_skip - 2 * channels;
+
+ newval0 *= w_times_z;
+ newval1 *= w_times_z;
+ newval2 *= w_times_z;
+ newval3 *= w_times_z;
+
+ newval0i *= x_times_z;
+ newval1i *= x_times_z;
+ newval2i *= x_times_z;
+ newval3i *= x_times_z;
+
+ newval0 += w_times_y * *input_bptr++;
+ newval1 += w_times_y * *input_bptr++;
+ newval2 += w_times_y * *input_bptr++;
+ newval3 += w_times_y * *input_bptr++;
+
+ newval0i += x_times_y * *input_bptr++;
+ newval1i += x_times_y * *input_bptr++;
+ newval2i += x_times_y * *input_bptr++;
+ newval3i += x_times_y * *input_bptr;
+
+ newval[0] = newval0 + newval0i;
+ newval[1] = newval1 + newval1i;
+ newval[2] = newval2 + newval2i;
+ newval[3] = newval3 + newval3i;
+ }
+ else /* Pure VSQBS or VSQBS blended with bilinear */
+ {
+ /*
+ * Calculate the needed shifts:
+ */
+ const gint ix_0 = FAST_PSEUDO_FLOOR (absolute_x + .5);
+ const gint iy_0 = FAST_PSEUDO_FLOOR (absolute_y + .5);
+
+ const gfloat* restrict input_bptr =
+ (gfloat*) gegl_sampler_get_ptr (self, ix_0, iy_0);
+
+ const gdouble x_0 = absolute_x - ix_0;
+ const gdouble y_0 = absolute_y - iy_0;
+
+ const gint sign_of_x_0 = 2 * ( x_0 >= 0. ) - 1;
+ const gint sign_of_y_0 = 2 * ( y_0 >= 0. ) - 1;
+
+ const gint shift_forw_1_pix = sign_of_x_0 * channels;
+ const gint shift_forw_1_row = sign_of_y_0 * row_skip;
+
+ const gint shift_back_1_pix = -shift_forw_1_pix;
+ const gint shift_back_1_row = -shift_forw_1_row;
+
+ const gint uno_two_shift = shift_back_1_row;
+ const gint uno_thr_shift = shift_forw_1_pix + shift_back_1_row;
+
+ const gint dos_one_shift = shift_back_1_pix;
+ const gint dos_two_shift = 0;
+ const gint dos_thr_shift = shift_forw_1_pix;
+
+ const gint tre_one_shift = shift_back_1_pix + shift_forw_1_row;
+ const gint tre_two_shift = shift_forw_1_row;
+ const gint tre_thr_shift = shift_forw_1_pix + shift_forw_1_row;
+
+ const gdouble abs_x_0 = sign_of_x_0 * x_0;
+ const gdouble abs_y_0 = sign_of_y_0 * y_0;
+ const gdouble twice_abs_x_0 = abs_x_0 + abs_x_0;
+ const gdouble twice_abs_y_0 = abs_y_0 + abs_y_0;
+ const gdouble x = twice_abs_x_0 + -0.5;
+ const gdouble y = twice_abs_y_0 + -0.5;
+ const gdouble cent = 0.75 - x * x;
+ const gdouble mid = 0.75 - y * y;
+ const gdouble left = -0.5 * ( x + cent ) + 0.5;
+ const gdouble top = -0.5 * ( y + mid ) + 0.5;
+ const gdouble left_p_cent = left + cent;
+ const gdouble top_p_mid = top + mid;
+ const gdouble cent_p_rite = 1.0 - left;
+ const gdouble mid_p_bot = 1.0 - top;
+ const gdouble rite = 1.0 - left_p_cent;
+ const gdouble bot = 1.0 - top_p_mid;
+
+ const gdouble four_c_uno_two = top * left_p_cent;
+ const gdouble four_c_dos_one = left * top_p_mid;
+ const gdouble four_c_dos_two = left_p_cent + top_p_mid;
+ const gdouble four_c_dos_thr = cent_p_rite * top_p_mid + rite;
+ const gdouble four_c_tre_two = mid_p_bot * left_p_cent + bot;
+ const gdouble four_c_tre_thr = mid_p_bot * rite + bot * cent_p_rite;
+ const gdouble four_c_uno_thr = top - four_c_uno_two;
+ const gdouble four_c_tre_one = left - four_c_dos_one;
+
+ if ( t>=4. ) /* Pure VSQBS */
+ {
+ /*
+ * First channel:
+ */
+ newval[0] = ( four_c_uno_two * input_bptr[ uno_two_shift ] +
+ four_c_uno_thr * input_bptr[ uno_thr_shift ] +
+ four_c_dos_one * input_bptr[ dos_one_shift ] +
+ four_c_dos_two * input_bptr[ dos_two_shift ] +
+ four_c_dos_thr * input_bptr[ dos_thr_shift ] +
+ four_c_tre_one * input_bptr[ tre_one_shift ] +
+ four_c_tre_two * input_bptr[ tre_two_shift ] +
+ four_c_tre_thr * input_bptr[ tre_thr_shift ] ) * 0.25;
+ /*
+ * Shift input pointer by one channel:
+ */
+ input_bptr++;
+ /*
+ * Compute the second channel result:
+ */
+ newval[1] = ( four_c_uno_two * input_bptr[ uno_two_shift ] +
+ four_c_uno_thr * input_bptr[ uno_thr_shift ] +
+ four_c_dos_one * input_bptr[ dos_one_shift ] +
+ four_c_dos_two * input_bptr[ dos_two_shift ] +
+ four_c_dos_thr * input_bptr[ dos_thr_shift ] +
+ four_c_tre_one * input_bptr[ tre_one_shift ] +
+ four_c_tre_two * input_bptr[ tre_two_shift ] +
+ four_c_tre_thr * input_bptr[ tre_thr_shift ] ) * 0.25;
+ input_bptr++;
+ newval[2] = ( four_c_uno_two * input_bptr[ uno_two_shift ] +
+ four_c_uno_thr * input_bptr[ uno_thr_shift ] +
+ four_c_dos_one * input_bptr[ dos_one_shift ] +
+ four_c_dos_two * input_bptr[ dos_two_shift ] +
+ four_c_dos_thr * input_bptr[ dos_thr_shift ] +
+ four_c_tre_one * input_bptr[ tre_one_shift ] +
+ four_c_tre_two * input_bptr[ tre_two_shift ] +
+ four_c_tre_thr * input_bptr[ tre_thr_shift ] ) * 0.25;
+ input_bptr++;
+ newval[3] = ( four_c_uno_two * input_bptr[ uno_two_shift ] +
+ four_c_uno_thr * input_bptr[ uno_thr_shift ] +
+ four_c_dos_one * input_bptr[ dos_one_shift ] +
+ four_c_dos_two * input_bptr[ dos_two_shift ] +
+ four_c_dos_thr * input_bptr[ dos_thr_shift ] +
+ four_c_tre_one * input_bptr[ tre_one_shift ] +
+ four_c_tre_two * input_bptr[ tre_two_shift ] +
+ four_c_tre_thr * input_bptr[ tre_thr_shift ] ) * 0.25;
+ }
+ else /* Blend VSQBS with bilinear */
+ {
+ /*
+ * Bilinear weights (Note: w = 1-x and z = 1-y):
+ */
+ const gdouble x_times_y = abs_x_0 * abs_y_0;
+ const gdouble w_times_y = abs_y_0 - x_times_y;
+ const gdouble x_times_z = abs_x_0 - x_times_y;
+ const gdouble w_times_z = 1. - ( abs_x_0 + w_times_y );
+
+ /*
+ * Blending coefficient:
+ */
+ const gdouble theta = (1./3.)*(t-1.);
+
+ /*
+ * Channel by channel computation of the vsqbs/bilinear blend:
+ */
+ newval[0] = vsqbs_bilinear_mix (four_c_uno_two,
+ four_c_uno_thr,
+ four_c_dos_one,
+ four_c_dos_two,
+ four_c_dos_thr,
+ four_c_tre_one,
+ four_c_tre_two,
+ four_c_tre_thr,
+ x_times_y,
+ w_times_y,
+ x_times_z,
+ w_times_z,
+ theta,
+ input_bptr[ uno_two_shift ],
+ input_bptr[ uno_thr_shift ],
+ input_bptr[ dos_one_shift ],
+ input_bptr[ dos_two_shift ],
+ input_bptr[ dos_thr_shift ],
+ input_bptr[ tre_one_shift ],
+ input_bptr[ tre_two_shift ],
+ input_bptr[ tre_thr_shift ]);
+ input_bptr++;
+ newval[1] = vsqbs_bilinear_mix (four_c_uno_two,
+ four_c_uno_thr,
+ four_c_dos_one,
+ four_c_dos_two,
+ four_c_dos_thr,
+ four_c_tre_one,
+ four_c_tre_two,
+ four_c_tre_thr,
+ x_times_y,
+ w_times_y,
+ x_times_z,
+ w_times_z,
+ theta,
+ input_bptr[ uno_two_shift ],
+ input_bptr[ uno_thr_shift ],
+ input_bptr[ dos_one_shift ],
+ input_bptr[ dos_two_shift ],
+ input_bptr[ dos_thr_shift ],
+ input_bptr[ tre_one_shift ],
+ input_bptr[ tre_two_shift ],
+ input_bptr[ tre_thr_shift ]);
+ input_bptr++;
+ newval[2] = vsqbs_bilinear_mix (four_c_uno_two,
+ four_c_uno_thr,
+ four_c_dos_one,
+ four_c_dos_two,
+ four_c_dos_thr,
+ four_c_tre_one,
+ four_c_tre_two,
+ four_c_tre_thr,
+ x_times_y,
+ w_times_y,
+ x_times_z,
+ w_times_z,
+ theta,
+ input_bptr[ uno_two_shift ],
+ input_bptr[ uno_thr_shift ],
+ input_bptr[ dos_one_shift ],
+ input_bptr[ dos_two_shift ],
+ input_bptr[ dos_thr_shift ],
+ input_bptr[ tre_one_shift ],
+ input_bptr[ tre_two_shift ],
+ input_bptr[ tre_thr_shift ]);
+ input_bptr++;
+ newval[3] = vsqbs_bilinear_mix (four_c_uno_two,
+ four_c_uno_thr,
+ four_c_dos_one,
+ four_c_dos_two,
+ four_c_dos_thr,
+ four_c_tre_one,
+ four_c_tre_two,
+ four_c_tre_thr,
+ x_times_y,
+ w_times_y,
+ x_times_z,
+ w_times_z,
+ theta,
+ input_bptr[ uno_two_shift ],
+ input_bptr[ uno_thr_shift ],
+ input_bptr[ dos_one_shift ],
+ input_bptr[ dos_two_shift ],
+ input_bptr[ dos_thr_shift ],
+ input_bptr[ tre_one_shift ],
+ input_bptr[ tre_two_shift ],
+ input_bptr[ tre_thr_shift ]);
+ }
+ }
+
+ /*
+ * Ship out the array of new pixel values:
+ */
+ babl_process (babl_fish (self->interpolate_format, self->format),
+ newval, output, 1);
+}
+
+static void
+set_property ( GObject* gobject,
+ guint property_id,
+ const GValue* value,
+ GParamSpec* pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+}
+
+static void
+get_property (GObject* gobject,
+ guint property_id,
+ GValue* value,
+ GParamSpec* pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+}
diff --git a/gegl/buffer/gegl-sampler-nohalo.h b/gegl/buffer/gegl-sampler-nohalo.h
new file mode 100644
index 0000000..491cdf1
--- /dev/null
+++ b/gegl/buffer/gegl-sampler-nohalo.h
@@ -0,0 +1,48 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __GEGL_SAMPLER_NOHALO_H__
+#define __GEGL_SAMPLER_NOHALO_H__
+
+#include "gegl-sampler.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_SAMPLER_NOHALO (gegl_sampler_nohalo_get_type ())
+#define GEGL_SAMPLER_NOHALO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_SAMPLER_NOHALO, GeglSamplerNohalo))
+#define GEGL_SAMPLER_NOHALO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEGL_TYPE_SAMPLER_NOHALO, GeglSamplerNohaloClass))
+#define GEGL_IS_SAMPLER_NOHALO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_SAMPLER_NOHALO))
+#define GEGL_IS_SAMPLER_NOHALO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_TYPE_SAMPLER_NOHALO))
+#define GEGL_SAMPLER_NOHALO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEGL_TYPE_SAMPLER_NOHALO, GeglSamplerNohaloClass))
+
+typedef struct _GeglSamplerNohalo GeglSamplerNohalo;
+typedef struct _GeglSamplerNohaloClass GeglSamplerNohaloClass;
+
+struct _GeglSamplerNohalo
+{
+ GeglSampler parent_instance;
+};
+
+struct _GeglSamplerNohaloClass
+{
+ GeglSamplerClass parent_class;
+};
+
+GType gegl_sampler_nohalo_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/gegl/buffer/gegl-sampler.c b/gegl/buffer/gegl-sampler.c
index 24a1de9..eaa5990 100644
--- a/gegl/buffer/gegl-sampler.c
+++ b/gegl/buffer/gegl-sampler.c
@@ -35,6 +35,7 @@
#include "gegl-sampler-cubic.h"
#include "gegl-sampler-lanczos.h"
#include "gegl-sampler-lohalo.h"
+#include "gegl-sampler-nohalo.h"
enum
{
@@ -568,6 +569,9 @@ gegl_buffer_interpolation_from_string (const gchar *string)
if (g_str_equal (string, "lohalo"))
return GEGL_INTERPOLATION_LOHALO;
+ if (g_str_equal (string, "nohalo"))
+ return GEGL_INTERPOLATION_NOHALO;
+
return GEGL_INTERPOLATION_NEAREST;
}
@@ -586,6 +590,8 @@ gegl_sampler_type_from_interpolation (GeglInterpolation interpolation)
return GEGL_TYPE_SAMPLER_LANCZOS;
case GEGL_INTERPOLATION_LOHALO:
return GEGL_TYPE_SAMPLER_LOHALO;
+ case GEGL_INTERPOLATION_NOHALO:
+ return GEGL_TYPE_SAMPLER_NOHALO;
default:
return GEGL_TYPE_SAMPLER_LINEAR;
}
diff --git a/operations/affine/affine.c b/operations/affine/affine.c
index 71f68d5..f849b3b 100644
--- a/operations/affine/affine.c
+++ b/operations/affine/affine.c
@@ -252,7 +252,7 @@ op_affine_class_init (OpAffineClass *klass)
g_param_spec_string (
"filter",
_("Filter"),
- _("Filter type (nearest, linear, lanczos, cubic, lohalo)"),
+ _("Filter type (nearest, linear, lanczos, cubic, lohalo, nohalo)"),
"linear",
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_HARD_EDGES,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]