diff options
Diffstat (limited to 'src/ufo-find-large-spots-task.c')
-rw-r--r-- | src/ufo-find-large-spots-task.c | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/src/ufo-find-large-spots-task.c b/src/ufo-find-large-spots-task.c new file mode 100644 index 0000000..9875ffc --- /dev/null +++ b/src/ufo-find-large-spots-task.c @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2011-2019 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 "ufo-find-large-spots-task.h" +#include "common/ufo-addressing.h" +#include "common/ufo-common.h" + +typedef enum { + SPOT_THRESHOLD_BELOW = -1, + SPOT_THRESHOLD_ABSOLUTE, + SPOT_THRESHOLD_ABOVE +} SpotThresholdMode; + +static GEnumValue spot_threshold_mode_values[] = { + { SPOT_THRESHOLD_BELOW, "SPOT_THRESHOLD_BELOW", "below" }, + { SPOT_THRESHOLD_ABSOLUTE, "SPOT_THRESHOLD_ABSOLUTE", "absolute" }, + { SPOT_THRESHOLD_ABOVE, "SPOT_THRESHOLD_ABOVE", "above" }, + { 0, NULL, NULL} +}; + +struct _UfoFindLargeSpotsTaskPrivate { + gfloat spot_threshold; + SpotThresholdMode spot_threshold_mode; + gfloat grow_threshold; + cl_context context; + cl_kernel set_ones_kernel, set_threshold_kernel, grow_kernel, holes_kernel, convolution_kernel, sum_kernel; + cl_sampler sampler; + cl_mem aux_mem[2], counter_mem; + AddressingMode addressing_mode; +}; + +static void ufo_task_interface_init (UfoTaskIface *iface); + +G_DEFINE_TYPE_WITH_CODE (UfoFindLargeSpotsTask, ufo_find_large_spots_task, UFO_TYPE_TASK_NODE, + G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK, + ufo_task_interface_init)) + +#define UFO_FIND_LARGE_SPOTS_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_FIND_LARGE_SPOTS_TASK, UfoFindLargeSpotsTaskPrivate)) + +enum { + PROP_0, + PROP_SPOT_THRESHOLD_MODE, + PROP_SPOT_THRESHOLD, + PROP_GROW_THRESHOLD, + PROP_ADDRESSING_MODE, + N_PROPERTIES +}; + +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; + +UfoNode * +ufo_find_large_spots_task_new (void) +{ + return UFO_NODE (g_object_new (UFO_TYPE_FIND_LARGE_SPOTS_TASK, NULL)); +} + +static void +ufo_find_large_spots_task_setup (UfoTask *task, + UfoResources *resources, + GError **error) +{ + cl_int err; + UfoFindLargeSpotsTaskPrivate *priv = UFO_FIND_LARGE_SPOTS_TASK_GET_PRIVATE (task); + + priv->context = ufo_resources_get_context (resources); + UFO_RESOURCES_CHECK_SET_AND_RETURN (clRetainContext (priv->context), error); + + priv->set_ones_kernel = ufo_resources_get_kernel (resources, "morphology.cl", "set_to_ones", NULL, error); + priv->set_threshold_kernel = ufo_resources_get_kernel (resources, "morphology.cl", "set_above_threshold", NULL, error); + priv->grow_kernel = ufo_resources_get_kernel (resources, "morphology.cl", "grow_region_above_threshold", NULL, error); + priv->holes_kernel = ufo_resources_get_kernel (resources, "morphology.cl", "fill_holes", NULL, error); + priv->convolution_kernel = ufo_resources_get_kernel (resources, "estimate-noise.cl", "convolve_abs_laplacian_diff", NULL, error); + priv->sum_kernel = ufo_resources_get_kernel (resources, "reductor.cl", "reduce_M_SUM", NULL, error); + for (gint i = 0; i < 2; i++) { + priv->aux_mem[i] = NULL; + } + priv->counter_mem = NULL; + + if (priv->set_ones_kernel) { + UFO_RESOURCES_CHECK_SET_AND_RETURN (clRetainKernel (priv->set_ones_kernel), error); + } + if (priv->set_threshold_kernel) { + UFO_RESOURCES_CHECK_SET_AND_RETURN (clRetainKernel (priv->set_threshold_kernel), error); + } + if (priv->grow_kernel) { + UFO_RESOURCES_CHECK_SET_AND_RETURN (clRetainKernel (priv->grow_kernel), error); + } + if (priv->holes_kernel) { + UFO_RESOURCES_CHECK_SET_AND_RETURN (clRetainKernel (priv->holes_kernel), error); + } + if (priv->convolution_kernel) { + UFO_RESOURCES_CHECK_SET_AND_RETURN (clRetainKernel (priv->convolution_kernel), error); + } + if (priv->sum_kernel) { + UFO_RESOURCES_CHECK_SET_AND_RETURN (clRetainKernel (priv->sum_kernel), error); + } + priv->sampler = clCreateSampler (priv->context, + (cl_bool) TRUE, + priv->addressing_mode, + CL_FILTER_NEAREST, + &err); + UFO_RESOURCES_CHECK_CLERR (err); +} + +static void +ufo_find_large_spots_task_get_requisition (UfoTask *task, + UfoBuffer **inputs, + UfoRequisition *requisition, + GError **error) +{ + cl_int err; + UfoFindLargeSpotsTaskPrivate *priv = UFO_FIND_LARGE_SPOTS_TASK_GET_PRIVATE (task); + + ufo_buffer_get_requisition (inputs[0], requisition); + + if (!priv->aux_mem[0]) { + for (gint i = 0; i < 2; i++) { + priv->aux_mem[i] = clCreateBuffer (priv->context, + CL_MEM_READ_WRITE, + sizeof (cl_float) * requisition->dims[0] * requisition->dims[1], + NULL, + &err); + UFO_RESOURCES_CHECK_CLERR (err); + } + priv->counter_mem = clCreateBuffer (priv->context, + CL_MEM_READ_WRITE, + sizeof (cl_int), + NULL, + &err); + UFO_RESOURCES_CHECK_CLERR (err); + } +} + +static guint +ufo_find_large_spots_task_get_num_inputs (UfoTask *task) +{ + return 1; +} + +static guint +ufo_find_large_spots_task_get_num_dimensions (UfoTask *task, + guint input) +{ + return 2; +} + +static UfoTaskMode +ufo_find_large_spots_task_get_mode (UfoTask *task) +{ + return UFO_TASK_MODE_PROCESSOR | UFO_TASK_MODE_GPU; +} + +static gboolean +ufo_find_large_spots_task_process (UfoTask *task, + UfoBuffer **inputs, + UfoBuffer *output, + UfoRequisition *requisition) +{ + UfoFindLargeSpotsTaskPrivate *priv; + UfoGpuNode *node; + UfoProfiler *profiler; + GValue *max_work_group_size_gvalue; + gsize max_work_group_size; + cl_command_queue cmd_queue; + cl_mem in_mem; + cl_mem out_mem; + gfloat estimated_sigma; + gsize global_size[2]; + gint counter = 1, fill_pattern = 0; + + priv = UFO_FIND_LARGE_SPOTS_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); + out_mem = ufo_buffer_get_device_array (output, cmd_queue); + profiler = ufo_task_node_get_profiler (UFO_TASK_NODE (task)); + global_size[0] = requisition->dims[0] - 2; + global_size[1] = requisition->dims[1] - 2; + + if (priv->grow_threshold <= 0.0f) { + max_work_group_size_gvalue = ufo_gpu_node_get_info (node, UFO_GPU_NODE_INFO_MAX_WORK_GROUP_SIZE); + max_work_group_size = g_value_get_ulong (max_work_group_size_gvalue); + g_value_unset (max_work_group_size_gvalue); + in_mem = ufo_buffer_get_device_image (inputs[0], cmd_queue); + estimated_sigma = ufo_common_estimate_sigma (priv->convolution_kernel, + priv->sum_kernel, + cmd_queue, + priv->sampler, + profiler, + in_mem, + out_mem, + max_work_group_size, + requisition->dims); + /* IF not specified, make grow_threshold FWTM of the assumed noise normal distribution. */ + priv->grow_threshold = 4.29 * estimated_sigma; + g_debug ("Estimated sigma: %g", estimated_sigma); + } + in_mem = ufo_buffer_get_device_array (inputs[0], cmd_queue); + + /* First set the mask to 1 where spot_threshold is exceeded */ + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->set_threshold_kernel, 0, sizeof (cl_mem), &in_mem)); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->set_threshold_kernel, 1, sizeof (cl_mem), &priv->aux_mem[0])); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->set_threshold_kernel, 2, sizeof (cl_int), &priv->spot_threshold)); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->set_threshold_kernel, 3, sizeof (cl_int), &priv->spot_threshold_mode)); + ufo_profiler_call (profiler, cmd_queue, priv->set_threshold_kernel, 2, requisition->dims, NULL); + UFO_RESOURCES_CHECK_CLERR (clEnqueueCopyBuffer (cmd_queue, + priv->aux_mem[0], + priv->aux_mem[1], + 0, 0, sizeof (cl_float) * requisition->dims[0] * requisition->dims[1], + 0, NULL, NULL)); + + while (counter) { + /* Grow the seeds until the difference between surrouding pixels is less + * than grow_threshold. */ + /* Reset counter */ + UFO_RESOURCES_CHECK_CLERR (clEnqueueFillBuffer (cmd_queue, priv->counter_mem, &fill_pattern, sizeof (cl_int), + 0, sizeof (cl_int), 0, NULL, NULL)); + + /* Grow region */ + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->grow_kernel, 0, sizeof (cl_mem), &in_mem)); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->grow_kernel, 1, sizeof (cl_mem), &priv->aux_mem[0])); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->grow_kernel, 2, sizeof (cl_mem), &priv->aux_mem[1])); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->grow_kernel, 3, sizeof (cl_mem), &priv->counter_mem)); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->grow_kernel, 4, sizeof (cl_int), &priv->grow_threshold)); + ufo_profiler_call (profiler, cmd_queue, priv->grow_kernel, 2, global_size, NULL); + /* New visited is the last grown. */ + UFO_RESOURCES_CHECK_CLERR (clEnqueueCopyBuffer (cmd_queue, + priv->aux_mem[1], + priv->aux_mem[0], + 0, 0, sizeof (cl_float) * requisition->dims[0] * requisition->dims[1], + 0, NULL, NULL)); + UFO_RESOURCES_CHECK_CLERR (clEnqueueReadBuffer (cmd_queue, + priv->counter_mem, + CL_TRUE, + 0, + sizeof (cl_int), + &counter, + 0, NULL, NULL)); + } + + /* Initialize resulting mask to ones except borders and pixels where current + * mask is set. This will serve for growing the boundary towards the center, + * i.e. filling holes. From now on, aux_mem[0] is the fixed mask with holes + * and aux_mem[1] with out_mem are the result/visited pair. + */ + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->set_ones_kernel, 0, sizeof (cl_mem), &priv->aux_mem[1])); + ufo_profiler_call (profiler, cmd_queue, priv->set_ones_kernel, 2, global_size, NULL); + UFO_RESOURCES_CHECK_CLERR (clEnqueueCopyBuffer (cmd_queue, + priv->aux_mem[1], + out_mem, + 0, 0, sizeof (cl_float) * requisition->dims[0] * requisition->dims[1], + 0, NULL, NULL)); + + counter = 1; + while (counter) { + /* Fill holes by progressing from the edges towards the center and + * taking into account the pre-computed mask. */ + /* Reset counter */ + UFO_RESOURCES_CHECK_CLERR (clEnqueueFillBuffer (cmd_queue, priv->counter_mem, &fill_pattern, sizeof (cl_int), + 0, sizeof (cl_int), 0, NULL, NULL)); + + /* Grow region towards the center */ + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->holes_kernel, 0, sizeof (cl_mem), &priv->aux_mem[0])); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->holes_kernel, 1, sizeof (cl_mem), &priv->aux_mem[1])); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->holes_kernel, 2, sizeof (cl_mem), &out_mem)); + UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->holes_kernel, 3, sizeof (cl_mem), &priv->counter_mem)); + ufo_profiler_call (profiler, cmd_queue, priv->holes_kernel, 2, global_size, NULL); + /* New visited is the last grown. */ + UFO_RESOURCES_CHECK_CLERR (clEnqueueCopyBuffer (cmd_queue, + out_mem, + priv->aux_mem[1], + 0, 0, sizeof (cl_float) * requisition->dims[0] * requisition->dims[1], + 0, NULL, NULL)); + UFO_RESOURCES_CHECK_CLERR (clEnqueueReadBuffer (cmd_queue, + priv->counter_mem, + CL_TRUE, + 0, + sizeof (cl_int), + &counter, + 0, NULL, NULL)); + } + + return TRUE; +} + + +static void +ufo_find_large_spots_task_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + UfoFindLargeSpotsTaskPrivate *priv = UFO_FIND_LARGE_SPOTS_TASK_GET_PRIVATE (object); + + switch (property_id) { + case PROP_SPOT_THRESHOLD: + priv->spot_threshold = g_value_get_float (value); + break; + case PROP_SPOT_THRESHOLD_MODE: + priv->spot_threshold_mode = g_value_get_enum (value); + break; + case PROP_GROW_THRESHOLD: + priv->grow_threshold = g_value_get_float (value); + break; + case PROP_ADDRESSING_MODE: + priv->addressing_mode = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +ufo_find_large_spots_task_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + UfoFindLargeSpotsTaskPrivate *priv = UFO_FIND_LARGE_SPOTS_TASK_GET_PRIVATE (object); + + switch (property_id) { + case PROP_SPOT_THRESHOLD: + g_value_set_float (value, priv->spot_threshold); + break; + case PROP_SPOT_THRESHOLD_MODE: + g_value_set_enum (value, priv->spot_threshold_mode); + break; + case PROP_GROW_THRESHOLD: + g_value_set_float (value, priv->grow_threshold); + break; + case PROP_ADDRESSING_MODE: + g_value_set_enum (value, priv->addressing_mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +ufo_find_large_spots_task_finalize (GObject *object) +{ + UfoFindLargeSpotsTaskPrivate *priv = UFO_FIND_LARGE_SPOTS_TASK_GET_PRIVATE (object); + + if (priv->set_ones_kernel) { + UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->set_ones_kernel)); + priv->set_ones_kernel = NULL; + } + if (priv->set_threshold_kernel) { + UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->set_threshold_kernel)); + priv->set_threshold_kernel = NULL; + } + if (priv->grow_kernel) { + UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->grow_kernel)); + priv->grow_kernel = NULL; + } + if (priv->holes_kernel) { + UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->holes_kernel)); + priv->holes_kernel = NULL; + } + if (priv->convolution_kernel) { + UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->convolution_kernel)); + priv->convolution_kernel = NULL; + } + if (priv->sum_kernel) { + UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->sum_kernel)); + priv->sum_kernel = NULL; + } + if (priv->sampler) { + UFO_RESOURCES_CHECK_CLERR (clReleaseSampler (priv->sampler)); + priv->sampler = NULL; + } + for (gint i = 0; i < 2; i++) { + if (priv->aux_mem[i]) { + UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->aux_mem[i])); + priv->aux_mem[i] = NULL; + } + } + if (priv->counter_mem) { + UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->counter_mem)); + priv->counter_mem = NULL; + } + if (priv->context) { + UFO_RESOURCES_CHECK_CLERR (clReleaseContext (priv->context)); + priv->context = NULL; + } + + G_OBJECT_CLASS (ufo_find_large_spots_task_parent_class)->finalize (object); +} + +static void +ufo_task_interface_init (UfoTaskIface *iface) +{ + iface->setup = ufo_find_large_spots_task_setup; + iface->get_num_inputs = ufo_find_large_spots_task_get_num_inputs; + iface->get_num_dimensions = ufo_find_large_spots_task_get_num_dimensions; + iface->get_mode = ufo_find_large_spots_task_get_mode; + iface->get_requisition = ufo_find_large_spots_task_get_requisition; + iface->process = ufo_find_large_spots_task_process; +} + +static void +ufo_find_large_spots_task_class_init (UfoFindLargeSpotsTaskClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->set_property = ufo_find_large_spots_task_set_property; + oclass->get_property = ufo_find_large_spots_task_get_property; + oclass->finalize = ufo_find_large_spots_task_finalize; + + properties[PROP_SPOT_THRESHOLD] = + g_param_spec_float ("spot-threshold", + "Pixels with grey value larger than this are considered as spots", + "Pixels with grey value larger than this are considered as spots", + -G_MAXFLOAT, G_MAXFLOAT, 0.0f, + G_PARAM_READWRITE); + + properties[PROP_SPOT_THRESHOLD_MODE] = + g_param_spec_enum ("spot-threshold-mode", + "Pixels must be either \"below\", \"above\" the spot threshold, or their \"absolute\" value can be compared", + "Pixels must be either \"below\", \"above\" the spot threshold, or their \"absolute\" value can be compared", + g_enum_register_static ("spot-threshold-mode", spot_threshold_mode_values), + SPOT_THRESHOLD_ABSOLUTE, G_PARAM_READWRITE); + + properties[PROP_GROW_THRESHOLD] = + g_param_spec_float ("grow-threshold", + "Spot growing threshold", + "Spot growing threshold", + 0.0f, G_MAXFLOAT, 0.0f, + G_PARAM_READWRITE); + + properties[PROP_ADDRESSING_MODE] = + g_param_spec_enum ("addressing-mode", + "Outlier treatment (\"none\", \"clamp\", \"clamp_to_edge\", \"repeat\", \"mirrored_repeat\")", + "Outlier treatment (\"none\", \"clamp\", \"clamp_to_edge\", \"repeat\", \"mirrored_repeat\")", + g_enum_register_static ("find_addressing_mode", addressing_values), + CL_ADDRESS_MIRRORED_REPEAT, + 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(UfoFindLargeSpotsTaskPrivate)); +} + +static void +ufo_find_large_spots_task_init(UfoFindLargeSpotsTask *self) +{ + self->priv = UFO_FIND_LARGE_SPOTS_TASK_GET_PRIVATE(self); + self->priv->spot_threshold = 0.0f; + self->priv->grow_threshold = 0.0f; + self->priv->spot_threshold_mode = SPOT_THRESHOLD_ABSOLUTE; + self->priv->addressing_mode = CL_ADDRESS_MIRRORED_REPEAT; +} |