[gegl] algorithms: implement a bilinear alternative to boxfilter



commit 72d8b84c30a635cce4223f51b0dcd0164a29f471
Author: Øyvind Kolås <pippin gimp org>
Date:   Thu Oct 15 17:19:41 2015 +0200

    algorithms: implement a bilinear alternative to boxfilter

 gegl/Makefile.am                  |    2 +-
 gegl/buffer/gegl-buffer-access.c  |   18 +++++
 gegl/gegl-algorithms-bilinear.inc |  137 +++++++++++++++++++++++++++++++++++++
 gegl/gegl-algorithms.c            |   82 +++++++++++++++++++++-
 gegl/gegl-algorithms.h            |   60 ++++++++++++++++-
 5 files changed, 293 insertions(+), 6 deletions(-)
---
diff --git a/gegl/Makefile.am b/gegl/Makefile.am
index 9e3e304..4128504 100644
--- a/gegl/Makefile.am
+++ b/gegl/Makefile.am
@@ -119,7 +119,7 @@ GEGL_sources = \
        gegl-types-internal.h           \
        gegl-xml.h
 
-EXTRA_DIST = gegl-algorithms-boxfilter.inc gegl-algorithms-2x2-downscale.inc
+EXTRA_DIST = gegl-algorithms-boxfilter.inc gegl-algorithms-2x2-downscale.inc gegl-algorithms-bilinear.inc
 
 lib_LTLIBRARIES = libgegl- GEGL_API_VERSION@.la
 
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 6239346..00cfc18 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -1488,6 +1488,24 @@ _gegl_buffer_get_unlocked (GeglBuffer          *buffer,
                                    format,
                                    rowstride);
         }
+#if 0
+      else if (scale <= 1.99)
+        {
+          sample_rect.x      = x1 - 1;
+          sample_rect.y      = y1 - 1;
+          sample_rect.width  = x2 - x1 + 2;
+          sample_rect.height = y2 - y1 + 2;
+
+          gegl_resample_boxfilter (dest_buf,
+                                   sample_buf,
+                                   rect,
+                                   &sample_rect,
+                                   buf_width * bpp,
+                                   scale,
+                                   format,
+                                   rowstride);
+        }
+#endif
       else
         {
           sample_rect.x      = x1;
diff --git a/gegl/gegl-algorithms-bilinear.inc b/gegl/gegl-algorithms-bilinear.inc
new file mode 100644
index 0000000..6daccdc
--- /dev/null
+++ b/gegl/gegl-algorithms-bilinear.inc
@@ -0,0 +1,137 @@
+void
+BILINEAR_FUNCNAME (guchar              *dest_buf,
+                   const guchar        *source_buf,
+                   const GeglRectangle *dst_rect,
+                   const GeglRectangle *src_rect,
+                   const gint           s_rowstride,
+                   const gdouble        scale,
+                   const gint           bpp,
+                   const gint           d_rowstride)
+{
+  const BILINEAR_TYPE *src[4];
+  gint  components = bpp / sizeof(BILINEAR_TYPE);
+
+  gfloat dx[dst_rect->width];
+  gint   jj[dst_rect->width];
+
+  for (gint x = 0; x < dst_rect->width; x++)
+  {
+    gfloat sx  = (dst_rect->x + x + .5) / scale - src_rect->x;
+    jj[x]  = int_floorf (sx);
+    dx[x]  = sx - jj[x];
+    jj[x] *= components;
+  }
+
+  for (gint y = 0; y < dst_rect->height; y++)
+    {
+      const gfloat sy = (dst_rect->y + y + .5) / scale - src_rect->y;
+      const gint   ii = int_floorf (sy);
+      const gfloat dy = (sy - ii);
+      const gfloat rdy = 1.0 - dy;
+      BILINEAR_TYPE *dst = (BILINEAR_TYPE*)(dest_buf + y * d_rowstride);
+      const guchar  *src_base = source_buf + ii * s_rowstride;
+
+      switch (components)
+      {
+        case 4:
+          for (gint x = 0; x < dst_rect->width; x++)
+            {
+            src[0] = src[1] = src[2] = src[3] = (const BILINEAR_TYPE*)src_base + jj[x];
+            src[1] += 4;
+            src[2] += s_rowstride;
+            src[5] += s_rowstride + 4;
+
+            if (src[0][3] == 0 &&  /* XXX: it would be even better to not call this at all for the abyss...  
*/
+                src[1][3] == 0 &&
+                src[2][3] == 0 &&
+                src[3][3] == 0)
+            {
+              dst[0] = dst[1] = dst[2] = dst[3] = 0;
+            }
+            else
+            {
+              dst[0] = BILINEAR_ROUND(
+                (src[0][0] * (1.0-dx[x]) + src[1][0] * (dx[x])) * (rdy) +
+                (src[2][0] * (1.0-dx[x]) + src[3][0] * (dx[x])) * (dy));
+              dst[1] = BILINEAR_ROUND(
+                (src[0][1] * (1.0-dx[x]) + src[1][1] * (dx[x])) * (rdy) +
+                (src[2][1] * (1.0-dx[x]) + src[3][1] * (dx[x])) * (dy));
+              dst[2] = BILINEAR_ROUND(
+                (src[0][2] * (1.0-dx[x]) + src[1][2] * (dx[x])) * (rdy) +
+                (src[2][2] * (1.0-dx[x]) + src[3][2] * (dx[x])) * (dy));
+              dst[3] = BILINEAR_ROUND(
+                (src[0][3] * (1.0-dx[x]) + src[1][3] * (dx[x])) * (rdy) +
+                (src[2][3] * (1.0-dx[x]) + src[3][3] * (dx[x])) * (dy));
+            }
+            dst += 4;
+            }
+          break;
+        case 3:
+          for (gint x = 0; x < dst_rect->width; x++)
+            {
+            src[0] = src[1] = src[2] = src[3] = (const BILINEAR_TYPE*)src_base + jj[x];
+            src[1] += 3;
+            src[2] += s_rowstride;
+            src[5] += s_rowstride + 3;
+            dst[0] = BILINEAR_ROUND(
+              (src[0][0] * (1.0-dx[x]) + src[1][0] * (dx[x])) * (rdy) +
+              (src[2][0] * (1.0-dx[x]) + src[3][0] * (dx[x])) * (dy));
+            dst[1] = BILINEAR_ROUND(
+              (src[0][1] * (1.0-dx[x]) + src[1][1] * (dx[x])) * (rdy) +
+              (src[2][1] * (1.0-dx[x]) + src[3][1] * (dx[x])) * (dy));
+            dst[2] = BILINEAR_ROUND(
+              (src[0][2] * (1.0-dx[x]) + src[1][2] * (dx[x])) * (rdy) +
+              (src[2][2] * (1.0-dx[x]) + src[3][2] * (dx[x])) * (dy));
+            dst += 3;
+            }
+          break;
+        case 2:
+          for (gint x = 0; x < dst_rect->width; x++)
+            {
+            src[0] = src[1] = src[2] = src[3] = (const BILINEAR_TYPE*)src_base + jj[x];
+            src[1] += 2;
+            src[2] += s_rowstride;
+            src[5] += s_rowstride + 2;
+            dst[0] = BILINEAR_ROUND(
+              (src[0][0] * (1.0-dx[x]) + src[1][0] * (dx[x])) * (rdy) +
+              (src[2][0] * (1.0-dx[x]) + src[3][0] * (dx[x])) * (dy));
+            dst[1] = BILINEAR_ROUND(
+              (src[0][1] * (1.0-dx[x]) + src[1][1] * (dx[x])) * (rdy) +
+              (src[2][1] * (1.0-dx[x]) + src[3][1] * (dx[x])) * (dy));
+            dst += 2;
+            }
+          break;
+        case 1:
+          for (gint x = 0; x < dst_rect->width; x++)
+            {
+            src[0] = src[1] = src[2] = src[3] = (const BILINEAR_TYPE*)src_base + jj[x];
+            src[1] += 1;
+            src[2] += s_rowstride;
+            src[5] += s_rowstride + 1;
+            dst[0] = BILINEAR_ROUND(
+              (src[0][0] * (1.0-dx[x]) + src[1][0] * (dx[x])) * (rdy) +
+              (src[2][0] * (1.0-dx[x]) + src[3][0] * (dx[x])) * (dy));
+            dst += 1;
+            }
+          break;
+        default:
+          for (gint x = 0; x < dst_rect->width; x++)
+          {
+            src[0] = src[1] = src[2] = src[3] = (const BILINEAR_TYPE*)src_base + jj[x];
+            src[1] += components;
+            src[2] += s_rowstride;
+            src[5] += s_rowstride + components;
+            {
+              for (gint i = 0; i < components; ++i)
+                {
+                  dst[i] = BILINEAR_ROUND(
+                   (src[0][i] * (1.0-dx[x]) + src[1][i] * (dx[x])) * (rdy) +
+                   (src[2][i] * (1.0-dx[x]) + src[3][i] * (dx[x])) * (dy));
+                }
+              }
+            dst += components;
+        }
+        break;
+      }
+    }
+}
diff --git a/gegl/gegl-algorithms.c b/gegl/gegl-algorithms.c
index 986a301..13bff45 100644
--- a/gegl/gegl-algorithms.c
+++ b/gegl/gegl-algorithms.c
@@ -13,7 +13,7 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
- * Copyright 2006,2007 Øyvind Kolås <pippin gimp org>
+ * Copyright 2006,2007,2015 Øyvind Kolås <pippin gimp org>
  *           2013 Daniel Sabo
  */
 
@@ -116,6 +116,38 @@ void gegl_resample_boxfilter (guchar              *dest_buf,
                            s_rowstride, scale, bpp, d_rowstride);
 }
 
+void gegl_resample_bilinear (guchar              *dest_buf,
+                             const guchar        *source_buf,
+                             const GeglRectangle *dst_rect,
+                             const GeglRectangle *src_rect,
+                             gint                 s_rowstride,
+                             gdouble              scale,
+                             const Babl          *format,
+                             gint                 d_rowstride)
+{
+  const Babl *comp_type  = babl_format_get_type (format, 0);
+  const gint bpp = babl_format_get_bytes_per_pixel (format);
+
+  if (comp_type == babl_type ("u8"))
+    gegl_resample_bilinear_u8 (dest_buf, source_buf, dst_rect, src_rect,
+                               s_rowstride, scale, bpp, d_rowstride);
+  else if (comp_type == babl_type ("u16"))
+    gegl_resample_bilinear_u16 (dest_buf, source_buf, dst_rect, src_rect,
+                                s_rowstride, scale, bpp, d_rowstride);
+  else if (comp_type == babl_type ("u32"))
+    gegl_resample_bilinear_u32 (dest_buf, source_buf, dst_rect, src_rect,
+                                s_rowstride, scale, bpp, d_rowstride);
+  else if (comp_type == babl_type ("float"))
+    gegl_resample_bilinear_float (dest_buf, source_buf, dst_rect, src_rect,
+                                  s_rowstride, scale, bpp, d_rowstride);
+  else if (comp_type == babl_type ("double"))
+    gegl_resample_bilinear_double (dest_buf, source_buf, dst_rect, src_rect,
+                                   s_rowstride, scale, bpp, d_rowstride);
+  else
+    gegl_resample_nearest (dest_buf, source_buf, dst_rect, src_rect,
+                           s_rowstride, scale, bpp, d_rowstride);
+}
+
 static inline int int_floorf (float x)
 {
   int i = (int)x; /* truncate */
@@ -169,7 +201,7 @@ gegl_resample_nearest (guchar              *dst,
 
 #define BOXFILTER_FUNCNAME   gegl_resample_boxfilter_u8
 #define BOXFILTER_TYPE       guchar
-#define BOXFILTER_ROUND(val) (lrint(val))
+#define BOXFILTER_ROUND(val) ((int)((val)+0.5))
 #include "gegl-algorithms-boxfilter.inc"
 #undef BOXFILTER_FUNCNAME
 #undef BOXFILTER_TYPE
@@ -177,7 +209,7 @@ gegl_resample_nearest (guchar              *dst,
 
 #define BOXFILTER_FUNCNAME   gegl_resample_boxfilter_u16
 #define BOXFILTER_TYPE       guint16
-#define BOXFILTER_ROUND(val) (lrint(val))
+#define BOXFILTER_ROUND(val) ((int)((val)+0.5))
 #include "gegl-algorithms-boxfilter.inc"
 #undef BOXFILTER_FUNCNAME
 #undef BOXFILTER_TYPE
@@ -185,7 +217,7 @@ gegl_resample_nearest (guchar              *dst,
 
 #define BOXFILTER_FUNCNAME   gegl_resample_boxfilter_u32
 #define BOXFILTER_TYPE       guint32
-#define BOXFILTER_ROUND(val) (lrint(val))
+#define BOXFILTER_ROUND(val) ((int)((val)+0.5))
 #include "gegl-algorithms-boxfilter.inc"
 #undef BOXFILTER_FUNCNAME
 #undef BOXFILTER_TYPE
@@ -240,3 +272,45 @@ gegl_resample_nearest (guchar              *dst,
 #undef DOWNSCALE_TYPE
 #undef DOWNSCALE_SUM
 #undef DOWNSCALE_DIVISOR
+
+
+#define BILINEAR_FUNCNAME   gegl_resample_bilinear_double
+#define BILINEAR_TYPE       gdouble
+#define BILINEAR_ROUND(val) (val)
+#include "gegl-algorithms-bilinear.inc"
+#undef BILINEAR_FUNCNAME
+#undef BILINEAR_TYPE
+#undef BILINEAR_ROUND
+
+#define BILINEAR_FUNCNAME   gegl_resample_bilinear_float
+#define BILINEAR_TYPE       gfloat
+#define BILINEAR_ROUND(val) (val)
+#include "gegl-algorithms-bilinear.inc"
+#undef BILINEAR_FUNCNAME
+#undef BILINEAR_TYPE
+#undef BILINEAR_ROUND
+
+#define BILINEAR_FUNCNAME   gegl_resample_bilinear_u8
+#define BILINEAR_TYPE       guchar
+#define BILINEAR_ROUND(val) ((int)((val)+0.5))
+#include "gegl-algorithms-bilinear.inc"
+#undef BILINEAR_FUNCNAME
+#undef BILINEAR_TYPE
+#undef BILINEAR_ROUND
+
+#define BILINEAR_FUNCNAME   gegl_resample_bilinear_u16
+#define BILINEAR_TYPE       guint16
+#define BILINEAR_ROUND(val) ((int)((val)+0.5))
+#include "gegl-algorithms-bilinear.inc"
+#undef BILINEAR_FUNCNAME
+#undef BILINEAR_TYPE
+#undef BILINEAR_ROUND
+
+#define BILINEAR_FUNCNAME   gegl_resample_bilinear_u32
+#define BILINEAR_TYPE       guint32
+#define BILINEAR_ROUND(val) ((int)((val)+0.5))
+#include "gegl-algorithms-bilinear.inc"
+#undef BILINEAR_FUNCNAME
+#undef BILINEAR_TYPE
+#undef BILINEAR_ROUND
+
diff --git a/gegl/gegl-algorithms.h b/gegl/gegl-algorithms.h
index 3faa12a..9d9ff6e 100644
--- a/gegl/gegl-algorithms.h
+++ b/gegl/gegl-algorithms.h
@@ -137,6 +137,63 @@ void gegl_resample_boxfilter_u8 (guchar              *dest_buf,
                                  gint                 bpp,
                                  gint                 d_rowstride);
 
+/* Attempt to resample with a 2x2 bilinear filter, if no implementation is
+ * available for #format fall back to nearest neighbor.
+ */
+void gegl_resample_bilinear (guchar              *dest_buf,
+                             const guchar        *source_buf,
+                             const GeglRectangle *dst_rect,
+                             const GeglRectangle *src_rect,
+                             gint                 s_rowstride,
+                             gdouble              scale,
+                             const Babl          *format,
+                             gint                 d_rowstride);
+
+void gegl_resample_bilinear_double (guchar              *dest_buf,
+                                    const guchar        *source_buf,
+                                    const GeglRectangle *dst_rect,
+                                    const GeglRectangle *src_rect,
+                                    gint                 s_rowstride,
+                                    gdouble              scale,
+                                    gint                 bpp,
+                                    gint                 d_rowstride);
+
+void gegl_resample_bilinear_float (guchar              *dest_buf,
+                                   const guchar        *source_buf,
+                                   const GeglRectangle *dst_rect,
+                                   const GeglRectangle *src_rect,
+                                   gint                 s_rowstride,
+                                   gdouble              scale,
+                                   gint                 bpp,
+                                   gint                 d_rowstride);
+
+void gegl_resample_bilinear_u32 (guchar              *dest_buf,
+                                 const guchar        *source_buf,
+                                 const GeglRectangle *dst_rect,
+                                 const GeglRectangle *src_rect,
+                                 gint                 s_rowstride,
+                                 gdouble              scale,
+                                 gint                 bpp,
+                                 gint                 d_rowstride);
+
+void gegl_resample_bilinear_u16 (guchar              *dest_buf,
+                                 const guchar        *source_buf,
+                                 const GeglRectangle *dst_rect,
+                                 const GeglRectangle *src_rect,
+                                 gint                 s_rowstride,
+                                 gdouble              scale,
+                                 gint                 bpp,
+                                 gint                 d_rowstride);
+
+void gegl_resample_bilinear_u8 (guchar              *dest_buf,
+                                const guchar        *source_buf,
+                                const GeglRectangle *dst_rect,
+                                const GeglRectangle *src_rect,
+                                gint                 s_rowstride,
+                                gdouble              scale,
+                                gint                 bpp,
+                                gint                 d_rowstride);
+
 void gegl_resample_nearest (guchar              *dst,
                             const guchar        *src,
                             const GeglRectangle *dst_rect,
@@ -146,6 +203,7 @@ void gegl_resample_nearest (guchar              *dst,
                             gint                 bpp,
                             gint                 dst_stride);
 
+
 G_END_DECLS
 
-#endif /* __GEGL_ALGORITHMS_H__ */
\ No newline at end of file
+#endif /* __GEGL_ALGORITHMS_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]