algorithms: implement a bilinear alternative to boxfilter

parent b0bf1925
......@@ -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
......
......@@ -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;
......
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;
}
}
}
......@@ -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
......@@ -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__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment