This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, master has been updated via 61f49dcc7034e8eeeccf9a950d1c2731f5c9969d (commit) via 8f908e18fb01faa8320ac4b2ae1905426ceddcd1 (commit) via 8e026f14b369c6d70f8a4954970d8d94864ca587 (commit) via a67438c203dd1b95d464a2482795d27318e00592 (commit) from 04f9434ac9e4649dba4c394b00187a7f1004b0a4 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/61f49dcc7034e8eeeccf9a950d1c2731f5c99...
commit 61f49dcc7034e8eeeccf9a950d1c2731f5c9969d Author: Cyril Hrubis metan@ucw.cz Date: Sun Jul 1 15:35:50 2012 +0200
filters: Cleanup and preparation for changes.
* Added public API for generic convolution.
* Added Ex functions that operate only on rectangular sub area of image.
* Convolution filters are now 10% faster
* Add simple example for convolution filter
diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile index 2107993..bfff75b 100644 --- a/demos/c_simple/Makefile +++ b/demos/c_simple/Makefile @@ -7,7 +7,7 @@ LDLIBS+=-lGP -lGP_backends -lSDL -L$(TOPDIR)/build/
APPS=backend_example loaders_example loaders filters_symmetry gfx_koch virtual_backend_example meta_data meta_data_dump tmp_file showimage- v4l2_show v4l2_grab + v4l2_show v4l2_grab convolution
v4l2_show: LDLIBS+=-lGP_grabbers v4l2_grab: LDLIBS+=-lGP_grabbers diff --git a/libs/filters/GP_Laplace.c b/demos/c_simple/convolution.c similarity index 51% copy from libs/filters/GP_Laplace.c copy to demos/c_simple/convolution.c index b6a91a1..e0399e3 100644 --- a/libs/filters/GP_Laplace.c +++ b/demos/c_simple/convolution.c @@ -20,83 +20,96 @@ * * *****************************************************************************/
-#include "core/GP_Debug.h" -#include "core/GP_GetPutPixel.h" + /*
-#include "GP_Linear.h" + Convolution filter example.
-#include "GP_Laplace.h" + */
-int GP_FilterLaplace(const GP_Context *src, GP_Context *dst, - GP_ProgressCallback *callback) -{ - GP_DEBUG(1, "Laplace filter %ux%u", src->w, src->h); +#include <stdio.h> +#include <string.h> +#include <errno.h>
- float kern[9] = {0, 1, 0, - 1, -4, 1, - 0, 1, 0}; +#include <GP.h>
- if (GP_FilterLinearConvolution_Raw(src, dst, kern, 3, 3, 1, callback)) - return 1; +struct callback_priv { + char *op; + char *name; +}; + +static int progress_callback(GP_ProgressCallback *self) +{ + struct callback_priv *priv = self->priv; + + printf("r%s '%s' %3.1f%%", priv->op, priv->name, self->percentage); + fflush(stdout);
+ /* + * It's important to return zero as non-zero return value + * aborts the operation. + */ return 0; }
-GP_Context *GP_FilterLaplaceAlloc(const GP_Context *src, - GP_ProgressCallback *callback) +int main(int argc, char *argv[]) { - GP_Context *ret = GP_ContextCopy(src, 0); + GP_Context *img; + struct callback_priv priv; + GP_ProgressCallback callback = {.callback = progress_callback, + .priv = &priv};
- if (ret == NULL) - return NULL; - - if (GP_FilterLaplace(src, ret, callback)) { - GP_ContextFree(ret); - return NULL; + if (argc != 2) { + fprintf(stderr, "Takes an image as an parametern"); + return 1; }
- return ret; -} + priv.op = "Loading"; + priv.name = argv[1]; + + img = GP_LoadImage(argv[1], &callback); + + if (img == NULL) { + fprintf(stderr, "Failed to load image '%s':%sn", argv[1], + strerror(errno)); + return 1; + }
+ printf("n");
-int GP_FilterEdgeSharpening(const GP_Context *src, GP_Context *dst, - float w, GP_ProgressCallback *callback) -{ - /* Identity kernel */ - float kern[9] = {0, 0, 0, - 0, 1, 0, - 0, 0, 0}; - - GP_DEBUG(1, "Laplace Edge Sharpening filter %ux%u w=%f", - src->w, src->h, w); + float box_kernel[] = { + 0.0, 0.1, 1.0, 0.1, 0.0, + 0.1, 0.5, 1.0, 0.5, 0.1, + 1.0, 1.0, 1.0, 1.0, 1.0, + 0.1, 0.5, 1.0, 0.5, 0.1, + 0.0, 0.1, 1.0, 0.1, 0.0, + };
- /* Create combined kernel */ - kern[1] -= 1.00 * w; - kern[3] -= 1.00 * w; - kern[4] -= -4.00 * w; - kern[5] -= 1.00 * w; - kern[7] -= 1.00 * w; + GP_FilterKernel2D box = { + .w = 5, + .h = 5, + .div = 11.8, + .kernel = box_kernel, + };
- GP_FilterKernelPrint(kern, 3, 3, 1); + priv.op = "Box Linear Convolution";
- if (GP_FilterLinearConvolution_Raw(src, dst, kern, 3, 3, 1, callback)) - return 1; + /* + * Blur in-place, inner rectangle of the image. + */ + GP_FilterConvolutionEx(img, img->w/4, img->h/4, img->w/2, img->h/2, + img, img->w/4, img->h/4, &box, &callback);
- return 0; -} + printf("n");
-GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w, - GP_ProgressCallback *callback) -{ - GP_Context *ret = GP_ContextCopy(src, 0); + priv.op = "Saving"; + priv.name = "out.png";
- if (ret == NULL) - return NULL; - - if (GP_FilterEdgeSharpening(src, ret, w, callback)) { - GP_ContextFree(ret); - return NULL; + if (GP_SavePNG(img, "out.png", &callback)) { + fprintf(stderr, "Failed to save image %s", strerror(errno)); + return 1; }
- return ret; + printf("n"); + + return 0; } diff --git a/demos/c_simple/v4l2_show.c b/demos/c_simple/v4l2_show.c index 077ba7b..681f30a 100644 --- a/demos/c_simple/v4l2_show.c +++ b/demos/c_simple/v4l2_show.c @@ -108,6 +108,7 @@ int main(int argc, char *argv[]) break; case 1: GP_FilterEdgePrewitt(img, &res, NULL, NULL); + // GP_FilterEdgeSobel(img, &res, NULL, NULL); break; case 2: GP_FilterGaussianBlur(img, img, 1, 1, NULL); diff --git a/include/filters/GP_Convolution.h b/include/filters/GP_Convolution.h new file mode 100644 index 0000000..858ead6 --- /dev/null +++ b/include/filters/GP_Convolution.h @@ -0,0 +1,119 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim 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 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim 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 gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +/* + + Convolution filters. + + */ + +#ifndef FILTERS_GP_CONVOLUTION_H +#define FILTERS_GP_CONVOLUTION_H + +#include "GP_Filter.h" + +/* + * 2D convolution kernel. + * + * The kernel array size must be w * h. + * + * The div is used to divide the resulting value which is commonly used for + * normalization. + * + * Example box smoothing filter kernel initialization: + * + * float box_filter[] = { + * 1, 1, 1, + * 1, 1, 1, + * 1, 1, 1, + * }; + * + * GP_FilterKernel2D box_kernel = { + * .w = 3, + * .h = 3, + * .div = 9, + * .kernel = box_filter, + * }; + */ +typedef struct GP_FilterKernel2D { + unsigned int w; + unsigned int h; + float div; + float *kernel; +} GP_FilterKernel2D; + +/* + * Extended convolution filter. + * + * Works on rectangle in src defined by x_src, y_src, w_src and h_src. + * + * The result is stored into dst strating from x_dst and y_dst. + * + */ +int GP_FilterConvolutionEx(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Coord h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, + const GP_FilterKernel2D *kernel, + GP_ProgressCallback *callback); + +/* + * Extended convolution filter. + * + * Works on rectangle in src defined by x_src, y_src, w_src and h_src. + * + * Allocates context of a w_src x h_src. + */ +GP_Context *GP_FilterConvolutionExAlloc(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + const GP_FilterKernel2D *kernel, + GP_ProgressCallback *callback); + + +static inline int GP_FilterConvolution(const GP_Context *src, GP_Context *dst, + const GP_FilterKernel2D *kernel, + GP_ProgressCallback *callback) +{ + return GP_FilterConvolutionEx(src, 0, 0, dst->w, dst->h, dst, 0, 0, + kernel, callback); +} + +static inline GP_Context *GP_FilterConvolutionAlloc(const GP_Context *src, + const GP_FilterKernel2D *kernel, + GP_ProgressCallback *callback) +{ + return GP_FilterConvolutionExAlloc(src, 0, 0, src->w, src->h, + kernel, callback); +} + +/* + * Prints a kernel into the stdout. + */ +static inline void GP_FilterKernel2DPrint(const GP_FilterKernel2D *kernel) +{ + GP_FilterKernelPrint_Raw(kernel->kernel, kernel->w, kernel->h, + kernel->div); +} + +#endif /* FILTERS_GP_CONVOLUTION_H */ diff --git a/include/filters/GP_Filters.h b/include/filters/GP_Filters.h index 92ce03a..3b0a95f 100644 --- a/include/filters/GP_Filters.h +++ b/include/filters/GP_Filters.h @@ -47,9 +47,12 @@ /* Image rotations (90 180 270 grads) and mirroring */ #include "filters/GP_Rotate.h"
-/* Linear convolution based filters (mostly blurs) */ +/* Linear convolution Raw API */ #include "filters/GP_Linear.h"
+/* Convolution filters */ +#include "filters/GP_Convolution.h" + /* Image scaling (resampling) */ #include "filters/GP_Resize.h"
diff --git a/include/filters/GP_Linear.h b/include/filters/GP_Linear.h index ba286ec..e6cf885 100644 --- a/include/filters/GP_Linear.h +++ b/include/filters/GP_Linear.h @@ -22,7 +22,7 @@
/*
- Linear filters. + Linear Convolution _Raw filters.
*/
@@ -65,6 +65,11 @@ GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst, * * The kernel is array of kw * kh floats and is indexed as two directional * array. + * + * The src coordinates and size defines rectangle in the source on which the + * filter operates. + * + * The dst coodinates defines start pixel of in the destination context. * * To define 3x3 average filter * @@ -80,7 +85,11 @@ GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst, * * This function works also in-place. */ -int GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, +int GP_FilterLinearConvolution_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, float kernel[], uint32_t kw, uint32_t kh, float kern_div, GP_ProgressCallback *callback);
@@ -94,11 +103,19 @@ int GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, * * Both works also in-place. */ -int GP_FilterHLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, +int GP_FilterHLinearConvolution_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, float kernel[], uint32_t kw, float kern_div, GP_ProgressCallback *callback);
-int GP_FilterVLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, +int GP_FilterVLinearConvolution_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, float kernel[], uint32_t kh, float kern_div, GP_ProgressCallback *callback);
@@ -107,14 +124,18 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, * correct progress callback (both horizontal and vertical kernels are expected * to be similar in size). */ -int GP_FilterVHLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, +int GP_FilterVHLinearConvolution_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, float hkernel[], uint32_t kw, float hkern_div, - float vkernel[], uint32_t kh, float vkern_div, - GP_ProgressCallback *callback); + float vkernel[], uint32_t kh, float vkern_div, + GP_ProgressCallback *callback);
/* * Prints a kernel into the stdout. */ -void GP_FilterKernelPrint(float kernel[], int kw, int kh, float kern_div); +void GP_FilterKernelPrint_Raw(float kernel[], int kw, int kh, float kern_div);
#endif /* FILTERS_GP_LINEAR_H */ diff --git a/libs/filters/GP_Laplace.c b/libs/filters/GP_Convolution.c similarity index 51% copy from libs/filters/GP_Laplace.c copy to libs/filters/GP_Convolution.c index b6a91a1..b628cba 100644 --- a/libs/filters/GP_Laplace.c +++ b/libs/filters/GP_Convolution.c @@ -21,82 +21,55 @@ *****************************************************************************/
#include "core/GP_Debug.h" -#include "core/GP_GetPutPixel.h"
#include "GP_Linear.h"
-#include "GP_Laplace.h" - -int GP_FilterLaplace(const GP_Context *src, GP_Context *dst, - GP_ProgressCallback *callback) -{ - GP_DEBUG(1, "Laplace filter %ux%u", src->w, src->h); - - float kern[9] = {0, 1, 0, - 1, -4, 1, - 0, 1, 0}; - - if (GP_FilterLinearConvolution_Raw(src, dst, kern, 3, 3, 1, callback)) - return 1; - - return 0; -} - -GP_Context *GP_FilterLaplaceAlloc(const GP_Context *src, - GP_ProgressCallback *callback) -{ - GP_Context *ret = GP_ContextCopy(src, 0); - - if (ret == NULL) - return NULL; - - if (GP_FilterLaplace(src, ret, callback)) { - GP_ContextFree(ret); - return NULL; - } - - return ret; -} - - -int GP_FilterEdgeSharpening(const GP_Context *src, GP_Context *dst, - float w, GP_ProgressCallback *callback) +#include "GP_Convolution.h" +int GP_FilterConvolutionEx(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Coord h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, + const GP_FilterKernel2D *kernel, + GP_ProgressCallback *callback) { - /* Identity kernel */ - float kern[9] = {0, 0, 0, - 0, 1, 0, - 0, 0, 0}; + GP_CHECK(src->pixel_type == dst->pixel_type); - GP_DEBUG(1, "Laplace Edge Sharpening filter %ux%u w=%f", - src->w, src->h, w); + /* Check that destination is large enough */ + GP_CHECK(x_dst + (GP_Coord)w_src <= (GP_Coord)dst->w); + GP_CHECK(y_dst + (GP_Coord)h_src <= (GP_Coord)dst->h);
- /* Create combined kernel */ - kern[1] -= 1.00 * w; - kern[3] -= 1.00 * w; - kern[4] -= -4.00 * w; - kern[5] -= 1.00 * w; - kern[7] -= 1.00 * w; + /* The source pixel coordinates are clamped inside of the filter */
- GP_FilterKernelPrint(kern, 3, 3, 1); + GP_DEBUG(1, "Linear convolution kernel size %ux%u", + kernel->w, kernel->h);
- if (GP_FilterLinearConvolution_Raw(src, dst, kern, 3, 3, 1, callback)) - return 1; - - return 0; + return GP_FilterLinearConvolution_Raw(src, x_src, y_src, w_src, h_src, + dst, x_dst, y_dst, kernel->kernel, + kernel->w, kernel->h, kernel->div, + callback); }
-GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w, - GP_ProgressCallback *callback) +GP_Context *GP_FilterConvolutionExAlloc(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + const GP_FilterKernel2D *kernel, + GP_ProgressCallback *callback) { - GP_Context *ret = GP_ContextCopy(src, 0); + GP_Context *ret = GP_ContextAlloc(w_src, h_src, src->pixel_type); + + GP_DEBUG(1, "Linear convolution kernel size %ux%u", + kernel->w, kernel->h);
if (ret == NULL) return NULL; - - if (GP_FilterEdgeSharpening(src, ret, w, callback)) { + + if (GP_FilterLinearConvolution_Raw(src, x_src, y_src, w_src, h_src, + ret, 0, 0, kernel->kernel, kernel->w, + kernel->h, kernel->div, callback)) { GP_ContextFree(ret); return NULL; }
- return ret; + return 0; } diff --git a/libs/filters/GP_Edge.c b/libs/filters/GP_Edge.c index 4f73c52..a9a42a6 100644 --- a/libs/filters/GP_Edge.c +++ b/libs/filters/GP_Edge.c @@ -36,11 +36,15 @@ static int prewitt(const GP_Context *src, GP_Context *dx, GP_Context *dy, float smooth_kern[3] = {1, 1, 1,}; float grad_kern[3] = {-1, 0, 1};
- if (GP_FilterVHLinearConvolution_Raw(src, dx, smooth_kern, 3, 1, + if (GP_FilterVHLinearConvolution_Raw(src, 0, 0, src->w, src->h, + dx, 0, 0, + smooth_kern, 3, 1, grad_kern, 3, 1, callback)) return 1;
- if (GP_FilterVHLinearConvolution_Raw(src, dy, grad_kern, 3, 1, + if (GP_FilterVHLinearConvolution_Raw(src, 0, 0, src->w, src->h, + dy, 0, 0, + grad_kern, 3, 1, smooth_kern, 3, 1, callback)) return 1; @@ -59,7 +63,8 @@ static int sobel(const GP_Context *src, GP_Context *dx, GP_Context *dy, -1, 0, 1, };
- if (GP_FilterLinearConvolution_Raw(src, dx, x_kern, 3, 3, 32, callback)) + if (GP_FilterLinearConvolution_Raw(src, 0, 0, src->w, src->h, + dx, 0, 0, x_kern, 3, 3, 32, callback)) return 1; float y_kern[] = { @@ -68,7 +73,8 @@ static int sobel(const GP_Context *src, GP_Context *dx, GP_Context *dy, 1, 2, 1, };
- if (GP_FilterLinearConvolution_Raw(src, dy, y_kern, 3, 3, 32, callback)) + if (GP_FilterLinearConvolution_Raw(src, 0, 0, src->w, src->h, + dy, 0, 0, y_kern, 3, 3, 32, callback)) return 1;
return 0; @@ -103,7 +109,7 @@ static int edge_detect(const GP_Context *src, } uint32_t i, j; - + for (i = 0; i < src->w; i++) { for (j = 0; j < src->h; j++) { GP_Pixel pix_x = GP_GetPixel_Raw_24BPP(dx, i, j); @@ -124,7 +130,7 @@ static int edge_detect(const GP_Context *src, RE = sqrt(Rx*Rx + Ry*Ry) + 0.5; GE = sqrt(Gx*Gx + Gy*Gy) + 0.5; BE = sqrt(Bx*Bx + By*By) + 0.5; - + GP_PutPixel_Raw_24BPP(dx, i, j, GP_Pixel_CREATE_RGB888(RE, GE, BE)); @@ -171,7 +177,7 @@ int GP_FilterEdgeSobel(const GP_Context *src, { GP_DEBUG(1, "Sobel edge detection image %ux%u", src->w, src->h);
- return edge_detect(src, E, Phi, 1, callback); + return edge_detect(src, E, Phi, 0, callback); }
int GP_FilterEdgePrewitt(const GP_Context *src, diff --git a/libs/filters/GP_Laplace.c b/libs/filters/GP_Laplace.c index b6a91a1..a21be78 100644 --- a/libs/filters/GP_Laplace.c +++ b/libs/filters/GP_Laplace.c @@ -36,7 +36,8 @@ int GP_FilterLaplace(const GP_Context *src, GP_Context *dst, 1, -4, 1, 0, 1, 0};
- if (GP_FilterLinearConvolution_Raw(src, dst, kern, 3, 3, 1, callback)) + if (GP_FilterLinearConvolution_Raw(src, 0, 0, src->w, src->h, + dst, 0, 0, kern, 3, 3, 1, callback)) return 1;
return 0; @@ -77,9 +78,8 @@ int GP_FilterEdgeSharpening(const GP_Context *src, GP_Context *dst, kern[5] -= 1.00 * w; kern[7] -= 1.00 * w;
- GP_FilterKernelPrint(kern, 3, 3, 1); - - if (GP_FilterLinearConvolution_Raw(src, dst, kern, 3, 3, 1, callback)) + if (GP_FilterLinearConvolution_Raw(src, 0, 0, src->w, src->h, + dst, 0, 0, kern, 3, 3, 1, callback)) return 1;
return 0; diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c index c84b17b..54ec6c9 100644 --- a/libs/filters/GP_Linear.c +++ b/libs/filters/GP_Linear.c @@ -94,7 +94,8 @@ int GP_FilterGaussianBlur_Raw(const GP_Context *src, GP_Context *dst, float kernel_x[size_x]; float sum = gaussian_kernel_init(sigma_x, kernel_x); - if (GP_FilterHLinearConvolution_Raw(src, dst, kernel_x, size_x, + if (GP_FilterHLinearConvolution_Raw(src, 0, 0, src->w, src->h, + dst, 0, 0, kernel_x, size_x, sum, new_callback)) return 1; } @@ -107,7 +108,8 @@ int GP_FilterGaussianBlur_Raw(const GP_Context *src, GP_Context *dst, float kernel_y[size_y]; float sum = gaussian_kernel_init(sigma_y, kernel_y); - if (GP_FilterVLinearConvolution_Raw(dst, dst, kernel_y, size_y, + if (GP_FilterVLinearConvolution_Raw(dst, 0, 0, src->w, src->h, + dst, 0, 0, kernel_y, size_y, sum, new_callback)) return 1; } @@ -150,51 +152,70 @@ GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst, val = 0; } while (0)
-int GP_FilterHLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, - float kernel[], uint32_t kw, float kern_div, - GP_ProgressCallback *callback) +int GP_FilterHLinearConvolution_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, + float kernel[], uint32_t kw, float kern_div, + GP_ProgressCallback *callback) { GP_Coord x, y; uint32_t i; int32_t ikernel[kw], ikern_div; - uint32_t size = dst->w + kw - 1; + uint32_t size = w_src + kw - 1; - GP_DEBUG(1, "Horizontal linear convolution kernel width %i image %ux%u", - kw, src->w, src->h); + GP_DEBUG(1, "Horizontal linear convolution kernel width %u " + "rectangle %ux%u", kw, w_src, h_src);
for (i = 0; i < kw; i++) ikernel[i] = kernel[i] * MUL + 0.5;
ikern_div = kern_div * MUL + 0.5;
- /* do linear convolution */ - for (y = 0; y < (GP_Coord)dst->h; y++) { + /* Do horizontal linear convolution */ + for (y = 0; y < (GP_Coord)h_src; y++) { uint8_t R[size], G[size], B[size]; + int yi = GP_MIN(y_src + y, (int)src->h - 1);
/* Fetch the whole row */ - GP_Pixel pix = GP_GetPixel_Raw_24BPP(src, 0, y); + GP_Pixel pix = GP_GetPixel_Raw_24BPP(src, 0, yi); + + int xi = x_src - kw/2; + i = 0;
- for (i = 0; i < kw/2; i++) { + /* Copy border pixel until the source image starts */ + while (xi <= 0) { R[i] = GP_Pixel_GET_R_RGB888(pix); G[i] = GP_Pixel_GET_G_RGB888(pix); B[i] = GP_Pixel_GET_B_RGB888(pix); - } - for (i = 0; i < src->w; i++) { - pix = GP_GetPixel_Raw_24BPP(src, i, y); + i++; + xi++; + }
- R[i+kw/2] = GP_Pixel_GET_R_RGB888(pix); - G[i+kw/2] = GP_Pixel_GET_G_RGB888(pix); - B[i+kw/2] = GP_Pixel_GET_B_RGB888(pix); + /* Use as much source image pixels as possible */ + while (xi < (int)src->w) { + pix = GP_GetPixel_Raw_24BPP(src, xi, yi); + + R[i] = GP_Pixel_GET_R_RGB888(pix); + G[i] = GP_Pixel_GET_G_RGB888(pix); + B[i] = GP_Pixel_GET_B_RGB888(pix); + + i++; + xi++; } - - for (i = src->w + kw/2; i < size; i++) { + + /* Copy the rest the border pixel when we are out again */ + while (i < size) { R[i] = GP_Pixel_GET_R_RGB888(pix); G[i] = GP_Pixel_GET_G_RGB888(pix); B[i] = GP_Pixel_GET_B_RGB888(pix); + + i++; }
- for (x = 0; x < (GP_Coord)dst->w; x++) { + for (x = 0; x < (GP_Coord)w_src; x++) { int32_t r = MUL/2, g = MUL/2, b = MUL/2;
/* count the pixel value from neighbours weighted by kernel */ @@ -214,7 +235,7 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, CLAMP(g); CLAMP(b);
- GP_PutPixel_Raw_24BPP(dst, x, y, + GP_PutPixel_Raw_24BPP(dst, x_dst + x, y_dst + y, GP_Pixel_CREATE_RGB888(r, g, b)); } @@ -226,51 +247,70 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, return 0; }
-int GP_FilterVLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, +int GP_FilterVLinearConvolution_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, float kernel[], uint32_t kh, float kern_div, GP_ProgressCallback *callback) { GP_Coord x, y; uint32_t i; int32_t ikernel[kh], ikern_div; - uint32_t size = dst->h + kh - 1; + uint32_t size = h_src + kh - 1;
for (i = 0; i < kh; i++) ikernel[i] = kernel[i] * MUL + 0.5;
- GP_DEBUG(1, "Vertical linear convolution kernel width %i image %ux%u", - kh, src->w, src->h); + GP_DEBUG(1, "Vertical linear convolution kernel width %u " + "rectangle %ux%u", kh, w_src, h_src);
ikern_div = kern_div * MUL + 0.5;
- /* do linear convolution */ - for (x = 0; x < (GP_Coord)dst->w; x++) { + /* Do vertical linear convolution */ + for (x = 0; x < (GP_Coord)w_src; x++) { uint8_t R[size], G[size], B[size]; + int xi = GP_MIN(x_src + x, (int)src->w - 1); + + /* Fetch the whole row */ + GP_Pixel pix = GP_GetPixel_Raw_24BPP(src, xi, 0);
- /* Fetch the whole column */ - GP_Pixel pix = GP_GetPixel_Raw_24BPP(src, x, 0); + int yi = y_src - kh/2; + i = 0;
- for (i = 0; i < kh/2; i++) { + /* Copy border pixel until the source image starts */ + while (yi <= 0) { R[i] = GP_Pixel_GET_R_RGB888(pix); G[i] = GP_Pixel_GET_G_RGB888(pix); B[i] = GP_Pixel_GET_B_RGB888(pix); - } - for (i = 0; i < src->h; i++) { - pix = GP_GetPixel_Raw_24BPP(src, x, i); + i++; + yi++; + }
- R[i+kh/2] = GP_Pixel_GET_R_RGB888(pix); - G[i+kh/2] = GP_Pixel_GET_G_RGB888(pix); - B[i+kh/2] = GP_Pixel_GET_B_RGB888(pix); + /* Use as much source image pixels as possible */ + while (yi < (int)src->h) { + pix = GP_GetPixel_Raw_24BPP(src, xi, yi); + + R[i] = GP_Pixel_GET_R_RGB888(pix); + G[i] = GP_Pixel_GET_G_RGB888(pix); + B[i] = GP_Pixel_GET_B_RGB888(pix); + + i++; + yi++; } - - for (i = src->h + kh/2; i < size; i++) { + + /* Copy the rest the border pixel when we are out again */ + while (i < size) { R[i] = GP_Pixel_GET_R_RGB888(pix); G[i] = GP_Pixel_GET_G_RGB888(pix); B[i] = GP_Pixel_GET_B_RGB888(pix); + + i++; }
- for (y = 0; y < (GP_Coord)dst->h; y++) { + for (y = 0; y < (GP_Coord)h_src; y++) { int32_t r = MUL/2, g = MUL/2, b = MUL/2; /* count the pixel value from neighbours weighted by kernel */ @@ -290,7 +330,7 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, CLAMP(g); CLAMP(b);
- GP_PutPixel_Raw_24BPP(dst, x, y, + GP_PutPixel_Raw_24BPP(dst, x_dst + x, y_dst + y, GP_Pixel_CREATE_RGB888(r, g, b)); } @@ -318,7 +358,11 @@ static int v_callback(GP_ProgressCallback *self) return callback->callback(callback); }
-int GP_FilterVHLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, +int GP_FilterVHLinearConvolution_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, float hkernel[], uint32_t kw, float hkern_div, float vkernel[], uint32_t kh, float vkern_div, GP_ProgressCallback *callback) @@ -332,54 +376,63 @@ int GP_FilterVHLinearConvolution_Raw(const GP_Context *src, GP_Context *dst,
new_callback = callback ? &conv_callback : NULL;
- if (GP_FilterVLinearConvolution_Raw(src, dst, hkernel, kw, hkern_div, new_callback)) + if (GP_FilterVLinearConvolution_Raw(src, x_src, y_src, w_src, h_src, + dst, x_dst, y_dst, + hkernel, kw, hkern_div, + new_callback)) return 1; conv_callback.callback = v_callback; - if (GP_FilterHLinearConvolution_Raw(dst, dst, vkernel, kh, vkern_div, new_callback)) + if (GP_FilterHLinearConvolution_Raw(dst, x_src, y_src, w_src, h_src, + dst, x_dst, y_dst, + vkernel, kh, vkern_div, + new_callback)) return 1; GP_ProgressCallbackDone(callback); return 0; }
-/* - * Linear convolution. - * - * Can be used in-place. - */ -int GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, +int GP_FilterLinearConvolution_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, float kernel[], uint32_t kw, uint32_t kh, float kern_div, GP_ProgressCallback *callback) { GP_Coord x, y; - uint32_t i, j; + unsigned int i, j;
- GP_DEBUG(1, "Linear convolution kernel %ix%i image %ux%u", - kw, kh, src->w, src->h); + GP_DEBUG(1, "Linear convolution kernel %ix%i rectangle %ux%u", + kw, kh, w_src, h_src);
- /* do linear convolution */ - for (y = 0; y < (GP_Coord)dst->h; y++) { - GP_Pixel pix; + /* Do linear convolution */ + for (y = 0; y < (GP_Coord)h_src; y++) { uint32_t R[kw][kh], G[kw][kh], B[kw][kh]; + GP_Pixel pix;
- /* prefill the buffer on the start */ + /* Prefill the buffer on the start */ for (j = 0; j < kh; j++) { for (i = 0; i < kw - 1; i++) { - int cx = i - kw/2; - int cy = y + j - kh/2; + int xi = x_src + i - kw/2; + int yi = y_src + y + j - kh/2; + + if (xi < 0) + xi = 0; + + if (xi > (int)src->w - 1) + xi = src->w - 1;
- if (cx < 0) - cx = 0; + if (yi < 0) + yi = 0; - if (cy < 0) - cy = 0; + if (yi > (int)src->h - 1) + yi = src->h - 1; - if (cy >= (int)src->h) - cy = src->h - 1; - pix = GP_GetPixel_Raw_24BPP(src, cx, cy); + pix = GP_GetPixel_Raw_24BPP(src, xi, yi);
R[i][j] = GP_Pixel_GET_R_RGB888(pix); G[i][j] = GP_Pixel_GET_G_RGB888(pix); @@ -389,30 +442,33 @@ int GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *dst,
int idx = kw - 1;
- for (x = 0; x < (GP_Coord)dst->w; x++) { + for (x = 0; x < (GP_Coord)w_src; x++) { float r = 0, g = 0, b = 0;
for (j = 0; j < kh; j++) { - int cy = y + j - kh/2; - int cx = x + kw/2; - - if (cy < 0) - cy = 0; + int xi = x_src + x + kw/2; + int yi = y_src + y + j - kh/2; + + if (xi < 0) + xi = 0; + + if (xi > (int)src->w - 1) + xi = src->w - 1;
- if (cy >= (int)src->h) - cy = src->h - 1; + if (yi < 0) + yi = 0;
- if (cx >= (int)src->w) - cx = src->w - 1; + if (yi > (int)src->h - 1) + yi = src->h - 1;
- pix = GP_GetPixel_Raw_24BPP(src, cx, cy); + pix = GP_GetPixel_Raw_24BPP(src, xi, yi);
R[idx][j] = GP_Pixel_GET_R_RGB888(pix); G[idx][j] = GP_Pixel_GET_G_RGB888(pix); B[idx][j] = GP_Pixel_GET_B_RGB888(pix); } - /* count the pixel value from neighbours weighted by kernel */ + /* Count the pixel value from neighbours weighted by kernel */ for (i = 0; i < kw; i++) { int k;
@@ -449,7 +505,7 @@ int GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *dst,
pix = GP_Pixel_CREATE_RGB888((uint32_t)r, (uint32_t)g, (uint32_t)b);
- GP_PutPixel_Raw_24BPP(dst, x, y, pix); + GP_PutPixel_Raw_24BPP(dst, x_dst + x, y_dst + y, pix); idx++;
@@ -465,7 +521,7 @@ int GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *dst, return 0; }
-void GP_FilterKernelPrint(float kernel[], int kw, int kh, float kern_div) +void GP_FilterKernelPrint_Raw(float kernel[], int kw, int kh, float kern_div) { int i, j;
http://repo.or.cz/w/gfxprim.git/commit/8f908e18fb01faa8320ac4b2ae1905426cedd...
commit 8f908e18fb01faa8320ac4b2ae1905426ceddcd1 Author: Cyril Hrubis metan@ucw.cz Date: Sat Jun 30 09:57:28 2012 +0200
doc: filters.txt, context.txt: small fixes and clarifications.
diff --git a/doc/context.txt b/doc/context.txt index 13d5270..7c812cc 100644 --- a/doc/context.txt +++ b/doc/context.txt @@ -238,7 +238,7 @@ GP_Context *GP_SubContextAlloc(const GP_Context *context, Creates subcontext of a context. The rectangular area must fit into the context.
The 'GP_SubContext()' function initializes the passed pointer as a subcontext -of a context and returns pointer to initialized subcontext (i.e. the same +of a context and returns pointer to the initialized subcontext (i.e. the same pointer you passed as the subcontext parameter).
The 'GP_SubContextAlloc()' function allocates 'GP_Context' structure and @@ -280,6 +280,6 @@ Misc void GP_ContextPrintInfo(const GP_Context *self); -------------------------------------------------------------------------------
-This function prints the content of 'GP_Context' structure, in a readable +This function prints the content of a 'GP_Context' structure, in a readable format, into the stdout.
diff --git a/doc/filters.txt b/doc/filters.txt index d685bb1..eac6bff 100644 --- a/doc/filters.txt +++ b/doc/filters.txt @@ -22,14 +22,17 @@ For convenience, the filters API is unified: * And the last argument is progress callback
When using allocating version of the filter, pointer to the newly allocated -context is returned, or in case of failure 'NULL' is returned. If filter has -been interrupted by a callback, all allocated memory is freed and 'NULL' is -returned. +context is returned, or in case of failure 'NULL' is returned. + +If 'malloc()' has failed 'NULL' is returned. + +If filter has been interrupted by a callback, all allocated memory is freed, +and 'NULL' is returned.
When using non-allocating variant of the filter, the destination context must -have correct pixel type and the context size must be big enough to store the -result. The return value from such filter is either zero, in case of success, -or non-zero when filter was interrupted by a callback. +have correct pixel type and the size must be big enough to store the result. +The return value from such filter is either zero, in case of success, or +non-zero when filter was interrupted by a callback.
For filters that work 'in-place' (which is explicitly said for each filter) the source and the destination could be the same context. Note that this is
http://repo.or.cz/w/gfxprim.git/commit/8e026f14b369c6d70f8a4954970d8d94864ca...
commit 8e026f14b369c6d70f8a4954970d8d94864ca587 Author: Cyril Hrubis metan@ucw.cz Date: Fri Jun 29 23:03:06 2012 +0200
doc: index.html spellchecks.
diff --git a/doc/index.html b/doc/index.html index 6132e6c..7dcc996 100644 --- a/doc/index.html +++ b/doc/index.html @@ -42,16 +42,16 @@ </p> <h3>License</h3> <p> - The code is licenced under LGPL 2.1 or (at your opinion) any later. + The code is licensed under LGPL 2.1 or (at your opinion) any later. </p> <h3>About</h3> <p> Once upon the time <i>GFXprim</i> had started as an simple attempt to replace SDL_gfx which was unusable at the time we started. Soon it outgrew the initial purpose and yielded into library that could be used as - replacement for SDL library. In constrast with SDL <i>GFXprim</i> is + replacement for SDL library. In contrast with SDL <i>GFXprim</i> is not aiming for abstracting the operating system interface. Instead of - that <i>GFXprim</i> provides means for keeping the system dependend + that <i>GFXprim</i> provides means for keeping the system dependent parts in well defined and isolated parts. </p> <p> @@ -71,7 +71,7 @@ <h3>Contact</h3> <p> We do have a <a href="http://www.ucw.cz/mailman/listinfo/gfxprim">mailing list</a> - and although there not much of discussion there now, we are there and listeing. + and although there not much of discussion there now, we are there and listening. </p> <h3>Documentation</h3> <p>
http://repo.or.cz/w/gfxprim.git/commit/a67438c203dd1b95d464a2482795d27318e00...
commit a67438c203dd1b95d464a2482795d27318e00592 Author: Cyril Hrubis metan@ucw.cz Date: Fri Jun 29 23:01:26 2012 +0200
doc: filters.txt spellchecks.
diff --git a/doc/filters.txt b/doc/filters.txt index 9f6c012..d685bb1 100644 --- a/doc/filters.txt +++ b/doc/filters.txt @@ -488,11 +488,11 @@ O(x,y)=sum_{i=-infty}^{infty}sum_{j=-infty}^{infty}I(x-i,y-j) cdot K(i,j) ] -------------------------------------------------------------------------------
-The K denotes convolution kernel and in practice, due to computional +The K denotes convolution kernel and in practice, due to computational complexity, the i and j are bounded in relatively small intervals. For example if i and j are in (-1,1) the kernel size is 3x3.
-Note that pixel values around the image cornes are undefined. The linear +Note that pixel values around the image corners are undefined. The linear convolution in GFXprim simply uses the corner pixel values for all pixels outside the image.
@@ -514,7 +514,7 @@ GP_Context *GP_FilterLaplaceAlloc(const GP_Context *src, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Discrete laplace filter that produces a second derivative of the original +Discrete Laplace filter that produces a second derivative of the original image.
The convolution kernel is defined as: @@ -558,7 +558,7 @@ GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Laplace based edge sharpening filter, substracts weighted second derivative +Laplace based edge sharpening filter, subtracts weighted second derivative from the original image.
[latex, laplacian_edge_sharpening.png, 140]
-----------------------------------------------------------------------
Summary of changes: demos/c_simple/Makefile | 2 +- demos/c_simple/{loaders.c => convolution.c} | 26 +++- demos/c_simple/v4l2_show.c | 1 + doc/context.txt | 4 +- doc/filters.txt | 23 ++- doc/index.html | 8 +- include/filters/GP_Convolution.h | 119 +++++++++++++ include/filters/GP_Filters.h | 5 +- include/filters/GP_Linear.h | 37 +++- libs/filters/{GP_Laplace.c => GP_Convolution.c} | 93 ++++------- libs/filters/GP_Edge.c | 20 ++- libs/filters/GP_Laplace.c | 8 +- libs/filters/GP_Linear.c | 216 ++++++++++++++--------- 13 files changed, 384 insertions(+), 178 deletions(-) copy demos/c_simple/{loaders.c => convolution.c} (84%) create mode 100644 include/filters/GP_Convolution.h copy libs/filters/{GP_Laplace.c => GP_Convolution.c} (51%)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.