Gfxprim
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- 929 discussions
[repo.or.cz] gfxprim.git branch master updated: b7b1aa5e558261c0787fad6e924969625cd465ce
by metan 06 Jul '12
by metan 06 Jul '12
06 Jul '12
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 b7b1aa5e558261c0787fad6e924969625cd465ce (commit)
from 0f6d751635c094c8857706c11538637cda8dfc6f (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/b7b1aa5e558261c0787fad6e924969625cd4…
commit b7b1aa5e558261c0787fad6e924969625cd465ce
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jul 6 14:50:23 2012 +0200
doc: Add grabbers docs + spellcheck in API.
diff --git a/doc/Makefile b/doc/Makefile
index 3fdfaad..7eb952d 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,7 +1,8 @@
all: api.html examples.html
api.html: general.txt api.txt context.txt loaders.txt filters.txt - basic_types.txt drawing_api.txt backends.txt gamma.txt
+ basic_types.txt drawing_api.txt backends.txt gamma.txt + grabbers.txt
asciidoc -a toc api.txt
examples.html: examples.txt ../demos/c_simple/*.c ../demos/py_simple/*.py
diff --git a/doc/api.txt b/doc/api.txt
index 402c6dd..37979b4 100644
--- a/doc/api.txt
+++ b/doc/api.txt
@@ -10,3 +10,4 @@ include::drawing_api.txt[]
include::filters.txt[]
include::loaders.txt[]
include::backends.txt[]
+include::grabbers.txt[]
diff --git a/doc/backends.txt b/doc/backends.txt
index ecd3468..66728f7 100644
--- a/doc/backends.txt
+++ b/doc/backends.txt
@@ -245,3 +245,4 @@ returned. If backend size already matches w and h, nothing is done.
Note that backend->context pointer may change upon calling this function and
at least backend->context->pixels pointer will change.
+
diff --git a/doc/grabbers.txt b/doc/grabbers.txt
new file mode 100644
index 0000000..571cc06
--- /dev/null
+++ b/doc/grabbers.txt
@@ -0,0 +1,126 @@
+Grabbers
+--------
+
+Grabber is an abstraction for a device whose output is a stream of images.
+
+There is currently V4L2 driver that implements a grabber.
+
+To link against grabbers use +-lGP_grabbers+ or better
++`gfxprim-config --libs-grabbers`+ in your linker flags.
+
+Grabber API
+~~~~~~~~~~~
+
+The grabber API consist of structure with callbacks. Every grabber
+initialization yields pointer to this structure. Although is possible to call
+these pointers directly it's not recommended and everybody should rather use
+the inline functions instead.
+
+The grabber API consist GP_Grabber structure and of several functions:
+
+[source,c]
+-------------------------------------------------------------------------------
+typdef struct GP_Grabber {
+ /*
+ * Currently loaded frame frame.
+ */
+ GP_Context *frame;
+
+ /*
+ * Connection fd usable for select() or poll().
+ *
+ * Set to -1 if not available.
+ */
+ int fd;
+
+ /* ... */
+};
+-------------------------------------------------------------------------------
+
+The frame is a pointer to currently loaded frame. Its content is undefined
+until you start the grabber with 'GP_GrabberStart()'.
+
+The 'fd' is a file descriptor suitable for select() or poll(). It's set to -1
+if there is none.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <grabbers/GP_Grabber.h>
+/* or */
+#include <GP.h>
+
+void GP_GrabberExit(GP_Grabber *backend);
+-------------------------------------------------------------------------------
+
+Exits the grabber, frees memory, unmaps memory mappings, closes file
+descriptors etc...
+
+Returns zero on success and non-zero on failure.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <grabbers/GP_Grabber.h>
+/* or */
+#include <GP.h>
+
+int GP_GrabberStart(struct GP_Grabber *self);
+-------------------------------------------------------------------------------
+
+Starts a grabber. After calling this calling you can start retrieving frames
+with 'GP_GrabberPoll()'.
+
+Returns zero on success and non-zero on failure.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <grabbers/GP_Grabber.h>
+/* or */
+#include <GP.h>
+
+int GP_GrabberStop(struct GP_Grabber *self);
+-------------------------------------------------------------------------------
+
+Stops a grabber. Call this when you doesn't need to receive frames but still
+plan to use the grabber later.
+
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <grabbers/GP_Grabber.h>
+/* or */
+#include <GP.h>
+
+int GP_GrabberPoll(struct GP_Grabber *self);
+-------------------------------------------------------------------------------
+
+Once grabber is created you can call this function to receive a frame. If
+grabber 'fd' is not -1 it's preferable to call it when select() or poll()
+returns that data are available on the 'fd'.
+
+This function returns non-zero if new frame was received and stored into the
+'frame' context. Otherwise zero is returned.
+
+Grabber Initializations
+~~~~~~~~~~~~~~~~~~~~~~
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <grabbers/GP_V4L2.h>
+/* or */
+#include <GP.h>
+
+struct GP_Grabber *GP_GrabberV4L2Init(const char *device,
+ unsigned int preferred_width,
+ unsigned int preferred_height);
+-------------------------------------------------------------------------------
+
+Opens and initializes V4L2 device. The device is a path in +/dev+ filesystem
+the first V4L2 device in your system should be +/dev/video0+.
+
+The height and width are preferred values, you will most likely get frame by
+that width and height, but the driver may return different values if chosen
+width and height are not supported.
+
+Returns either pointer to the initialized grabber or, in case of failure, NULL
+and errno is filled.
diff --git a/include/grabbers/GP_V4L2.h b/include/grabbers/GP_V4L2.h
index aa6bf08..9b7b043 100644
--- a/include/grabbers/GP_V4L2.h
+++ b/include/grabbers/GP_V4L2.h
@@ -32,7 +32,7 @@ struct GP_Grabber;
* fixed image size.
*/
struct GP_Grabber *GP_GrabberV4L2Init(const char *device,
- unsigned int prefered_width,
- unsigned int prefered_height);
+ unsigned int preferred_width,
+ unsigned int preferred_height);
#endif /* GP_GRABBERS_V4L2_H */
diff --git a/libs/grabbers/GP_V4L2.c b/libs/grabbers/GP_V4L2.c
index fa8a795..4a00e51 100644
--- a/libs/grabbers/GP_V4L2.c
+++ b/libs/grabbers/GP_V4L2.c
@@ -233,8 +233,8 @@ static int v4l2_stop(struct GP_Grabber *self)
}
struct GP_Grabber *GP_GrabberV4L2Init(const char *device,
- unsigned int prefered_width,
- unsigned int prefered_height)
+ unsigned int preferred_width,
+ unsigned int preferred_height)
{
int fd, i, err;
int mode = 0;
@@ -308,8 +308,8 @@ struct GP_Grabber *GP_GrabberV4L2Init(const char *device,
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = prefered_width;
- fmt.fmt.pix.height = prefered_height;
+ fmt.fmt.pix.width = preferred_width;
+ fmt.fmt.pix.height = preferred_height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
@@ -422,8 +422,8 @@ err:
#else
struct GP_Grabber *GP_GrabberV4L2Init(const char GP_UNUSED(*device),
- unsigned int GP_UNUSED(prefered_width),
- unsigned int GP_UNUSED(prefered_height))
+ unsigned int GP_UNUSED(preferred_width),
+ unsigned int GP_UNUSED(preferred_height))
{
GP_WARN("V4L2 support not compiled in.");
-----------------------------------------------------------------------
Summary of changes:
doc/Makefile | 3 +-
doc/api.txt | 1 +
doc/backends.txt | 1 +
doc/grabbers.txt | 126 ++++++++++++++++++++++++++++++++++++++++++++
include/grabbers/GP_V4L2.h | 4 +-
libs/grabbers/GP_V4L2.c | 12 ++--
6 files changed, 138 insertions(+), 9 deletions(-)
create mode 100644 doc/grabbers.txt
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 0f6d751635c094c8857706c11538637cda8dfc6f
by metan 03 Jul '12
by metan 03 Jul '12
03 Jul '12
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
discards 9f9b4467ff22f7341d61b9820098769f33d9f17e (commit)
via 0f6d751635c094c8857706c11538637cda8dfc6f (commit)
via e19bfecb48d67a5903328380fe26a5601c69878e (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (9f9b4467ff22f7341d61b9820098769f33d9f17e)
N -- N -- N (0f6d751635c094c8857706c11538637cda8dfc6f)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
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/0f6d751635c094c8857706c11538637cda8d…
commit 0f6d751635c094c8857706c11538637cda8dfc6f
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jul 3 13:41:07 2012 +0200
doc: Update backend docs.
diff --git a/doc/backends.txt b/doc/backends.txt
index 9ce83d7..ecd3468 100644
--- a/doc/backends.txt
+++ b/doc/backends.txt
@@ -138,15 +138,34 @@ typdef struct GP_Backend {
};
-------------------------------------------------------------------------------
+The file descriptor 'fd' is either set to -1 (in case of SDL that shadows it)
+or to a backend connection file descriptor usable for 'select()' or 'poll()'.
+
[source,c]
-------------------------------------------------------------------------------
+#include <backends/GP_Backend.h>
+/* or */
+#include <GP.h>
+
void GP_BackendExit(GP_Backend *backend);
-------------------------------------------------------------------------------
-Calls an backend exit callback.
+Calls an backend exit callback. Resets the display, keyboard, etc. state back.
+
+WARNING: It's very important to call this functions on application exit. If you
+ doesn't do so, the state of the display, resolution etc. may not be
+ reset back to its original state. This includes program crashes and
+ iterruptions. Also this function may not be signal-async-safe, it's
+ better to set signal hanlers that calls it as this usually works and
+ not doing so may leave non-working system with black display or
+ non-responding keyboard.
[source,c]
-------------------------------------------------------------------------------
+#include <backends/GP_Backend.h>
+/* or */
+#include <GP.h>
+
GP_BackendFlip(GP_Backend *backend);
-------------------------------------------------------------------------------
@@ -154,6 +173,10 @@ Flips a screen. Updates rectangle for a buffered backends.
[source,c]
-------------------------------------------------------------------------------
+#include <backends/GP_Backend.h>
+/* or */
+#include <GP.h>
+
void GP_BackendUpdateRect(GP_Backend *backend,
GP_Coord x0, GP_Coord y0,
GP_Coord x1, GP_Coord y1);
@@ -163,6 +186,10 @@ Updates particular rectangle for a buffered backends.
[source,c]
-------------------------------------------------------------------------------
+#include <backends/GP_Backend.h>
+/* or */
+#include <GP.h>
+
void GP_BackendPoll(GP_Backend *backend);
-------------------------------------------------------------------------------
@@ -170,8 +197,33 @@ Polls for backend events. For backends that do not expose file descriptor
(namely SDL) this should be called repeatedly. For other backend it may be
called either repeatedly or when data are ready on file-descriptor.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <backends/GP_Backend.h>
+/* or */
+#include <GP.h>
+
+void GP_BackendWait(GP_Backend *backend);
+-------------------------------------------------------------------------------
+
+Blocks until backend event arrives.
+
+NOTE: Events recieved by backend are not necessarily translated into the input
+ events.
+
+WARNING: Using GP_BackendWait() in multithreaded program will most likely
+ cause deadlocks. As the backend data structures and connection is
+ guarded by a lock any other backend function (called from different
+ thread while GP_BackendWait() is blocking) will lock until
+ GP_BackendWait() returns (i.e. event was recieved).
+
[source,c]
-------------------------------------------------------------------------------
+#include <backends/GP_Backend.h>
+/* or */
+#include <GP.h>
+
int GP_BackendSetCaption(GP_Backend *backend, const char *caption)
-------------------------------------------------------------------------------
@@ -180,6 +232,10 @@ support caption, operation failed) non zero is returned.
[source,c]
-------------------------------------------------------------------------------
+#include <backends/GP_Backend.h>
+/* or */
+#include <GP.h>
+
int GP_BackendResize(GP_Backend *backend, uint32_t w, uint32_t h);
-------------------------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/e19bfecb48d67a5903328380fe26a5601c69…
commit e19bfecb48d67a5903328380fe26a5601c69878e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jul 3 12:42:31 2012 +0200
filters: Add initial version of multithreaded linear convolution.
diff --git a/include/filters/GP_LinearThreads.h b/include/filters/GP_LinearThreads.h
new file mode 100644
index 0000000..76c46db
--- /dev/null
+++ b/include/filters/GP_LinearThreads.h
@@ -0,0 +1,52 @@
+/*****************************************************************************
+ * 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(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#ifndef FILTERS_GP_LINEAR_THREADS_H
+#define FILTERS_GP_LINEAR_THREADS_H
+
+#include "GP_Filter.h"
+
+int GP_FilterLinearConvolutionMP_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);
+
+int GP_FilterHLinearConvolutionMP_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_FilterVLinearConvolutionMP_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);
+
+#endif /* FILTERS_GP_LINEAR_THREADS_H */
diff --git a/libs/filters/GP_LinearThreads.c b/libs/filters/GP_LinearThreads.c
new file mode 100644
index 0000000..5ccdebc
--- /dev/null
+++ b/libs/filters/GP_LinearThreads.c
@@ -0,0 +1,300 @@
+/*****************************************************************************
+ * 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(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "core/GP_Common.h"
+#include "core/GP_Debug.h"
+
+#include "GP_Linear.h"
+#include "GP_LinearThreads.h"
+
+static int nr_threads(GP_Size w, GP_Size h)
+{
+ int count = sysconf(_SC_NPROCESSORS_ONLN);
+ int threads = GP_MIN(count, (int)(w * h / 1024) + 1);
+
+ if (count < -1)
+ threads = 1;
+
+ GP_DEBUG(1, "Found %u CPUs size %ux%u runnig %u threads",
+ count, w, h, threads);
+
+ return threads;
+}
+
+/*
+ * Multithreaded callback wrapper.
+ */
+struct callback_priv {
+ float max;
+ int abort;
+ unsigned int nr_threads;
+ pthread_mutex_t mutex;
+ GP_ProgressCallback *orig_callback;
+};
+
+static int progress_callback_mp(GP_ProgressCallback *self)
+{
+ struct callback_priv *priv = self->priv;
+
+ /* If any thread got non-zero return value from a callback, abort all */
+ if (priv->abort)
+ return 1;
+
+ if (pthread_mutex_trylock(&priv->mutex)) {
+ GP_DEBUG(1, "Mutex locked, skipping calllback.");
+ return 0;
+ }
+
+ /* Compute max value for the percentage */
+ priv->orig_callback->percentage = GP_MAX(self->percentage, priv->max);
+ priv->max = priv->orig_callback->percentage;
+
+ /* Call the original callback */
+ int ret = priv->orig_callback->callback(priv->orig_callback);
+
+ /* Turn on abort flag if callback returned nonzero */
+ if (ret)
+ priv->abort = 1;
+
+ pthread_mutex_unlock(&priv->mutex);
+
+ return ret;
+}
+
+static void callback_priv_init(struct callback_priv *priv, int nr_threads,
+ GP_ProgressCallback *orig_callback)
+{
+ priv->nr_threads = nr_threads;
+ priv->orig_callback = orig_callback;
+ priv->max = 0;
+ priv->abort = 0;
+ pthread_mutex_init(&priv->mutex, NULL);
+}
+
+static void callback_priv_exit(struct callback_priv *priv)
+{
+ pthread_mutex_destroy(&priv->mutex);
+}
+
+/*
+ * This code just packs and unpacks convolution parameters.
+ */
+struct convolution {
+ 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;
+ unsigned int ks;
+ float kern_div;
+
+ GP_ProgressCallback *callback;
+};
+
+static void convolution_init(struct convolution *conv, 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[], unsigned int ks, float kern_div,
+ GP_ProgressCallback *callback)
+{
+ conv->src = src;
+ conv->x_src = x_src;
+ conv->y_src = y_src;
+ conv->w_src = w_src;
+ conv->h_src = h_src;
+ conv->dst = dst;
+ conv->x_dst = x_dst;
+ conv->y_dst = y_dst;
+ conv->kernel = kernel;
+ conv->ks = ks;
+ conv->kern_div = kern_div;
+ conv->callback = callback;
+}
+
+static void *h_linear_convolution(void *arg)
+{
+ struct convolution *conv = arg;
+
+ long ret;
+
+ ret = GP_FilterHLinearConvolution_Raw(conv->src, conv->x_src, conv->y_src,
+ conv->w_src, conv->h_src, conv->dst,
+ conv->x_dst, conv->y_dst, conv->kernel,
+ conv->ks, conv->kern_div, conv->callback);
+ return (void*)ret;
+}
+
+static void *v_linear_convolution(void *arg)
+{
+ struct convolution *conv = arg;
+
+ long ret;
+
+ ret = GP_FilterVLinearConvolution_Raw(conv->src, conv->x_src, conv->y_src,
+ conv->w_src, conv->h_src, conv->dst,
+ conv->x_dst, conv->y_dst, conv->kernel,
+ conv->ks, conv->kern_div, conv->callback);
+ return (void*)ret;
+}
+
+
+int GP_FilterHLinearConvolutionMP_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 t = nr_threads(w_src, h_src);
+
+ if (t == 1) {
+ return GP_FilterHLinearConvolution_Raw(src, x_src, y_src,
+ w_src, h_src,
+ dst, x_dst, y_dst,
+ kernel, kw, kern_div,
+ callback);
+ }
+
+ /* Create multithreaded safe callback on the stack */
+ struct callback_priv priv;
+ callback_priv_init(&priv, t, callback);
+ GP_ProgressCallback callback_mp = {0, progress_callback_mp, &priv};
+
+ /* Run t threads */
+ int i;
+ pthread_t threads[t];
+ struct convolution convs[t];
+ GP_Size h = h_src/t;
+
+ for (i = 0; i < t; i++) {
+ GP_Coord y_src_2 = y_src + i * h;
+ GP_Coord y_dst_2 = y_dst + i * h;
+ GP_Size h_src_2 = h;
+
+ if (i == t - 1)
+ h_src_2 = h_src - i * h;
+
+ /* Pack convolution parameters into the structure */
+ convolution_init(&convs[i], src, x_src, y_src_2, w_src, h_src_2,
+ dst, x_dst, y_dst_2, kernel, kw, kern_div,
+ callback ? &callback_mp : NULL);
+
+ pthread_create(&threads[i], NULL, h_linear_convolution, &convs[i]);
+ }
+
+ int ret = 0;
+
+ for (i = 0; i < t; i++) {
+ long r;
+
+ pthread_join(threads[i], (void*)&r);
+
+ ret |= (int)r;
+ }
+
+ callback_priv_exit(&priv);
+
+ return ret;
+}
+
+
+int GP_FilterVLinearConvolutionMP_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)
+{
+ int t = nr_threads(w_src, h_src);
+
+ if (t == 1) {
+ return GP_FilterVLinearConvolution_Raw(src, x_src, y_src,
+ w_src, h_src,
+ dst, x_dst, y_dst,
+ kernel, kh, kern_div,
+ callback);
+ }
+
+ /* Create multithreaded safe callback on the stack */
+ struct callback_priv priv;
+ callback_priv_init(&priv, t, callback);
+ GP_ProgressCallback callback_mp = {0, progress_callback_mp, &priv};
+
+ int i;
+ pthread_t threads[t];
+ struct convolution convs[t];
+ GP_Size h = h_src/t;
+
+ for (i = 0; i < t; i++) {
+ GP_Coord y_src_2 = y_src + i * h;
+ GP_Coord y_dst_2 = y_dst + i * h;
+ GP_Size h_src_2 = h;
+
+ if (i == t - 1)
+ h_src_2 = h_src - i * h;
+
+ /* Pack convolution parameters into the structure */
+ convolution_init(&convs[i], src, x_src, y_src_2, w_src, h_src_2,
+ dst, x_dst, y_dst_2, kernel, kh, kern_div,
+ callback ? &callback_mp : NULL);
+
+ pthread_create(&threads[i], NULL, v_linear_convolution, &convs[i]);
+ }
+
+ int ret = 0;
+
+ for (i = 0; i < t; i++) {
+ long r;
+ pthread_join(threads[i], (void*)&r);
+
+ ret |= (int)r;
+ }
+
+ callback_priv_exit(&priv);
+
+ return ret;
+}
+
+/*
+int GP_FilterLinearConvolutionMP_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)
+{
+}
+*/
-----------------------------------------------------------------------
Summary of changes:
doc/backends.txt | 58 ++++++++++++++++++++++++++++++++++++++-
libs/filters/GP_LinearThreads.c | 3 +-
2 files changed, 58 insertions(+), 3 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 9f9b4467ff22f7341d61b9820098769f33d9f17e
by metan 03 Jul '12
by metan 03 Jul '12
03 Jul '12
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
discards 2b5429389de2a646451066572a1c143b80b2efd5 (commit)
via 9f9b4467ff22f7341d61b9820098769f33d9f17e (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (2b5429389de2a646451066572a1c143b80b2efd5)
N -- N -- N (9f9b4467ff22f7341d61b9820098769f33d9f17e)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
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/9f9b4467ff22f7341d61b9820098769f33d9…
commit 9f9b4467ff22f7341d61b9820098769f33d9f17e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jul 3 12:42:31 2012 +0200
filters: Add initial version of multithreaded linear convolution.
diff --git a/include/filters/GP_LinearThreads.h b/include/filters/GP_LinearThreads.h
new file mode 100644
index 0000000..76c46db
--- /dev/null
+++ b/include/filters/GP_LinearThreads.h
@@ -0,0 +1,52 @@
+/*****************************************************************************
+ * 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(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#ifndef FILTERS_GP_LINEAR_THREADS_H
+#define FILTERS_GP_LINEAR_THREADS_H
+
+#include "GP_Filter.h"
+
+int GP_FilterLinearConvolutionMP_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);
+
+int GP_FilterHLinearConvolutionMP_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_FilterVLinearConvolutionMP_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);
+
+#endif /* FILTERS_GP_LINEAR_THREADS_H */
diff --git a/libs/filters/GP_LinearThreads.c b/libs/filters/GP_LinearThreads.c
new file mode 100644
index 0000000..e309e80
--- /dev/null
+++ b/libs/filters/GP_LinearThreads.c
@@ -0,0 +1,301 @@
+/*****************************************************************************
+ * 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(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "core/GP_Common.h"
+#include "core/GP_Debug.h"
+
+#include "GP_Linear.h"
+#include "GP_LinearThreads.h"
+
+static int nr_threads(GP_Size w, GP_Size h)
+{
+ int count = sysconf(_SC_NPROCESSORS_ONLN);
+ int threads = GP_MIN(count, (int)(w * h / 1024) + 1);
+
+ if (count < -1)
+ threads = 1;
+
+ GP_DEBUG(1, "Found %u CPUs size %ux%u runnig %u threads",
+ count, w, h, threads);
+
+// return threads;
+ return 4;
+}
+
+/*
+ * Multithreaded callback wrapper.
+ */
+struct callback_priv {
+ float max;
+ int abort;
+ unsigned int nr_threads;
+ pthread_mutex_t mutex;
+ GP_ProgressCallback *orig_callback;
+};
+
+static int progress_callback_mp(GP_ProgressCallback *self)
+{
+ struct callback_priv *priv = self->priv;
+
+ /* If any thread got non-zero return value from a callback, abort all */
+ if (priv->abort)
+ return 1;
+
+ if (pthread_mutex_trylock(&priv->mutex)) {
+ GP_DEBUG(1, "Mutex locked, skipping calllback.");
+ return 0;
+ }
+
+ /* Compute max value for the percentage */
+ priv->orig_callback->percentage = GP_MAX(self->percentage, priv->max);
+ priv->max = priv->orig_callback->percentage;
+
+ /* Call the original callback */
+ int ret = priv->orig_callback->callback(priv->orig_callback);
+
+ /* Turn on abort flag if callback returned nonzero */
+ if (ret)
+ priv->abort = 1;
+
+ pthread_mutex_unlock(&priv->mutex);
+
+ return ret;
+}
+
+static void callback_priv_init(struct callback_priv *priv, int nr_threads,
+ GP_ProgressCallback *orig_callback)
+{
+ priv->nr_threads = nr_threads;
+ priv->orig_callback = orig_callback;
+ priv->max = 0;
+ priv->abort = 0;
+ pthread_mutex_init(&priv->mutex, NULL);
+}
+
+static void callback_priv_exit(struct callback_priv *priv)
+{
+ pthread_mutex_destroy(&priv->mutex);
+}
+
+/*
+ * This code just packs and unpacks convolution parameters.
+ */
+struct convolution {
+ 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;
+ unsigned int ks;
+ float kern_div;
+
+ GP_ProgressCallback *callback;
+};
+
+static void convolution_init(struct convolution *conv, 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[], unsigned int ks, float kern_div,
+ GP_ProgressCallback *callback)
+{
+ conv->src = src;
+ conv->x_src = x_src;
+ conv->y_src = y_src;
+ conv->w_src = w_src;
+ conv->h_src = h_src;
+ conv->dst = dst;
+ conv->x_dst = x_dst;
+ conv->y_dst = y_dst;
+ conv->kernel = kernel;
+ conv->ks = ks;
+ conv->kern_div = kern_div;
+ conv->callback = callback;
+}
+
+static void *h_linear_convolution(void *arg)
+{
+ struct convolution *conv = arg;
+
+ long ret;
+
+ ret = GP_FilterHLinearConvolution_Raw(conv->src, conv->x_src, conv->y_src,
+ conv->w_src, conv->h_src, conv->dst,
+ conv->x_dst, conv->y_dst, conv->kernel,
+ conv->ks, conv->kern_div, conv->callback);
+ return (void*)ret;
+}
+
+static void *v_linear_convolution(void *arg)
+{
+ struct convolution *conv = arg;
+
+ long ret;
+
+ ret = GP_FilterVLinearConvolution_Raw(conv->src, conv->x_src, conv->y_src,
+ conv->w_src, conv->h_src, conv->dst,
+ conv->x_dst, conv->y_dst, conv->kernel,
+ conv->ks, conv->kern_div, conv->callback);
+ return (void*)ret;
+}
+
+
+int GP_FilterHLinearConvolutionMP_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 t = nr_threads(w_src, h_src);
+
+ if (t == 1) {
+ return GP_FilterHLinearConvolution_Raw(src, x_src, y_src,
+ w_src, h_src,
+ dst, x_dst, y_dst,
+ kernel, kw, kern_div,
+ callback);
+ }
+
+ /* Create multithreaded safe callback on the stack */
+ struct callback_priv priv;
+ callback_priv_init(&priv, t, callback);
+ GP_ProgressCallback callback_mp = {0, progress_callback_mp, &priv};
+
+ /* Run t threads */
+ int i;
+ pthread_t threads[t];
+ struct convolution convs[t];
+ GP_Size h = h_src/t;
+
+ for (i = 0; i < t; i++) {
+ GP_Coord y_src_2 = y_src + i * h;
+ GP_Coord y_dst_2 = y_dst + i * h;
+ GP_Size h_src_2 = h;
+
+ if (i == t - 1)
+ h_src_2 = h_src - i * h;
+
+ /* Pack convolution parameters into the structure */
+ convolution_init(&convs[i], src, x_src, y_src_2, w_src, h_src_2,
+ dst, x_dst, y_dst_2, kernel, kw, kern_div,
+ callback ? &callback_mp : NULL);
+
+ pthread_create(&threads[i], NULL, h_linear_convolution, &convs[i]);
+ }
+
+ int ret = 0;
+
+ for (i = 0; i < t; i++) {
+ long r;
+
+ pthread_join(threads[i], (void*)&r);
+
+ ret |= (int)r;
+ }
+
+ callback_priv_exit(&priv);
+
+ return ret;
+}
+
+
+int GP_FilterVLinearConvolutionMP_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)
+{
+ int t = nr_threads(w_src, h_src);
+
+ if (t == 1) {
+ return GP_FilterVLinearConvolution_Raw(src, x_src, y_src,
+ w_src, h_src,
+ dst, x_dst, y_dst,
+ kernel, kh, kern_div,
+ callback);
+ }
+
+ /* Create multithreaded safe callback on the stack */
+ struct callback_priv priv;
+ callback_priv_init(&priv, t, callback);
+ GP_ProgressCallback callback_mp = {0, progress_callback_mp, &priv};
+
+ int i;
+ pthread_t threads[t];
+ struct convolution convs[t];
+ GP_Size h = h_src/t;
+
+ for (i = 0; i < t; i++) {
+ GP_Coord y_src_2 = y_src + i * h;
+ GP_Coord y_dst_2 = y_dst + i * h;
+ GP_Size h_src_2 = h;
+
+ if (i == t - 1)
+ h_src_2 = h_src - i * h;
+
+ /* Pack convolution parameters into the structure */
+ convolution_init(&convs[i], src, x_src, y_src_2, w_src, h_src_2,
+ dst, x_dst, y_dst_2, kernel, kh, kern_div,
+ callback ? &callback_mp : NULL);
+
+ pthread_create(&threads[i], NULL, v_linear_convolution, &convs[i]);
+ }
+
+ int ret = 0;
+
+ for (i = 0; i < t; i++) {
+ long r;
+ pthread_join(threads[i], (void*)&r);
+
+ ret |= (int)r;
+ }
+
+ callback_priv_exit(&priv);
+
+ return ret;
+}
+
+/*
+int GP_FilterLinearConvolutionMP_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)
+{
+}
+*/
-----------------------------------------------------------------------
Summary of changes:
include/filters/{GP_Blur.h => GP_LinearThreads.h} | 66 +++++++++------------
1 files changed, 27 insertions(+), 39 deletions(-)
copy include/filters/{GP_Blur.h => GP_LinearThreads.h} (52%)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 2b5429389de2a646451066572a1c143b80b2efd5
by metan 03 Jul '12
by metan 03 Jul '12
03 Jul '12
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 2b5429389de2a646451066572a1c143b80b2efd5 (commit)
via d8048d925822c4528faf5c31f02dbc04bcf3dd1e (commit)
via 84d09f0d259d317aaddf552c9a4d8f2b0b640ef4 (commit)
via 7f869a1b5a909e54300e43194f804430c7bd3739 (commit)
via b0e6247fbfb2a2741292723eeba71353d11bd322 (commit)
from 090ff9d7d97bdde4cb8daac440294a7460319f2d (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/2b5429389de2a646451066572a1c143b80b2…
commit 2b5429389de2a646451066572a1c143b80b2efd5
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jul 3 12:42:31 2012 +0200
filters: Add initial version of multithreaded linear convolution.
diff --git a/libs/filters/GP_LinearThreads.c b/libs/filters/GP_LinearThreads.c
new file mode 100644
index 0000000..e309e80
--- /dev/null
+++ b/libs/filters/GP_LinearThreads.c
@@ -0,0 +1,301 @@
+/*****************************************************************************
+ * 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(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "core/GP_Common.h"
+#include "core/GP_Debug.h"
+
+#include "GP_Linear.h"
+#include "GP_LinearThreads.h"
+
+static int nr_threads(GP_Size w, GP_Size h)
+{
+ int count = sysconf(_SC_NPROCESSORS_ONLN);
+ int threads = GP_MIN(count, (int)(w * h / 1024) + 1);
+
+ if (count < -1)
+ threads = 1;
+
+ GP_DEBUG(1, "Found %u CPUs size %ux%u runnig %u threads",
+ count, w, h, threads);
+
+// return threads;
+ return 4;
+}
+
+/*
+ * Multithreaded callback wrapper.
+ */
+struct callback_priv {
+ float max;
+ int abort;
+ unsigned int nr_threads;
+ pthread_mutex_t mutex;
+ GP_ProgressCallback *orig_callback;
+};
+
+static int progress_callback_mp(GP_ProgressCallback *self)
+{
+ struct callback_priv *priv = self->priv;
+
+ /* If any thread got non-zero return value from a callback, abort all */
+ if (priv->abort)
+ return 1;
+
+ if (pthread_mutex_trylock(&priv->mutex)) {
+ GP_DEBUG(1, "Mutex locked, skipping calllback.");
+ return 0;
+ }
+
+ /* Compute max value for the percentage */
+ priv->orig_callback->percentage = GP_MAX(self->percentage, priv->max);
+ priv->max = priv->orig_callback->percentage;
+
+ /* Call the original callback */
+ int ret = priv->orig_callback->callback(priv->orig_callback);
+
+ /* Turn on abort flag if callback returned nonzero */
+ if (ret)
+ priv->abort = 1;
+
+ pthread_mutex_unlock(&priv->mutex);
+
+ return ret;
+}
+
+static void callback_priv_init(struct callback_priv *priv, int nr_threads,
+ GP_ProgressCallback *orig_callback)
+{
+ priv->nr_threads = nr_threads;
+ priv->orig_callback = orig_callback;
+ priv->max = 0;
+ priv->abort = 0;
+ pthread_mutex_init(&priv->mutex, NULL);
+}
+
+static void callback_priv_exit(struct callback_priv *priv)
+{
+ pthread_mutex_destroy(&priv->mutex);
+}
+
+/*
+ * This code just packs and unpacks convolution parameters.
+ */
+struct convolution {
+ 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;
+ unsigned int ks;
+ float kern_div;
+
+ GP_ProgressCallback *callback;
+};
+
+static void convolution_init(struct convolution *conv, 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[], unsigned int ks, float kern_div,
+ GP_ProgressCallback *callback)
+{
+ conv->src = src;
+ conv->x_src = x_src;
+ conv->y_src = y_src;
+ conv->w_src = w_src;
+ conv->h_src = h_src;
+ conv->dst = dst;
+ conv->x_dst = x_dst;
+ conv->y_dst = y_dst;
+ conv->kernel = kernel;
+ conv->ks = ks;
+ conv->kern_div = kern_div;
+ conv->callback = callback;
+}
+
+static void *h_linear_convolution(void *arg)
+{
+ struct convolution *conv = arg;
+
+ long ret;
+
+ ret = GP_FilterHLinearConvolution_Raw(conv->src, conv->x_src, conv->y_src,
+ conv->w_src, conv->h_src, conv->dst,
+ conv->x_dst, conv->y_dst, conv->kernel,
+ conv->ks, conv->kern_div, conv->callback);
+ return (void*)ret;
+}
+
+static void *v_linear_convolution(void *arg)
+{
+ struct convolution *conv = arg;
+
+ long ret;
+
+ ret = GP_FilterVLinearConvolution_Raw(conv->src, conv->x_src, conv->y_src,
+ conv->w_src, conv->h_src, conv->dst,
+ conv->x_dst, conv->y_dst, conv->kernel,
+ conv->ks, conv->kern_div, conv->callback);
+ return (void*)ret;
+}
+
+
+int GP_FilterHLinearConvolutionMP_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 t = nr_threads(w_src, h_src);
+
+ if (t == 1) {
+ return GP_FilterHLinearConvolution_Raw(src, x_src, y_src,
+ w_src, h_src,
+ dst, x_dst, y_dst,
+ kernel, kw, kern_div,
+ callback);
+ }
+
+ /* Create multithreaded safe callback on the stack */
+ struct callback_priv priv;
+ callback_priv_init(&priv, t, callback);
+ GP_ProgressCallback callback_mp = {0, progress_callback_mp, &priv};
+
+ /* Run t threads */
+ int i;
+ pthread_t threads[t];
+ struct convolution convs[t];
+ GP_Size h = h_src/t;
+
+ for (i = 0; i < t; i++) {
+ GP_Coord y_src_2 = y_src + i * h;
+ GP_Coord y_dst_2 = y_dst + i * h;
+ GP_Size h_src_2 = h;
+
+ if (i == t - 1)
+ h_src_2 = h_src - i * h;
+
+ /* Pack convolution parameters into the structure */
+ convolution_init(&convs[i], src, x_src, y_src_2, w_src, h_src_2,
+ dst, x_dst, y_dst_2, kernel, kw, kern_div,
+ callback ? &callback_mp : NULL);
+
+ pthread_create(&threads[i], NULL, h_linear_convolution, &convs[i]);
+ }
+
+ int ret = 0;
+
+ for (i = 0; i < t; i++) {
+ long r;
+
+ pthread_join(threads[i], (void*)&r);
+
+ ret |= (int)r;
+ }
+
+ callback_priv_exit(&priv);
+
+ return ret;
+}
+
+
+int GP_FilterVLinearConvolutionMP_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)
+{
+ int t = nr_threads(w_src, h_src);
+
+ if (t == 1) {
+ return GP_FilterVLinearConvolution_Raw(src, x_src, y_src,
+ w_src, h_src,
+ dst, x_dst, y_dst,
+ kernel, kh, kern_div,
+ callback);
+ }
+
+ /* Create multithreaded safe callback on the stack */
+ struct callback_priv priv;
+ callback_priv_init(&priv, t, callback);
+ GP_ProgressCallback callback_mp = {0, progress_callback_mp, &priv};
+
+ int i;
+ pthread_t threads[t];
+ struct convolution convs[t];
+ GP_Size h = h_src/t;
+
+ for (i = 0; i < t; i++) {
+ GP_Coord y_src_2 = y_src + i * h;
+ GP_Coord y_dst_2 = y_dst + i * h;
+ GP_Size h_src_2 = h;
+
+ if (i == t - 1)
+ h_src_2 = h_src - i * h;
+
+ /* Pack convolution parameters into the structure */
+ convolution_init(&convs[i], src, x_src, y_src_2, w_src, h_src_2,
+ dst, x_dst, y_dst_2, kernel, kh, kern_div,
+ callback ? &callback_mp : NULL);
+
+ pthread_create(&threads[i], NULL, v_linear_convolution, &convs[i]);
+ }
+
+ int ret = 0;
+
+ for (i = 0; i < t; i++) {
+ long r;
+ pthread_join(threads[i], (void*)&r);
+
+ ret |= (int)r;
+ }
+
+ callback_priv_exit(&priv);
+
+ return ret;
+}
+
+/*
+int GP_FilterLinearConvolutionMP_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)
+{
+}
+*/
http://repo.or.cz/w/gfxprim.git/commit/d8048d925822c4528faf5c31f02dbc04bcf3…
commit d8048d925822c4528faf5c31f02dbc04bcf3dd1e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jul 3 10:47:21 2012 +0200
filters: Linear Convolution make use of the TempAllocator.
diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c
index ca5c38a..f06d0f6 100644
--- a/libs/filters/GP_Linear.c
+++ b/libs/filters/GP_Linear.c
@@ -22,6 +22,7 @@
#include "core/GP_Context.h"
#include "core/GP_GetPutPixel.h"
+#include "core/GP_TempAlloc.h"
#include "core/GP_Clamp.h"
#include "core/GP_Debug.h"
@@ -42,18 +43,25 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
uint32_t i;
int32_t ikernel[kw], ikern_div;
uint32_t size = w_src + kw - 1;
-
+
GP_DEBUG(1, "Horizontal linear convolution kernel width %u "
- "rectangle %ux%u", kw, w_src, h_src);
+ "offset %ix%i rectangle %ux%u",
+ kw, x_src, y_src, w_src, h_src);
for (i = 0; i < kw; i++)
ikernel[i] = kernel[i] * MUL + 0.5;
ikern_div = kern_div * MUL + 0.5;
+ /* Create temporary buffers */
+ GP_TempAllocCreate(temp, 3 * size * sizeof(int));
+
+ int *R = GP_TempAllocGet(temp, size * sizeof(int));
+ int *G = GP_TempAllocGet(temp, size * sizeof(int));
+ int *B = GP_TempAllocGet(temp, size * sizeof(int));
+
/* Do horizontal linear convolution */
for (y = 0; y < (GP_Coord)h_src; y++) {
- int R[size], G[size], B[size];
int yi = GP_MIN(y_src + y, (int)src->h - 1);
/* Fetch the whole row */
@@ -63,7 +71,7 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
i = 0;
/* Copy border pixel until the source image starts */
- while (xi <= 0) {
+ while (xi <= 0 && 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);
@@ -73,7 +81,7 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
}
/* Use as much source image pixels as possible */
- while (xi < (int)src->w) {
+ while (xi < (int)src->w && i < size) {
pix = GP_GetPixel_Raw_24BPP(src, xi, yi);
R[i] = GP_Pixel_GET_R_RGB888(pix);
@@ -108,10 +116,6 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
g /= ikern_div;
b /= ikern_div;
- R[x] = r;
- G[x] = g;
- B[x] = b;
-
/* and clamp just to be extra sure */
r = GP_CLAMP(r, 0, 255);
g = GP_CLAMP(g, 0, 255);
@@ -121,9 +125,13 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
GP_Pixel_CREATE_RGB888(r, g, b));
}
- if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w))
+ if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w)) {
+ GP_TempAllocFree(temp);
return 1;
+ }
}
+
+ GP_TempAllocFree(temp);
GP_ProgressCallbackDone(callback);
return 0;
@@ -146,13 +154,20 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
ikernel[i] = kernel[i] * MUL + 0.5;
GP_DEBUG(1, "Vertical linear convolution kernel width %u "
- "rectangle %ux%u", kh, w_src, h_src);
+ "offset %ix%i rectangle %ux%u",
+ kh, x_src, y_src, w_src, h_src);
ikern_div = kern_div * MUL + 0.5;
+
+ /* Create temporary buffers */
+ GP_TempAllocCreate(temp, 3 * size * sizeof(int));
+
+ int *R = GP_TempAllocGet(temp, size * sizeof(int));
+ int *G = GP_TempAllocGet(temp, size * sizeof(int));
+ int *B = GP_TempAllocGet(temp, size * sizeof(int));
/* Do vertical linear convolution */
for (x = 0; x < (GP_Coord)w_src; x++) {
- int R[size], G[size], B[size];
int xi = GP_MIN(x_src + x, (int)src->w - 1);
/* Fetch the whole row */
@@ -162,7 +177,7 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
i = 0;
/* Copy border pixel until the source image starts */
- while (yi <= 0) {
+ while (yi <= 0 && 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);
@@ -172,7 +187,7 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
}
/* Use as much source image pixels as possible */
- while (yi < (int)src->h) {
+ while (yi < (int)src->h && i < size) {
pix = GP_GetPixel_Raw_24BPP(src, xi, yi);
R[i] = GP_Pixel_GET_R_RGB888(pix);
@@ -216,10 +231,14 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
GP_Pixel_CREATE_RGB888(r, g, b));
}
- if (GP_ProgressCallbackReport(callback, x, dst->w, dst->h))
+ if (GP_ProgressCallbackReport(callback, x, dst->w, dst->h)) {
+ GP_TempAllocFree(temp);
return 1;
+ }
}
+ GP_TempAllocFree(temp);
+
GP_ProgressCallbackDone(callback);
return 0;
}
http://repo.or.cz/w/gfxprim.git/commit/84d09f0d259d317aaddf552c9a4d8f2b0b64…
commit 84d09f0d259d317aaddf552c9a4d8f2b0b640ef4
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Mon Jul 2 14:43:20 2012 +0200
core: Add simple temporary buffer allocator.
diff --git a/include/core/GP_TempAlloc.h b/include/core/GP_TempAlloc.h
new file mode 100644
index 0000000..925b112
--- /dev/null
+++ b/include/core/GP_TempAlloc.h
@@ -0,0 +1,85 @@
+/*****************************************************************************
+ * 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(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+/*
+
+ Temporary block allocator implementation.
+
+ Creates pool for block allocation (small ones are done on the stack, bigger
+ using malloc).
+
+ The usage is:
+
+ // Creates new allocation pool
+ GP_TempAllocCrate(buf, 3 * 1024);
+
+ // Make use of it
+ int *R = GP_TempAllocGet(buf, 1024);
+ int *G = GP_TempAllocGet(buf, 1024);
+ int *B = GP_TempAllocGet(buf, 1024);
+
+ ...
+
+ // Free it
+ GP_TempAllocDestroy(buf);
+
+ */
+
+#ifndef CORE_GP_TEMP_ALLOC_H
+#define CORE_GP_TEMP_ALLOC_H
+
+#include <alloca.h>
+#include <stdlib.h>
+
+#include "core/GP_Common.h"
+
+#ifndef GP_ALLOCA_THRESHOLD
+# define GP_ALLOCA_THRESHOLD 2048
+#endif
+
+struct GP_TempAlloc {
+ void *buffer;
+ size_t pos;
+ size_t size;
+};
+
+#define GP_TEMP_ALLOC(size) ({ + ((size) > GP_ALLOCA_THRESHOLD) ? malloc(size) : alloca(size); +})
+
+#define GP_TempAllocCreate(name, bsize) + struct GP_TempAlloc name = {.size = (bsize), .pos = 0, + .buffer = GP_TEMP_ALLOC(bsize)};
+
+#define GP_TempAllocGet(self, bsize) ({ + GP_ASSERT(self.pos + bsize <= self.size); + size_t _pos = self.pos; + self.pos += bsize; + (void*)(((char*)(self.buffer)) + _pos); +})
+
+#define GP_TempAllocFree(self) do { + if (self.size > GP_ALLOCA_THRESHOLD) + free(self.buffer); +} while (0)
+
+#endif /* CORE_GP_TEMP_ALLOC_H */
http://repo.or.cz/w/gfxprim.git/commit/7f869a1b5a909e54300e43194f804430c7bd…
commit 7f869a1b5a909e54300e43194f804430c7bd3739
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jul 1 23:32:47 2012 +0200
demos: spiv: Update cpu counter for multithread filters.
diff --git a/demos/spiv/cpu_timer.c b/demos/spiv/cpu_timer.c
index 88455eb..6c26d61 100644
--- a/demos/spiv/cpu_timer.c
+++ b/demos/spiv/cpu_timer.c
@@ -23,26 +23,40 @@
#include <stdio.h>
#include "cpu_timer.h"
+static void to_time(int *sec, int *nsec, struct timespec *start,
+ struct timespec *stop)
+{
+ if (stop->tv_nsec < start->tv_nsec) {
+ *sec = stop->tv_sec - start->tv_sec - 1;
+ *nsec = stop->tv_nsec + 1000000000 - start->tv_nsec;
+ } else {
+ *sec = stop->tv_sec - start->tv_sec;
+ *nsec = stop->tv_nsec - start->tv_nsec;
+ }
+}
+
void cpu_timer_start(struct cpu_timer *self, const char *name)
{
self->name = name;
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &self->t_start);
+
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &self->t_cpu_start);
+ clock_gettime(CLOCK_MONOTONIC, &self->t_real_start);
}
void cpu_timer_stop(struct cpu_timer *self)
{
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &self->t_stop);
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &self->t_cpu_stop);
+ clock_gettime(CLOCK_MONOTONIC, &self->t_real_stop);
- int sec;
- int nsec;
+ int cpu_sec;
+ int cpu_nsec;
- if (self->t_stop.tv_nsec < self->t_start.tv_nsec) {
- sec = self->t_stop.tv_sec - self->t_start.tv_sec - 1;
- nsec = self->t_stop.tv_nsec + 1000000000 - self->t_start.tv_nsec;
- } else {
- sec = self->t_stop.tv_sec - self->t_start.tv_sec;
- nsec = self->t_stop.tv_nsec - self->t_start.tv_nsec;
- }
+ int real_sec;
+ int real_nsec;
+
+ to_time(&cpu_sec, &cpu_nsec, &self->t_cpu_start, &self->t_cpu_stop);
+ to_time(&real_sec, &real_nsec, &self->t_real_start, &self->t_real_stop);
- printf("TIMER '%s' %i.%09i secn", self->name, sec, nsec);
+ printf("TIMER '%s' CPU=%i.%09is REAL=%i.%09isn", self->name,
+ cpu_sec, cpu_nsec, real_sec, real_nsec);
}
diff --git a/demos/spiv/cpu_timer.h b/demos/spiv/cpu_timer.h
index 1b41144..1d8c8e7 100644
--- a/demos/spiv/cpu_timer.h
+++ b/demos/spiv/cpu_timer.h
@@ -32,8 +32,10 @@
#include <time.h>
struct cpu_timer {
- struct timespec t_start;
- struct timespec t_stop;
+ struct timespec t_cpu_start;
+ struct timespec t_cpu_stop;
+ struct timespec t_real_start;
+ struct timespec t_real_stop;
const char *name;
};
http://repo.or.cz/w/gfxprim.git/commit/b0e6247fbfb2a2741292723eeba71353d11b…
commit b0e6247fbfb2a2741292723eeba71353d11bd322
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jul 1 23:16:33 2012 +0200
filters: GP_Linear.h remove the forgotten blur functions.
diff --git a/include/filters/GP_Linear.h b/include/filters/GP_Linear.h
index e6cf885..ae96e34 100644
--- a/include/filters/GP_Linear.h
+++ b/include/filters/GP_Linear.h
@@ -32,35 +32,6 @@
#include "GP_Filter.h"
/*
- * Gaussian blur
- *
- * The sigma parameters defines the blur radii in horizontal and vertical
- * direction.
- *
- * Internaly this is implemented as separable linear filter (calls vertical and
- * horizontal convolution with generated gaussian kernel).
- *
- * This variant could work in-place so it's perectly okay to call
- *
- * GP_FilterGaussianBlur_Raw(context, context, ...);
- */
-int GP_FilterGaussianBlur_Raw(const GP_Context *src, GP_Context *dst,
- float sigma_x, float sigma_y,
- GP_ProgressCallback *callback);
-/*
- * Gaussian blur.
- *
- * If dst is NULL, new bitmap is allocated.
- *
- * This variant could work in-place.
- *
- * Returns pointer to destination bitmap or NULL if allocation failed.
- */
-GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
- float sigma_x, float sigma_y,
- GP_ProgressCallback *callback);
-
-/*
* Linear convolution.
*
* The kernel is array of kw * kh floats and is indexed as two directional
-----------------------------------------------------------------------
Summary of changes:
demos/spiv/cpu_timer.c | 38 ++-
demos/spiv/cpu_timer.h | 6 +-
.../GP_Backend.c => include/core/GP_TempAlloc.h | 83 ++++--
include/filters/GP_Linear.h | 29 --
libs/filters/GP_Linear.c | 49 +++-
libs/filters/GP_LinearThreads.c | 301 ++++++++++++++++++++
6 files changed, 419 insertions(+), 87 deletions(-)
copy libs/backends/GP_Backend.c => include/core/GP_TempAlloc.h (55%)
create mode 100644 libs/filters/GP_LinearThreads.c
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 090ff9d7d97bdde4cb8daac440294a7460319f2d
by metan 01 Jul '12
by metan 01 Jul '12
01 Jul '12
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 090ff9d7d97bdde4cb8daac440294a7460319f2d (commit)
from 079d90a0e58cde797f3816a793a7cdb05d18d2bc (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/090ff9d7d97bdde4cb8daac440294a746031…
commit 090ff9d7d97bdde4cb8daac440294a7460319f2d
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jul 1 21:59:03 2012 +0200
filters: GP_Linear.c: Further speedups.
Don't use uint8_t temporary array which fairly slows down
the computation, use array of int values instead.
diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c
index b6e5983..ca5c38a 100644
--- a/libs/filters/GP_Linear.c
+++ b/libs/filters/GP_Linear.c
@@ -53,7 +53,7 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
/* Do horizontal linear convolution */
for (y = 0; y < (GP_Coord)h_src; y++) {
- uint8_t R[size], G[size], B[size];
+ int R[size], G[size], B[size];
int yi = GP_MIN(y_src + y, (int)src->h - 1);
/* Fetch the whole row */
@@ -107,7 +107,11 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
r /= ikern_div;
g /= ikern_div;
b /= ikern_div;
-
+
+ R[x] = r;
+ G[x] = g;
+ B[x] = b;
+
/* and clamp just to be extra sure */
r = GP_CLAMP(r, 0, 255);
g = GP_CLAMP(g, 0, 255);
@@ -116,7 +120,7 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
GP_PutPixel_Raw_24BPP(dst, x_dst + x, y_dst + y,
GP_Pixel_CREATE_RGB888(r, g, b));
}
-
+
if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w))
return 1;
}
@@ -148,7 +152,7 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
/* Do vertical linear convolution */
for (x = 0; x < (GP_Coord)w_src; x++) {
- uint8_t R[size], G[size], B[size];
+ int R[size], G[size], B[size];
int xi = GP_MIN(x_src + x, (int)src->w - 1);
/* Fetch the whole row */
-----------------------------------------------------------------------
Summary of changes:
libs/filters/GP_Linear.c | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 079d90a0e58cde797f3816a793a7cdb05d18d2bc
by metan 01 Jul '12
by metan 01 Jul '12
01 Jul '12
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 079d90a0e58cde797f3816a793a7cdb05d18d2bc (commit)
from 43f5f45fcff837cf1f091fb9933d454e36800f3e (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/079d90a0e58cde797f3816a793a7cdb05d18…
commit 079d90a0e58cde797f3816a793a7cdb05d18d2bc
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jul 1 21:38:57 2012 +0200
doc: Update resapling docs.
diff --git a/doc/filters.txt b/doc/filters.txt
index 9d4228e..074e7d4 100644
--- a/doc/filters.txt
+++ b/doc/filters.txt
@@ -693,8 +693,8 @@ int GP_FilterConvolution(const GP_Context *src, GP_Context *dst,
GP_ProgressCallback *callback);
GP_Context *GP_FilterConvolutionAlloc(const GP_Context *src,
- const GP_FilterKernel2D *kernel,
- GP_ProgressCallback *callback);
+ const GP_FilterKernel2D *kernel,
+ GP_ProgressCallback *callback);
void GP_FilterKernel2DPrint(const GP_FilterKernel2D *kernel);
-------------------------------------------------------------------------------
@@ -854,8 +854,12 @@ Interpolation filters
#include <GP_Filters.h>
typedef enum GP_InterpolationType {
- GP_INTERP_NN, /* Nearest Neighbour */
- GP_INTERP_CUBIC, /* Bicubic */
+ GP_INTERP_NN, /* Nearest Neighbour */
+ GP_INTERP_LINEAR_INT, /* Bilinear - fixed point arithmetics */
+ GP_INTERP_LINEAR_LF_INT, /* Bilinear + low pass filter on downscaling */
+ GP_INTERP_CUBIC, /* Bicubic */
+ GP_INTERP_CUBIC_INT, /* Bicubic - fixed point arithmetics */
+ GP_INTERP_MAX = GP_INTERP_CUBIC_INT,
} GP_InterpolationType;
GP_Context *GP_FilterResize(const GP_Context *src, GP_Context *dst,
@@ -882,6 +886,14 @@ Fast, but produces "pixelated" images. May however work better for images with
sharp edges mostly consisting of big one color regions (it doesn't blur the
result on upscaling).
+Also is commonly used to show preview before you resample the image correctly.
+
+Bilinear Interpolation
+^^^^^^^^^^^^^^^^^^^^^^
+
+Bilinear is faster than bicubic interpolation and produces quite good results
+expecially the low pass variant doesn't need additional filter on downsampling.
+
Bicubic Interpolation
^^^^^^^^^^^^^^^^^^^^^
-----------------------------------------------------------------------
Summary of changes:
doc/filters.txt | 20 ++++++++++++++++----
1 files changed, 16 insertions(+), 4 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 43f5f45fcff837cf1f091fb9933d454e36800f3e
by metan 01 Jul '12
by metan 01 Jul '12
01 Jul '12
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 43f5f45fcff837cf1f091fb9933d454e36800f3e (commit)
via d09f22f7d44d377319e81eba29ef18a2bf752328 (commit)
via b949577b1a210f9822c39afcbe914e9d5c5bec05 (commit)
from c42e0dadc0536639298fe8d898726f565c7b2168 (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/43f5f45fcff837cf1f091fb9933d454e3680…
commit 43f5f45fcff837cf1f091fb9933d454e36800f3e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jul 1 20:57:51 2012 +0200
filters: Cubic Resampling, simplify the code.
diff --git a/libs/filters/GP_ResizeCubic.gen.c.t b/libs/filters/GP_ResizeCubic.gen.c.t
index 811885e..d8400d5 100644
--- a/libs/filters/GP_ResizeCubic.gen.c.t
+++ b/libs/filters/GP_ResizeCubic.gen.c.t
@@ -62,15 +62,10 @@ static int GP_FilterResizeCubicInt_{{ pt.name }}_Raw(const GP_Context *src,
xmap_c[i][1] = cubic_int((xmap[i][1] - x) * MUL + 0.5);
xmap_c[i][2] = cubic_int((xmap[i][2] - x) * MUL + 0.5);
xmap_c[i][3] = cubic_int((xmap[i][3] - x) * MUL + 0.5);
-
- if (xmap[i][0] < 0)
- xmap[i][0] = 0;
-
- if (xmap[i][2] >= (int32_t)src->w)
- xmap[i][2] = src->w - 1;
-
- if (xmap[i][3] >= (int32_t)src->w)
- xmap[i][3] = src->w - 1;
+
+ xmap[i][0] = GP_MAX(xmap[i][0], 0);
+ xmap[i][2] = GP_MIN(xmap[i][2], (int)src->w - 1);
+ xmap[i][3] = GP_MIN(xmap[i][3], (int)src->w - 1);
}
/* cubic resampling */
@@ -89,14 +84,9 @@ static int GP_FilterResizeCubicInt_{{ pt.name }}_Raw(const GP_Context *src,
cvy[2] = cubic_int((yi[2] - y) * MUL + 0.5);
cvy[3] = cubic_int((yi[3] - y) * MUL + 0.5);
- if (yi[0] < 0)
- yi[0] = 0;
-
- if (yi[2] >= (int)src->h)
- yi[2] = src->h - 1;
-
- if (yi[3] >= (int)src->h)
- yi[3] = src->h - 1;
+ yi[0] = GP_MAX(yi[0], 0);
+ yi[2] = GP_MIN(yi[2], (int)src->h - 1);
+ yi[3] = GP_MIN(yi[3], (int)src->h - 1);
/* Generate interpolated row */
for (j = 0; j < src->w; j++) {
http://repo.or.cz/w/gfxprim.git/commit/d09f22f7d44d377319e81eba29ef18a2bf75…
commit d09f22f7d44d377319e81eba29ef18a2bf752328
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jul 1 20:51:51 2012 +0200
core, filters: Add clamping macros.
diff --git a/include/core/GP_Clamp.h b/include/core/GP_Clamp.h
new file mode 100644
index 0000000..6b6443a
--- /dev/null
+++ b/include/core/GP_Clamp.h
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * 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(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+ /*
+
+ Fast clamping.
+
+ */
+
+#ifndef CORE_GP_CLAMP_H
+#define CORE_GP_CLAMP_H
+
+#ifdef __GNUC__
+# define GP_IS_CONSTANT(x) __builtin_constant_p(x)
+#else
+# define GP_IS_CONSTANT(x) 0
+#endif
+
+#define GP_CLAMP_GENERIC(val, min, max) ({ + typeof(val) _val = (val); + typeof(max) _max = (max); + typeof(min) _min = (min); + _val = _val < _min ? _min : _val; + _val = _val > _max ? _max : _val; + _val; +})
+
+/*
+ * Special case clamping for 8 bit values, which is sometimes faster.
+ *
+ * We first look if the number needs to be clamped and then do accordingly.
+ */
+#define GP_CLAMP_INT_0_255(val) ({ + typeof(val) _val = (val); + typeof(val) _mask = ~0xff; + (_val & _mask) ? (_val < 0 ? 0 : 255) : _val; +})
+
+#define GP_CLAMP(val, min, max) ({ + (GP_IS_CONSTANT(min) && GP_IS_CONSTANT(max) && + min == 0 && max == 255) ? + GP_CLAMP_INT_0_255(val) : + GP_CLAMP_GENERIC(val, min, max); +})
+
+#endif /* CORE_GP_CLAMP_H */
diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c
index 27575a6..b6e5983 100644
--- a/libs/filters/GP_Linear.c
+++ b/libs/filters/GP_Linear.c
@@ -22,6 +22,7 @@
#include "core/GP_Context.h"
#include "core/GP_GetPutPixel.h"
+#include "core/GP_Clamp.h"
#include "core/GP_Debug.h"
@@ -29,13 +30,6 @@
#define MUL 1024
-#define CLAMP(val) do { - if (val > 255) - val = 255; - if (val < 0) - val = 0; -} while (0)
-
int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
GP_Coord x_src, GP_Coord y_src,
GP_Size w_src, GP_Size h_src,
@@ -115,9 +109,9 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
b /= ikern_div;
/* and clamp just to be extra sure */
- CLAMP(r);
- CLAMP(g);
- CLAMP(b);
+ r = GP_CLAMP(r, 0, 255);
+ g = GP_CLAMP(g, 0, 255);
+ b = GP_CLAMP(b, 0, 255);
GP_PutPixel_Raw_24BPP(dst, x_dst + x, y_dst + y,
GP_Pixel_CREATE_RGB888(r, g, b));
@@ -210,9 +204,9 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
b /= ikern_div;
/* and clamp just to be extra sure */
- CLAMP(r);
- CLAMP(g);
- CLAMP(b);
+ r = GP_CLAMP(r, 0, 255);
+ g = GP_CLAMP(g, 0, 255);
+ b = GP_CLAMP(b, 0, 255);
GP_PutPixel_Raw_24BPP(dst, x_dst + x, y_dst + y,
GP_Pixel_CREATE_RGB888(r, g, b));
@@ -303,18 +297,8 @@ int GP_FilterLinearConvolution_Raw(const GP_Context *src,
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 (yi < 0)
- yi = 0;
-
- if (yi > (int)src->h - 1)
- yi = src->h - 1;
-
+ xi = GP_CLAMP(xi, 0, (int)src->w - 1);
+ yi = GP_CLAMP(yi, 0, (int)src->h - 1);
pix = GP_GetPixel_Raw_24BPP(src, xi, yi);
@@ -333,17 +317,8 @@ int GP_FilterLinearConvolution_Raw(const GP_Context *src,
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 (yi < 0)
- yi = 0;
-
- if (yi > (int)src->h - 1)
- yi = src->h - 1;
+ xi = GP_CLAMP(xi, 0, (int)src->w - 1);
+ yi = GP_CLAMP(yi, 0, (int)src->h - 1);
pix = GP_GetPixel_Raw_24BPP(src, xi, yi);
@@ -374,18 +349,9 @@ int GP_FilterLinearConvolution_Raw(const GP_Context *src,
b /= kern_div;
/* and clamp just to be extra sure */
- if (r > 255)
- r = 255;
- if (r < 0)
- r = 0;
- if (g > 255)
- g = 255;
- if (g < 0)
- g = 0;
- if (b > 255)
- b = 255;
- if (b < 0)
- b = 0;
+ r = GP_CLAMP((int)r, 0, 255);
+ g = GP_CLAMP((int)g, 0, 255);
+ b = GP_CLAMP((int)b, 0, 255);
pix = GP_Pixel_CREATE_RGB888((uint32_t)r, (uint32_t)g, (uint32_t)b);
diff --git a/libs/filters/GP_ResizeCubic.gen.c.t b/libs/filters/GP_ResizeCubic.gen.c.t
index 901e253..811885e 100644
--- a/libs/filters/GP_ResizeCubic.gen.c.t
+++ b/libs/filters/GP_ResizeCubic.gen.c.t
@@ -9,6 +9,7 @@
#include "core/GP_Context.h"
#include "core/GP_GetPutPixel.h"
#include "core/GP_Gamma.h"
+#include "core/GP_Clamp.h"
#include "core/GP_Debug.h"
#include "GP_Cubic.h"
@@ -27,13 +28,6 @@
#define SUM_I(a) ((a)[0] + (a)[1] + (a)[2] + (a)[3])
-#define CLAMP(val, max) do { - if (val < 0) - val = 0; - if (val > max) - val = max; -} while (0)
-
%% for pt in pixeltypes
%% if not pt.is_unknown() and not pt.is_palette()
@@ -165,14 +159,14 @@ static int GP_FilterResizeCubicInt_{{ pt.name }}_Raw(const GP_Context *src,
if (src->gamma) {
%% for c in pt.chanslist
- CLAMP({{ c[0] }}, {{ 2 ** (c[2] + 2) - 1 }});
+ {{ c[0] }} = GP_CLAMP_GENERIC({{ c[0] }}, 0, {{ 2 ** (c[2] + 2) - 1 }});
%% endfor
%% for c in pt.chanslist
{{ c[0] }} = {{ c[0] }}_2_GAMMA[{{ c[0] }}];
%% endfor
} else {
%% for c in pt.chanslist
- CLAMP({{ c[0] }}, {{ 2 ** c[2] - 1 }});
+ {{ c[0] }} = GP_CLAMP_GENERIC({{ c[0] }}, 0, {{ 2 ** c[2] - 1 }});
%% endfor
}
http://repo.or.cz/w/gfxprim.git/commit/b949577b1a210f9822c39afcbe914e9d5c5b…
commit b949577b1a210f9822c39afcbe914e9d5c5bec05
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jul 1 18:22:55 2012 +0200
filters: Move gaussian blur into separate file.
diff --git a/include/filters/GP_Filters.h b/include/filters/GP_Blur.h
similarity index 57%
copy from include/filters/GP_Filters.h
copy to include/filters/GP_Blur.h
index 3b0a95f..22694bc 100644
--- a/include/filters/GP_Filters.h
+++ b/include/filters/GP_Blur.h
@@ -16,50 +16,49 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
- * <jiri.bluebear.dluhos(a)gmail.com> *
- * *
- * Copyright (C) 2009-2011 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
- GP_Context filters.
+ Gaussian blur implementation.
*/
-#ifndef GP_FILTERS_H
-#define GP_FILTERS_H
-
-/* Filter per channel parameter passing interface */
-#include "filters/GP_FilterParam.h"
-
-/* Point filters, brightness, contrast ... */
-#include "filters/GP_Point.h"
-
-/* Addition, difference, min, max ... */
-#include "filters/GP_Arithmetic.h"
-
-/* Histograms, ... */
-#include "filters/GP_Stats.h"
-
-/* Image rotations (90 180 270 grads) and mirroring */
-#include "filters/GP_Rotate.h"
+#ifndef FILTERS_GP_BLUR_H
+#define FILTERS_GP_BLUR_H
-/* Linear convolution Raw API */
-#include "filters/GP_Linear.h"
+#include "GP_Filter.h"
-/* Convolution filters */
-#include "filters/GP_Convolution.h"
-
-/* Image scaling (resampling) */
-#include "filters/GP_Resize.h"
-
-/* Bitmap dithering */
-#include "filters/GP_Dither.h"
+/*
+ * Gaussian blur
+ *
+ * The sigma parameters defines the blur radii in horizontal and vertical
+ * direction.
+ *
+ * Internaly this is implemented as separable linear filter (calls vertical and
+ * horizontal convolution with generated gaussian kernel).
+ *
+ * This variant could work in-place so it's perectly okay to call
+ *
+ * GP_FilterGaussianBlur_Raw(context, context, ...);
+ */
+int GP_FilterGaussianBlur_Raw(const GP_Context *src, GP_Context *dst,
+ float sigma_x, float sigma_y,
+ GP_ProgressCallback *callback);
-/* Laplace based filters */
-#include "filters/GP_Laplace.h"
+/*
+ * Gaussian blur.
+ *
+ * If dst is NULL, new bitmap is allocated.
+ *
+ * This variant could work in-place.
+ *
+ * Returns pointer to destination bitmap or NULL if allocation failed.
+ */
+GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
+ float sigma_x, float sigma_y,
+ GP_ProgressCallback *callback);
-#endif /* GP_FILTERS_H */
+#endif /* FILTERS_GP_BLUR_H */
diff --git a/include/filters/GP_Filters.h b/include/filters/GP_Filters.h
index 3b0a95f..1bcc6f8 100644
--- a/include/filters/GP_Filters.h
+++ b/include/filters/GP_Filters.h
@@ -53,6 +53,9 @@
/* Convolution filters */
#include "filters/GP_Convolution.h"
+/* Blur filters */
+#include "filters/GP_Blur.h"
+
/* Image scaling (resampling) */
#include "filters/GP_Resize.h"
diff --git a/libs/filters/GP_Blur.c b/libs/filters/GP_Blur.c
new file mode 100644
index 0000000..22b99fd
--- /dev/null
+++ b/libs/filters/GP_Blur.c
@@ -0,0 +1,143 @@
+/*****************************************************************************
+ * 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(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <math.h>
+
+#include "core/GP_Debug.h"
+
+#include "GP_Linear.h"
+
+#include "GP_Blur.h"
+
+static inline unsigned int gaussian_kernel_size(float sigma)
+{
+ int center = 3 * sigma;
+
+ return 2 * center + 1;
+}
+
+static inline float gaussian_kernel_init(float sigma, float *kernel)
+{
+ int i, center = 3 * sigma;
+ int N = 2 * center + 1;
+ float ret = 0;
+
+ double sigma2 = sigma * sigma;
+
+ for (i = 0; i < N; i++) {
+ double r = center - i;
+ kernel[i] = exp(-0.5 * (r * r) / sigma2);
+ ret += kernel[i];
+ }
+
+ return ret;
+}
+
+static int gaussian_callback_horiz(GP_ProgressCallback *self)
+{
+ GP_ProgressCallback *callback = self->priv;
+
+ callback->percentage = self->percentage / 2;
+ return callback->callback(callback);
+}
+
+static int gaussian_callback_vert(GP_ProgressCallback *self)
+{
+ GP_ProgressCallback *callback = self->priv;
+
+ callback->percentage = self->percentage / 2 + 50;
+ return callback->callback(callback);
+}
+
+int GP_FilterGaussianBlur_Raw(const GP_Context *src, GP_Context *dst,
+ float sigma_x, float sigma_y,
+ GP_ProgressCallback *callback)
+{
+ unsigned int size_x = gaussian_kernel_size(sigma_x);
+ unsigned int size_y = gaussian_kernel_size(sigma_y);
+
+ GP_DEBUG(1, "Gaussian blur sigma_x=%2.3f sigma_y=%2.3f kernel %ix%i image %ux%u",
+ sigma_x, sigma_y, size_x, size_y, src->w, src->h);
+
+ GP_ProgressCallback *new_callback = NULL;
+
+ GP_ProgressCallback gaussian_callback = {
+ .callback = gaussian_callback_horiz,
+ .priv = callback
+ };
+
+ if (callback != NULL)
+ new_callback = &gaussian_callback;
+
+ /* compute kernel and apply in horizontal direction */
+ if (sigma_x > 0) {
+ float kernel_x[size_x];
+ float sum = gaussian_kernel_init(sigma_x, kernel_x);
+
+ if (GP_FilterHLinearConvolution_Raw(src, 0, 0, src->w, src->h,
+ dst, 0, 0, kernel_x, size_x,
+ sum, new_callback))
+ return 1;
+ }
+
+ if (new_callback != NULL)
+ new_callback->callback = gaussian_callback_vert;
+
+ /* compute kernel and apply in vertical direction */
+ if (sigma_y > 0) {
+ float kernel_y[size_y];
+ float sum = gaussian_kernel_init(sigma_y, kernel_y);
+
+ if (GP_FilterVLinearConvolution_Raw(dst, 0, 0, src->w, src->h,
+ dst, 0, 0, kernel_y, size_y,
+ sum, new_callback))
+ return 1;
+ }
+
+ GP_ProgressCallbackDone(callback);
+ return 0;
+}
+
+GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
+ float sigma_x, float sigma_y,
+ GP_ProgressCallback *callback)
+{
+ /* TODO: templatetize */
+ if (src->pixel_type != GP_PIXEL_RGB888)
+ return NULL;
+
+ if (dst == NULL) {
+ dst = GP_ContextCopy(src, 0);
+
+ if (dst == NULL)
+ return NULL;
+ } else {
+ GP_ASSERT(src->pixel_type == dst->pixel_type,
+ "The src and dst pixel types must match");
+ GP_ASSERT(src->w <= dst->w && src->h <= dst->h,
+ "Destination is not big enough");
+ }
+
+ GP_FilterGaussianBlur_Raw(src, dst, sigma_x, sigma_y, callback);
+
+ return dst;
+}
diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c
index 54ec6c9..27575a6 100644
--- a/libs/filters/GP_Linear.c
+++ b/libs/filters/GP_Linear.c
@@ -20,8 +20,6 @@
* *
*****************************************************************************/
-#include <math.h>
-
#include "core/GP_Context.h"
#include "core/GP_GetPutPixel.h"
@@ -29,120 +27,6 @@
#include "GP_Linear.h"
-static inline unsigned int gaussian_kernel_size(float sigma)
-{
- int center = 3 * sigma;
-
- return 2 * center + 1;
-}
-
-static inline float gaussian_kernel_init(float sigma, float *kernel)
-{
- int i, center = 3 * sigma;
- int N = 2 * center + 1;
- float ret = 0;
-
- double sigma2 = sigma * sigma;
-
- for (i = 0; i < N; i++) {
- double r = center - i;
- kernel[i] = exp(-0.5 * (r * r) / sigma2);
- ret += kernel[i];
- }
-
- return ret;
-}
-
-static int gaussian_callback_horiz(GP_ProgressCallback *self)
-{
- GP_ProgressCallback *callback = self->priv;
-
- callback->percentage = self->percentage / 2;
- return callback->callback(callback);
-}
-
-static int gaussian_callback_vert(GP_ProgressCallback *self)
-{
- GP_ProgressCallback *callback = self->priv;
-
- callback->percentage = self->percentage / 2 + 50;
- return callback->callback(callback);
-}
-
-int GP_FilterGaussianBlur_Raw(const GP_Context *src, GP_Context *dst,
- float sigma_x, float sigma_y,
- GP_ProgressCallback *callback)
-{
- unsigned int size_x = gaussian_kernel_size(sigma_x);
- unsigned int size_y = gaussian_kernel_size(sigma_y);
-
- GP_DEBUG(1, "Gaussian blur sigma_x=%2.3f sigma_y=%2.3f kernel %ix%i image %ux%u",
- sigma_x, sigma_y, size_x, size_y, src->w, src->h);
-
- GP_ProgressCallback *new_callback = NULL;
-
- GP_ProgressCallback gaussian_callback = {
- .callback = gaussian_callback_horiz,
- .priv = callback
- };
-
- if (callback != NULL)
- new_callback = &gaussian_callback;
-
- /* compute kernel and apply in horizontal direction */
- if (sigma_x > 0) {
- float kernel_x[size_x];
- float sum = gaussian_kernel_init(sigma_x, kernel_x);
-
- if (GP_FilterHLinearConvolution_Raw(src, 0, 0, src->w, src->h,
- dst, 0, 0, kernel_x, size_x,
- sum, new_callback))
- return 1;
- }
-
- if (new_callback != NULL)
- new_callback->callback = gaussian_callback_vert;
-
- /* compute kernel and apply in vertical direction */
- if (sigma_y > 0) {
- float kernel_y[size_y];
- float sum = gaussian_kernel_init(sigma_y, kernel_y);
-
- if (GP_FilterVLinearConvolution_Raw(dst, 0, 0, src->w, src->h,
- dst, 0, 0, kernel_y, size_y,
- sum, new_callback))
- return 1;
- }
-
- GP_ProgressCallbackDone(callback);
- return 0;
-}
-
-GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
- float sigma_x, float sigma_y,
- GP_ProgressCallback *callback)
-{
- /* TODO: templatetize */
- if (src->pixel_type != GP_PIXEL_RGB888)
- return NULL;
-
- if (dst == NULL) {
- dst = GP_ContextCopy(src, 0);
-
- if (dst == NULL)
- return NULL;
- } else {
- GP_ASSERT(src->pixel_type == dst->pixel_type,
- "The src and dst pixel types must match");
- GP_ASSERT(src->w <= dst->w && src->h <= dst->h,
- "Destination is not big enough");
- }
-
- GP_FilterGaussianBlur_Raw(src, dst, sigma_x, sigma_y, callback);
-
- return dst;
-}
-
#define MUL 1024
#define CLAMP(val) do {
-----------------------------------------------------------------------
Summary of changes:
include/{loaders/GP_TmpFile.h => core/GP_Clamp.h} | 55 ++++---
include/filters/{GP_Laplace.h => GP_Blur.h} | 47 +++---
include/filters/GP_Filters.h | 3 +
libs/filters/GP_Blur.c | 143 +++++++++++++++++
libs/filters/GP_Linear.c | 178 ++-------------------
libs/filters/GP_ResizeCubic.gen.c.t | 36 ++---
6 files changed, 226 insertions(+), 236 deletions(-)
copy include/{loaders/GP_TmpFile.h => core/GP_Clamp.h} (60%)
copy include/filters/{GP_Laplace.h => GP_Blur.h} (64%)
create mode 100644 libs/filters/GP_Blur.c
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: c42e0dadc0536639298fe8d898726f565c7b2168
by metan 01 Jul '12
by metan 01 Jul '12
01 Jul '12
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 c42e0dadc0536639298fe8d898726f565c7b2168 (commit)
from 61f49dcc7034e8eeeccf9a950d1c2731f5c9969d (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/c42e0dadc0536639298fe8d898726f565c7b…
commit c42e0dadc0536639298fe8d898726f565c7b2168
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jul 1 18:13:55 2012 +0200
doc: Update filters.txt doc.
diff --git a/doc/filters.txt b/doc/filters.txt
index eac6bff..9d4228e 100644
--- a/doc/filters.txt
+++ b/doc/filters.txt
@@ -487,23 +487,262 @@ It's defined as:
[latex, discrete_linear_convolution.png, 140]
-------------------------------------------------------------------------------
[
-O(x,y)=sum_{i=-infty}^{infty}sum_{j=-infty}^{infty}I(x-i,y-j) cdot K(i,j)
+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 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.
+i and j are in (-1,1) and the kernel size is 3x3.
-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.
+Note that pixel values outside the image are undefined. The linear convolution
+in GFXprim simply uses the closest border pixel values for all pixels outside
+the image.
Particular convolution kernel is called separable if it could be decomposed
into two one dimensional kernels (these when combined yields back the original
kernel). Such convolution then could be applied as two one dimensional
convolutions which is faster operation (especially for big kernels).
+Generic Linear Convolution
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Following paragraph describes linear convolution implementation as well as a
+little of the math background skip it if you just need to use one of the
+ready-to-use filters.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <filters/GP_Linear.h>
+/* or */
+#include <GP.h>
+
+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);
+-------------------------------------------------------------------------------
+
+Internal generic convolution filter, this is a base for all linear convolution
+filters with non-separable kernel.
+
+The src coordinate and sizes denotes rectangle in the source context that the
+filter operates on.
+
+The dst coordinates defines offset into the dst context.
+
+The kernel is two-dimensional array of a size kw * kh indexed as
+kernel[x + y*kw].
+
+The kern_div is a coeficient that is used to divide the resuting values often
+used to normalize the result.
+
+This filter works 'in-place'.
+
+The pixel value is computed as:
+[latex, discrete_linear_convolution_alg1.png, 140]
+-------------------------------------------------------------------------------
+[
+O(x,y)={1 over kern_div} cdot sum_{i=0}^{kw - 1}sum_{j=0}^{kh - 1}
+ I(x + i - lfloor kw/2 rfloor, y + j - lfloor kh/2 rfloor)
+ cdot kernel(i,j)
+]
+-------------------------------------------------------------------------------
+
+Which is the same as:
+
+[latex, discrete_linear_convolution_alg2.png, 140]
+-------------------------------------------------------------------------------
+[
+O(x,y)={1 over kern_div} cdot
+ sum_{i=-lfloor kw/2 rfloor}^{lfloor kw/2 rfloor}
+ sum_{j=-lfloor kh/2 rfloor}^{lfloor kh/2 rfloor}
+ I(x + i, y + j)
+ cdot kernel(i + lfloor kw/2 rfloor, j + lfloor kh/2 rfloor)
+]
+-------------------------------------------------------------------------------
+
+NOTE: The number of kernel rows and columns is expected to be odd number.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <filters/GP_Linear.h>
+/* or */
+#include <GP.h>
+
+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_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);
+
+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);
+
+void GP_FilterKernelPrint_Raw(float kernel[], int kw, int kh, float kern_div);
+-------------------------------------------------------------------------------
+
+Internal special functions for one dimensional vertical and horizontal
+convolution these two functions are base for all separable convolution filters.
+
+The src coordinate and sizes denotes rectangle in the source context that the
+filter operates on.
+
+The dst coordinates are offset into the dst.
+
+The kernel is one-dimensional array of floats of size kw or kh.
+
+The kern_div is a coeficient that is used to divide the resuting values.
+
+The last function does both vertical and horizontal convolution and takes care
+of correct progress callback.
+
+These filters work 'in-place'.
+
+The pixel value is computed as:
+[latex, discrete_linear_1D_convolution_alg1.png, 140]
+-------------------------------------------------------------------------------
+[
+O(x,y)={1 over kern_div} cdot sum_{i=0}^{kw - 1}
+ I(x + i - lfloor kw/2 rfloor, y)
+ cdot kernel(i)
+]
+
+[
+O(x,y)={1 over kern_div} cdot sum_{j=0}^{kw - 1}
+ I(x, y + j - lfloor kh/2 rfloor)
+ cdot kernel(j)
+]
+-------------------------------------------------------------------------------
+
+Which is the same as:
+
+[latex, discrete_linear_1D_convolution_alg2.png, 140]
+-------------------------------------------------------------------------------
+[
+O(x,y)={1 over kern_div} cdot
+ sum_{i=-lfloor kw/2 rfloor}^{lfloor kw/2 rfloor}
+ I(x + i, y)
+ cdot kernel(i + lfloor kw/2 rfloor)
+]
+
+[
+O(x,y)={1 over kern_div} cdot
+ sum_{j=-lfloor kh/2 rfloor}^{lfloor kh/2 rfloor}
+ I(x, y + j)
+ cdot kernel(i, j + lfloor kh/2 rfloor)
+]
+-------------------------------------------------------------------------------
+
+NOTE: The number of kernel rows and columns is expected to be odd number.
+
+NOTE: The linear convolutions are internally implemented using integer
+ arithmetics, which works fine, but you need to take a care not to
+ overflow 32bit signed integer. If the pixel channel size is 8bit
+ long and 10bits are used for the fixed point part of the number
+ the rest must fit into about 10 bits to be safe.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <filters/GP_Convolution.h>
+/* or */
+#include <GP.h>
+
+typedef struct GP_FilterKernel2D {
+ unsigned int w;
+ unsigned int h;
+ float div;
+ float *kernel;
+} GP_FilterKernel2D;
+
+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);
+
+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);
+
+int GP_FilterConvolution(const GP_Context *src, GP_Context *dst,
+ const GP_FilterKernel2D *kernel,
+ GP_ProgressCallback *callback);
+
+GP_Context *GP_FilterConvolutionAlloc(const GP_Context *src,
+ const GP_FilterKernel2D *kernel,
+ GP_ProgressCallback *callback);
+
+void GP_FilterKernel2DPrint(const GP_FilterKernel2D *kernel);
+-------------------------------------------------------------------------------
+
+Linear convolution filters, you should prefferably use this API over the _Raw
+variants.
+
+The Ex variants takes a rectangle on which the filter should operate as well
+as offset into the destination. The destination must be large enough so that
+starting with offset there is at least w_dst and h_dst pixels.
+
+The kernel is a pointer to a structure initalized with the kernel size, divider
+and array of kernel values.
+
+The last function prints convolution kernel in human-readable format into the
+stdout.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <GP.h>
+
+/*
+ * Example box smoothing filter.
+ */
+static void box_smoothing(GP_Context *img)
+{
+ 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,
+ };
+
+ GP_FilterConvolution(img, img, &box_kernel, NULL);
+}
+-------------------------------------------------------------------------------
+
+Example function that implements simple 'in-place' smoothing filter.
+
+Laplace Filter
+^^^^^^^^^^^^^^
+
[source,c]
-------------------------------------------------------------------------------
#include <GP_Filters.h>
@@ -548,6 +787,9 @@ The convolution kernel is defined as:
NOTE: This filter is not separable but could be written as a sum of two one
dimensional filters as the kernel definition suggests.
+Laplacian Edge Sharpening
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
[source,c]
-------------------------------------------------------------------------------
#include <GP_Filters.h>
@@ -585,6 +827,9 @@ image:images/edge_sharpening/lenna_small_w_0_5.png[
"Edge Sharpening w=0.5",
link="images/edge_sharpening/lenna_w_0_5.png"]
+Gaussian Blur
+^^^^^^^^^^^^^
+
[source,c]
-------------------------------------------------------------------------------
#include <GP_Filters.h>
-----------------------------------------------------------------------
Summary of changes:
doc/filters.txt | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 250 insertions(+), 5 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 61f49dcc7034e8eeeccf9a950d1c2731f5c9969d
by metan 01 Jul '12
by metan 01 Jul '12
01 Jul '12
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/61f49dcc7034e8eeeccf9a950d1c2731f5c9…
commit 61f49dcc7034e8eeeccf9a950d1c2731f5c9969d
Author: Cyril Hrubis <metan(a)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(a)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/8f908e18fb01faa8320ac4b2ae1905426ced…
commit 8f908e18fb01faa8320ac4b2ae1905426ceddcd1
Author: Cyril Hrubis <metan(a)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/8e026f14b369c6d70f8a4954970d8d94864c…
commit 8e026f14b369c6d70f8a4954970d8d94864ca587
Author: Cyril Hrubis <metan(a)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/a67438c203dd1b95d464a2482795d27318e0…
commit a67438c203dd1b95d464a2482795d27318e00592
Author: Cyril Hrubis <metan(a)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(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 04f9434ac9e4649dba4c394b00187a7f1004b0a4
by metan 29 Jun '12
by metan 29 Jun '12
29 Jun '12
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 04f9434ac9e4649dba4c394b00187a7f1004b0a4 (commit)
via dad06bc1a3ee9080149efdce008821be2ce64754 (commit)
via b348a1d81f3a985f258b57a467827fafbc2923d9 (commit)
from fc824cf87cc0e855dbbc14082dbd9cfd1d41045d (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/04f9434ac9e4649dba4c394b00187a7f1004…
commit 04f9434ac9e4649dba4c394b00187a7f1004b0a4
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 29 22:57:13 2012 +0200
doc: Add Laplace based filter docs.
diff --git a/doc/README b/doc/README
index 8298f04..87e78a6 100644
--- a/doc/README
+++ b/doc/README
@@ -2,7 +2,7 @@ This directory contains asciidoc documentation.
The html pages are generated by typing 'make'.
-In order to do that asciidoc and source-highlight must be installed.
+In order to do that asciidoc and source-highlight, latex and dvipng must be installed.
The pdf documentation could be generated by typing 'make api.pdf' for that fop
diff --git a/doc/filters.txt b/doc/filters.txt
index 1abf977..9f6c012 100644
--- a/doc/filters.txt
+++ b/doc/filters.txt
@@ -476,6 +476,112 @@ Catch all function for symmetry filters.
Linear filters
~~~~~~~~~~~~~~
+Linear filters family consists of filters based on discrete linear
+convolution, that means that computed pixel value depends on linear
+combination of the image pixels.
+
+It's defined as:
+[latex, discrete_linear_convolution.png, 140]
+-------------------------------------------------------------------------------
+[
+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
+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
+convolution in GFXprim simply uses the corner pixel values for all pixels
+outside the image.
+
+Particular convolution kernel is called separable if it could be decomposed
+into two one dimensional kernels (these when combined yields back the original
+kernel). Such convolution then could be applied as two one dimensional
+convolutions which is faster operation (especially for big kernels).
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <GP_Filters.h>
+/* or */
+#include <GP.h>
+
+int GP_FilterLaplace(const GP_Context *src, GP_Context *dst,
+ GP_ProgressCallback *callback);
+
+GP_Context *GP_FilterLaplaceAlloc(const GP_Context *src,
+ GP_ProgressCallback *callback);
+-------------------------------------------------------------------------------
+
+Discrete laplace filter that produces a second derivative of the original
+image.
+
+The convolution kernel is defined as:
+
+[latex, laplacian_kernel.png, 130]
+-------------------------------------------------------------------------------
+[
+begin{bmatrix}
+0 & 1 & 0 \
+0 & -2 & 0 \
+0 & 1 & 0
+end{bmatrix}
++
+begin{bmatrix}
+0 & 0 & 0 \
+1 & -2 & 1 \
+0 & 0 & 0
+end{bmatrix}
+=
+begin{bmatrix}
+0 & 1 & 0 \
+1 & -4 & 1 \
+0 & 1 & 0
+end{bmatrix}
+]
+-------------------------------------------------------------------------------
+
+NOTE: This filter is not separable but could be written as a sum of two one
+ dimensional filters as the kernel definition suggests.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <GP_Filters.h>
+/* or */
+#include <GP.h>
+
+int GP_FilterEdgeSharpening(const GP_Context *src, GP_Context *dst,
+ float w, GP_ProgressCallback *callback);
+
+GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w,
+ GP_ProgressCallback *callback);
+-------------------------------------------------------------------------------
+
+Laplace based edge sharpening filter, substracts weighted second derivative
+from the original image.
+
+[latex, laplacian_edge_sharpening.png, 140]
+-------------------------------------------------------------------------------
+[
+O(x,y) = I(x,y) - w * I''(x,y)
+]
+-------------------------------------------------------------------------------
+
+.Original Image; Edge Sharpening w=0.1, w=0.3, w=0.5
+image:images/dither/lenna_small.png[
+ "Original Image",
+ link="images/dither/lenna.png"]
+image:images/edge_sharpening/lenna_small_w_0_1.png[
+ "Edge Sharpening w=0.1",
+ link="images/edge_sharpening/lenna_w_0_1.png"]
+image:images/edge_sharpening/lenna_small_w_0_3.png[
+ "Edge Sharpening w=0.5",
+ link="images/edge_sharpening/lenna_w_0_3.png"]
+image:images/edge_sharpening/lenna_small_w_0_5.png[
+ "Edge Sharpening w=0.5",
+ link="images/edge_sharpening/lenna_w_0_5.png"]
+
[source,c]
-------------------------------------------------------------------------------
#include <GP_Filters.h>
diff --git a/doc/images/edge_sharpening/lenna_small_w_0_1.png b/doc/images/edge_sharpening/lenna_small_w_0_1.png
new file mode 100644
index 0000000..848ccea
Binary files /dev/null and b/doc/images/edge_sharpening/lenna_small_w_0_1.png differ
diff --git a/doc/images/edge_sharpening/lenna_small_w_0_3.png b/doc/images/edge_sharpening/lenna_small_w_0_3.png
new file mode 100644
index 0000000..a311e36
Binary files /dev/null and b/doc/images/edge_sharpening/lenna_small_w_0_3.png differ
diff --git a/doc/images/edge_sharpening/lenna_small_w_0_5.png b/doc/images/edge_sharpening/lenna_small_w_0_5.png
new file mode 100644
index 0000000..46891b2
Binary files /dev/null and b/doc/images/edge_sharpening/lenna_small_w_0_5.png differ
diff --git a/doc/images/edge_sharpening/lenna_w_0_1.png b/doc/images/edge_sharpening/lenna_w_0_1.png
new file mode 100644
index 0000000..405291f
Binary files /dev/null and b/doc/images/edge_sharpening/lenna_w_0_1.png differ
diff --git a/doc/images/edge_sharpening/lenna_w_0_3.png b/doc/images/edge_sharpening/lenna_w_0_3.png
new file mode 100644
index 0000000..4417327
Binary files /dev/null and b/doc/images/edge_sharpening/lenna_w_0_3.png differ
diff --git a/doc/images/edge_sharpening/lenna_w_0_5.png b/doc/images/edge_sharpening/lenna_w_0_5.png
new file mode 100644
index 0000000..0a9e7c9
Binary files /dev/null and b/doc/images/edge_sharpening/lenna_w_0_5.png differ
http://repo.or.cz/w/gfxprim.git/commit/dad06bc1a3ee9080149efdce008821be2ce6…
commit dad06bc1a3ee9080149efdce008821be2ce64754
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 29 22:54:26 2012 +0200
filters: Fix the laplace filter (it's not separable, gah)
diff --git a/include/filters/GP_Laplace.h b/include/filters/GP_Laplace.h
index e250cd6..ead7e6e 100644
--- a/include/filters/GP_Laplace.h
+++ b/include/filters/GP_Laplace.h
@@ -32,17 +32,30 @@
#include "GP_Filter.h"
/*
- * Laplace, second-derivative filter.
+ * Discrete Laplace, second-derivative filter.
+ *
+ * Implemented by separable linear convolution with kernels
+ *
+ * [1 -2 1] and [ 1 ]
+ * [-2 ]
+ * [ 1 ]
*/
int GP_FilterLaplace(const GP_Context *src, GP_Context *dst,
GP_ProgressCallback *callback);
+GP_Context *GP_FilterLaplaceAlloc(const GP_Context *src,
+ GP_ProgressCallback *callback);
+
/*
* Laplace based filter sharpening.
*
- * The w is direct weight used to multiply the result.
+ * This filter substract result of Laplace filter weigted by w from the
+ * original image which amplifies edges.
*/
int GP_FilterEdgeSharpening(const GP_Context *src, GP_Context *dst,
float w, GP_ProgressCallback *callback);
+GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w,
+ GP_ProgressCallback *callback);
+
#endif /* FILTERS_GP_LAPLACE_H */
diff --git a/libs/filters/GP_Laplace.c b/libs/filters/GP_Laplace.c
index 3de0a97..b6a91a1 100644
--- a/libs/filters/GP_Laplace.c
+++ b/libs/filters/GP_Laplace.c
@@ -32,30 +32,71 @@ int GP_FilterLaplace(const GP_Context *src, GP_Context *dst,
{
GP_DEBUG(1, "Laplace filter %ux%u", src->w, src->h);
- float kern[3] = {1, -2, 1};
+ float kern[9] = {0, 1, 0,
+ 1, -4, 1,
+ 0, 1, 0};
- if (GP_FilterVHLinearConvolution_Raw(src, dst, kern, 3, 1,
- kern, 3, 1, callback))
+ 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)
{
- float kern[3] = {0, 1, 0};
-
+ /* 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);
- kern[0] -= 1.00 * w;
- kern[1] -= -2.00 * w;
- kern[2] -= 1.00 * w;
+ /* 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;
- if (GP_FilterVHLinearConvolution_Raw(src, dst, kern, 3, 1,
- kern, 3, 1, callback))
+ GP_FilterKernelPrint(kern, 3, 3, 1);
+
+ if (GP_FilterLinearConvolution_Raw(src, dst, kern, 3, 3, 1, callback))
return 1;
return 0;
}
+
+GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w,
+ GP_ProgressCallback *callback)
+{
+ GP_Context *ret = GP_ContextCopy(src, 0);
+
+ if (ret == NULL)
+ return NULL;
+
+ if (GP_FilterEdgeSharpening(src, ret, w, callback)) {
+ GP_ContextFree(ret);
+ return NULL;
+ }
+
+ return ret;
+}
http://repo.or.cz/w/gfxprim.git/commit/b348a1d81f3a985f258b57a467827fafbc29…
commit b348a1d81f3a985f258b57a467827fafbc2923d9
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 29 22:43:19 2012 +0200
filters: Added GP_FilterKernelPrint() function.
diff --git a/include/filters/GP_Linear.h b/include/filters/GP_Linear.h
index 56be135..ba286ec 100644
--- a/include/filters/GP_Linear.h
+++ b/include/filters/GP_Linear.h
@@ -112,4 +112,9 @@ int GP_FilterVHLinearConvolution_Raw(const GP_Context *src, GP_Context *dst,
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);
+
#endif /* FILTERS_GP_LINEAR_H */
diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c
index 6f906b8..c84b17b 100644
--- a/libs/filters/GP_Linear.c
+++ b/libs/filters/GP_Linear.c
@@ -464,3 +464,21 @@ int GP_FilterLinearConvolution_Raw(const GP_Context *src, GP_Context *dst,
GP_ProgressCallbackDone(callback);
return 0;
}
+
+void GP_FilterKernelPrint(float kernel[], int kw, int kh, float kern_div)
+{
+ int i, j;
+
+ for (i = 0; i < kw; i++) {
+
+ if (i == kw/2)
+ printf("% 8.2f * | ", 1/kern_div);
+ else
+ printf(" | ");
+
+ for (j = 0; j < kh; j++)
+ printf("% 8.2f ", kernel[j + i * kw]);
+
+ printf("|n");
+ }
+}
-----------------------------------------------------------------------
Summary of changes:
doc/README | 2 +-
doc/filters.txt | 106 ++++++++++++++++++++++
doc/images/edge_sharpening/lenna_small_w_0_1.png | Bin 0 -> 127188 bytes
doc/images/edge_sharpening/lenna_small_w_0_3.png | Bin 0 -> 143643 bytes
doc/images/edge_sharpening/lenna_small_w_0_5.png | Bin 0 -> 156274 bytes
doc/images/edge_sharpening/lenna_w_0_1.png | Bin 0 -> 429215 bytes
doc/images/edge_sharpening/lenna_w_0_3.png | Bin 0 -> 476119 bytes
doc/images/edge_sharpening/lenna_w_0_5.png | Bin 0 -> 514664 bytes
include/filters/GP_Laplace.h | 17 +++-
include/filters/GP_Linear.h | 5 +
libs/filters/GP_Laplace.c | 61 +++++++++++--
libs/filters/GP_Linear.c | 18 ++++
12 files changed, 196 insertions(+), 13 deletions(-)
create mode 100644 doc/images/edge_sharpening/lenna_small_w_0_1.png
create mode 100644 doc/images/edge_sharpening/lenna_small_w_0_3.png
create mode 100644 doc/images/edge_sharpening/lenna_small_w_0_5.png
create mode 100644 doc/images/edge_sharpening/lenna_w_0_1.png
create mode 100644 doc/images/edge_sharpening/lenna_w_0_3.png
create mode 100644 doc/images/edge_sharpening/lenna_w_0_5.png
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0