Browse Source

* Rework the convolution template system.

git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@2793 92316355-f0b4-4df1-b90c-862c8a59935f
remotes/tiles
sam 16 years ago
parent
commit
8ddfafa5ba
5 changed files with 289 additions and 281 deletions
  1. +2
    -1
      pipi/Makefile.am
  2. +216
    -53
      pipi/filter/convolution.c
  3. +0
    -227
      pipi/filter/convolution_template.h
  4. +3
    -0
      pipi/pipi_internals.h
  5. +68
    -0
      pipi/pipi_template.h

+ 2
- 1
pipi/Makefile.am View File

@@ -16,6 +16,7 @@ libpipi_la_SOURCES = \
pipi.c \
pipi.h \
pipi_internals.h \
pipi_template.h \
context.c \
pixels.c \
codec.c \
@@ -61,7 +62,7 @@ combine_sources = \
filter_sources = \
filter/autocontrast.c \
filter/blur.c \
filter/convolution.c filter/convolution_template.h \
filter/convolution.c \
filter/color.c \
filter/transform.c \
filter/median.c \


+ 216
- 53
pipi/filter/convolution.c View File

@@ -27,51 +27,10 @@
#include "pipi.h"
#include "pipi_internals.h"

#define FLAG_GRAY ((FLAGS) & SET_FLAG_GRAY)
#define FLAG_WRAP ((FLAGS) & SET_FLAG_WRAP)

#define SET_FLAG_GRAY 0x01
#define SET_FLAG_WRAP 0x02

#undef FUNC1
#undef FUNC2
#undef PIXEL
#undef FLAGS
#define FUNC1 conv_std_rgba_f
#define FUNC2 conv_sep_rgba_f
#define PIXEL float
#define FLAGS 0
#include "convolution_template.h"

#undef FUNC1
#undef FUNC2
#undef PIXEL
#undef FLAGS
#define FUNC1 conv_std_y_f
#define FUNC2 conv_sep_y_f
#define PIXEL float
#define FLAGS SET_FLAG_GRAY
#include "convolution_template.h"

#undef FUNC1
#undef FUNC2
#undef PIXEL
#undef FLAGS
#define FUNC1 wrap_std_rgba_f
#define FUNC2 wrap_sep_rgba_f
#define PIXEL float
#define FLAGS SET_FLAG_WRAP
#include "convolution_template.h"

#undef FUNC1
#undef FUNC2
#undef PIXEL
#undef FLAGS
#define FUNC1 wrap_std_y_f
#define FUNC2 wrap_sep_y_f
#define PIXEL float
#define FLAGS SET_FLAG_GRAY|SET_FLAG_WRAP
#include "convolution_template.h"
#if !defined TEMPLATE_FILE /* This file uses the template system */
#define TEMPLATE_FLAGS SET_FLAG_GRAY | SET_FLAG_WRAP
#define TEMPLATE_FILE "filter/convolution.c"
#include "pipi_template.h"

pipi_image_t *pipi_convolution(pipi_image_t *src, int m, int n, double mat[])
{
@@ -115,14 +74,14 @@ pipi_image_t *pipi_convolution(pipi_image_t *src, int m, int n, double mat[])
if(src->last_modified == PIPI_PIXELS_Y_F)
{
if(src->wrap)
return wrap_std_y_f(src, m, n, mat);
return conv_std_y_f(src, m, n, mat);
return conv_gray_wrap(src, m, n, mat);
return conv_gray(src, m, n, mat);
}
else
{
if(src->wrap)
return wrap_std_rgba_f(src, m, n, mat);
return conv_std_rgba_f(src, m, n, mat);
return conv_wrap(src, m, n, mat);
return conv(src, m, n, mat);
}
}
}
@@ -139,11 +98,11 @@ pipi_image_t *pipi_convolution(pipi_image_t *src, int m, int n, double mat[])
vvec[j] = mat[j * m + besti] / tmp;

if(src->last_modified == PIPI_PIXELS_Y_F)
ret = src->wrap ? wrap_sep_y_f(src, m, hvec, n, vvec)
: conv_sep_y_f(src, m, hvec, n, vvec);
ret = src->wrap ? sepconv_gray_wrap(src, m, hvec, n, vvec)
: sepconv_gray(src, m, hvec, n, vvec);
else
ret = src->wrap ? wrap_sep_rgba_f(src, m, hvec, n, vvec)
: conv_sep_rgba_f(src, m, hvec, n, vvec);
ret = src->wrap ? sepconv_wrap(src, m, hvec, n, vvec)
: sepconv(src, m, hvec, n, vvec);

free(hvec);
free(vvec);
@@ -151,3 +110,207 @@ pipi_image_t *pipi_convolution(pipi_image_t *src, int m, int n, double mat[])
return ret;
}

#else /* XXX: the following functions use the template system */

static pipi_image_t *SUFFIX(conv)(pipi_image_t *src,
int m, int n, double mat[])
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
int x, y, i, j, w, h;

w = src->w;
h = src->h;

srcp = FLAG_GRAY ? pipi_getpixels(src, PIPI_PIXELS_Y_F)
: pipi_getpixels(src, PIPI_PIXELS_RGBA_F);
srcdata = (float *)srcp->pixels;

dst = pipi_new(w, h);
dstp = FLAG_GRAY ? pipi_getpixels(dst, PIPI_PIXELS_Y_F)
: pipi_getpixels(dst, PIPI_PIXELS_RGBA_F);
dstdata = (float *)dstp->pixels;

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(FLAG_GRAY)
{
double Y = 0.;
int x2, y2;

for(j = 0; j < n; j++)
{
y2 = y + j - n / 2;
if(y2 < 0) y2 = FLAG_WRAP ? h - 1 - ((-y2 - 1) % h) : 0;
else if(y2 >= h) y2 = FLAG_WRAP ? y2 % h : h - 1;

for(i = 0; i < m; i++)
{
x2 = x + i - m / 2;
if(x2 < 0) x2 = FLAG_WRAP ? w - 1 - ((-x2 - 1) % w) : 0;
else if(x2 >= w) x2 = FLAG_WRAP ? x2 % w : w - 1;

Y += mat[j * m + i] * srcdata[y2 * w + x2];
}
}

dstdata[y * w + x] = Y < 0.0 ? 0.0 : Y > 1.0 ? 1.0 : Y;
}
else
{
double R = 0., G = 0., B = 0.;
int x2, y2, off = 4 * (y * w + x);

for(j = 0; j < n; j++)
{
y2 = y + j - n / 2;
if(y2 < 0) y2 = FLAG_WRAP ? h - 1 - ((-y2 - 1) % h) : 0;
else if(y2 >= h) y2 = FLAG_WRAP ? y2 % h : h - 1;

for(i = 0; i < m; i++)
{
double f = mat[j * m + i];

x2 = x + i - m / 2;
if(x2 < 0) x2 = FLAG_WRAP ? w - 1 - ((-x2 - 1) % w) : 0;
else if(x2 >= w) x2 = FLAG_WRAP ? x2 % w : w - 1;

R += f * srcdata[(y2 * w + x2) * 4];
G += f * srcdata[(y2 * w + x2) * 4 + 1];
B += f * srcdata[(y2 * w + x2) * 4 + 2];
}
}

dstdata[off] = R < 0.0 ? 0.0 : R > 1.0 ? 1.0 : R;
dstdata[off + 1] = G < 0.0 ? 0.0 : G > 1.0 ? 1.0 : G;
dstdata[off + 2] = B < 0.0 ? 0.0 : B > 1.0 ? 1.0 : B;
}
}
}

return dst;
}

static pipi_image_t *SUFFIX(sepconv)(pipi_image_t *src,
int m, double hvec[], int n, double vvec[])
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
double *buffer;
int x, y, i, j, w, h;

w = src->w;
h = src->h;

srcp = FLAG_GRAY ? pipi_getpixels(src, PIPI_PIXELS_Y_F)
: pipi_getpixels(src, PIPI_PIXELS_RGBA_F);
srcdata = (float *)srcp->pixels;

dst = pipi_new(w, h);
dstp = FLAG_GRAY ? pipi_getpixels(dst, PIPI_PIXELS_Y_F)
: pipi_getpixels(dst, PIPI_PIXELS_RGBA_F);
dstdata = (float *)dstp->pixels;

buffer = malloc(w * h * (FLAG_GRAY ? 1 : 4) * sizeof(double));

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(FLAG_GRAY)
{
double Y = 0.;
int x2;

for(i = 0; i < m; i++)
{
x2 = x + i - m / 2;
if(x2 < 0) x2 = FLAG_WRAP ? w - 1 - ((-x2 - 1) % w) : 0;
else if(x2 >= w) x2 = FLAG_WRAP ? x2 % w : w - 1;

Y += hvec[i] * srcdata[y * w + x2];
}

buffer[y * w + x] = Y;
}
else
{
double R = 0., G = 0., B = 0.;
int x2, off = 4 * (y * w + x);

for(i = 0; i < m; i++)
{
double f = hvec[i];

x2 = x + i - m / 2;
if(x2 < 0) x2 = FLAG_WRAP ? w - 1 - ((-x2 - 1) % w) : 0;
else if(x2 >= w) x2 = FLAG_WRAP ? x2 % w : w - 1;

R += f * srcdata[(y * w + x2) * 4];
G += f * srcdata[(y * w + x2) * 4 + 1];
B += f * srcdata[(y * w + x2) * 4 + 2];
}

buffer[off] = R;
buffer[off + 1] = G;
buffer[off + 2] = B;
}
}
}

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(FLAG_GRAY)
{
double Y = 0.;
int y2;

for(j = 0; j < n; j++)
{
y2 = y + j - n / 2;
if(y2 < 0) y2 = FLAG_WRAP ? h - 1 - ((-y2 - 1) % h) : 0;
else if(y2 >= h) y2 = FLAG_WRAP ? y2 % h : h - 1;

Y += vvec[j] * buffer[y2 * w + x];
}

dstdata[y * w + x] = Y < 0.0 ? 0.0 : Y > 1.0 ? 1.0 : Y;
}
else
{
double R = 0., G = 0., B = 0.;
int y2, off = 4 * (y * w + x);

for(j = 0; j < n; j++)
{
double f = vvec[j];

y2 = y + j - n / 2;
if(y2 < 0) y2 = FLAG_WRAP ? h - 1 - ((-y2 - 1) % h) : 0;
else if(y2 >= h) y2 = FLAG_WRAP ? y2 % h : h - 1;

R += f * buffer[(y2 * w + x) * 4];
G += f * buffer[(y2 * w + x) * 4 + 1];
B += f * buffer[(y2 * w + x) * 4 + 2];
}

dstdata[off] = R < 0.0 ? 0.0 : R > 1.0 ? 1.0 : R;
dstdata[off + 1] = G < 0.0 ? 0.0 : G > 1.0 ? 1.0 : G;
dstdata[off + 2] = B < 0.0 ? 0.0 : B > 1.0 ? 1.0 : B;
}
}
}

free(buffer);

return dst;
}

#endif


+ 0
- 227
pipi/filter/convolution_template.h View File

@@ -1,227 +0,0 @@
/*
* libpipi Proper image processing implementation library
* Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This library is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/

/*
* convolution_template.h: convolution templates
* required macros:
* FUNC1 standard function name
* FUNC2 separable function name
* PIXEL pixel type
* FLAGS 1 (grayscale)
* 2 (loop)
*/

static pipi_image_t *FUNC1(pipi_image_t *src, int m, int n, double mat[]);
static pipi_image_t *FUNC2(pipi_image_t *src, int m, double hvec[],
int n, double vvec[]);

static pipi_image_t *FUNC1(pipi_image_t *src, int m, int n, double mat[])
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
PIXEL *srcdata, *dstdata;
int x, y, i, j, w, h;

w = src->w;
h = src->h;

srcp = FLAG_GRAY ? pipi_getpixels(src, PIPI_PIXELS_Y_F)
: pipi_getpixels(src, PIPI_PIXELS_RGBA_F);
srcdata = (PIXEL *)srcp->pixels;

dst = pipi_new(w, h);
dstp = FLAG_GRAY ? pipi_getpixels(dst, PIPI_PIXELS_Y_F)
: pipi_getpixels(dst, PIPI_PIXELS_RGBA_F);
dstdata = (PIXEL *)dstp->pixels;

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(FLAG_GRAY)
{
double Y = 0.;
int x2, y2;

for(j = 0; j < n; j++)
{
y2 = y + j - n / 2;
if(y2 < 0) y2 = FLAG_WRAP ? h - 1 - ((-y2 - 1) % h) : 0;
else if(y2 >= h) y2 = FLAG_WRAP ? y2 % h : h - 1;

for(i = 0; i < m; i++)
{
x2 = x + i - m / 2;
if(x2 < 0) x2 = FLAG_WRAP ? w - 1 - ((-x2 - 1) % w) : 0;
else if(x2 >= w) x2 = FLAG_WRAP ? x2 % w : w - 1;

Y += mat[j * m + i] * srcdata[y2 * w + x2];
}
}

dstdata[y * w + x] = Y < 0.0 ? 0.0 : Y > 1.0 ? 1.0 : Y;
}
else
{
double R = 0., G = 0., B = 0.;
int x2, y2, off = 4 * (y * w + x);

for(j = 0; j < n; j++)
{
y2 = y + j - n / 2;
if(y2 < 0) y2 = FLAG_WRAP ? h - 1 - ((-y2 - 1) % h) : 0;
else if(y2 >= h) y2 = FLAG_WRAP ? y2 % h : h - 1;

for(i = 0; i < m; i++)
{
double f = mat[j * m + i];

x2 = x + i - m / 2;
if(x2 < 0) x2 = FLAG_WRAP ? w - 1 - ((-x2 - 1) % w) : 0;
else if(x2 >= w) x2 = FLAG_WRAP ? x2 % w : w - 1;

R += f * srcdata[(y2 * w + x2) * 4];
G += f * srcdata[(y2 * w + x2) * 4 + 1];
B += f * srcdata[(y2 * w + x2) * 4 + 2];
}
}

dstdata[off] = R < 0.0 ? 0.0 : R > 1.0 ? 1.0 : R;
dstdata[off + 1] = G < 0.0 ? 0.0 : G > 1.0 ? 1.0 : G;
dstdata[off + 2] = B < 0.0 ? 0.0 : B > 1.0 ? 1.0 : B;
}
}
}

return dst;
}

static pipi_image_t *FUNC2(pipi_image_t *src,
int m, double hvec[], int n, double vvec[])
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
PIXEL *srcdata, *dstdata;
double *buffer;
int x, y, i, j, w, h;

w = src->w;
h = src->h;

srcp = FLAG_GRAY ? pipi_getpixels(src, PIPI_PIXELS_Y_F)
: pipi_getpixels(src, PIPI_PIXELS_RGBA_F);
srcdata = (PIXEL *)srcp->pixels;

dst = pipi_new(w, h);
dstp = FLAG_GRAY ? pipi_getpixels(dst, PIPI_PIXELS_Y_F)
: pipi_getpixels(dst, PIPI_PIXELS_RGBA_F);
dstdata = (PIXEL *)dstp->pixels;

buffer = malloc(w * h * (FLAG_GRAY ? 1 : 4) * sizeof(double));

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(FLAG_GRAY)
{
double Y = 0.;
int x2;

for(i = 0; i < m; i++)
{
x2 = x + i - m / 2;
if(x2 < 0) x2 = FLAG_WRAP ? w - 1 - ((-x2 - 1) % w) : 0;
else if(x2 >= w) x2 = FLAG_WRAP ? x2 % w : w - 1;

Y += hvec[i] * srcdata[y * w + x2];
}

buffer[y * w + x] = Y;
}
else
{
double R = 0., G = 0., B = 0.;
int x2, off = 4 * (y * w + x);

for(i = 0; i < m; i++)
{
double f = hvec[i];

x2 = x + i - m / 2;
if(x2 < 0) x2 = FLAG_WRAP ? w - 1 - ((-x2 - 1) % w) : 0;
else if(x2 >= w) x2 = FLAG_WRAP ? x2 % w : w - 1;

R += f * srcdata[(y * w + x2) * 4];
G += f * srcdata[(y * w + x2) * 4 + 1];
B += f * srcdata[(y * w + x2) * 4 + 2];
}

buffer[off] = R;
buffer[off + 1] = G;
buffer[off + 2] = B;
}
}
}

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(FLAG_GRAY)
{
double Y = 0.;
int y2;

for(j = 0; j < n; j++)
{
y2 = y + j - n / 2;
if(y2 < 0) y2 = FLAG_WRAP ? h - 1 - ((-y2 - 1) % h) : 0;
else if(y2 >= h) y2 = FLAG_WRAP ? y2 % h : h - 1;

Y += vvec[j] * buffer[y2 * w + x];
}

dstdata[y * w + x] = Y < 0.0 ? 0.0 : Y > 1.0 ? 1.0 : Y;
}
else
{
double R = 0., G = 0., B = 0.;
int y2, off = 4 * (y * w + x);

for(j = 0; j < n; j++)
{
double f = vvec[j];

y2 = y + j - n / 2;
if(y2 < 0) y2 = FLAG_WRAP ? h - 1 - ((-y2 - 1) % h) : 0;
else if(y2 >= h) y2 = FLAG_WRAP ? y2 % h : h - 1;

R += f * buffer[(y2 * w + x) * 4];
G += f * buffer[(y2 * w + x) * 4 + 1];
B += f * buffer[(y2 * w + x) * 4 + 2];
}

dstdata[off] = R < 0.0 ? 0.0 : R > 1.0 ? 1.0 : R;
dstdata[off + 1] = G < 0.0 ? 0.0 : G > 1.0 ? 1.0 : G;
dstdata[off + 2] = B < 0.0 ? 0.0 : B > 1.0 ? 1.0 : B;
}
}
}

free(buffer);

return dst;
}


+ 3
- 0
pipi/pipi_internals.h View File

@@ -19,6 +19,9 @@
#ifndef __PIPI_INTERNALS_H__
#define __PIPI_INTERNALS_H__

#define SET_FLAG_GRAY 0x00000001
#define SET_FLAG_WRAP 0x00000002

/* pipi_image_t: the image structure. This is probably going to be the most
* complex structure in the library, but right now it only has fairly normal
* stuff, like width and height and pointers to pixel areas. */


+ 68
- 0
pipi/pipi_template.h View File

@@ -0,0 +1,68 @@
/*
* libpipi Proper image processing implementation library
* Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This library is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/

/* pipi_template.h: the magic template preprocessing file
*
* Define the following macros before including this file:
* * TEMPLATE_FLAGS is set to a list of toggle flags, a binary OR of:
* - SET_FLAG_GRAY
* - SET_FLAG_WRAP
* * TEMPLATE_FILE is set to the template file. The following macros
* will be defined when including it. Their value depend on the flags
* specified above:
* - FLAG_GRAY is set to 0 or 1
* - FLAG_WRAP is set to 0 or 1
* - SUFFIX(x) expands x by adding relevant information, eg. x##_gray_wrap
*/

#if !defined FLAG_GRAY
# if (TEMPLATE_FLAGS) & SET_FLAG_GRAY
# define FLAG_GRAY 1
# include __FILE__
# undef FLAG_GRAY
# endif
# define FLAG_GRAY 0
# include __FILE__
# undef FLAG_GRAY

#elif !defined FLAG_WRAP
# if (TEMPLATE_FLAGS) & SET_FLAG_WRAP
# define FLAG_WRAP 1
# include __FILE__
# undef FLAG_WRAP
# endif
# define FLAG_WRAP 0
# include __FILE__
# undef FLAG_WRAP

#else
/* FIXME: I couldn't find a way to do this in one preprocessor pass,
* too many levels of indirection seem to be needed. */
# if FLAG_GRAY
# if FLAG_WRAP
# define SUFFIX(x) x##_gray_wrap
# else
# define SUFFIX(x) x##_gray
# endif
# else
# if FLAG_WRAP
# define SUFFIX(x) x##_wrap
# else
# define SUFFIX(x) x
# endif
# endif
# include TEMPLATE_FILE
# undef SUFFIX
#endif


Loading…
Cancel
Save