[gegl] algorithms: implement a bilinear alternative to boxfilter
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] algorithms: implement a bilinear alternative to boxfilter
- Date: Thu, 15 Oct 2015 15:23:34 +0000 (UTC)
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]