summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Vogelgesang <matthias.vogelgesang@kit.edu>2015-02-11 16:59:25 +0100
committerMatthias Vogelgesang <matthias.vogelgesang@kit.edu>2015-02-16 12:39:26 +0100
commitcbb237a5350860ee67392ee58dec1db894abac38 (patch)
tree41806f50b2e5811d101f0ef49125e832ee8c6d32
parent5d9bd8d81fad8154bb3b1376b00e24025e1e6663 (diff)
Import uPIV related filters by Alexandre Lewkowicz
This commit adds relevant filters and kernels to compute rings for the PIV application.
-rw-r--r--src/CMakeLists.txt21
-rw-r--r--src/kernels/denoise.cl82
-rw-r--r--src/kernels/fftmult.cl17
-rw-r--r--src/kernels/ordfilt.cl85
-rw-r--r--src/kernels/piv.cl48
-rw-r--r--src/ufo-concatenate-result-task.c381
-rw-r--r--src/ufo-concatenate-result-task.h66
-rw-r--r--src/ufo-contrast-task.c311
-rw-r--r--src/ufo-contrast-task.h66
-rw-r--r--src/ufo-denoise-task.c356
-rw-r--r--src/ufo-denoise-task.h66
-rw-r--r--src/ufo-dump-ring-task.c239
-rw-r--r--src/ufo-dump-ring-task.h66
-rw-r--r--src/ufo-duplicate-task.c130
-rw-r--r--src/ufo-duplicate-task.h66
-rw-r--r--src/ufo-fftmult-task.c224
-rw-r--r--src/ufo-fftmult-task.h66
-rw-r--r--src/ufo-filter-particle-task.c602
-rw-r--r--src/ufo-filter-particle-task.h66
-rw-r--r--src/ufo-get-dup-circ-task.c234
-rw-r--r--src/ufo-get-dup-circ-task.h66
-rw-r--r--src/ufo-multi-search-task.c513
-rw-r--r--src/ufo-multi-search-task.h66
-rw-r--r--src/ufo-ordfilt-task.c329
-rw-r--r--src/ufo-ordfilt-task.h66
-rw-r--r--src/ufo-priv.c12
-rw-r--r--src/ufo-priv.h17
-rw-r--r--src/ufo-reduce-task.c124
-rw-r--r--src/ufo-reduce-task.h66
-rw-r--r--src/ufo-remove-circle-task.c330
-rw-r--r--src/ufo-remove-circle-task.h66
-rw-r--r--src/ufo-replicate-task.c134
-rw-r--r--src/ufo-replicate-task.h66
-rw-r--r--src/ufo-ring-coordinates.h20
-rw-r--r--src/ufo-ring-pattern-task.c314
-rw-r--r--src/ufo-ring-pattern-task.h66
-rw-r--r--src/ufo-ringwriter-task.c278
-rw-r--r--src/ufo-ringwriter-task.h66
38 files changed, 5789 insertions, 2 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2811a1d..5f92044 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,28 +7,43 @@ set(ufofilter_SRCS
ufo-buffer-task.c
ufo-cut-sinogram-task.c
ufo-center-of-rotation-task.c
+ ufo-concatenate-result-task.c
+ ufo-contrast-task.c
ufo-dfi-sinc-task.c
+ ufo-denoise-task.c
ufo-downsample-task.c
+ ufo-dump-ring-task.c
+ ufo-duplicate-task.c
ufo-filter-task.c
ufo-flatten-task.c
ufo-flatten-inplace-task.c
ufo-flat-field-correction-task.c
ufo-fft-task.c
+ ufo-fftmult-task.c
+ ufo-filter-particle-task.c
ufo-forwardproject-task.c
ufo-gaussian-blur-task.c
ufo-generate-task.c
+ ufo-get-dup-circ-task.c
ufo-ifft-task.c
ufo-interpolate-task.c
ufo-sharpness-measure-task.c
ufo-map-slice-task.c
ufo-median-filter-task.c
ufo-meta-balls-task.c
+ ufo-multi-search-task.c
ufo-null-task.c
ufo-opencl-task.c
+ ufo-ordfilt-task.c
ufo-pad-task.c
ufo-phase-retrieval-task.c
ufo-polar-coordinates-task.c
ufo-region-of-interest-task.c
+ ufo-reduce-task.c
+ ufo-remove-circle-task.c
+ ufo-ring-pattern-task.c
+ ufo-ringwriter-task.c
+ ufo-replicate-task.c
ufo-sino-generator-task.c
ufo-slice-task.c
ufo-stack-task.c
@@ -40,6 +55,8 @@ set(ufofilter_SRCS
ufo-zeropadding-task.c
)
+set(ufoaux_SRCS ufo-priv.c)
+
file(GLOB ufofilter_KERNELS "kernels/*.cl")
#}}}
#{{{ Variables
@@ -135,9 +152,9 @@ foreach(_src ${ufofilter_SRCS})
# build single shared library per filter
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- add_library(${target} MODULE ${_src} ${${_misc}})
+ add_library(${target} MODULE ${ufoaux_SRCS} ${_src} ${${_misc}})
else()
- add_library(${target} SHARED ${_src} ${${_misc}})
+ add_library(${target} SHARED ${ufoaux_SRCS} ${_src} ${${_misc}})
endif()
target_link_libraries(${target} ${ufofilter_LIBS})
diff --git a/src/kernels/denoise.cl b/src/kernels/denoise.cl
new file mode 100644
index 0000000..68d18c9
--- /dev/null
+++ b/src/kernels/denoise.cl
@@ -0,0 +1,82 @@
+#include "piv.cl"
+
+
+kernel void
+load_elements (global float *src,
+ global float *dst,
+ int dimension)
+{
+ const int2 imsize = (int2) (get_global_size(0), get_global_size(1));
+ const int x = get_global_id(0);
+ const int y = get_global_id(1);
+
+ unsigned short buffer[12];
+
+ int offset = dimension * dimension * (x + y * get_global_size(0));
+ int2 center;
+ get_center (dimension, dimension, &center);
+ global float* tmpDst = dst + offset;
+
+ for(int j = 0; j < dimension; ++j) {
+ for(int i = 0; i < dimension; ++i) {
+ *tmpDst = src[get_pel_position (imsize, (int2)(i, j), (int2)(x, y), center)];
+ ++tmpDst;
+ }
+ }
+}
+
+kernel void
+sort_and_set (global const float *src, global float *dst, int num_elements,
+ int arrayLength, float threshold, local float *s_key)
+{
+ // ascendent order
+ unsigned dir = 1;
+ unsigned block_idx = get_global_id(0) / get_local_size(0);
+ //Offset to the beginning of subbatch and load data
+ global const float *d_SrcKey = src + block_idx * num_elements;
+
+ s_key[get_local_id(0)] = d_SrcKey[get_local_id(0)];
+ unsigned next_index = get_local_id(0) + arrayLength / 2;
+
+ s_key[next_index] = next_index < num_elements ? d_SrcKey[next_index] : 0xFFFF;
+
+ for (int size = 2; size < arrayLength; size <<= 1) {
+ //Bitonic merge. ddd tells if ordering is ascendent or descendent
+ unsigned ddd = dir ^ ((get_local_id(0) & (size / 2)) != 0);
+
+ for (int stride = size / 2; stride > 0; stride >>= 1) {
+ barrier(CLK_LOCAL_MEM_FENCE);
+ unsigned pos = 2 * get_local_id(0) - (get_local_id(0) & (stride - 1));
+ compare_and_exchange (&s_key[pos], &s_key[pos + stride], ddd);
+ }
+ }
+
+ {
+ for (int stride = arrayLength / 2; stride > 0; stride >>= 1) {
+ barrier(CLK_LOCAL_MEM_FENCE);
+ unsigned pos = 2 * get_local_id(0) - (get_local_id(0) & (stride - 1));
+ compare_and_exchange (&s_key[pos], &s_key[pos + stride], dir);
+ }
+ }
+
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ if (get_local_id(0) == 0) {
+ dst[block_idx] = s_key[(int)(num_elements * threshold - 1)];
+ }
+}
+
+kernel void
+/* remove pixels darker than the background image */
+remove_background (global float *src, global float *dst)
+{
+ int2 pel = (int2)(get_global_id(0), get_global_id(1));
+ int idx = pel.x + pel.y * get_global_size(0);
+ /* foreground pixel */
+ float fg = src[idx];
+ /* background pixel */
+ float bk = dst[idx];
+ fg -= bk;
+
+ dst[idx] = fg < 0 ? 0 : fg;
+}
diff --git a/src/kernels/fftmult.cl b/src/kernels/fftmult.cl
new file mode 100644
index 0000000..7d4c578
--- /dev/null
+++ b/src/kernels/fftmult.cl
@@ -0,0 +1,17 @@
+kernel
+void mult(global float* a, global float* b, global float* res)
+{
+ int width = get_global_size(0) * 2;
+ int x = get_global_id(0) * 2;
+ int y = get_global_id(1);
+ int idx_r = x + y * width;
+ int idx_i = 1 + x + y * width;
+
+ float ra = a[idx_r];
+ float rb = b[idx_r];
+ float ia = a[idx_i];
+ float ib = b[idx_i];
+
+ res[idx_r] = ra * rb - ia * ib;
+ res[idx_i] = ra * ib + rb * ia;
+}
diff --git a/src/kernels/ordfilt.cl b/src/kernels/ordfilt.cl
new file mode 100644
index 0000000..70bf042
--- /dev/null
+++ b/src/kernels/ordfilt.cl
@@ -0,0 +1,85 @@
+#include "piv.cl"
+
+
+/* For each pixel, sorts neighboring elements, picks the low_threshold and
+ * high_threshold pixel, computes a value, and stores it in the dst image */
+__kernel void
+bitonic_ordfilt (global const float *src, global float *dst, int num_elements,
+ int arrayLength, float low_threshold, float high_threshold,
+ __local float *s_key, unsigned idx_offset)
+{
+ // ascendent order
+ unsigned dir = 1;
+ unsigned block_idx = get_global_id(0) / get_local_size(0);
+ //Offset to the beginning of subbatch and load data
+ global const float *d_SrcKey = src + block_idx * num_elements;
+
+ s_key[get_local_id(0)] = d_SrcKey[get_local_id(0)];
+ unsigned next_index = get_local_id(0) + arrayLength / 2;
+
+ s_key[next_index] = next_index < num_elements ? d_SrcKey[next_index] : 0xFFFF;
+
+ for (int size = 2; size < arrayLength; size <<= 1) {
+ //Bitonic merge. ddd tells if ordering is ascendent or descendent
+ unsigned ddd = dir ^ ((get_local_id(0) & (size / 2)) != 0);
+
+ for (int stride = size / 2; stride > 0; stride >>= 1) {
+ barrier(CLK_LOCAL_MEM_FENCE);
+ unsigned pos = 2 * get_local_id(0) - (get_local_id(0) & (stride - 1));
+ compare_and_exchange (&s_key[pos], &s_key[pos + stride], ddd);
+ }
+ }
+
+ {
+ for (int stride = arrayLength / 2; stride > 0; stride >>= 1) {
+ barrier(CLK_LOCAL_MEM_FENCE);
+ unsigned pos = 2 * get_local_id(0) - (get_local_id(0) & (stride - 1));
+ compare_and_exchange (&s_key[pos], &s_key[pos + stride], dir);
+ }
+ }
+
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ if (get_local_id(0) == 0) {
+ float low_p = s_key[(int) (num_elements * low_threshold - 1)];
+ float high_p = s_key[(int) (num_elements * high_threshold - 1)];
+
+ unsigned global_idx = block_idx + idx_offset;
+ float intensity = (high_p + low_p) / 2.;
+ float contrast = high_p - low_p;
+ dst[global_idx] = intensity * (1 - contrast);
+ }
+}
+
+kernel void
+/* Load only elements that match the pattern */
+/* Dst is the size of image * number of ones found in pattern */
+load_elements_from_pattern (global float *src,
+ global float *dst,
+ global float *pattern,
+ int dimension,
+ int num_ones,
+ unsigned height,
+ unsigned y_offset)
+{
+ const int2 imsize = (int2) (get_global_size(0), height);
+ const int x = get_global_id(0);
+ const int y = get_global_id(1) + y_offset;
+ const int local_y = get_global_id(1);
+
+ unsigned short buffer[12];
+
+ int2 center;
+ get_center (dimension, dimension, &center);
+ /* Don't apply the offset for the dst buffer */
+ int offset = num_ones * (x + local_y * imsize.x);
+ global float* tmpDst = dst + offset;
+ for(int j = 0; j < dimension; ++j) {
+ for(int i = 0; i < dimension; ++i) {
+ if (pattern[i + j * dimension]) {
+ *tmpDst = src[get_pel_position (imsize, (int2)(i,j), (int2)(x, y), center)];
+ ++tmpDst;
+ }
+ }
+ }
+}
diff --git a/src/kernels/piv.cl b/src/kernels/piv.cl
new file mode 100644
index 0000000..3a744aa
--- /dev/null
+++ b/src/kernels/piv.cl
@@ -0,0 +1,48 @@
+void
+compare_and_exchange (local float *keyA, local float *keyB, unsigned dir)
+{
+ float t;
+
+ if ((*keyA > *keyB) == dir) {
+ t = *keyA;
+ *keyA = *keyB;
+ *keyB = t;
+ }
+}
+
+int
+get_position (int position, int size)
+{
+ int newPos = 0;
+
+ if (position < 0) {
+ ++position;
+ position *= (-1);
+ }
+
+ int divisor = (position / size);
+ return divisor % 2 ? position % size : size - 1 - (position % size);
+}
+
+void
+get_center (const unsigned width, const unsigned height, int2 *center)
+{
+ center->x = width % 2 == 0 ? width / 2 - 1 : width / 2;
+ center->y = height % 2 == 0 ? height / 2 - 1 : height / 2;
+}
+
+int
+get_pel_position (int2 imageDim, int2 filterPos, int2 pel, int2 center)
+{
+ int2 posInImage = (int2)(filterPos.x - center.x + pel.x, filterPos.y - center.y + pel.y);
+
+ if (posInImage.x < 0 || posInImage.x >= imageDim.x) {
+ posInImage.x = get_position (posInImage.x, imageDim.x);
+ }
+
+ if (posInImage.y < 0 || posInImage.y >= imageDim.y) {
+ posInImage.y = get_position (posInImage.y, imageDim.y);
+ }
+
+ return (posInImage.x + posInImage.y * imageDim.x);
+}
diff --git a/src/ufo-concatenate-result-task.c b/src/ufo-concatenate-result-task.c
new file mode 100644
index 0000000..43cb17b
--- /dev/null
+++ b/src/ufo-concatenate-result-task.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <stdlib.h> /* realloc */
+#include <string.h> /* memcpy */
+#include <assert.h>
+
+#include "ufo-concatenate-result-task.h"
+#include "ufo-ring-coordinates.h"
+
+
+struct _PivFileMetadata {
+ char *piv_file_name;
+ unsigned piv_file_idx;
+};
+
+typedef struct _PivFileMetadata PivFileMetadata;
+
+struct _UfoConcatenateResultTaskPrivate {
+ URCS **data;
+ PivFileMetadata *metadata;
+ unsigned alloc_size;
+ unsigned idx;
+ unsigned current_output_idx;
+ unsigned max_count;
+ unsigned ring_count;
+ unsigned img_alloc_size;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoConcatenateResultTask, ufo_concatenate_result_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_CONCATENATE_RESULT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_CONCATENATE_RESULT_TASK, UfoConcatenateResultTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_MAX_COUNT,
+ PROP_RING_COUNT,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_concatenate_result_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_CONCATENATE_RESULT_TASK, NULL));
+}
+
+static void
+ufo_concatenate_result_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_concatenate_result_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ requisition->n_dims = 1;
+ /* Output size varies according to number of inputs to merge, and data
+ * whithin the data */
+ /* I don't know the output size, I'll allocate it myself once I have
+ * processed the data */
+ requisition->dims[0] = 0;
+}
+
+static guint
+ufo_concatenate_result_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_concatenate_result_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_concatenate_result_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_REDUCTOR | UFO_TASK_MODE_CPU;
+}
+
+static void
+ufo_concatenate_get_metadata(UfoBuffer *src, const char **piv_file_name,
+ unsigned *piv_file_idx)
+{
+ GValue *value;
+
+ value = ufo_buffer_get_metadata(src, "piv_file_name");
+ *piv_file_name = g_value_get_string(value);
+
+ value = ufo_buffer_get_metadata(src, "piv_file_idx");
+ *piv_file_idx = g_value_get_uint(value);
+}
+
+static void
+initialize_field(UfoConcatenateResultTaskPrivate *priv, const char *piv_file_name,
+ unsigned piv_file_idx)
+{
+ priv->idx = 0;
+ priv->alloc_size = 16;
+ priv->data[piv_file_idx] = g_malloc (16 * sizeof (UfoRingCoordinate) +
+ sizeof (float));
+ priv->data[piv_file_idx]->nb_elt = 0;
+ priv->metadata[piv_file_idx].piv_file_idx = piv_file_idx;
+ priv->metadata[piv_file_idx].piv_file_name = g_strdup (piv_file_name);
+}
+
+static void
+increase_buffer_size(UfoConcatenateResultTaskPrivate *priv)
+{
+ priv->img_alloc_size *= 2;
+ priv->data = g_realloc (priv->data, sizeof (URCS *) * priv->img_alloc_size);
+ priv->metadata = g_realloc (priv->metadata, sizeof (PivFileMetadata) * priv->img_alloc_size);
+
+ // Make sure that we inform that the newly allocated image buffer do not
+ // have any data yet.
+ for (unsigned i = priv->img_alloc_size / 2; i < priv->img_alloc_size; ++i) {
+ priv->data[i] = NULL;
+ priv->metadata[i].piv_file_idx = (unsigned) -1;
+ priv->metadata[i].piv_file_name = NULL;
+ }
+}
+
+static gboolean
+ufo_concatenate_result_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ const char *piv_file_name;
+ unsigned piv_file_idx;
+ UfoConcatenateResultTaskPrivate *priv;
+
+ priv = UFO_CONCATENATE_RESULT_TASK_GET_PRIVATE (task);
+ ufo_concatenate_get_metadata (inputs[0], &piv_file_name, &piv_file_idx);
+ assert(priv->ring_count && "Ring count must be set\n");
+ // Check if buffer needs to be increased to be able to store more images.
+
+ if (piv_file_idx >= priv->img_alloc_size)
+ increase_buffer_size (priv);
+
+ if (priv->data[piv_file_idx] == NULL)
+ initialize_field (priv, piv_file_name, piv_file_idx);
+
+ float *input = ufo_buffer_get_host_array (inputs[0], NULL);
+ unsigned nb_coord = (unsigned) *input;
+ UfoRingCoordinate *coord = (UfoRingCoordinate *) (input + 1);
+
+ if (nb_coord > priv->max_count) {
+ g_print("Concatenate: max_count : Ignoring radius %f. %u rings found, "
+ "maximum is %u\n", coord[0].r, nb_coord, priv->max_count);
+ return TRUE;
+ }
+
+ if (priv->idx + nb_coord > priv->alloc_size) {
+ priv->alloc_size += nb_coord;
+ priv->data[piv_file_idx] = g_realloc (priv->data[piv_file_idx], sizeof (UfoRingCoordinate) * priv->alloc_size + sizeof (float));
+ }
+
+ for (unsigned i = 0; i < nb_coord; ++i)
+ priv->data[piv_file_idx]->coord[priv->idx++] = coord[i];
+
+ priv->data[piv_file_idx]->nb_elt += (float) nb_coord;
+
+ return TRUE;
+}
+
+static unsigned
+find_next_idx_for_output (UfoConcatenateResultTaskPrivate *priv)
+{
+ unsigned res = priv->current_output_idx;
+
+ while (res < priv->img_alloc_size && priv->data[res] == NULL)
+ ++res;
+
+ return res;
+}
+
+static void
+attach_output_metadata (UfoBuffer *output, PivFileMetadata *meta)
+{
+ GValue value_uint = G_VALUE_INIT;
+ GValue value_string = G_VALUE_INIT;
+
+ g_value_init (&value_uint, G_TYPE_UINT);
+ g_value_set_uint (&value_uint, meta->piv_file_idx);
+ ufo_buffer_set_metadata (output, "piv_file_idx", &value_uint);
+
+ g_value_init (&value_string, G_TYPE_STRING);
+ g_value_set_string (&value_string, meta->piv_file_name);
+ ufo_buffer_set_metadata(output, "piv_file_name", &value_string);
+}
+
+static gboolean
+ufo_concatenate_result_task_generate (UfoTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoConcatenateResultTaskPrivate *priv = UFO_CONCATENATE_RESULT_TASK_GET_PRIVATE (task);
+ priv->current_output_idx = find_next_idx_for_output (priv);
+
+ if (priv->current_output_idx >= priv->img_alloc_size)
+ return FALSE;
+
+ unsigned ring_idx = priv->current_output_idx;
+ attach_output_metadata (output, &priv->metadata[ring_idx]);
+ URCS *rings = priv->data[ring_idx];
+ /* There will be at most idx elements */
+ UfoRequisition new_req = {
+ .dims[0] = 1 + (unsigned) rings->nb_elt * sizeof (UfoRingCoordinate) / sizeof (float),
+ .n_dims = 1,
+ };
+ ufo_buffer_resize (output, &new_req);
+ float *res = ufo_buffer_get_host_array (output, NULL);
+ memcpy (res, rings, (unsigned) (rings->nb_elt) * sizeof (UfoRingCoordinate) + sizeof (float));
+ ++priv->current_output_idx;
+ return TRUE;
+}
+
+static void
+ufo_concatenate_result_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoConcatenateResultTaskPrivate *priv = UFO_CONCATENATE_RESULT_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_MAX_COUNT:
+ priv->max_count = g_value_get_uint (value);
+ break;
+
+ case PROP_RING_COUNT:
+ if (priv->data != NULL)
+ g_free (priv->data);
+
+ if (priv->metadata != NULL)
+ g_free (priv->metadata);
+
+ priv->ring_count = g_value_get_uint (value);
+ priv->data = g_malloc (sizeof (URCS *) * priv->ring_count);
+ priv->metadata = g_malloc (sizeof (PivFileMetadata) * priv->ring_count);
+ priv->img_alloc_size = priv->ring_count;
+
+ for (unsigned i = 0; i < priv->ring_count; ++i) {
+ priv->data[i] = NULL;
+ priv->metadata[i].piv_file_idx = (unsigned) -1;
+ priv->metadata[i].piv_file_name = NULL;
+ }
+
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_concatenate_result_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoConcatenateResultTaskPrivate *priv = UFO_CONCATENATE_RESULT_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_MAX_COUNT:
+ g_value_set_uint (value, priv->max_count);
+ break;
+
+ case PROP_RING_COUNT:
+ g_value_set_uint (value, priv->ring_count);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_concatenate_result_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_concatenate_result_task_parent_class)->finalize (object);
+ UfoConcatenateResultTaskPrivate *priv = UFO_CONCATENATE_RESULT_TASK_GET_PRIVATE (object);
+
+ for (unsigned i = 0; i < priv->img_alloc_size; ++i) {
+ if (priv->data[i])
+ g_free (priv->data[i]);
+
+ if (priv->metadata[i].piv_file_name)
+ g_free (priv->metadata[i].piv_file_name);
+ }
+
+ g_free (priv->data);
+ g_free (priv->metadata);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_concatenate_result_task_setup;
+ iface->get_num_inputs = ufo_concatenate_result_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_concatenate_result_task_get_num_dimensions;
+ iface->get_mode = ufo_concatenate_result_task_get_mode;
+ iface->get_requisition = ufo_concatenate_result_task_get_requisition;
+ iface->process = ufo_concatenate_result_task_process;
+ iface->generate = ufo_concatenate_result_task_generate;
+}
+
+static void
+ufo_concatenate_result_task_class_init (UfoConcatenateResultTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_concatenate_result_task_set_property;
+ gobject_class->get_property = ufo_concatenate_result_task_get_property;
+ gobject_class->finalize = ufo_concatenate_result_task_finalize;
+
+ properties[PROP_MAX_COUNT] =
+ g_param_spec_uint ("max_count",
+ "The maximum number of rings desired per ring pattern",
+ "The maximum number of rings desired per ring pattern",
+ 1, G_MAXUINT, 60,
+ G_PARAM_READWRITE);
+
+ properties[PROP_RING_COUNT] =
+ g_param_spec_uint ("ring_count",
+ "The number of ring pattern generated per image",
+ "The maximum number of rings desired per ring pattern",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoConcatenateResultTaskPrivate));
+}
+
+static void
+ufo_concatenate_result_task_init(UfoConcatenateResultTask *self)
+{
+ self->priv = UFO_CONCATENATE_RESULT_TASK_GET_PRIVATE(self);
+ self->priv->idx = 0;
+ self->priv->alloc_size = 0;
+ self->priv->data = NULL;
+ self->priv->metadata = NULL;
+ self->priv->max_count = 60;
+ self->priv->ring_count = 0;
+ self->priv->img_alloc_size = 0;
+ self->priv->current_output_idx = 0;
+}
diff --git a/src/ufo-concatenate-result-task.h b/src/ufo-concatenate-result-task.h
new file mode 100644
index 0000000..6774743
--- /dev/null
+++ b/src/ufo-concatenate-result-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_CONCATENATE_RESULT_TASK_H
+#define __UFO_CONCATENATE_RESULT_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_CONCATENATE_RESULT_TASK (ufo_concatenate_result_task_get_type())
+#define UFO_CONCATENATE_RESULT_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_CONCATENATE_RESULT_TASK, UfoConcatenateResultTask))
+#define UFO_IS_CONCATENATE_RESULT_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_CONCATENATE_RESULT_TASK))
+#define UFO_CONCATENATE_RESULT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_CONCATENATE_RESULT_TASK, UfoConcatenateResultTaskClass))
+#define UFO_IS_CONCATENATE_RESULT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_CONCATENATE_RESULT_TASK))
+#define UFO_CONCATENATE_RESULT_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_CONCATENATE_RESULT_TASK, UfoConcatenateResultTaskClass))
+
+typedef struct _UfoConcatenateResultTask UfoConcatenateResultTask;
+typedef struct _UfoConcatenateResultTaskClass UfoConcatenateResultTaskClass;
+typedef struct _UfoConcatenateResultTaskPrivate UfoConcatenateResultTaskPrivate;
+
+/**
+ * UfoConcatenateResultTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoConcatenateResultTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoConcatenateResultTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoConcatenateResultTaskPrivate *priv;
+};
+
+/**
+ * UfoConcatenateResultTaskClass:
+ *
+ * #UfoConcatenateResultTask class
+ */
+struct _UfoConcatenateResultTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_concatenate_result_task_new (void);
+GType ufo_concatenate_result_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-contrast-task.c b/src/ufo-contrast-task.c
new file mode 100644
index 0000000..b8f5b2b
--- /dev/null
+++ b/src/ufo-contrast-task.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "ufo-contrast-task.h"
+
+struct _UfoContrastTaskPrivate {
+ gboolean remove_high;
+};
+
+typedef struct _UfoHistogram {
+ float max;
+ float min;
+ double median;
+ unsigned num_bins;
+ /* value of pic in histogram */
+ double pic;
+ double step;
+ /* array of bins if num_bins size */
+ unsigned *bins;
+} UfoHistogram;
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoContrastTask, ufo_contrast_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_CONTRAST_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_CONTRAST_TASK, UfoContrastTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_REMOVE_HIGH,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_contrast_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_CONTRAST_TASK, NULL));
+}
+
+static void
+ufo_contrast_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_contrast_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition(inputs[0], requisition);
+}
+
+static guint
+ufo_contrast_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_contrast_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_contrast_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_CPU;
+}
+
+static UfoHistogram *
+new_histogram(UfoBuffer *ufo_input)
+{
+ UfoRequisition input_req;
+ ufo_buffer_get_requisition(ufo_input, &input_req);
+ double num_elt = (double) input_req.dims[0] * (double) input_req.dims[1];
+ unsigned num_bins = (unsigned) sqrt(num_elt);
+ float *input = ufo_buffer_get_host_array(ufo_input, NULL);
+
+ UfoHistogram *res;
+
+ res = g_new0 (UfoHistogram, 1);
+ res->bins = g_new0 (unsigned, num_bins);
+ res->num_bins = num_bins;
+ res->min = input[0];
+ res->max = input[0];
+
+ /* Compute max and min element */
+ for (unsigned j = 0; j < input_req.dims[1]; ++j) {
+ for (unsigned i = 0; i < input_req.dims[0]; ++i) {
+ if (res->max < input[i + j * input_req.dims[0]])
+ res->max = input[i + j * input_req.dims[0]];
+
+ if (res->min > input[i + j * input_req.dims[0]])
+ res->min = input[i + j * input_req.dims[0]];
+ }
+ }
+
+ /* Compute histogram */
+ res->step = (double) (res->max - res->min) / (num_bins - 1);
+
+ for (unsigned j = 0; j < input_req.dims[1]; ++j) {
+ for (unsigned i = 0; i < input_req.dims[0]; ++i) {
+ unsigned idx = (unsigned) round((input[i + j * input_req.dims[0]] - res->min) / res->step);
+ ++res->bins[idx];
+ }
+ }
+
+ /* Compute median and pic value */
+ unsigned nb_elt_seen = 0;
+ unsigned max_elt_count_idx = 0;
+
+ for (unsigned i = 0; i < num_bins; ++i) {
+ nb_elt_seen += res->bins[i];
+
+ /* Once median value is set, don't set it again */
+ if (res->median == 0 &&
+ nb_elt_seen >= (input_req.dims[0] * input_req.dims[1]) / 2)
+ res->median = i * res->step + res->min;
+
+ if (res->bins[max_elt_count_idx] < res->bins[i])
+ max_elt_count_idx = i;
+ }
+
+ res->pic = max_elt_count_idx * res->step + res->min;
+ return res;
+}
+
+/* search [start, end[ interval, return index with highest value */
+static double
+histogram_get_pic (UfoHistogram *histogram, unsigned start, unsigned end)
+{
+ unsigned res = start;
+
+ for (unsigned i = start + 1; i < end; ++i) {
+ if (histogram->bins[i] > histogram->bins[res])
+ res = i;
+ }
+
+ return res * histogram->step + histogram->min;
+}
+
+/* Rescale image from low -> high to 0 -> 1 values and enhance constrast by
+ * gamma. Gamma == 1 makes a linear mapping. gamma < 1 produces brighter image.
+ * gamma > 1 produces darker image */
+static void
+imadjust (UfoBuffer *ufo_src, UfoBuffer *ufo_dst, double low, double high,
+ double gamma, float new_high)
+{
+ UfoRequisition req;
+ ufo_buffer_get_requisition (ufo_src, &req);
+ float *src = ufo_buffer_get_host_array(ufo_src, NULL);
+ float *dst = ufo_buffer_get_host_array(ufo_dst, NULL);
+
+ for (unsigned j = 0; j < req.dims[1]; ++j) {
+ for (unsigned i = 0; i < req.dims[0]; ++i) {
+ if (src[i + j * req.dims[0]] >= high)
+ dst[i + j * req.dims[0]] = new_high;
+ else if (src[i + j * req.dims[0]] <= low)
+ dst[i + j * req.dims[0]] = 0.0;
+ else {
+ double normalized = (src[i + j * req.dims[0]] - low) / (double) (high - low);
+ double val = pow(normalized, gamma);
+ dst[i + j * req.dims[0]] = (float) val;
+ }
+ }
+ }
+}
+
+static gboolean
+ufo_contrast_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoContrastTaskPrivate *priv = UFO_CONTRAST_TASK_GET_PRIVATE (task);
+ UfoRequisition input_req;
+ ufo_buffer_get_requisition (inputs[0], &input_req);
+ UfoHistogram *histogram = new_histogram (inputs[0]);
+ /* gamma < 1 to make image more bright and enhance contrast */
+ double gamma = 0.3;
+
+ /* Remove values under pic, enhance contrast and normalize image */
+ double pic = histogram_get_pic(histogram, 1, histogram->num_bins - 1);
+
+ /* Remove high pixels of output */
+ if (priv->remove_high) {
+ double crop_max = histogram->max - (histogram->max - pic) / 2;
+ imadjust (inputs[0], output, pic, crop_max, gamma, 0.0);
+ }
+ else {
+ /* transpose image from [pic, 1] to [0, 1] */
+ imadjust (inputs[0], output, pic, histogram->max, gamma, 1.0);
+ }
+
+ g_free (histogram->bins);
+ g_free (histogram);
+ return TRUE;
+}
+
+static void
+ufo_contrast_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoContrastTaskPrivate *priv = UFO_CONTRAST_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_REMOVE_HIGH:
+ priv->remove_high = g_value_get_boolean(value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_contrast_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoContrastTaskPrivate *priv = UFO_CONTRAST_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_REMOVE_HIGH:
+ g_value_set_boolean(value, priv->remove_high);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_contrast_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_contrast_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_contrast_task_setup;
+ iface->get_num_inputs = ufo_contrast_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_contrast_task_get_num_dimensions;
+ iface->get_mode = ufo_contrast_task_get_mode;
+ iface->get_requisition = ufo_contrast_task_get_requisition;
+ iface->process = ufo_contrast_task_process;
+}
+
+static void
+ufo_contrast_task_class_init (UfoContrastTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_contrast_task_set_property;
+ gobject_class->get_property = ufo_contrast_task_get_property;
+ gobject_class->finalize = ufo_contrast_task_finalize;
+
+ properties[PROP_REMOVE_HIGH] =
+ g_param_spec_boolean ("remove_high",
+ "Tells whether or not to set high intensity pixels to 0",
+ "Tells whether or not to set high intensity pixels to 0",
+ 0,
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoContrastTaskPrivate));
+}
+
+static void
+ufo_contrast_task_init(UfoContrastTask *self)
+{
+ self->priv = UFO_CONTRAST_TASK_GET_PRIVATE(self);
+ self->priv->remove_high = 0;
+}
diff --git a/src/ufo-contrast-task.h b/src/ufo-contrast-task.h
new file mode 100644
index 0000000..f03907d
--- /dev/null
+++ b/src/ufo-contrast-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_CONTRAST_TASK_H
+#define __UFO_CONTRAST_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_CONTRAST_TASK (ufo_contrast_task_get_type())
+#define UFO_CONTRAST_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_CONTRAST_TASK, UfoContrastTask))
+#define UFO_IS_CONTRAST_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_CONTRAST_TASK))
+#define UFO_CONTRAST_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_CONTRAST_TASK, UfoContrastTaskClass))
+#define UFO_IS_CONTRAST_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_CONTRAST_TASK))
+#define UFO_CONTRAST_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_CONTRAST_TASK, UfoContrastTaskClass))
+
+typedef struct _UfoContrastTask UfoContrastTask;
+typedef struct _UfoContrastTaskClass UfoContrastTaskClass;
+typedef struct _UfoContrastTaskPrivate UfoContrastTaskPrivate;
+
+/**
+ * UfoContrastTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoContrastTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoContrastTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoContrastTaskPrivate *priv;
+};
+
+/**
+ * UfoContrastTaskClass:
+ *
+ * #UfoContrastTask class
+ */
+struct _UfoContrastTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_contrast_task_new (void);
+GType ufo_contrast_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-denoise-task.c b/src/ufo-denoise-task.c
new file mode 100644
index 0000000..1157d14
--- /dev/null
+++ b/src/ufo-denoise-task.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include <math.h>
+#include "ufo-denoise-task.h"
+#include "ufo-priv.h"
+
+
+struct _UfoDenoiseTaskPrivate {
+ cl_kernel k_sort_and_set;
+ cl_kernel k_load_elements;
+ cl_kernel k_remove_background;
+ unsigned matrix_size;
+ gpointer context;
+ UfoResources *resources;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoDenoiseTask, ufo_denoise_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_DENOISE_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_DENOISE_TASK, UfoDenoiseTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_MATRIX_SIZE,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_denoise_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_DENOISE_TASK, NULL));
+}
+
+static void
+ufo_denoise_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+ UfoDenoiseTaskPrivate *priv;
+
+ priv = UFO_DENOISE_TASK_GET_PRIVATE (task);
+ priv->context = ufo_resources_get_context (resources);
+ priv->resources = resources;
+
+ priv->k_sort_and_set = ufo_resources_get_kernel (resources, "denoise.cl", "sort_and_set", error);
+
+ if (priv->k_sort_and_set != NULL)
+ UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->k_sort_and_set));
+
+ priv->k_load_elements = ufo_resources_get_kernel (resources, "denoise.cl", "load_elements", error);
+
+ if (priv->k_load_elements != NULL)
+ UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->k_load_elements));
+
+ priv->k_remove_background = ufo_resources_get_kernel (resources, "denoise.cl", "remove_background", error);
+
+ if (priv->k_remove_background != NULL)
+ UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->k_remove_background));
+}
+
+static void
+ufo_denoise_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition (inputs[0], requisition);
+}
+
+static guint
+ufo_denoise_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_denoise_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_denoise_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_GPU;
+}
+
+static void
+launch_kernel_1D(cl_kernel kernel, UfoBuffer *ufo_src, UfoBuffer *ufo_dst,
+ cl_command_queue cmd_queue, size_t dimension)
+{
+ cl_mem dst;
+ cl_mem src;
+ UfoRequisition requisition;
+ size_t global_work_size[1];
+ size_t local_work_size[1];
+
+ dst = ufo_buffer_get_device_array(ufo_dst, cmd_queue);
+ src = ufo_buffer_get_device_array(ufo_src, cmd_queue);
+
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof (cl_mem),
+ &src));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof (cl_mem),
+ &dst));
+ size_t num_elements = dimension * dimension;
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 2, sizeof (cl_int),
+ &num_elements));
+ /* Power of 2 above dimension * dimension */
+ size_t array_length = (size_t) ceil_power_of_two (dimension * dimension);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 3, sizeof (cl_int),
+ &array_length));
+ float threshold = (float) 0.3;
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 4, sizeof (cl_float),
+ &threshold));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 5, sizeof (cl_float) *
+ array_length, NULL));
+
+ /* Launch the kernel over 1D grid */
+ ufo_buffer_get_requisition(ufo_src, &requisition);
+ global_work_size[0] = requisition.dims[0] * requisition.dims[1] *
+ (array_length / 2);
+ /* Power of two below number of elements to sort */
+ local_work_size[0] = array_length / 2;
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (cmd_queue,
+ kernel,
+ 1, NULL, global_work_size,
+ local_work_size,
+ 0, NULL, NULL));
+}
+
+static void
+get_max_work_group_size (UfoResources *resources, size_t *x_worker_count,
+ size_t * y_worker_count)
+{
+ *x_worker_count = ULLONG_MAX;
+ GList *devices = ufo_resources_get_devices (resources);
+ GList *it;
+ g_list_for (devices, it) {
+ cl_device_id device = (cl_device_id) it->data;
+ size_t byte_count = 0;
+ size_t max_group_size = 0;
+ clGetDeviceInfo (device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof (size_t),
+ &max_group_size, &byte_count);
+ g_assert (sizeof (size_t) == byte_count);
+ if (max_group_size < *x_worker_count)
+ *x_worker_count = max_group_size;
+ }
+ *x_worker_count = (unsigned) sqrtf((float)*x_worker_count);
+ *y_worker_count = *x_worker_count;
+}
+
+static void
+launch_kernel_2D(UfoDenoiseTaskPrivate *priv,
+ cl_kernel kernel, UfoBuffer *ufo_src, UfoBuffer *ufo_dst,
+ cl_command_queue cmd_queue, size_t dimension)
+{
+ cl_mem dst;
+ cl_mem src;
+ UfoRequisition requisition;
+ size_t global_work_size[2];
+ size_t local_work_size[2];
+ dst = ufo_buffer_get_device_array(ufo_dst, cmd_queue);
+ src = ufo_buffer_get_device_array(ufo_src, cmd_queue);
+
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof (cl_mem),
+ &src));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof (cl_mem),
+ &dst));
+ if (dimension)
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 2, sizeof (cl_int),
+ &dimension));
+
+ ufo_buffer_get_requisition(ufo_src, &requisition);
+ global_work_size[0] = requisition.dims[0];
+ global_work_size[1] = requisition.dims[1];
+ size_t y_worker_count, x_worker_count;
+ get_max_work_group_size(priv->resources, &x_worker_count, &y_worker_count);
+
+ while (global_work_size[1] % y_worker_count)
+ --y_worker_count;
+
+ while (global_work_size[0] % x_worker_count)
+ --x_worker_count;
+
+ local_work_size[0] = x_worker_count; /* Multiple of image_width=1080 */
+ local_work_size[1] = y_worker_count; /* Multiple of image_height=1280 */
+ /* Launch the kernel over 1D grid */
+ local_work_size[0] = x_worker_count; /* Multiple of image_width=1080 */
+ local_work_size[1] = y_worker_count; /* Multiple of image_height=1280 */
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (cmd_queue,
+ kernel,
+ 2, NULL, global_work_size,
+ local_work_size,
+ 0, NULL, NULL));
+}
+
+static void
+get_background_image (UfoDenoiseTaskPrivate *priv, UfoBuffer *src, UfoBuffer *dst,
+ cl_command_queue cmd_queue)
+{
+ size_t dimension = priv->matrix_size;
+ UfoRequisition image_requisition;
+ ufo_buffer_get_requisition(src, &image_requisition);
+ UfoRequisition requisition = {
+ .n_dims = 3,
+ .dims[0] = image_requisition.dims[0],
+ .dims[1] = image_requisition.dims[1],
+ .dims[2] = dimension * dimension,
+ };
+ UfoBuffer *ufo_buffer = ufo_buffer_new(&requisition, priv->context);
+
+ /* loads surrounding dimension * dimension pixels of each pixel in image.
+ * Result in buffer */
+ launch_kernel_2D (priv, priv->k_load_elements, src, ufo_buffer, cmd_queue, dimension);
+
+ /* Create background image using sorted neigbhooring pixels */
+ launch_kernel_1D (priv->k_sort_and_set, ufo_buffer, dst, cmd_queue, dimension);
+
+ g_object_unref(ufo_buffer);
+}
+
+static gboolean
+ufo_denoise_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoDenoiseTaskPrivate *priv;
+ UfoGpuNode *node;
+ cl_command_queue cmd_queue;
+
+ priv = UFO_DENOISE_TASK_GET_PRIVATE (task);
+ node = UFO_GPU_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (task)));
+ cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+
+ get_background_image (priv, inputs[0], output, cmd_queue);
+ launch_kernel_2D (priv, priv->k_remove_background, inputs[0], output, cmd_queue, 0);
+ return TRUE;
+}
+
+static void
+ufo_denoise_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoDenoiseTaskPrivate *priv = UFO_DENOISE_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_MATRIX_SIZE:
+ priv->matrix_size = g_value_get_uint(value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_denoise_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoDenoiseTaskPrivate *priv = UFO_DENOISE_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_MATRIX_SIZE:
+ g_value_set_uint (value, priv->matrix_size);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_denoise_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_denoise_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_denoise_task_setup;
+ iface->get_num_inputs = ufo_denoise_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_denoise_task_get_num_dimensions;
+ iface->get_mode = ufo_denoise_task_get_mode;
+ iface->get_requisition = ufo_denoise_task_get_requisition;
+ iface->process = ufo_denoise_task_process;
+}
+
+static void
+ufo_denoise_task_class_init (UfoDenoiseTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_denoise_task_set_property;
+ gobject_class->get_property = ufo_denoise_task_get_property;
+ gobject_class->finalize = ufo_denoise_task_finalize;
+
+ properties[PROP_MATRIX_SIZE] =
+ g_param_spec_uint ("matrix_size",
+ "determines the number of surrounding pixels to be compared with",
+ "determines the number of surrounding pixels to be compared with",
+ 1, G_MAXUINT, 13,
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoDenoiseTaskPrivate));
+}
+
+static void
+ufo_denoise_task_init(UfoDenoiseTask *self)
+{
+ self->priv = UFO_DENOISE_TASK_GET_PRIVATE(self);
+ self->priv->context = NULL;
+ self->priv->matrix_size = 13;
+ self->priv->k_sort_and_set = NULL;
+ self->priv->k_load_elements = NULL;
+ self->priv->k_remove_background = NULL;
+}
diff --git a/src/ufo-denoise-task.h b/src/ufo-denoise-task.h
new file mode 100644
index 0000000..6410599
--- /dev/null
+++ b/src/ufo-denoise-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_DENOISE_TASK_H
+#define __UFO_DENOISE_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_DENOISE_TASK (ufo_denoise_task_get_type())
+#define UFO_DENOISE_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_DENOISE_TASK, UfoDenoiseTask))
+#define UFO_IS_DENOISE_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_DENOISE_TASK))
+#define UFO_DENOISE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_DENOISE_TASK, UfoDenoiseTaskClass))
+#define UFO_IS_DENOISE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_DENOISE_TASK))
+#define UFO_DENOISE_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_DENOISE_TASK, UfoDenoiseTaskClass))
+
+typedef struct _UfoDenoiseTask UfoDenoiseTask;
+typedef struct _UfoDenoiseTaskClass UfoDenoiseTaskClass;
+typedef struct _UfoDenoiseTaskPrivate UfoDenoiseTaskPrivate;
+
+/**
+ * UfoDenoiseTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoDenoiseTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoDenoiseTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoDenoiseTaskPrivate *priv;
+};
+
+/**
+ * UfoDenoiseTaskClass:
+ *
+ * #UfoDenoiseTask class
+ */
+struct _UfoDenoiseTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_denoise_task_new (void);
+GType ufo_denoise_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ufo-dump-ring-task.c b/src/ufo-dump-ring-task.c
new file mode 100644
index 0000000..582a783
--- /dev/null
+++ b/src/ufo-dump-ring-task.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <math.h>
+
+#include "ufo-dump-ring-task.h"
+#include "ufo-ring-coordinates.h"
+#include "ufo-priv.h"
+
+struct _UfoDumpRingTaskPrivate {
+ unsigned scale;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoDumpRingTask, ufo_dump_ring_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_DUMP_RING_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_DUMP_RING_TASK, UfoDumpRingTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_SCALE,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_dump_ring_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_DUMP_RING_TASK, NULL));
+}
+
+static void
+ufo_dump_ring_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_dump_ring_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition(inputs[0], requisition);
+}
+
+static guint
+ufo_dump_ring_task_get_num_inputs (UfoTask *task)
+{
+ return 2;
+}
+
+static guint
+ufo_dump_ring_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ if (input == 0)
+ /* First input is source image */
+ return 2;
+ else
+ /* Second input is coordinates array */
+ return 1;
+}
+
+static UfoTaskMode
+ufo_dump_ring_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_CPU;
+}
+
+static void
+copy_image_and_get_max (UfoBuffer *ufo_img, UfoBuffer *ufo_dst, float *max)
+{
+ float *img = ufo_buffer_get_host_array (ufo_img, NULL);
+ float *dst = ufo_buffer_get_host_array (ufo_dst, NULL);
+ *max = img[0];
+ UfoRequisition req;
+ ufo_buffer_get_requisition (ufo_img, &req);
+
+ for (size_t y = 0; y < req.dims[1]; ++y) {
+ for (size_t x = 0; x < req.dims[0]; ++x) {
+ float value = img[y * req.dims[0] + x];
+ dst[y * req.dims[0] + x] = value;
+ *max = *max < value ? value : *max;
+ }
+ }
+}
+
+static void
+dump_circles (UfoDumpRingTaskPrivate *priv, UfoBuffer *ufo_rings,
+ UfoBuffer *ufo_dst, float max)
+{
+ if (max > 100)
+ max += 100;
+ else
+ max *= 2;
+
+ float *rings = ufo_buffer_get_host_array (ufo_rings, NULL);
+ float *dst = ufo_buffer_get_host_array (ufo_dst, NULL);
+ unsigned nb_rings = (unsigned) *rings;
+ UfoRequisition req;
+ ufo_buffer_get_requisition (ufo_dst, &req);
+ UfoRingCoordinate *coord = (UfoRingCoordinate *) (rings + 1);
+
+ for (unsigned i = 0; i < nb_rings; ++i) {
+ float x = roundf (coord[i].x * (float) priv->scale);
+ float y = roundf (coord[i].y * (float) priv->scale);
+ float r = roundf (coord[i].r * (float) priv->scale);
+
+ for (float t = 0; t < 2 * G_PI; t += (float) 0.005) {
+ int x2 = (int) round (r * cos (t) + x);
+ int y2 = (int) round (r * sin (t) + y);
+ if (x2 >= 0 && x2 < (int) req.dims[0] && y2 >=0 && y2 < (int) req.dims[1]) {
+ unsigned idx = (unsigned) ((unsigned) x2 + (unsigned) y2 * req.dims[0]);
+ dst[idx] = max;
+ }
+ }
+ }
+}
+
+static gboolean
+ufo_dump_ring_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ float max;
+ copy_image_and_get_max (inputs[0], output, &max);
+ UfoDumpRingTaskPrivate *priv = UFO_DUMP_RING_TASK_GET_PRIVATE (task);
+ /* use max_value for drawing circles */
+ dump_circles (priv, inputs[1], output, max);
+ return TRUE;
+}
+
+static void
+ufo_dump_ring_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoDumpRingTaskPrivate *priv = UFO_DUMP_RING_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_SCALE:
+ priv->scale = g_value_get_uint(value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_dump_ring_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoDumpRingTaskPrivate *priv = UFO_DUMP_RING_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_SCALE:
+ g_value_set_uint (value, priv->scale);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_dump_ring_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_dump_ring_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_dump_ring_task_setup;
+ iface->get_num_inputs = ufo_dump_ring_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_dump_ring_task_get_num_dimensions;
+ iface->get_mode = ufo_dump_ring_task_get_mode;
+ iface->get_requisition = ufo_dump_ring_task_get_requisition;
+ iface->process = ufo_dump_ring_task_process;
+}
+
+static void
+ufo_dump_ring_task_class_init (UfoDumpRingTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_dump_ring_task_set_property;
+ gobject_class->get_property = ufo_dump_ring_task_get_property;
+ gobject_class->finalize = ufo_dump_ring_task_finalize;
+
+ properties[PROP_SCALE] =
+ g_param_spec_uint ("scale",
+ "Says by how much rings should be increased",
+ "Says by how much rings should be increased",
+ 1, G_MAXUINT, 1,
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoDumpRingTaskPrivate));
+}
+
+static void
+ufo_dump_ring_task_init(UfoDumpRingTask *self)
+{
+ self->priv = UFO_DUMP_RING_TASK_GET_PRIVATE(self);
+ self->priv->scale = 1;
+}
diff --git a/src/ufo-dump-ring-task.h b/src/ufo-dump-ring-task.h
new file mode 100644
index 0000000..e1c203d
--- /dev/null
+++ b/src/ufo-dump-ring-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_DUMP_RING_TASK_H
+#define __UFO_DUMP_RING_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_DUMP_RING_TASK (ufo_dump_ring_task_get_type())
+#define UFO_DUMP_RING_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_DUMP_RING_TASK, UfoDumpRingTask))
+#define UFO_IS_DUMP_RING_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_DUMP_RING_TASK))
+#define UFO_DUMP_RING_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_DUMP_RING_TASK, UfoDumpRingTaskClass))
+#define UFO_IS_DUMP_RING_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_DUMP_RING_TASK))
+#define UFO_DUMP_RING_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_DUMP_RING_TASK, UfoDumpRingTaskClass))
+
+typedef struct _UfoDumpRingTask UfoDumpRingTask;
+typedef struct _UfoDumpRingTaskClass UfoDumpRingTaskClass;
+typedef struct _UfoDumpRingTaskPrivate UfoDumpRingTaskPrivate;
+
+/**
+ * UfoDumpRingTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoDumpRingTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoDumpRingTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoDumpRingTaskPrivate *priv;
+};
+
+/**
+ * UfoDumpRingTaskClass:
+ *
+ * #UfoDumpRingTask class
+ */
+struct _UfoDumpRingTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_dump_ring_task_new (void);
+GType ufo_dump_ring_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-duplicate-task.c b/src/ufo-duplicate-task.c
new file mode 100644
index 0000000..3541a90
--- /dev/null
+++ b/src/ufo-duplicate-task.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <stdlib.h>
+#include "ufo-duplicate-task.h"
+
+
+struct _UfoDuplicateTaskPrivate {
+ unsigned alloc_size;
+ unsigned idx;
+ UfoBuffer *data;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoDuplicateTask, ufo_duplicate_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_DUPLICATE_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_DUPLICATE_TASK, UfoDuplicateTaskPrivate))
+
+UfoNode *
+ufo_duplicate_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_DUPLICATE_TASK, NULL));
+}
+
+static void
+ufo_duplicate_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_duplicate_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition(inputs[0], requisition);
+}
+
+static guint
+ufo_duplicate_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_duplicate_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_duplicate_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_REDUCTOR;
+}
+
+static gboolean
+ufo_duplicate_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoDuplicateTaskPrivate *priv = UFO_DUPLICATE_TASK_GET_PRIVATE (task);
+
+ if (priv->idx > priv->alloc_size) {
+ priv->alloc_size *= 2;
+ size_t nb_bytes = priv->alloc_size * sizeof (UfoBuffer *);
+ priv->data = realloc (priv->data, nb_bytes);
+ }
+ return TRUE;
+}
+
+static void
+ufo_duplicate_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_duplicate_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_duplicate_task_setup;
+ iface->get_num_inputs = ufo_duplicate_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_duplicate_task_get_num_dimensions;
+ iface->get_mode = ufo_duplicate_task_get_mode;
+ iface->get_requisition = ufo_duplicate_task_get_requisition;
+ iface->process = ufo_duplicate_task_process;
+}
+
+static void
+ufo_duplicate_task_class_init (UfoDuplicateTaskClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->finalize = ufo_duplicate_task_finalize;
+
+ g_type_class_add_private (oclass, sizeof(UfoDuplicateTaskPrivate));
+}
+
+static void
+ufo_duplicate_task_init(UfoDuplicateTask *self)
+{
+ self->priv = UFO_DUPLICATE_TASK_GET_PRIVATE(self);
+ self->priv->alloc_size = 256;
+ self->priv->data = malloc (sizeof (UfoBuffer *) * self->priv->alloc_size);
+ self->priv->idx = 0;
+}
diff --git a/src/ufo-duplicate-task.h b/src/ufo-duplicate-task.h
new file mode 100644
index 0000000..f40b5fa
--- /dev/null
+++ b/src/ufo-duplicate-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_DUPLICATE_TASK_H
+#define __UFO_DUPLICATE_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_DUPLICATE_TASK (ufo_duplicate_task_get_type())
+#define UFO_DUPLICATE_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_DUPLICATE_TASK, UfoDuplicateTask))
+#define UFO_IS_DUPLICATE_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_DUPLICATE_TASK))
+#define UFO_DUPLICATE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_DUPLICATE_TASK, UfoDuplicateTaskClass))
+#define UFO_IS_DUPLICATE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_DUPLICATE_TASK))
+#define UFO_DUPLICATE_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_DUPLICATE_TASK, UfoDuplicateTaskClass))
+
+typedef struct _UfoDuplicateTask UfoDuplicateTask;
+typedef struct _UfoDuplicateTaskClass UfoDuplicateTaskClass;
+typedef struct _UfoDuplicateTaskPrivate UfoDuplicateTaskPrivate;
+
+/**
+ * UfoDuplicateTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoDuplicateTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoDuplicateTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoDuplicateTaskPrivate *priv;
+};
+
+/**
+ * UfoDuplicateTaskClass:
+ *
+ * #UfoDuplicateTask class
+ */
+struct _UfoDuplicateTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_duplicate_task_new (void);
+GType ufo_duplicate_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-fftmult-task.c b/src/ufo-fftmult-task.c
new file mode 100644
index 0000000..68d1bf2
--- /dev/null
+++ b/src/ufo-fftmult-task.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#ifdef __APPLE__
+# include <OpenCL/cl.h>
+#else
+# include <CL/cl.h>
+#endif
+
+#include <math.h>
+#include "ufo-fftmult-task.h"
+#include "ufo-priv.h"
+
+struct _UfoFftmultTaskPrivate {
+ cl_kernel k_fftmult;
+ UfoResources *resources;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoFftmultTask, ufo_fftmult_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_FFTMULT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_FFTMULT_TASK, UfoFftmultTaskPrivate))
+
+UfoNode *
+ufo_fftmult_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_FFTMULT_TASK, NULL));
+}
+
+static void
+ufo_fftmult_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+ UfoFftmultTaskPrivate *priv;
+
+ priv = UFO_FFTMULT_TASK_GET_PRIVATE (task);
+ priv->resources = resources;
+
+ priv->k_fftmult = ufo_resources_get_kernel (resources, "fftmult.cl", "mult", error);
+
+ if (priv->k_fftmult != NULL)
+ UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->k_fftmult));
+}
+
+static void
+ufo_fftmult_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition(inputs[1], requisition);
+}
+
+static guint
+ufo_fftmult_task_get_num_inputs (UfoTask *task)
+{
+ return 2;
+}
+
+static guint
+ufo_fftmult_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_fftmult_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_GPU;
+}
+
+static void
+get_ring_metadata(UfoBuffer *src, unsigned *number_ones, unsigned *radius)
+{
+ GValue *value;
+ value = ufo_buffer_get_metadata(src, "radius");
+ *radius = g_value_get_uint(value);
+ value = ufo_buffer_get_metadata(src, "number_ones");
+ *number_ones = g_value_get_uint(value);
+}
+
+static void
+get_max_work_group_size (UfoResources *resources, size_t *x_worker_count,
+ size_t * y_worker_count)
+{
+ *x_worker_count = ULLONG_MAX;
+ GList *devices = ufo_resources_get_devices (resources);
+ GList *it;
+
+ g_list_for (devices, it) {
+ cl_device_id device = (cl_device_id) it->data;
+ size_t byte_count = 0;
+ size_t max_group_size = 0;
+ clGetDeviceInfo (device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof (size_t),
+ &max_group_size, &byte_count);
+ g_assert (sizeof (size_t) == byte_count);
+ if (max_group_size < *x_worker_count)
+ *x_worker_count = max_group_size;
+ }
+
+ *x_worker_count = (unsigned) sqrtf((float)*x_worker_count);
+ *y_worker_count = *x_worker_count;
+}
+
+static void
+launch_kernel_2D(UfoFftmultTaskPrivate *priv,
+ UfoBuffer *ufo_a, UfoBuffer *ufo_b,
+ UfoBuffer *ufo_dst, cl_command_queue cmd_queue)
+{
+ cl_kernel kernel = priv->k_fftmult;
+ cl_mem a, b, dst;
+ UfoRequisition requisition;
+ size_t global_work_size[2];
+ size_t local_work_size[2];
+ dst = ufo_buffer_get_device_array(ufo_dst, cmd_queue);
+ a = ufo_buffer_get_device_array(ufo_a, cmd_queue);
+ b = ufo_buffer_get_device_array(ufo_b, cmd_queue);
+
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof (cl_mem), &a));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof (cl_mem), &b));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 2, sizeof (cl_mem), &dst));
+
+ /* Launch the kernel over 2D grid, using dst requisition which reperesents a
+ * crop of the image */
+ ufo_buffer_get_requisition (ufo_dst, &requisition);
+ global_work_size[0] = requisition.dims[0] / 2;
+ /* Buffer may have mod extra rows, don't take them into account */
+ g_assert(requisition.dims[0] % 2 == 0 && "FFT images are multiples of 2\n");
+ global_work_size[1] = requisition.dims[1];
+ size_t y_worker_count, x_worker_count;
+ get_max_work_group_size(priv->resources, &x_worker_count, &y_worker_count);
+
+ while (global_work_size[1] % y_worker_count)
+ --y_worker_count;
+
+ while (global_work_size[0] % x_worker_count)
+ --x_worker_count;
+
+ local_work_size[0] = x_worker_count; /* Multiple of image_width=1080 */
+ local_work_size[1] = y_worker_count; /* Multiple of image_height=1280 */
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (cmd_queue,
+ kernel,
+ 2, NULL, global_work_size,
+ local_work_size,
+ 0, NULL, NULL));
+}
+
+static gboolean
+ufo_fftmult_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoFftmultTaskPrivate *priv;
+ priv = UFO_FFTMULT_TASK_GET_PRIVATE (task);
+ /* Forwarding ring radius metada to next plugin */
+ unsigned radius, number_ones;
+ get_ring_metadata(inputs[1], &number_ones, &radius);
+
+ UfoGpuNode *node;
+ cl_command_queue cmd_queue;
+
+ node = UFO_GPU_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (task)));
+ cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+
+ priv = UFO_FFTMULT_TASK_GET_PRIVATE (task);
+ launch_kernel_2D (priv, inputs[0], inputs[1], output, cmd_queue);
+ return TRUE;
+}
+
+static void
+ufo_fftmult_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_fftmult_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_fftmult_task_setup;
+ iface->get_num_inputs = ufo_fftmult_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_fftmult_task_get_num_dimensions;
+ iface->get_mode = ufo_fftmult_task_get_mode;
+ iface->get_requisition = ufo_fftmult_task_get_requisition;
+ iface->process = ufo_fftmult_task_process;
+}
+
+static void
+ufo_fftmult_task_class_init (UfoFftmultTaskClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->finalize = ufo_fftmult_task_finalize;
+
+ g_type_class_add_private (oclass, sizeof(UfoFftmultTaskPrivate));
+}
+
+static void
+ufo_fftmult_task_init(UfoFftmultTask *self)
+{
+ self->priv = UFO_FFTMULT_TASK_GET_PRIVATE(self);
+}
diff --git a/src/ufo-fftmult-task.h b/src/ufo-fftmult-task.h
new file mode 100644
index 0000000..9d4416d
--- /dev/null
+++ b/src/ufo-fftmult-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_FFTMULT_TASK_H
+#define __UFO_FFTMULT_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_FFTMULT_TASK (ufo_fftmult_task_get_type())
+#define UFO_FFTMULT_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_FFTMULT_TASK, UfoFftmultTask))
+#define UFO_IS_FFTMULT_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_FFTMULT_TASK))
+#define UFO_FFTMULT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_FFTMULT_TASK, UfoFftmultTaskClass))
+#define UFO_IS_FFTMULT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_FFTMULT_TASK))
+#define UFO_FFTMULT_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_FFTMULT_TASK, UfoFftmultTaskClass))
+
+typedef struct _UfoFftmultTask UfoFftmultTask;
+typedef struct _UfoFftmultTaskClass UfoFftmultTaskClass;
+typedef struct _UfoFftmultTaskPrivate UfoFftmultTaskPrivate;
+
+/**
+ * UfoFftmultTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoFftmultTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoFftmultTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoFftmultTaskPrivate *priv;
+};
+
+/**
+ * UfoFftmultTaskClass:
+ *
+ * #UfoFftmultTask class
+ */
+struct _UfoFftmultTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_fftmult_task_new (void);
+GType ufo_fftmult_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-filter-particle-task.c b/src/ufo-filter-particle-task.c
new file mode 100644
index 0000000..e054fc5
--- /dev/null
+++ b/src/ufo-filter-particle-task.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "ufo-filter-particle-task.h"
+#include "ufo-ring-coordinates.h"
+
+struct _UfoFilterParticleTaskPrivate {
+ unsigned *img;
+ size_t num_pixels;
+ float threshold;
+ float min;
+};
+
+/*Maximal number of particles that can be tagged*/
+#define nVectMax 100000
+
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoFilterParticleTask, ufo_filter_particle_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_FILTER_PARTICLE_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_FILTER_PARTICLE_TASK, UfoFilterParticleTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_MIN,
+ PROP_THRESHOLD,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_filter_particle_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_FILTER_PARTICLE_TASK, NULL));
+}
+
+static void
+ufo_filter_particle_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_filter_particle_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ UfoFilterParticleTaskPrivate *priv = UFO_FILTER_PARTICLE_TASK_GET_PRIVATE (task);
+ requisition->n_dims = 1;
+ ufo_buffer_get_requisition(inputs[0], requisition);
+ size_t num_pixels = requisition->dims[0] * requisition->dims[1];
+
+ /* Allocate internal buffer to hold copy of image */
+ /* Reuse buffer when size is the smae */
+ if (priv->num_pixels != num_pixels) {
+ priv->num_pixels = num_pixels;
+ priv->img = realloc (priv->img, sizeof (unsigned) * num_pixels);
+ }
+
+ /* Output size varies according to data whithin the input */
+ /* I don't know the output size, I'll allocate it myself once I have
+ * processed the data */
+ requisition->dims[0] = 0;
+ requisition->n_dims = 1;
+}
+
+static guint
+ufo_filter_particle_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_filter_particle_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_filter_particle_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_CPU;
+}
+
+static void
+part_cen_radius(float *img, unsigned *bin, unsigned nc, unsigned nr,
+ unsigned pc, double *cx, double *cy, double *rr)
+{
+ /* nr == number of rows */
+ /* nc == number of columns */
+ /* pc == pixel count, (i-e nb of detected rings) */
+ /* cx, cy, rr, (x, y, r) coordinates of each ring */
+ unsigned i,j,k, itop, ibot, jleft, jright;
+ unsigned b;
+ unsigned *tops,*bots,*lefts,*rights;
+ float cenx, radx, ceny, rady, wei;
+
+ tops = malloc((pc+1)*sizeof(unsigned) * 100);
+ bots = malloc((pc+1)*sizeof(unsigned) * 100);
+ lefts = malloc((pc+1)*sizeof(unsigned) * 100);
+ rights = malloc((pc+1)*sizeof(unsigned) * 100);
+
+ for (k=0;k<=pc;k++) {
+ tops[k]= (unsigned)nr; bots[k]=0; lefts[k]=(unsigned)nc; rights[k]=0;
+ }
+
+ /* Find extremities of each clustered pixels */
+ for (i=0;i<nr;i++) {
+ for(j=0;j<nc;j++) {
+ b = bin[i * nc + j];
+ if ( tops[b]>i ) tops[b]=i;
+ if ( bots[b]<i ) bots[b]=i;
+ if ( lefts[b]>j ) lefts[b]=j;
+ if ( rights[b]<j ) rights[b]=j;
+ }
+ }
+
+ /* calculate center of each clustered pixel using img to put weight on each
+ * candidate pixel, at the same time calculate radius of the cluster */
+ for (k = 0; k < pc; k++) {
+ itop=tops[k+1]; ibot=bots[k+1];
+ jleft=lefts[k+1]; jright=rights[k+1];
+
+ cenx=0.0; radx=0.0;
+ ceny=0.0; rady=0.0;
+ wei=0.0;
+
+ for (i=itop;i<=ibot;i++) {
+ for (j=jleft;j<=jright;j++)
+ {
+ if (bin[i * nc + j]==k+1) {
+ float value = img[i * nc + j];
+ cenx += (float) j * value;
+ radx = radx + (float) (j * j) * value;
+ ceny = ceny + (float) i * value;
+ rady = rady + (float) (i * i) * value;
+ wei = wei + value;
+ }
+ }
+ }
+ cenx=cenx/wei;
+ ceny=ceny/wei;
+ radx=sqrtf (fabsf ((radx/wei) - cenx*cenx)) + (float) 0.25;
+ rady=sqrtf (fabsf ((rady/wei) - ceny*ceny)) + (float) 0.25;
+
+ cx[k] = cenx+1;
+ cy[k] = ceny+1;
+ rr[k] = sqrt(radx*rady);
+ }
+
+ free(tops); free(bots); free(lefts); free(rights);
+
+}
+
+static void
+pfind (float *input, unsigned *out, unsigned nc, unsigned nr, unsigned *pcount,
+ double threshold)
+{
+ unsigned pc;
+ unsigned ndup;
+ unsigned i,j,k;
+ int ncase;
+ char iodd;
+ unsigned ncc;
+ unsigned *dupx,*dupy;
+ unsigned *dupindex, *binloc;
+ unsigned k1,k2,temp;
+
+ unsigned b;
+
+ pc=0;
+ ndup=0;
+
+ dupx = malloc (nVectMax * sizeof (unsigned));
+ dupy = malloc (nVectMax * sizeof (unsigned));
+
+ /* 0, 0 is top left of image */
+ for(j=0;j<nc;j++) {
+ for(i=0;i<nr;i++) {
+ /* Bit mask of surrounding pixels */
+ ncase=0;
+ /* Set if bottom left pixel is set */
+ iodd=0;
+ if(input[i * nc + j] > threshold) {
+ /* Bottom left pixel */
+ if (i < (nr - 1) && j > 0 && input[(i + 1) * nc + (j - 1)] > threshold)
+ { ncase += 1; iodd = 1; }
+ /* Bottom right pixel */
+ if (i < (nr - 1) && j < (nc - 1) && input[(i + 1) * nc + (j + 1)] > threshold)
+ ncase += 2;
+ /* Top right pixel */
+ if (i > 0 && j < (nc - 1) && input[(i - 1) * nc + (j + 1)] > threshold)
+ ncase += 4;
+ /* Top left pixel */
+ if (i > 0 && j > 0 && input[(i - 1) * nc + (j - 1)] > threshold)
+ ncase += 8;
+ /* Bottom pixel */
+ if (i < (nr - 1) && input[(i + 1) * nc + j] > threshold)
+ ncase += 16;
+ /* Right pixel */
+ if (j < (nc - 1) && input[i * nc + (j + 1)] > threshold)
+ ncase += 32;
+ /* Top pixel */
+ if (i > 0 && input[(i - 1) * nc + j] > threshold)
+ ncase += 64;
+ /* Left pixel */
+ if (j > 0 && input[i * nc + (j - 1)] > threshold)
+ ncase += 128;
+
+ /* Pixel has no : Bottom, Right, Top, Left */
+ if (ncase <= 15) {
+ // if (NO1 == 1)
+ // bin[i][j] = ++pc;
+ // else
+ out[i * nc + j] = 0;
+ }
+ /* Pixel has no : Right, Top, Left */
+ /* and Pixel has : Bottom */
+ else if (ncase <= 31) {
+ if(iodd == 1)
+ out[i * nc + j] = out[(i + 1) * nc + (j - 1)]; /* Clone id */
+ else
+ out[i * nc + j] = ++pc;
+ }
+ /* Pixel has no : Top, Left, Bottom */
+ /* Pixel has : Right */
+ else if (ncase <= 47)
+ out[i * nc + j] = ++pc;
+ /* Pixel has no : Top, Left */
+ /* Pixel has : Right, Bottom */
+ else if (ncase <= 63) {
+ if (iodd == 1)
+ out[i * nc + j] = out[(i + 1) * nc + (j - 1)];
+ else
+ out[i * nc + j] = ++pc;
+ }
+ /* Pixel has no : Left */
+ /* Pixel has : Top */
+ else if (ncase <= 127)
+ out[i * nc + j] = out[(i - 1) * nc + j];
+ /* Pixel has : Left */
+ else
+ out[i * nc + j] = out[i * nc + (j - 1)];
+
+
+ /* Bottom Left && Bottom && Top && not(Left) */
+ if ((ncase & 1) && (ncase & 16) && (ncase & 64) && !(ncase & 128)) {
+ /* Find duplicates, and locate them by x, and y list */
+ /* These duplicates shall be joined later */
+ k1 = out[i * nc + j];
+ /* 11
+ * 1
+ * 22
+ * in this case, bottom left was processed later, which
+ * explains the comparison */
+ k2 = out[(i + 1) * nc + (j - 1)];
+ dupx[ndup] = (k1 > k2 ? k2 : k1);
+ dupy[ndup] = (k1 > k2 ? k1 : k2);
+ ndup++;
+ }
+ }
+ else
+ out[i * nc + j] = 0;
+ }
+ }
+
+ dupindex = malloc ((unsigned) (pc + 1) * sizeof (unsigned));
+ /* binloc stores the 1D position (on row basis, like matlab) of each
+ * candidate block of pixel (Most left-top of block)
+ * or MAX_POS_VAL otherwise */
+ binloc = malloc ((unsigned) (pc + 1) * sizeof(unsigned));
+ for(k=0;k<=pc;k++) {
+ binloc[k]= nr * nc;
+ dupindex[k] = k;
+ }
+
+ for(j=0;j<nc;j++) {
+ for(i=0;i<nr;i++) {
+ b = out[i * nc + j];
+ if(b > 0 && binloc[b] > (j*nr+i) )
+ binloc[b]=j*nr+i;
+ }
+ }
+
+ for(k=0; k < ndup; k++) {
+ /* 11
+ * 1
+ * 22 in this case*/
+ if( binloc[dupx[k]] > binloc[dupy[k]] ) {
+ /* Dupx has always been afected the smaller id
+ * ==> with row wise basis, locations dupx > dupy is always false */
+ temp = dupx[k]; dupx[k]=dupy[k]; dupy[k]=temp;
+ }
+ }
+
+ /* Sort dupx to be in crescent order */
+ /* i-e
+ * 22
+ * 2
+ * 33
+ * 3
+ *111
+ * Here dupx = { 2, 1 } ==> Not in crescent order */
+ if (ndup != 0) {
+ for (k=0;k<ndup-1;k++) {
+ for(j=k+1;j<ndup;j++) {
+ if(binloc[dupx[k]]>binloc[dupx[j]]) {
+ temp=dupx[k];
+ dupx[k]=dupx[j];
+ dupx[j]=temp;
+ temp=dupy[k];
+ dupy[k]=dupy[j];
+ dupy[j]=temp;
+ }
+ else if( dupx[k]== dupx[j] && binloc[dupy[k]] > binloc[dupy[j]]) {
+ temp=dupy[k];
+ dupy[k]=dupy[j];
+ dupy[j]=temp;
+ }
+ }
+ }
+ }
+
+ /* dupindex gives the new index for each index, when two index are duplicates
+ * dupindex will affect those two indexes a same value */
+ for(k=0;k<ndup;k++) {
+ k1=dupx[k]; k2=dupy[k];
+ for(j=k;j<ndup;j++) {
+ if(dupy[j]== dupy[k]||dupx[j]== dupy[k]) {
+ dupindex[ dupx[j] ]=dupindex[k1];
+ dupindex[ dupy[j] ]=dupindex[k1];
+ }
+ }
+ }
+
+ /* copy dupindex in dupx */
+ for (k=0;k<=pc;k++) {
+ dupx[k]= dupindex[k];
+ dupy[k]=0;
+ }
+ /* order dupx in crescent order, is it not already ordered though ?!? */
+ for (k=0;k<=pc;k++) {
+ for(j=k+1;j<=pc;j++) {
+ if(dupx[k]>dupx[j]) {
+ temp=dupx[k];
+ dupx[k]=dupx[j];
+ dupx[j]=temp;
+ }
+ }
+ }
+
+ ncc=0;
+ dupy[0]=0;
+ /* map dupindex values to values from 1 to number_of_detected_ring, this
+ * allows to have a constant step of one, eg: converting {1,3,6} -> {1,2,3} */
+ for(k=1;k<=pc;k++) {
+ if(dupx[k]>dupx[k-1])
+ dupy[ dupx[k] ] = ++ncc;
+ }
+
+ *pcount=ncc;
+ /* set dupindex to its newly mapped value, (making dupindex have a step of
+ * one */
+ for (k=0;k<=pc;k++)
+ dupindex[k]= dupy[ dupindex[k] ];
+
+ /* Make all duplicates have the same ID */
+ for(i=0;i<nr;i++) {
+ for(j=0;j<nc;j++)
+ out[i * nc + j]= dupindex[ out[i * nc + j] ];
+ }
+
+ free(dupx);
+ free(dupy);
+ free(dupindex);
+ free(binloc);
+
+ return;
+}
+
+static void
+get_radius_metadata(UfoBuffer *src, unsigned *radius)
+{
+ GValue *value;
+
+ value = ufo_buffer_get_metadata(src, "radius");
+ *radius = g_value_get_uint(value);
+}
+
+static double
+get_max_value(float* img, size_t width, size_t height)
+{
+ double res = 0;
+
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ if (res < img[y * width + x])
+ res = img[y * width + x];
+ }
+ }
+
+ return res;
+}
+
+static unsigned
+min(unsigned a, unsigned b)
+{
+ return a > b ? b : a;
+}
+
+static gboolean
+ufo_filter_particle_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ (void) requisition;
+ UfoFilterParticleTaskPrivate *priv = UFO_FILTER_PARTICLE_TASK_GET_PRIVATE (task);
+ UfoRequisition req;
+ ufo_buffer_get_requisition(inputs[0], &req);
+ unsigned pcount = 0;
+ float *input = ufo_buffer_get_host_array(inputs[0], NULL);
+ unsigned radius;
+ get_radius_metadata(inputs[0], &radius);
+
+ /* Give unique ID to each cluster of pixels */
+ double max_value = get_max_value(input, req.dims[0], req.dims[1]);
+ double threshold = priv->threshold * max_value;
+
+ // When max_value is too low, it is unlikely for there to be any rings
+ if (max_value < priv->min) {
+ g_print("Filter_particle: min : Ignoring radius %u. Inputs max value is"
+ " %f, at least %f expected\n", radius, max_value, priv->min);
+ UfoRequisition out_req = {
+ .n_dims = 1,
+ .dims[0] = 1
+ };
+ ufo_buffer_resize (output, &out_req);
+ float *out = ufo_buffer_get_host_array(output, NULL);
+ *out = 0;
+ return TRUE;
+ }
+
+ pfind (input, priv->img, (unsigned) req.dims[0], (unsigned) req.dims[1], &pcount, threshold);
+
+ /* Compute center of each cluster and store coordinates in cx, cy */
+ double *cx = malloc (sizeof (double) * pcount);
+ double *cy = malloc (sizeof (double) * pcount);
+ double *rr = malloc (sizeof (double) * pcount);
+ part_cen_radius(input, priv->img, (unsigned) req.dims[0],
+ (unsigned) req.dims[1], pcount, cx, cy, rr);
+
+ /* a list of pcount UfoRingCoordinate are generated in output */
+ /* first element is the number of rings detected */
+ UfoRequisition out_req = {
+ .n_dims = 1,
+ .dims[0] = 1 + pcount * sizeof (UfoRingCoordinate) / sizeof (float),
+ };
+ ufo_buffer_resize (output, &out_req);
+ float *out = ufo_buffer_get_host_array(output, NULL);
+ UfoRingCoordinate *res = (UfoRingCoordinate *) (out + 1);
+ *out = (float) pcount;
+
+ for (unsigned i = 0; i < pcount; ++i) {
+ res[i].x = (float) cx[i];
+ res[i].y = (float) cy[i];
+ res[i].r = (float) radius;
+ unsigned x = min((unsigned)round(cx[i]), (unsigned) (req.dims[0] - 1));
+ unsigned y = min((unsigned)round(cy[i]), (unsigned) (req.dims[1] - 1));
+ res[i].intensity = input[y * req.dims[0] + x];
+ }
+
+ return TRUE;
+}
+
+static void
+ufo_filter_particle_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoFilterParticleTaskPrivate *priv = UFO_FILTER_PARTICLE_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_MIN:
+ priv->min = g_value_get_float(value);
+ break;
+ case PROP_THRESHOLD:
+ priv->threshold = g_value_get_float(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_filter_particle_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoFilterParticleTaskPrivate *priv = UFO_FILTER_PARTICLE_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_MIN:
+ g_value_set_float(value, priv->min);
+ break;
+ case PROP_THRESHOLD:
+ g_value_set_float(value, priv->threshold);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_filter_particle_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_filter_particle_task_parent_class)->finalize (object);
+ UfoFilterParticleTaskPrivate *priv = UFO_FILTER_PARTICLE_TASK_GET_PRIVATE (object);
+ free (priv->img);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_filter_particle_task_setup;
+ iface->get_num_inputs = ufo_filter_particle_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_filter_particle_task_get_num_dimensions;
+ iface->get_mode = ufo_filter_particle_task_get_mode;
+ iface->get_requisition = ufo_filter_particle_task_get_requisition;
+ iface->process = ufo_filter_particle_task_process;
+}
+
+static void
+ufo_filter_particle_task_class_init (UfoFilterParticleTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_filter_particle_task_set_property;
+ gobject_class->get_property = ufo_filter_particle_task_get_property;
+ gobject_class->finalize = ufo_filter_particle_task_finalize;
+
+ properties[PROP_MIN] =
+ g_param_spec_float ("min",
+ "Ignore image when it's maximal value is less than min",
+ "Ignore image when it's maximal value is less than min",
+ 0, 1, 0.125f,
+ G_PARAM_READWRITE);
+ properties[PROP_THRESHOLD] =
+ g_param_spec_float ("threshold",
+ "Set threshold value which is relative to the image maximum value",
+ "Set threshold value which is relative to the image maximum value",
+ 0, 1, 0.8f,
+ G_PARAM_READWRITE);
+
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoFilterParticleTaskPrivate));
+}
+
+static void
+ufo_filter_particle_task_init(UfoFilterParticleTask *self)
+{
+ self->priv = UFO_FILTER_PARTICLE_TASK_GET_PRIVATE(self);
+ self->priv->img = NULL;
+ self->priv->num_pixels = 0;
+ self->priv->min = 0.125f;
+ self->priv->threshold = 0.8f;
+}
diff --git a/src/ufo-filter-particle-task.h b/src/ufo-filter-particle-task.h
new file mode 100644
index 0000000..6220a0d
--- /dev/null
+++ b/src/ufo-filter-particle-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_FILTER_PARTICLE_TASK_H
+#define __UFO_FILTER_PARTICLE_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_FILTER_PARTICLE_TASK (ufo_filter_particle_task_get_type())
+#define UFO_FILTER_PARTICLE_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_FILTER_PARTICLE_TASK, UfoFilterParticleTask))
+#define UFO_IS_FILTER_PARTICLE_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_FILTER_PARTICLE_TASK))
+#define UFO_FILTER_PARTICLE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_FILTER_PARTICLE_TASK, UfoFilterParticleTaskClass))
+#define UFO_IS_FILTER_PARTICLE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_FILTER_PARTICLE_TASK))
+#define UFO_FILTER_PARTICLE_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_FILTER_PARTICLE_TASK, UfoFilterParticleTaskClass))
+
+typedef struct _UfoFilterParticleTask UfoFilterParticleTask;
+typedef struct _UfoFilterParticleTaskClass UfoFilterParticleTaskClass;
+typedef struct _UfoFilterParticleTaskPrivate UfoFilterParticleTaskPrivate;
+
+/**
+ * UfoFilterParticleTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoFilterParticleTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoFilterParticleTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoFilterParticleTaskPrivate *priv;
+};
+
+/**
+ * UfoFilterParticleTaskClass:
+ *
+ * #UfoFilterParticleTask class
+ */
+struct _UfoFilterParticleTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_filter_particle_task_new (void);
+GType ufo_filter_particle_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-get-dup-circ-task.c b/src/ufo-get-dup-circ-task.c
new file mode 100644
index 0000000..e8a45e5
--- /dev/null
+++ b/src/ufo-get-dup-circ-task.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <math.h> /* sqrt */
+#include <string.h> /* memcpy */
+
+#include "ufo-get-dup-circ-task.h"
+#include "ufo-ring-coordinates.h"
+
+struct _UfoGetDupCircTaskPrivate {
+ float threshold;
+ UfoRingCoordinate *coord;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoGetDupCircTask, ufo_get_dup_circ_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_GET_DUP_CIRC_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_GET_DUP_CIRC_TASK, UfoGetDupCircTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_THRESHOLD,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_get_dup_circ_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_GET_DUP_CIRC_TASK, NULL));
+}
+
+static void
+ufo_get_dup_circ_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_get_dup_circ_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition (inputs[0], requisition);
+}
+
+static guint
+ufo_get_dup_circ_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_get_dup_circ_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 1;
+}
+
+static UfoTaskMode
+ufo_get_dup_circ_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_CPU;
+}
+
+static void
+merge_rings (UfoBuffer *output, UfoGetDupCircTaskPrivate *priv, unsigned nb_elt)
+{
+ float *res = ufo_buffer_get_host_array (output, NULL);
+ UfoRingCoordinate *coord = (UfoRingCoordinate *) (res + 1);
+ unsigned nb_coord = 0;
+ for (unsigned i = 0; i < nb_elt; ++i) {
+ /* We set rings to a radius of 0 when they have already been merged */
+ if (priv->coord[i].r == 0)
+ continue;
+ coord[nb_coord] = priv->coord[i];
+ float nb_merged_elt = 1;
+ for (unsigned j = i + 1; j < nb_elt; ++j) {
+ if (priv->coord[j].r == 0)
+ continue;
+ float distance = sqrtf ((priv->coord[j].x - priv->coord[i].x) *
+ (priv->coord[j].x - priv->coord[i].x) +
+ (priv->coord[j].y - priv->coord[i].y) *
+ (priv->coord[j].y - priv->coord[i].y));
+ float radius_diff = priv->coord[j].r - priv->coord[i].r;
+ radius_diff = radius_diff < 0 ? -radius_diff : radius_diff;
+ if (distance < priv->threshold && radius_diff < priv->threshold) {
+ coord[nb_coord].x += priv->coord[j].x;
+ coord[nb_coord].y += priv->coord[j].y;
+ coord[nb_coord].r += priv->coord[j].r;
+ /* Say that the j-th ring has been merged */
+ priv->coord[j].r = 0;
+ ++nb_merged_elt;
+ }
+ }
+ coord[nb_coord].x /= nb_merged_elt;
+ coord[nb_coord].y /= nb_merged_elt;
+ coord[nb_coord].r /= nb_merged_elt;
+ /* When merging occurs, search again for new candidates */
+ if (nb_merged_elt > 1) {
+ priv->coord[i] = coord[nb_coord];
+ --i;
+ }
+ else
+ ++nb_coord;
+ }
+ *res = (float) nb_coord;
+}
+
+static gboolean
+ufo_get_dup_circ_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoGetDupCircTaskPrivate *priv = UFO_GET_DUP_CIRC_TASK_GET_PRIVATE (task);
+ float *input = ufo_buffer_get_host_array (inputs[0], NULL);
+ unsigned nb_elt = (unsigned) *input;
+ UfoRingCoordinate *coord = (UfoRingCoordinate *) (input + 1);
+ priv->coord = g_malloc (sizeof (UfoRingCoordinate) * nb_elt);
+ memcpy (priv->coord, coord, nb_elt * sizeof (UfoRingCoordinate));
+ merge_rings (output, priv, nb_elt);
+ return TRUE;
+}
+
+static void
+ufo_get_dup_circ_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoGetDupCircTaskPrivate *priv = UFO_GET_DUP_CIRC_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_THRESHOLD:
+ priv->threshold = g_value_get_float (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_get_dup_circ_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoGetDupCircTaskPrivate *priv = UFO_GET_DUP_CIRC_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_THRESHOLD:
+ g_value_set_float (value, priv->threshold);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_get_dup_circ_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_get_dup_circ_task_parent_class)->finalize (object);
+ UfoGetDupCircTaskPrivate *priv = UFO_GET_DUP_CIRC_TASK_GET_PRIVATE (object);
+ g_free (priv->coord);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_get_dup_circ_task_setup;
+ iface->get_num_inputs = ufo_get_dup_circ_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_get_dup_circ_task_get_num_dimensions;
+ iface->get_mode = ufo_get_dup_circ_task_get_mode;
+ iface->get_requisition = ufo_get_dup_circ_task_get_requisition;
+ iface->process = ufo_get_dup_circ_task_process;
+}
+
+static void
+ufo_get_dup_circ_task_class_init (UfoGetDupCircTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_get_dup_circ_task_set_property;
+ gobject_class->get_property = ufo_get_dup_circ_task_get_property;
+ gobject_class->finalize = ufo_get_dup_circ_task_finalize;
+
+ properties[PROP_THRESHOLD] =
+ g_param_spec_float ("threshold",
+ "Give maximum ring distance, and radius difference",
+ "Give maximum ring distance, and radius difference",
+ 1, G_MAXFLOAT, 10,
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoGetDupCircTaskPrivate));
+}
+
+static void
+ufo_get_dup_circ_task_init(UfoGetDupCircTask *self)
+{
+ self->priv = UFO_GET_DUP_CIRC_TASK_GET_PRIVATE(self);
+ self->priv->threshold = 10;
+ self->priv->coord = NULL;
+}
diff --git a/src/ufo-get-dup-circ-task.h b/src/ufo-get-dup-circ-task.h
new file mode 100644
index 0000000..138fec5
--- /dev/null
+++ b/src/ufo-get-dup-circ-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_GET_DUP_CIRC_TASK_H
+#define __UFO_GET_DUP_CIRC_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_GET_DUP_CIRC_TASK (ufo_get_dup_circ_task_get_type())
+#define UFO_GET_DUP_CIRC_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_GET_DUP_CIRC_TASK, UfoGetDupCircTask))
+#define UFO_IS_GET_DUP_CIRC_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_GET_DUP_CIRC_TASK))
+#define UFO_GET_DUP_CIRC_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_GET_DUP_CIRC_TASK, UfoGetDupCircTaskClass))
+#define UFO_IS_GET_DUP_CIRC_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_GET_DUP_CIRC_TASK))
+#define UFO_GET_DUP_CIRC_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_GET_DUP_CIRC_TASK, UfoGetDupCircTaskClass))
+
+typedef struct _UfoGetDupCircTask UfoGetDupCircTask;
+typedef struct _UfoGetDupCircTaskClass UfoGetDupCircTaskClass;
+typedef struct _UfoGetDupCircTaskPrivate UfoGetDupCircTaskPrivate;
+
+/**
+ * UfoGetDupCircTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoGetDupCircTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoGetDupCircTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoGetDupCircTaskPrivate *priv;
+};
+
+/**
+ * UfoGetDupCircTaskClass:
+ *
+ * #UfoGetDupCircTask class
+ */
+struct _UfoGetDupCircTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_get_dup_circ_task_new (void);
+GType ufo_get_dup_circ_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-multi-search-task.c b/src/ufo-multi-search-task.c
new file mode 100644
index 0000000..1996f19
--- /dev/null
+++ b/src/ufo-multi-search-task.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <float.h>
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ufo-multi-search-task.h"
+#include "ufo-ring-coordinates.h"
+
+
+struct _UfoMultiSearchTaskPrivate {
+ /* number of elements desired in computations of polynomial */
+ unsigned radii_range;
+ float threshold;
+ unsigned displacement;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoMultiSearchTask, ufo_multi_search_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_MULTI_SEARCH_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_MULTI_SEARCH_TASK, UfoMultiSearchTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_RADII_RANGE,
+ PROP_THRESHOLD,
+ PROP_DISPLACEMENT,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_multi_search_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_MULTI_SEARCH_TASK, NULL));
+}
+
+static void
+ufo_multi_search_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_multi_search_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ /* input[0] : contrasted image */
+ /* input[1] : coordinate list */
+ ufo_buffer_get_requisition (inputs[1], requisition);
+}
+
+static guint
+ufo_multi_search_task_get_num_inputs (UfoTask *task)
+{
+ return 2;
+}
+
+static guint
+ufo_multi_search_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 1;
+}
+
+static UfoTaskMode
+ufo_multi_search_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_CPU;
+}
+
+static int
+min (int l, int r)
+{
+ if (l > r)
+ return r;
+
+ return l;
+}
+
+static int
+max (int l, int r)
+{
+ if (l > r)
+ return l;
+ return r;
+}
+
+static void
+get_coords(int *left, int *right, int *top, int *bot, int rad,
+ UfoRequisition *req, UfoRingCoordinate *center)
+{
+ int l = (int) roundf (center->x - (float) rad);
+ int r = (int) roundf (center->x + (float) rad);
+ int t = (int) roundf (center->y - (float) rad);
+ int b = (int) roundf (center->y + (float) rad);
+ *left = max (l, 0);
+ *right = min (r, (int) (req->dims[0]) - 1);
+ // Bottom most point is req->dims[1]
+ *top = max (t, 0);
+ // Top most point is 0
+ *bot = min (b, (int) (req->dims[1]) - 1);
+
+}
+
+/* Sum each pixel of ring from center with a radius of r */
+static float
+compute_intensity (UfoBuffer *ufo_image, UfoRingCoordinate *center, int r)
+{
+ float intensity = 0;
+ UfoRequisition req;
+ ufo_buffer_get_requisition(ufo_image, &req);
+ float *image = ufo_buffer_get_host_array(ufo_image, NULL);
+ int x_center = (int) roundf (center->x);
+ int y_center = (int) roundf (center->y);
+ int left, right, top, bot;
+ get_coords(&left, &right, &top, &bot, r, &req, center);
+ unsigned counter = 0;
+ for (int y = top; y <= bot; ++y) {
+ for (int x = left; x <= right; ++x) {
+ int xx = (x - x_center) * (x - x_center);
+ int yy = (y - y_center) * (y - y_center);
+ /* Check if point is on ring */
+ if (fabs (sqrtf ((float) (xx + yy)) - (float) r) < 0.5) {
+ intensity += image[x + y * (int) req.dims[0]];
+ ++counter;
+ }
+ }
+ }
+ return intensity / (float) counter;
+}
+
+/* X_1^order ..... X^0
+ * |
+ * |
+ * X_i^order ..... X^0
+ */
+static float *
+vandermonde_new (unsigned x, unsigned nb_elt, unsigned order)
+{
+ float *vandermonde = malloc (sizeof (float) * nb_elt * (order + 1));
+ for (unsigned j = 0; j <= order; ++j) {
+ for (unsigned i = 0; i < nb_elt; ++i) {
+ vandermonde[i * (order + 1) + j] = powf ((float) (x + i),
+ (float) (order - j));
+ }
+ }
+ return vandermonde;
+}
+
+/* Computes the projectios of vector A(:, j) over e */
+static void
+compute_projection (float *e, float *A, unsigned j, unsigned row,
+ unsigned column, float *dst)
+{
+ float sc1 = 0;
+ float sc2 = 0;
+ /* Scalar product */
+ for (unsigned i = 0; i < row; ++i) {
+ sc1 += e[i] * A[i * column + j];
+ sc2 += e[i] * e[i];
+ }
+
+ /* Compute projection */
+ for (unsigned i = 0; i < row; ++i) {
+ dst[i] = e[i] * sc1 / sc2;
+ }
+}
+
+static float *
+Gram_Schmidt_U(float *A, unsigned row, unsigned column)
+{
+ float *U = malloc (sizeof (float) * row * column);
+ float *norms = malloc (sizeof (float) * column);
+ float *proj_sum = malloc (sizeof (float) * row);
+ float *e = malloc (sizeof (float) * row);
+ float *proj = malloc (sizeof (float) * row);
+ for (unsigned j = 0; j < column; ++j) {
+
+ /* Compute the sum of projections of column j over each vector in the
+ * orthonrmal basis */
+ memset (proj_sum, 0, sizeof (float) * row);
+ for (int k = 0; k < (int) j; ++k) {
+ /* k represents a column */
+ for (unsigned i = 0; i < row; ++i) {
+ e[i] = U[i * column + (unsigned) k] / norms[k];
+ }
+ compute_projection (e, A, j, row, column, proj);
+ for (unsigned i = 0; i < row; ++i) {
+ proj_sum[i] += proj[i];
+ }
+ }
+
+ /* compute column j of matrix U */
+ for (unsigned i = 0; i < row; ++i) {
+ U[i * column + j] = A[i * column + j] - proj_sum[i];
+ }
+
+ /* compute new norm of column j */
+ norms[j] = 0;
+ for (unsigned i = 0; i < row; ++i) {
+ norms[j] += U[i * column + j] * U[i * column + j];
+ }
+ norms[j] = sqrtf (norms[j]);
+ }
+
+ free (norms);
+ free (proj_sum);
+ free (e);
+ free (proj);
+
+ return U;
+}
+
+static float *
+Gram_Schmidt_Q (float *A, unsigned row, unsigned column)
+{
+ float *Q = malloc (sizeof (float) * row * column);
+ float *U = Gram_Schmidt_U(A, row, column);
+ for (unsigned j = 0; j < column; ++j) {
+ float norm = 0;
+ for (unsigned i = 0; i < row; ++i) {
+ norm += U[i * column + j] * U[i * column + j];
+ }
+ norm = sqrtf (norm);
+ for (unsigned i = 0; i < row; ++i) {
+ Q[i * column + j] = U[i * column + j] / norm;
+ }
+ }
+ free (U);
+ return Q;
+}
+/* Transpose first matrix, and multiply to second matrix */
+/* column_Q is the number of column in Q befor being transposed */
+static float *
+matrix_transpose_mul2(float *Q, float *A, unsigned column_Q,
+ unsigned row, unsigned column_A)
+{
+ float *res = calloc (1, sizeof (float) * column_Q * column_A);
+ for (unsigned i = 0; i < column_Q; ++i) {
+ for (unsigned j = 0; j < column_A; ++j) {
+ for (unsigned k = 0; k < row; ++k) {
+ res[i * column_A + j] += Q[k * column_Q + i] * A[k * column_A + j];
+ }
+ }
+ }
+ return res;
+}
+
+/* Transpose first matrix, and multiply to second matrix */
+static float *
+matrix_transpose_mul(float *Q, float *A, unsigned row, unsigned column)
+{
+ float *res = calloc (1, sizeof (float) * column * column);
+ for (unsigned i = 0; i < column; ++i) {
+ for (unsigned j = 0; j < column; ++j) {
+ for (unsigned k = 0; k < row; ++k) {
+ res[i * column + j] += Q[k * column + i] * A[k * column + j];
+ }
+ }
+ }
+ return res;
+}
+/* P(r_min) = values[0] */
+/* P(r_min + 1) = values[1] */
+/* P(r_min + nb_elt - 1) = values[nb_elt - 1] */
+/* The step is always of 1 */
+static void
+polyfit (float *values, unsigned nb_elt, unsigned r_min,
+ float *a, float *b, float *c)
+{
+ /* We have as many column as the order + 1 of the polynomial */
+ unsigned column = 3;
+ /* Compute vandermonde matrix */
+ float *vandermonde = vandermonde_new(r_min, nb_elt, 2);
+
+ /* Compute V = QR using Gram-Schmidt method */
+ float *Q = Gram_Schmidt_Q(vandermonde, nb_elt, column);
+ float *R = matrix_transpose_mul (Q, vandermonde, nb_elt, column);
+ /* Q' x Values */
+ float *Qtxy = matrix_transpose_mul2 (Q, values, column, nb_elt, 1);
+
+ *c = Qtxy[2] / R[2 * column + 2];
+ *b = (Qtxy[1] - R[1 * column + 2] * *c) / R[1 * column + 1];
+ *a = (Qtxy[0] - R[2] * *c - R[1] * *b) / R[0];
+
+ free (vandermonde);
+ free (Q);
+ free(R);
+ free(Qtxy);
+}
+
+/* From a given image, vary the radius size and compare the variation of the
+ * intensity for each radii. From these intensities compute a polynomial P(r)
+ * where r represents a radius */
+static void
+create_profile_advanced (UfoMultiSearchTaskPrivate *priv, UfoBuffer *image,
+ UfoRingCoordinate *center, float *a, float *b, float *c)
+{
+ unsigned min_rad = 1;
+ if (center->r > priv->radii_range)
+ min_rad = (unsigned) center->r - priv->radii_range;
+ unsigned max_rad = (unsigned) center->r + priv->radii_range;
+ /* The value associated to each radius */
+ float values[max_rad - min_rad + 1];
+
+ unsigned pic_idx = 0;
+ values[pic_idx] = 0;
+ float max_a = 0;
+ int displacement = (int) priv->displacement;
+ UfoRingCoordinate copy = *center;
+ for (int x = -displacement; x <= displacement; ++x) {
+ for (int y = -displacement; y <= displacement; ++y) {
+ UfoRingCoordinate urc =
+ { copy.x + (float) x, copy.y + (float) y, copy.r, 0.0f, 0.0f };
+ for (unsigned r = 0; r <= max_rad - min_rad; ++r) {
+ values[r] = compute_intensity (image, &urc, (int) (r + min_rad));
+ if (values[r] > values[pic_idx]) {
+ pic_idx = r;
+ }
+ }
+
+ polyfit (values, max_rad - min_rad + 1, min_rad, a, b, c);
+ if (*a <= max_a) {
+ center->x = urc.x;
+ center->y = urc.y;
+ center->r = -*b / (2.0f * *a);
+ max_a = *a;
+ }
+ }
+ }
+ *a = max_a;
+}
+
+static char
+center_search (UfoMultiSearchTaskPrivate *priv, UfoBuffer *image,
+ UfoRingCoordinate *src, UfoRingCoordinate *dst)
+{
+ float a, b, c;
+ /* Compute polynomial aX^2 + bX + c */
+ create_profile_advanced(priv, image, src, &a, &b, &c);
+ /* When contrast is too low, we delete ring */
+ /* A represents the steepness of the polynomial, the more steep i-e the more
+ * negative a is, the more contrast we have. The ideal function is a
+ * dirac */
+ if (a <= -priv->threshold) {
+ *dst = *src;
+ dst->contrast = a;
+ return 1;
+ }
+
+ return 0;
+}
+
+static gboolean
+ufo_multi_search_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ (void) requisition;
+ URCS *src = (URCS *) ufo_buffer_get_host_array(inputs[1], NULL);
+ URCS *dst = (URCS *) ufo_buffer_get_host_array(output, NULL);
+ unsigned nb_elt = (unsigned) src->nb_elt;
+ UfoMultiSearchTaskPrivate *priv = UFO_MULTI_SEARCH_TASK_GET_PRIVATE (task);
+
+ unsigned del_count = 0;
+ /* Check rings contrast, if it's too low, delete it */
+ for (unsigned idx = 0; idx < nb_elt; ++idx) {
+ if (!center_search(priv, inputs[0], &src->coord[idx],
+ &dst->coord[idx - del_count]))
+ del_count++;
+ }
+ dst->nb_elt = src->nb_elt - (float) del_count;
+ return TRUE;
+}
+
+static void
+ufo_multi_search_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoMultiSearchTaskPrivate *priv = UFO_MULTI_SEARCH_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_RADII_RANGE:
+ priv->radii_range = g_value_get_uint (value);
+ break;
+ case PROP_THRESHOLD:
+ priv->threshold = g_value_get_float (value);
+ break;
+ case PROP_DISPLACEMENT:
+ priv->displacement = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_multi_search_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoMultiSearchTaskPrivate *priv = UFO_MULTI_SEARCH_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_RADII_RANGE:
+ g_value_set_uint (value, priv->radii_range);
+ break;
+ case PROP_THRESHOLD:
+ g_value_set_float (value, priv->threshold);
+ break;
+ case PROP_DISPLACEMENT:
+ g_value_set_uint (value, priv->displacement);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_multi_search_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_multi_search_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_multi_search_task_setup;
+ iface->get_num_inputs = ufo_multi_search_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_multi_search_task_get_num_dimensions;
+ iface->get_mode = ufo_multi_search_task_get_mode;
+ iface->get_requisition = ufo_multi_search_task_get_requisition;
+ iface->process = ufo_multi_search_task_process;
+}
+
+static void
+ufo_multi_search_task_class_init (UfoMultiSearchTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_multi_search_task_set_property;
+ gobject_class->get_property = ufo_multi_search_task_get_property;
+ gobject_class->finalize = ufo_multi_search_task_finalize;
+
+ properties[PROP_RADII_RANGE] =
+ g_param_spec_uint ("radii_range",
+ "Gives the radius scanning range",
+ "Gives the radius scanning range",
+ 0, G_MAXUINT, 3,
+ G_PARAM_READWRITE);
+
+ properties[PROP_THRESHOLD] =
+ g_param_spec_float ("threshold",
+ "Give minimum contrast a ring should have",
+ "Give minimum contrast a ring should have",
+ 0, G_MAXFLOAT, 0.01f,
+ G_PARAM_READWRITE);
+
+ properties[PROP_DISPLACEMENT] =
+ g_param_spec_uint ("displacement",
+ "How much rings center can be displaced",
+ "How much rings center can be displaced",
+ 0, G_MAXUINT, 2,
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoMultiSearchTaskPrivate));
+}
+
+static void
+ufo_multi_search_task_init(UfoMultiSearchTask *self)
+{
+ self->priv = UFO_MULTI_SEARCH_TASK_GET_PRIVATE(self);
+ self->priv->radii_range = 3;
+ self->priv->threshold = 0.01f;
+ self->priv->displacement = 2;
+}
diff --git a/src/ufo-multi-search-task.h b/src/ufo-multi-search-task.h
new file mode 100644
index 0000000..3b043a2
--- /dev/null
+++ b/src/ufo-multi-search-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_MULTI_SEARCH_TASK_H
+#define __UFO_MULTI_SEARCH_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_MULTI_SEARCH_TASK (ufo_multi_search_task_get_type())
+#define UFO_MULTI_SEARCH_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_MULTI_SEARCH_TASK, UfoMultiSearchTask))
+#define UFO_IS_MULTI_SEARCH_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_MULTI_SEARCH_TASK))
+#define UFO_MULTI_SEARCH_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_MULTI_SEARCH_TASK, UfoMultiSearchTaskClass))
+#define UFO_IS_MULTI_SEARCH_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_MULTI_SEARCH_TASK))
+#define UFO_MULTI_SEARCH_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_MULTI_SEARCH_TASK, UfoMultiSearchTaskClass))
+
+typedef struct _UfoMultiSearchTask UfoMultiSearchTask;
+typedef struct _UfoMultiSearchTaskClass UfoMultiSearchTaskClass;
+typedef struct _UfoMultiSearchTaskPrivate UfoMultiSearchTaskPrivate;
+
+/**
+ * UfoMultiSearchTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoMultiSearchTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoMultiSearchTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoMultiSearchTaskPrivate *priv;
+};
+
+/**
+ * UfoMultiSearchTaskClass:
+ *
+ * #UfoMultiSearchTask class
+ */
+struct _UfoMultiSearchTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_multi_search_task_new (void);
+GType ufo_multi_search_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-ordfilt-task.c b/src/ufo-ordfilt-task.c
new file mode 100644
index 0000000..96a2426
--- /dev/null
+++ b/src/ufo-ordfilt-task.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef __APPLE__
+# include <OpenCL/cl.h>
+#else
+# include <CL/cl.h>
+#endif
+
+#include <limits.h>
+#include <glib.h>
+
+#include "ufo-ordfilt-task.h"
+#include "ufo-priv.h"
+
+struct _UfoOrdfiltTaskPrivate {
+ cl_kernel k_bitonic_ordfilt;
+ cl_kernel k_load_elements_from_patern;
+ size_t max_alloc_size;
+ gpointer context;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoOrdfiltTask, ufo_ordfilt_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_ORDFILT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_ORDFILT_TASK, UfoOrdfiltTaskPrivate))
+
+UfoNode *
+ufo_ordfilt_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_ORDFILT_TASK, NULL));
+}
+
+static void
+get_max_alloc_size (UfoResources *resources, UfoOrdfiltTaskPrivate *priv)
+{
+ priv->max_alloc_size = ULLONG_MAX;
+ GList *devices = ufo_resources_get_devices (resources);
+ GList *it;
+
+ g_list_for (devices, it) {
+ cl_device_id device = (cl_device_id) it->data;
+ size_t byte_count = 0;
+ size_t max_alloc_size = 0;
+ clGetDeviceInfo (device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof (size_t), &max_alloc_size, &byte_count);
+ g_assert (sizeof (size_t) == byte_count);
+
+ if (max_alloc_size < priv->max_alloc_size)
+ priv->max_alloc_size = max_alloc_size;
+ }
+}
+
+static void
+ufo_ordfilt_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+ UfoOrdfiltTaskPrivate *priv;
+
+ priv = UFO_ORDFILT_TASK_GET_PRIVATE (task);
+ priv->context = ufo_resources_get_context (resources);
+ get_max_alloc_size (resources, priv);
+
+ priv->k_bitonic_ordfilt = ufo_resources_get_kernel (resources, "ordfilt.cl", "bitonic_ordfilt", error);
+
+ if (priv->k_bitonic_ordfilt != NULL)
+ UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->k_bitonic_ordfilt));
+
+ priv->k_load_elements_from_patern = ufo_resources_get_kernel (resources, "ordfilt.cl", "load_elements_from_pattern", error);
+
+ if (priv->k_load_elements_from_patern != NULL)
+ UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->k_load_elements_from_patern));
+}
+
+static void
+ufo_ordfilt_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition (inputs[0], requisition);
+}
+
+static guint
+ufo_ordfilt_task_get_num_inputs (UfoTask *task)
+{
+ return 2;
+}
+
+static guint
+ufo_ordfilt_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_ordfilt_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_GPU;
+}
+
+/* K is ordfilt kernel */
+static void
+launch_kernel_1D (cl_kernel k, UfoBuffer *ufo_src, UfoBuffer *ufo_dst,
+ cl_command_queue cmd_queue, size_t num_elements,
+ unsigned idx_offset, unsigned mod)
+{
+ cl_mem dst;
+ cl_mem src;
+ UfoRequisition requisition;
+ size_t global_work_size[1];
+ size_t local_work_size[1];
+
+ dst = ufo_buffer_get_device_array (ufo_dst, cmd_queue);
+ src = ufo_buffer_get_device_array (ufo_src, cmd_queue);
+
+ /* Power of 2 above num_elements */
+ size_t array_length = (size_t) ceil_power_of_two (num_elements);
+ cl_float low_threshold = 0.25;
+ cl_float high_threshold = 0.50;
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (k, 0, sizeof (cl_mem), &src));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (k, 1, sizeof (cl_mem), &dst));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (k, 2, sizeof (cl_int), &num_elements));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (k, 3, sizeof (cl_int), &array_length));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (k, 4, sizeof (cl_float), &low_threshold));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (k, 5, sizeof (cl_float), &high_threshold));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (k, 6, sizeof (cl_float) * array_length, NULL));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (k, 7, sizeof (cl_uint), &idx_offset));
+
+ /* Launch the kernel over 1D grid */
+ ufo_buffer_get_requisition(ufo_src, &requisition);
+
+ /* buffer may have mod extra rows -> so dont do extra work */
+ global_work_size[0] = requisition.dims[0] * (requisition.dims[1] - mod) *
+ (array_length / 2);
+ /* Power of two below number of elements to sort */
+ local_work_size[0] = array_length / 2;
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (cmd_queue,
+ k,
+ 1, NULL, global_work_size,
+ local_work_size,
+ 0, NULL, NULL));
+}
+
+static void
+launch_kernel_2D(cl_kernel kernel, UfoBuffer *ufo_src, UfoBuffer *ufo_pattern,
+ UfoBuffer *ufo_dst, cl_command_queue cmd_queue, size_t dimension,
+ size_t num_ones, unsigned height, unsigned y_offset, unsigned mod)
+{
+ cl_mem dst;
+ cl_mem src;
+ cl_mem pattern;
+ UfoRequisition requisition;
+ size_t global_work_size[2];
+ size_t local_work_size[2];
+ dst = ufo_buffer_get_device_array(ufo_dst, cmd_queue);
+ src = ufo_buffer_get_device_array(ufo_src, cmd_queue);
+ pattern = ufo_buffer_get_device_array(ufo_pattern, cmd_queue);
+
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof (cl_mem), &src));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof (cl_mem), &dst));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 2, sizeof (cl_mem), &pattern));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 3, sizeof (cl_int), &dimension));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 4, sizeof (cl_int), &num_ones));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 5, sizeof (cl_uint), &height));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 6, sizeof (cl_uint), &y_offset));
+
+ /* Launch the kernel over 2D grid, using dst requisition which reperesents a
+ * crop of the image */
+ ufo_buffer_get_requisition (ufo_dst, &requisition);
+ global_work_size[0] = requisition.dims[0];
+ /* Buffer may have mod extra rows, don't take them into account */
+ global_work_size[1] = requisition.dims[1] - mod;
+ unsigned y_worker_count = 32;
+ unsigned x_worker_count = 32;
+
+ while (global_work_size[1] % y_worker_count)
+ --y_worker_count;
+
+ while (global_work_size[0] % x_worker_count)
+ --x_worker_count;
+
+ local_work_size[0] = x_worker_count; /* Multiple of image_width=1080 */
+ local_work_size[1] = y_worker_count; /* Multiple of image_height=1280 */
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (cmd_queue,
+ kernel,
+ 2, NULL, global_work_size,
+ local_work_size,
+ 0, NULL, NULL));
+}
+
+static void
+get_ring_metadata(UfoBuffer *pattern, unsigned *number_ones, unsigned *radius)
+{
+ GValue *value;
+ value = ufo_buffer_get_metadata(pattern, "number_ones");
+ *number_ones = g_value_get_uint(value);
+
+ value = ufo_buffer_get_metadata(pattern, "radius");
+ *radius = g_value_get_uint(value);
+}
+
+static void
+compute_ordfilt (UfoOrdfiltTaskPrivate *priv, UfoBuffer *src, UfoBuffer *pattern,
+ UfoBuffer *dst, cl_command_queue cmd_queue)
+{
+
+ UfoRequisition image_requisition;
+ UfoRequisition pattern_requisition;
+ ufo_buffer_get_requisition(src, &image_requisition);
+ ufo_buffer_get_requisition(pattern, &pattern_requisition);
+
+ unsigned number_ones;
+ unsigned radius;
+ get_ring_metadata(pattern, &number_ones, &radius);
+
+ unsigned height = (unsigned) image_requisition.dims[1];
+ unsigned width = (unsigned) image_requisition.dims[0];
+ /* Tells us in how many chunks to chop image */
+ unsigned iter_count = (unsigned) (1 + sizeof (float) * height * width * number_ones / (priv->max_alloc_size + 1));
+ unsigned y_offset = 0;
+
+ /* On first iteration process mod rows more, this is needed when the height
+ * of image is not divisible by iter_count */
+ unsigned mod = (unsigned) (image_requisition.dims[1] % iter_count);
+
+ UfoRequisition requisition = {
+ .n_dims = 3,
+ .dims[0] = image_requisition.dims[0],
+ .dims[1] = image_requisition.dims[1] / iter_count + mod,
+ .dims[2] = number_ones,
+ };
+ UfoBuffer *ufo_buffer = ufo_buffer_new(&requisition, priv->context);
+
+ /* loads surrounding number_ones pixels of each pixel in image.
+ * Result in buffer */
+ launch_kernel_2D (priv->k_load_elements_from_patern, src, pattern,
+ ufo_buffer, cmd_queue, pattern_requisition.dims[0],
+ number_ones, height, y_offset, 0);
+ /* Create image of threshold telling how likely a pixel is a center of a
+ * ring */
+ launch_kernel_1D (priv->k_bitonic_ordfilt, ufo_buffer, dst, cmd_queue,
+ number_ones, width * y_offset, 0);
+
+ for (unsigned iter = 0; iter < iter_count; ++iter) {
+ /* start at mod offset, since first iteration manipulated
+ * iter * height + mod rows */
+ y_offset = mod + iter * (height - mod) / iter_count;
+ launch_kernel_2D (priv->k_load_elements_from_patern, src, pattern,
+ ufo_buffer, cmd_queue, pattern_requisition.dims[0],
+ number_ones, height, y_offset, mod);
+ launch_kernel_1D (priv->k_bitonic_ordfilt, ufo_buffer, dst, cmd_queue,
+ number_ones, width * y_offset, mod);
+ }
+
+ g_object_unref(ufo_buffer);
+}
+
+static gboolean
+ufo_ordfilt_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoOrdfiltTaskPrivate *priv;
+ UfoGpuNode *node;
+ cl_command_queue cmd_queue;
+
+ priv = UFO_ORDFILT_TASK_GET_PRIVATE (task);
+ node = UFO_GPU_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (task)));
+ cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+
+ priv = UFO_ORDFILT_TASK_GET_PRIVATE (task);
+ compute_ordfilt (priv, inputs[0], inputs[1], output, cmd_queue);
+
+ return TRUE;
+}
+
+static void
+ufo_ordfilt_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_ordfilt_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_ordfilt_task_setup;
+ iface->get_num_inputs = ufo_ordfilt_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_ordfilt_task_get_num_dimensions;
+ iface->get_mode = ufo_ordfilt_task_get_mode;
+ iface->get_requisition = ufo_ordfilt_task_get_requisition;
+ iface->process = ufo_ordfilt_task_process;
+}
+
+static void
+ufo_ordfilt_task_class_init (UfoOrdfiltTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = ufo_ordfilt_task_finalize;
+
+ g_type_class_add_private (gobject_class, sizeof(UfoOrdfiltTaskPrivate));
+}
+
+static void
+ufo_ordfilt_task_init(UfoOrdfiltTask *self)
+{
+ self->priv = UFO_ORDFILT_TASK_GET_PRIVATE(self);
+}
diff --git a/src/ufo-ordfilt-task.h b/src/ufo-ordfilt-task.h
new file mode 100644
index 0000000..3b3d61f
--- /dev/null
+++ b/src/ufo-ordfilt-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_ORDFILT_TASK_H
+#define __UFO_ORDFILT_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_ORDFILT_TASK (ufo_ordfilt_task_get_type())
+#define UFO_ORDFILT_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_ORDFILT_TASK, UfoOrdfiltTask))
+#define UFO_IS_ORDFILT_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_ORDFILT_TASK))
+#define UFO_ORDFILT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_ORDFILT_TASK, UfoOrdfiltTaskClass))
+#define UFO_IS_ORDFILT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_ORDFILT_TASK))
+#define UFO_ORDFILT_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_ORDFILT_TASK, UfoOrdfiltTaskClass))
+
+typedef struct _UfoOrdfiltTask UfoOrdfiltTask;
+typedef struct _UfoOrdfiltTaskClass UfoOrdfiltTaskClass;
+typedef struct _UfoOrdfiltTaskPrivate UfoOrdfiltTaskPrivate;
+
+/**
+ * UfoOrdfiltTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoOrdfiltTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoOrdfiltTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoOrdfiltTaskPrivate *priv;
+};
+
+/**
+ * UfoOrdfiltTaskClass:
+ *
+ * #UfoOrdfiltTask class
+ */
+struct _UfoOrdfiltTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_ordfilt_task_new (void);
+GType ufo_ordfilt_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-priv.c b/src/ufo-priv.c
new file mode 100644
index 0000000..b37ef26
--- /dev/null
+++ b/src/ufo-priv.c
@@ -0,0 +1,12 @@
+#include "ufo-priv.h"
+
+guint
+ceil_power_of_two (guint x)
+{
+ guint res = 1;
+
+ while (res < x)
+ res *= 2;
+
+ return res;
+}
diff --git a/src/ufo-priv.h b/src/ufo-priv.h
new file mode 100644
index 0000000..98f08d7
--- /dev/null
+++ b/src/ufo-priv.h
@@ -0,0 +1,17 @@
+#ifndef UFO_PRIV_H
+#define UFO_PRIV_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define g_list_for(list, it) \
+ for (it = g_list_first (list); \
+ it != NULL; \
+ it = g_list_next (it))
+
+guint ceil_power_of_two (guint x);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ufo-reduce-task.c b/src/ufo-reduce-task.c
new file mode 100644
index 0000000..7fb7384
--- /dev/null
+++ b/src/ufo-reduce-task.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include "ufo-reduce-task.h"
+
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoReduceTask, ufo_reduce_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_REDUCE_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_REDUCE_TASK, UfoReduceTaskPrivate))
+
+
+UfoNode *
+ufo_reduce_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_REDUCE_TASK, NULL));
+}
+
+static void
+ufo_reduce_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_reduce_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition(inputs[0], requisition);
+ requisition->dims[0] /= 2;
+ requisition->dims[1] /= 2;
+}
+
+static guint
+ufo_reduce_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_reduce_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_reduce_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_CPU;
+}
+
+static gboolean
+ufo_reduce_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoRequisition input_req;
+ ufo_buffer_get_requisition(inputs[0], &input_req);
+ float *src = ufo_buffer_get_host_array(inputs[0], NULL);
+ float *out = ufo_buffer_get_host_array(output, NULL);
+
+ for (unsigned i = 0; i < requisition->dims[0]; ++i) {
+ for (unsigned j = 0; j < requisition->dims[1]; ++j) {
+ out[i + j * requisition->dims[0]] = src[2 * i + 2 * j * input_req.dims[0]];
+ out[i + j * requisition->dims[0]] += src[2 * i + 1 + 2 * j * input_req.dims[0]];
+ out[i + j * requisition->dims[0]] += src[2 * i + j * 2 * input_req.dims[0] + input_req.dims[0]];
+ out[i + j * requisition->dims[0]] += src[2 * i + 1 + j * 2 * input_req.dims[0] + input_req.dims[0]];
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_reduce_task_setup;
+ iface->get_num_inputs = ufo_reduce_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_reduce_task_get_num_dimensions;
+ iface->get_mode = ufo_reduce_task_get_mode;
+ iface->get_requisition = ufo_reduce_task_get_requisition;
+ iface->process = ufo_reduce_task_process;
+}
+
+static void
+ufo_reduce_task_class_init (UfoReduceTaskClass *klass)
+{
+}
+
+static void
+ufo_reduce_task_init(UfoReduceTask *self)
+{
+}
diff --git a/src/ufo-reduce-task.h b/src/ufo-reduce-task.h
new file mode 100644
index 0000000..bb55f6b
--- /dev/null
+++ b/src/ufo-reduce-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_REDUCE_TASK_H
+#define __UFO_REDUCE_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_REDUCE_TASK (ufo_reduce_task_get_type())
+#define UFO_REDUCE_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_REDUCE_TASK, UfoReduceTask))
+#define UFO_IS_REDUCE_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_REDUCE_TASK))
+#define UFO_REDUCE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_REDUCE_TASK, UfoReduceTaskClass))
+#define UFO_IS_REDUCE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_REDUCE_TASK))
+#define UFO_REDUCE_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_REDUCE_TASK, UfoReduceTaskClass))
+
+typedef struct _UfoReduceTask UfoReduceTask;
+typedef struct _UfoReduceTaskClass UfoReduceTaskClass;
+typedef struct _UfoReduceTaskPrivate UfoReduceTaskPrivate;
+
+/**
+ * UfoReduceTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoReduceTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoReduceTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoReduceTaskPrivate *priv;
+};
+
+/**
+ * UfoReduceTaskClass:
+ *
+ * #UfoReduceTask class
+ */
+struct _UfoReduceTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_reduce_task_new (void);
+GType ufo_reduce_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-remove-circle-task.c b/src/ufo-remove-circle-task.c
new file mode 100644
index 0000000..c1b2e9d
--- /dev/null
+++ b/src/ufo-remove-circle-task.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <math.h>
+#include "ufo-remove-circle-task.h"
+#include "ufo-ring-coordinates.h"
+
+
+struct _UfoRemoveCircleTaskPrivate {
+ float threshold;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoRemoveCircleTask, ufo_remove_circle_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_REMOVE_CIRCLE_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_REMOVE_CIRCLE_TASK, UfoRemoveCircleTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_THRESHOLD,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_remove_circle_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_REMOVE_CIRCLE_TASK, NULL));
+}
+
+static void
+ufo_remove_circle_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_remove_circle_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ /* At most we will have same sized buffer as input since we are only
+ * removing circles */
+ ufo_buffer_get_requisition(inputs[0], requisition);
+}
+
+static guint
+ufo_remove_circle_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_remove_circle_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 1;
+}
+
+static UfoTaskMode
+ufo_remove_circle_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_CPU;
+}
+
+static unsigned
+is_intersection(UfoRemoveCircleTaskPrivate *priv, UfoRingCoordinate *left,
+ UfoRingCoordinate *center, UfoRingCoordinate *right)
+{
+ float threshold = priv->threshold;
+ float lr_dx = left->x - right->x;
+ float lr_dy = left->y - right->y;
+ float lr_dist = sqrtf(lr_dx * lr_dx + lr_dy * lr_dy);
+
+ /* We want left and right to intersect */
+ if (left->r + right->r <= lr_dist)
+ return 0;
+
+ UfoRingCoordinate lr_mid = {
+ .x = (left->x + right->x) / 2,
+ .y = (left->y + right->y) / 2,
+ .r = (left->r + right->r) / 2
+ };
+ float r_inner = (left->r + right->r - lr_dist) / 2;
+ float r_outer = (left->r + right->r + lr_dist) / 2;
+
+ float dr_in = fabsf(center->r - r_inner);
+ float dr_out = fabsf(center->r - r_outer);
+ /* Center radi must have a raddi approximately equal to the inner or outer
+ * ring radius */
+ if (dr_out >= threshold && dr_in >= threshold)
+ return 0;
+
+ /* Compute distance from center to the midpoint location of left and right */
+ float cm_dx = center->x - lr_mid.x;
+ float cm_dy = center->y - lr_mid.y;
+ float cm_dist = sqrtf(cm_dx * cm_dx + cm_dy * cm_dy);
+ /* Center has to be close enough to the optimal intersection center point */
+ if (cm_dist >= lr_dist / 2)
+ return 0;
+
+ return 1;
+}
+
+static void remove_circle(UfoRemoveCircleTaskPrivate *priv, URCS *src, URCS *dst)
+{
+ unsigned nb_elt = (unsigned) src->nb_elt;
+ /* Number of elements to keep */
+ unsigned res_counter = 0;
+ /* Check if any of the elements is actually the intersection of two others
+ * rings */
+ for (unsigned center = 0; center < nb_elt; ++center) {
+ /* Flag to check if center is an intersecting ring */
+ unsigned is_intersecting_ring = 0;
+ /* Check if there exists a pair (not containing center) of rings such
+ * as center rings is indeed the intersection of that pair of rings */
+ for (unsigned left = 0; left < nb_elt; ++left) {
+ if (left == center)
+ continue;
+
+ for (unsigned right = left + 1; right < nb_elt; ++right) {
+ if (right == center)
+ continue;
+
+ if (is_intersection(priv, &src->coord[left], &src->coord[center], &src->coord[right])) {
+ is_intersecting_ring = 1;
+ break;
+ }
+ }
+
+ /* Stop searching if we know that centers needs removing */
+ if (is_intersecting_ring)
+ break;
+ }
+
+ if (!is_intersecting_ring) {
+ dst->coord[res_counter] = src->coord[center];
+ ++res_counter;
+ }
+ }
+ dst->nb_elt = (float) res_counter;
+}
+
+static
+int get_min_contrast(URCS *src)
+{
+ int min_i = 0;
+ char found = 0;
+ for (int i = 0; i < src->nb_elt; ++i){
+ if (src->coord[i].contrast) {
+ found = 1;
+ if (src->coord[min_i].contrast * src->coord[min_i].intensity >
+ src->coord[i].contrast * src->coord[i].intensity ||
+ src->coord[min_i].contrast == 0)
+ min_i = i;
+ }
+ }
+ if (!found)
+ return -1;
+ return min_i;
+}
+
+static
+void remove_inner_circle(URCS *src, URCS *dst)
+{
+ int min_i = get_min_contrast(src);
+ unsigned counter = 0;
+
+ while (min_i != -1 && counter < src->nb_elt) {
+ for (int i = 0; i < src->nb_elt; ++i) {
+ if (!src->coord[i].contrast || i == min_i)
+ continue;
+
+ float dx = src->coord[i].x - src->coord[min_i].x;
+ float dy = src->coord[i].y - src->coord[min_i].y;
+ float dist = sqrtf(dx * dx + dy * dy);
+ /* Check if other ring is touching current ring */
+ float big_rad = src->coord[min_i].r;
+ float small_rad = src->coord[i].r;
+
+ if (small_rad > big_rad) {
+ small_rad = big_rad;
+ big_rad = src->coord[i].r;
+ }
+
+ if (fabs(dist + small_rad - big_rad) < 6) {
+ /* Check if other ring contrast is less to current ring */
+ /* If so remove it, as it likely is a false positive, i-e it was
+ * using part of current ring */
+ if ((src->coord[i].contrast * src->coord[i].intensity) /
+ (src->coord[min_i].contrast * src->coord[min_i].intensity) < 0.75)
+ src->coord[i].contrast = 0;
+ }
+ }
+ dst->coord[counter] = src->coord[min_i];
+ ++counter;
+ /* Notify that we have check this ring to not process it again */
+ src->coord[min_i].contrast = 0;
+ min_i = get_min_contrast(src);
+ }
+ dst->nb_elt = (float) counter;
+ if (counter >= src->nb_elt && min_i != -1)
+ g_print("Remove Circle : Some memory corruption occured. This is a bug "
+ " in the software that needs fixing\n");
+}
+
+static gboolean
+ufo_remove_circle_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoBuffer* dup = ufo_buffer_dup(inputs[0]);
+ ufo_buffer_copy(inputs[0], dup);
+ URCS *coord = (URCS *) ufo_buffer_get_host_array(dup, NULL);
+ URCS *out_coord = (URCS *) ufo_buffer_get_host_array(output, NULL);
+ UfoRemoveCircleTaskPrivate *priv = UFO_REMOVE_CIRCLE_TASK_GET_PRIVATE(task);
+ remove_inner_circle(coord, out_coord);
+
+ ufo_buffer_copy(output, dup);
+ remove_circle(priv, coord, out_coord);
+
+ g_object_unref(dup);
+ return TRUE;
+}
+
+static void
+ufo_remove_circle_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoRemoveCircleTaskPrivate *priv = UFO_REMOVE_CIRCLE_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_THRESHOLD:
+ priv->threshold = g_value_get_float (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_remove_circle_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoRemoveCircleTaskPrivate *priv = UFO_REMOVE_CIRCLE_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_THRESHOLD:
+ g_value_set_float (value, priv->threshold);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_remove_circle_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_remove_circle_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_remove_circle_task_setup;
+ iface->get_num_inputs = ufo_remove_circle_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_remove_circle_task_get_num_dimensions;
+ iface->get_mode = ufo_remove_circle_task_get_mode;
+ iface->get_requisition = ufo_remove_circle_task_get_requisition;
+ iface->process = ufo_remove_circle_task_process;
+}
+
+static void
+ufo_remove_circle_task_class_init (UfoRemoveCircleTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_remove_circle_task_set_property;
+ gobject_class->get_property = ufo_remove_circle_task_get_property;
+ gobject_class->finalize = ufo_remove_circle_task_finalize;
+
+ properties[PROP_THRESHOLD] =
+ g_param_spec_float ("threshold",
+ "Set maximum Inner and outer ring radii size difference",
+ "Set maximum inner and outer ring radii size difference",
+ 1, G_MAXFLOAT, 5,
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoRemoveCircleTaskPrivate));
+}
+
+static void
+ufo_remove_circle_task_init(UfoRemoveCircleTask *self)
+{
+ self->priv = UFO_REMOVE_CIRCLE_TASK_GET_PRIVATE(self);
+ self->priv->threshold = 5;
+}
diff --git a/src/ufo-remove-circle-task.h b/src/ufo-remove-circle-task.h
new file mode 100644
index 0000000..c7e5dcf
--- /dev/null
+++ b/src/ufo-remove-circle-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_REMOVE_CIRCLE_TASK_H
+#define __UFO_REMOVE_CIRCLE_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_REMOVE_CIRCLE_TASK (ufo_remove_circle_task_get_type())
+#define UFO_REMOVE_CIRCLE_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_REMOVE_CIRCLE_TASK, UfoRemoveCircleTask))
+#define UFO_IS_REMOVE_CIRCLE_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_REMOVE_CIRCLE_TASK))
+#define UFO_REMOVE_CIRCLE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_REMOVE_CIRCLE_TASK, UfoRemoveCircleTaskClass))
+#define UFO_IS_REMOVE_CIRCLE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_REMOVE_CIRCLE_TASK))
+#define UFO_REMOVE_CIRCLE_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_REMOVE_CIRCLE_TASK, UfoRemoveCircleTaskClass))
+
+typedef struct _UfoRemoveCircleTask UfoRemoveCircleTask;
+typedef struct _UfoRemoveCircleTaskClass UfoRemoveCircleTaskClass;
+typedef struct _UfoRemoveCircleTaskPrivate UfoRemoveCircleTaskPrivate;
+
+/**
+ * UfoRemoveCircleTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoRemoveCircleTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoRemoveCircleTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoRemoveCircleTaskPrivate *priv;
+};
+
+/**
+ * UfoRemoveCircleTaskClass:
+ *
+ * #UfoRemoveCircleTask class
+ */
+struct _UfoRemoveCircleTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_remove_circle_task_new (void);
+GType ufo_remove_circle_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-replicate-task.c b/src/ufo-replicate-task.c
new file mode 100644
index 0000000..98cb5cc
--- /dev/null
+++ b/src/ufo-replicate-task.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <stdlib.h>
+#include "ufo-replicate-task.h"
+
+struct _UfoReplicateTaskPrivate {
+ unsigned alloc_size;
+ unsigned idx;
+ UfoBuffer *data;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoReplicateTask, ufo_replicate_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_REPLICATE_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_REPLICATE_TASK, UfoReplicateTaskPrivate))
+
+UfoNode *
+ufo_replicate_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_REPLICATE_TASK, NULL));
+}
+
+static void
+ufo_replicate_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_replicate_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ ufo_buffer_get_requisition(inputs[0], requisition);
+}
+
+static guint
+ufo_replicate_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_replicate_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 2;
+}
+
+static UfoTaskMode
+ufo_replicate_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_REDUCTOR;
+}
+
+static gboolean
+ufo_replicate_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoReplicateTaskPrivate *priv = UFO_REPLICATE_TASK_GET_PRIVATE (task);
+
+ if (priv->idx > priv->alloc_size) {
+ priv->alloc_size *= 2;
+ size_t nb_bytes = priv->alloc_size * sizeof (UfoBuffer *);
+ priv->data = realloc (priv->data, nb_bytes);
+ }
+
+ return TRUE;
+}
+
+static void
+ufo_replicate_task_finalize (GObject *object)
+{
+ UfoReplicateTaskPrivate *priv;
+
+ priv = UFO_REPLICATE_TASK_GET_PRIVATE (object);
+ g_free (priv->data);
+ G_OBJECT_CLASS (ufo_replicate_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_replicate_task_setup;
+ iface->get_num_inputs = ufo_replicate_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_replicate_task_get_num_dimensions;
+ iface->get_mode = ufo_replicate_task_get_mode;
+ iface->get_requisition = ufo_replicate_task_get_requisition;
+ iface->process = ufo_replicate_task_process;
+}
+
+static void
+ufo_replicate_task_class_init (UfoReplicateTaskClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->finalize = ufo_replicate_task_finalize;
+
+ g_type_class_add_private (oclass, sizeof(UfoReplicateTaskPrivate));
+}
+
+static void
+ufo_replicate_task_init(UfoReplicateTask *self)
+{
+ self->priv = UFO_REPLICATE_TASK_GET_PRIVATE(self);
+ self->priv->alloc_size = 256;
+ self->priv->data = g_malloc (sizeof (UfoBuffer *) * self->priv->alloc_size);
+ self->priv->idx = 0;
+}
diff --git a/src/ufo-replicate-task.h b/src/ufo-replicate-task.h
new file mode 100644
index 0000000..af39d88
--- /dev/null
+++ b/src/ufo-replicate-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_REPLICATE_TASK_H
+#define __UFO_REPLICATE_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_REPLICATE_TASK (ufo_replicate_task_get_type())
+#define UFO_REPLICATE_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_REPLICATE_TASK, UfoReplicateTask))
+#define UFO_IS_REPLICATE_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_REPLICATE_TASK))
+#define UFO_REPLICATE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_REPLICATE_TASK, UfoReplicateTaskClass))
+#define UFO_IS_REPLICATE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_REPLICATE_TASK))
+#define UFO_REPLICATE_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_REPLICATE_TASK, UfoReplicateTaskClass))
+
+typedef struct _UfoReplicateTask UfoReplicateTask;
+typedef struct _UfoReplicateTaskClass UfoReplicateTaskClass;
+typedef struct _UfoReplicateTaskPrivate UfoReplicateTaskPrivate;
+
+/**
+ * UfoReplicateTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoReplicateTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoReplicateTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoReplicateTaskPrivate *priv;
+};
+
+/**
+ * UfoReplicateTaskClass:
+ *
+ * #UfoReplicateTask class
+ */
+struct _UfoReplicateTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_replicate_task_new (void);
+GType ufo_replicate_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-ring-coordinates.h b/src/ufo-ring-coordinates.h
new file mode 100644
index 0000000..e52c800
--- /dev/null
+++ b/src/ufo-ring-coordinates.h
@@ -0,0 +1,20 @@
+#ifndef UFO_RING_COORDINATES_H
+#define UFO_RING_COORDINATES_H
+
+struct _UfoRingCoordinate {
+ float x;
+ float y;
+ float r;
+ float contrast;
+ float intensity;
+};
+
+struct _UfoRingCoordinatesStream {
+ float nb_elt;
+ struct _UfoRingCoordinate *coord;
+};
+
+typedef struct _UfoRingCoordinate UfoRingCoordinate;
+typedef struct _UfoRingCoordinatesStream URCS;
+
+#endif
diff --git a/src/ufo-ring-pattern-task.c b/src/ufo-ring-pattern-task.c
new file mode 100644
index 0000000..510764e
--- /dev/null
+++ b/src/ufo-ring-pattern-task.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "ufo-ring-pattern-task.h"
+
+
+struct _UfoRingPatternTaskPrivate {
+ unsigned ring_thickness;
+ unsigned ring_end;
+ unsigned ring_start;
+ unsigned ring_current;
+ unsigned ring_step;
+ unsigned width;
+ unsigned height;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoRingPatternTask, ufo_ring_pattern_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_RING_PATTERN_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_RING_PATTERN_TASK, UfoRingPatternTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_RING_START,
+ PROP_RING_STEP,
+ PROP_RING_END,
+ PROP_RING_THICKNESS,
+ PROP_WIDTH,
+ PROP_HEIGHT,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_ring_pattern_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_RING_PATTERN_TASK, NULL));
+}
+
+static void
+ufo_ring_pattern_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_ring_pattern_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ UfoRingPatternTaskPrivate *priv = UFO_RING_PATTERN_TASK_GET_PRIVATE (task);
+ requisition->dims[0] = priv->width;
+ requisition->dims[1] = priv->height;
+ requisition->n_dims = 2;
+}
+
+static guint
+ufo_ring_pattern_task_get_num_inputs (UfoTask *task)
+{
+ return 0;
+}
+
+static guint
+ufo_ring_pattern_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 0;
+}
+
+static UfoTaskMode
+ufo_ring_pattern_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_GENERATOR | UFO_TASK_MODE_CPU;
+}
+
+static void add_ring_metadata(UfoBuffer *output, unsigned number_ones,
+ unsigned radius)
+{
+ GValue value = G_VALUE_INIT;
+ g_value_init(&value, G_TYPE_UINT);
+
+ g_value_set_uint(&value, number_ones);
+ ufo_buffer_set_metadata (output, "number_ones", &value);
+
+ g_value_set_uint(&value, radius);
+ ufo_buffer_set_metadata (output, "radius", &value);
+}
+
+static gboolean
+ufo_ring_pattern_task_generate (UfoTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoRingPatternTaskPrivate *priv = UFO_RING_PATTERN_TASK_GET_PRIVATE (task);
+
+ if (priv->ring_current > priv->ring_end)
+ return FALSE;
+
+ float *out = ufo_buffer_get_host_array (output, NULL);
+ int dimx = (int) priv->width;
+ int dimy = (int) priv->height;
+ unsigned counter = 0;
+
+ for (int y = -(dimy / 2); y < dimy / 2; ++y) {
+ for (int x = -(dimx / 2); x < dimx / 2; ++x) {
+ double dist = sqrt (x * x + y * y) - priv->ring_current;
+ dist = dist < 0 ? -dist : dist;
+ if (dist < (double) priv->ring_thickness / 2) {
+ out[(x + (dimx)) % dimx + ((y + (dimy)) % dimy) * dimx] = 1;
+ ++counter;
+ }
+ else
+ out[(x + (dimx)) % dimx + ((y + (dimy)) % dimy) * dimx] = 0;
+ }
+ }
+
+ add_ring_metadata(output, counter, priv->ring_current);
+
+ for (int y = -(dimy / 2); y < dimy / 2; ++y) {
+ for (int x = -(dimx / 2); x < dimx / 2; ++x) {
+ double dist = sqrt (x * x + y * y) - priv->ring_current;
+ dist = dist < 0 ? -dist : dist;
+ if (dist < (double) priv->ring_thickness / 2) {
+ out[(x + (dimx)) % dimx + ((y + (dimy)) % dimy) * dimx] /=
+ (float) counter;
+ }
+ else
+ out[(x + (dimx)) % dimx + ((y + (dimy)) % dimy) * dimx] = 0;
+ }
+ }
+
+ priv->ring_current += priv->ring_step;
+ return TRUE;
+}
+
+static void
+ufo_ring_pattern_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoRingPatternTaskPrivate *priv = UFO_RING_PATTERN_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_RING_START:
+ priv->ring_start = g_value_get_uint(value);
+ priv->ring_current = g_value_get_uint(value);
+ break;
+ case PROP_RING_STEP:
+ priv->ring_step = g_value_get_uint(value);
+ break;
+ case PROP_RING_END:
+ priv->ring_end = g_value_get_uint(value);
+ break;
+ case PROP_RING_THICKNESS:
+ priv->ring_thickness = g_value_get_uint(value);
+ break;
+ case PROP_WIDTH:
+ priv->width = ceil_power_of_two (g_value_get_uint (value));
+ break;
+ case PROP_HEIGHT:
+ priv->height = ceil_power_of_two (g_value_get_uint (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_ring_pattern_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoRingPatternTaskPrivate *priv = UFO_RING_PATTERN_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_RING_START:
+ g_value_set_uint (value, priv->ring_start);
+ break;
+ case PROP_RING_STEP:
+ g_value_set_uint (value, priv->ring_step);
+ break;
+ case PROP_RING_END:
+ g_value_set_uint (value, priv->ring_end);
+ break;
+ case PROP_RING_THICKNESS:
+ g_value_set_uint (value, priv->ring_thickness);
+ break;
+ case PROP_WIDTH:
+ g_value_set_uint (value, priv->width);
+ break;
+ case PROP_HEIGHT:
+ g_value_set_uint (value, priv->height);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_ring_pattern_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_ring_pattern_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_ring_pattern_task_setup;
+ iface->get_num_inputs = ufo_ring_pattern_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_ring_pattern_task_get_num_dimensions;
+ iface->get_mode = ufo_ring_pattern_task_get_mode;
+ iface->get_requisition = ufo_ring_pattern_task_get_requisition;
+ iface->generate = ufo_ring_pattern_task_generate;
+}
+
+static void
+ufo_ring_pattern_task_class_init (UfoRingPatternTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_ring_pattern_task_set_property;
+ gobject_class->get_property = ufo_ring_pattern_task_get_property;
+ gobject_class->finalize = ufo_ring_pattern_task_finalize;
+
+ properties[PROP_RING_START] =
+ g_param_spec_uint ("ring_start",
+ "give starting radius size",
+ "give starting radius size",
+ 1, G_MAXUINT, 5,
+ G_PARAM_READWRITE);
+
+ properties[PROP_RING_STEP] =
+ g_param_spec_uint ("ring_step",
+ "Gives ring step",
+ "Gives ring step",
+ 1, G_MAXUINT, 2,
+ G_PARAM_READWRITE);
+
+ properties[PROP_RING_END] =
+ g_param_spec_uint ("ring_end",
+ "give ending radius size",
+ "give ending radius size",
+ 1, G_MAXUINT, 5,
+ G_PARAM_READWRITE);
+
+ properties[PROP_RING_THICKNESS] =
+ g_param_spec_uint ("ring_thickness",
+ "give desired ring thickness",
+ "give desired ring thickness",
+ 1, G_MAXUINT, 13,
+ G_PARAM_READWRITE);
+
+ properties[PROP_WIDTH] =
+ g_param_spec_uint ("width",
+ "Give x size of output image",
+ "Give x size of output image",
+ 1, G_MAXUINT, 1024,
+ G_PARAM_READWRITE);
+
+ properties[PROP_HEIGHT] =
+ g_param_spec_uint ("height",
+ "Give y size of output image",
+ "Give y size of output image",
+ 1, G_MAXUINT, 1024,
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(UfoRingPatternTaskPrivate));
+}
+
+static void
+ufo_ring_pattern_task_init(UfoRingPatternTask *self)
+{
+ self->priv = UFO_RING_PATTERN_TASK_GET_PRIVATE(self);
+ self->priv->ring_start = 5;
+ self->priv->ring_end = 5;
+ self->priv->ring_thickness = 13;
+ self->priv->ring_current = self->priv->ring_start;
+ self->priv->width = 1024;
+ self->priv->height = 1024;
+ self->priv->ring_step = 2;
+}
diff --git a/src/ufo-ring-pattern-task.h b/src/ufo-ring-pattern-task.h
new file mode 100644
index 0000000..131fbb6
--- /dev/null
+++ b/src/ufo-ring-pattern-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_RING_PATTERN_TASK_H
+#define __UFO_RING_PATTERN_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_RING_PATTERN_TASK (ufo_ring_pattern_task_get_type())
+#define UFO_RING_PATTERN_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_RING_PATTERN_TASK, UfoRingPatternTask))
+#define UFO_IS_RING_PATTERN_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_RING_PATTERN_TASK))
+#define UFO_RING_PATTERN_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_RING_PATTERN_TASK, UfoRingPatternTaskClass))
+#define UFO_IS_RING_PATTERN_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_RING_PATTERN_TASK))
+#define UFO_RING_PATTERN_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_RING_PATTERN_TASK, UfoRingPatternTaskClass))
+
+typedef struct _UfoRingPatternTask UfoRingPatternTask;
+typedef struct _UfoRingPatternTaskClass UfoRingPatternTaskClass;
+typedef struct _UfoRingPatternTaskPrivate UfoRingPatternTaskPrivate;
+
+/**
+ * UfoRingPatternTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoRingPatternTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoRingPatternTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoRingPatternTaskPrivate *priv;
+};
+
+/**
+ * UfoRingPatternTaskClass:
+ *
+ * #UfoRingPatternTask class
+ */
+struct _UfoRingPatternTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_ring_pattern_task_new (void);
+GType ufo_ring_pattern_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file
diff --git a/src/ufo-ringwriter-task.c b/src/ufo-ringwriter-task.c
new file mode 100644
index 0000000..dcbfeb1
--- /dev/null
+++ b/src/ufo-ringwriter-task.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2011-2015 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Alexandre Lewkowicz (lewkow_a@epita.fr)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "ufo-ringwriter-task.h"
+#include "ufo-ring-coordinates.h"
+
+struct _UfoRingwriterTaskPrivate {
+ char *filename;
+ unsigned scale;
+ FILE *file;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoRingwriterTask, ufo_ringwriter_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_RINGWRITER_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_RINGWRITER_TASK, UfoRingwriterTaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_PATH,
+ PROP_SCALE,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_ringwriter_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_RINGWRITER_TASK, NULL));
+}
+
+static void
+ufo_ringwriter_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_ringwriter_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ requisition->n_dims = 0;
+}
+
+static guint
+ufo_ringwriter_task_get_num_inputs (UfoTask *task)
+{
+ return 1;
+}
+
+static guint
+ufo_ringwriter_task_get_num_dimensions (UfoTask *task,
+ guint input)
+{
+ return 1;
+}
+
+static UfoTaskMode
+ufo_ringwriter_task_get_mode (UfoTask *task)
+{
+ return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_CPU;
+}
+
+static void
+get_file_metadata (UfoBuffer *src, const char **piv_file_name, unsigned *piv_file_idx)
+{
+ GValue *value;
+
+ value = ufo_buffer_get_metadata(src, "piv_file_name");
+ *piv_file_name = g_value_get_string(value);
+
+ value = ufo_buffer_get_metadata(src, "piv_file_idx");
+ *piv_file_idx = g_value_get_uint(value);
+}
+
+static void
+ufo_ringwriter_write_metadata (UfoBuffer *src, FILE *file)
+{
+ const char *piv_file_name;
+ unsigned piv_file_idx;
+ char str[256];
+ int count;
+
+ get_file_metadata (src, &piv_file_name, &piv_file_idx);
+ count = sprintf(str, "filename %s\n", piv_file_name);
+
+ if (count < 0)
+ g_print ("Unable to convert data to output text file\n");
+
+ fwrite (str, sizeof (char), (size_t) count, file);
+ count = sprintf(str, "index %u\n", piv_file_idx);
+
+ if (count < 0)
+ g_print ("Unable to convert data to output text file\n");
+
+ fwrite (str, sizeof (char), (size_t) count, file);
+}
+
+static gboolean
+ufo_ringwriter_task_process (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoRingwriterTaskPrivate *priv = UFO_RINGWRITER_TASK_GET_PRIVATE (task);
+
+ if (priv->file == NULL) {
+ static int file_count = 0;
+ char filename[256];
+ sprintf(filename, "%s%i.txt", priv->filename, file_count);
+ priv->file = fopen (filename, "w");
+ ++file_count;
+ }
+
+ URCS *ring_stream = (URCS *) ufo_buffer_get_host_array (inputs[0], NULL);
+
+ FILE *file = priv->file;
+ ufo_ringwriter_write_metadata(inputs[0], file);
+ char str[256];
+ int count = sprintf(str, "ring_count %u\n", (unsigned) ring_stream->nb_elt);
+
+ if (count < 0)
+ g_print ("Unable to convert data to output text file\n");
+
+ fwrite (str, sizeof (char), (size_t) count, file);
+
+ for (unsigned i = 0; i < ring_stream->nb_elt; ++i) {
+ int x = (int) roundf (ring_stream->coord[i].x * (float) priv->scale);
+ int y = (int) roundf (ring_stream->coord[i].y * (float) priv->scale);
+ float r = ring_stream->coord[i].r * (float) priv->scale;
+ count = sprintf(str, "ring_coord %i %i %f\n", x, y, r);
+ if (count < 0)
+ g_print ("Unable to convert data to output text file\n");
+ size_t write_count = 0;
+ char *tmp = str;
+
+ while (write_count != (size_t) count) {
+ size_t c = fwrite (tmp, sizeof (char), (size_t) count, file);
+ if (c == 0)
+ g_print ("Unable to write data to output text file\n");
+ tmp += c;
+ write_count += c;
+ }
+ }
+ return TRUE;
+}
+
+static void
+ufo_ringwriter_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoRingwriterTaskPrivate *priv = UFO_RINGWRITER_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_SCALE:
+ priv->scale = g_value_get_uint(value);
+ break;
+ case PROP_PATH:
+ priv->filename = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_ringwriter_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoRingwriterTaskPrivate *priv = UFO_RINGWRITER_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_SCALE:
+ g_value_set_uint (value, priv->scale);
+ break;
+ case PROP_PATH:
+ g_value_set_string (value, priv->filename);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_ringwriter_task_finalize (GObject *object)
+{
+ UfoRingwriterTaskPrivate *priv = UFO_RINGWRITER_TASK_GET_PRIVATE (object);
+
+ if (priv->file)
+ fclose (priv->file);
+
+ if (priv->filename)
+ g_free (priv->filename);
+
+ G_OBJECT_CLASS (ufo_ringwriter_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_ringwriter_task_setup;
+ iface->get_num_inputs = ufo_ringwriter_task_get_num_inputs;
+ iface->get_num_dimensions = ufo_ringwriter_task_get_num_dimensions;
+ iface->get_mode = ufo_ringwriter_task_get_mode;
+ iface->get_requisition = ufo_ringwriter_task_get_requisition;
+ iface->process = ufo_ringwriter_task_process;
+}
+
+static void
+ufo_ringwriter_task_class_init (UfoRingwriterTaskClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->set_property = ufo_ringwriter_task_set_property;
+ oclass->get_property = ufo_ringwriter_task_get_property;
+ oclass->finalize = ufo_ringwriter_task_finalize;
+
+ properties[PROP_SCALE] =
+ g_param_spec_uint ("scale",
+ "Says by how much rings should be increased",
+ "Says by how much rings should be increased",
+ 1, G_MAXUINT, 1,
+ G_PARAM_READWRITE);
+
+ properties[PROP_PATH] =
+ g_param_spec_string ("filename",
+ "Path for the output file to write data",
+ "Path for the output file to write data",
+ "results",
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (oclass, i, properties[i]);
+
+ g_type_class_add_private (oclass, sizeof(UfoRingwriterTaskPrivate));
+}
+
+static void
+ufo_ringwriter_task_init(UfoRingwriterTask *self)
+{
+ self->priv = UFO_RINGWRITER_TASK_GET_PRIVATE(self);
+ self->priv->filename = g_strdup ("results");
+ self->priv->file = NULL;
+ self->priv->scale = 1;
+}
diff --git a/src/ufo-ringwriter-task.h b/src/ufo-ringwriter-task.h
new file mode 100644
index 0000000..bacf3ef
--- /dev/null
+++ b/src/ufo-ringwriter-task.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library 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 3 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_RINGWRITER_TASK_H
+#define __UFO_RINGWRITER_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_RINGWRITER_TASK (ufo_ringwriter_task_get_type())
+#define UFO_RINGWRITER_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_RINGWRITER_TASK, UfoRingwriterTask))
+#define UFO_IS_RINGWRITER_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_RINGWRITER_TASK))
+#define UFO_RINGWRITER_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_RINGWRITER_TASK, UfoRingwriterTaskClass))
+#define UFO_IS_RINGWRITER_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_RINGWRITER_TASK))
+#define UFO_RINGWRITER_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_RINGWRITER_TASK, UfoRingwriterTaskClass))
+
+typedef struct _UfoRingwriterTask UfoRingwriterTask;
+typedef struct _UfoRingwriterTaskClass UfoRingwriterTaskClass;
+typedef struct _UfoRingwriterTaskPrivate UfoRingwriterTaskPrivate;
+
+/**
+ * UfoRingwriterTask:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #UfoRingwriterTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoRingwriterTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoRingwriterTaskPrivate *priv;
+};
+
+/**
+ * UfoRingwriterTaskClass:
+ *
+ * #UfoRingwriterTask class
+ */
+struct _UfoRingwriterTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_ringwriter_task_new (void);
+GType ufo_ringwriter_task_get_type (void);
+
+G_END_DECLS
+
+#endif \ No newline at end of file