/* * Copyright (C) 2011-2014 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 . */ #include #include #ifdef __APPLE__ #include #else #include #endif #include "ufo-anka-backproject-task.h" #define EXTRACT_INT(region, index) g_value_get_int (g_value_array_get_nth ((region), (index))) #define EXTRACT_FLOAT(region, index) g_value_get_float (g_value_array_get_nth ((region), (index))) #define REGION_SIZE(region) ((EXTRACT_INT ((region), 2)) == 0) ? 0 : \ ((EXTRACT_INT ((region), 1) - EXTRACT_INT ((region), 0) - 1) /\ EXTRACT_INT ((region), 2) + 1) /** * SECTION:ufo-anka-backproject-task * @Short_description: Backproject projection by projection * @Title: anka_backproject * */ struct _UfoAnkaBackprojectTaskPrivate { /* private */ gboolean generated; guint count; float tmatrix[8]; /* OpenCL */ cl_context context; cl_kernel bp_kernel; cl_sampler sampler; /* properties */ GValueArray *x_region; GValueArray *y_region; GValueArray *z_region; GValueArray *center; GValueArray *projection_offset; gboolean tomo_angle_is_absolute; gfloat tomo_angle; gfloat lamino_angle; }; static void ufo_task_interface_init (UfoTaskIface *iface); G_DEFINE_TYPE_WITH_CODE (UfoAnkaBackprojectTask, ufo_anka_backproject_task, UFO_TYPE_TASK_NODE, G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK, ufo_task_interface_init)) #define UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_ANKA_BACKPROJECT_TASK, UfoAnkaBackprojectTaskPrivate)) enum { PROP_0, PROP_X_REGION, PROP_Y_REGION, PROP_Z_REGION, PROP_PROJECTION_OFFSET, PROP_CENTER, PROP_TOMO_ANGLE_IS_ABSOLUTE, PROP_TOMO_ANGLE, PROP_LAMINO_ANGLE, N_PROPERTIES }; static GParamSpec *properties[N_PROPERTIES] = { NULL, }; static void create_transformation_matrix (UfoAnkaBackprojectTaskPrivate *priv, float tomo_angle) { priv->tmatrix[0] = cos (tomo_angle); priv->tmatrix[1] = sin (tomo_angle); priv->tmatrix[2] = 0.0f; priv->tmatrix[3] = EXTRACT_FLOAT (priv->center, 0); priv->tmatrix[4] = cos (priv->lamino_angle) * sin (tomo_angle); priv->tmatrix[5] = -cos (priv->lamino_angle) * cos(tomo_angle); priv->tmatrix[6] = sin(priv->lamino_angle); priv->tmatrix[7] = EXTRACT_FLOAT (priv->center, 1); } UfoNode * ufo_anka_backproject_task_new (void) { return UFO_NODE (g_object_new (UFO_TYPE_ANKA_BACKPROJECT_TASK, NULL)); } static void ufo_anka_backproject_task_setup (UfoTask *task, UfoResources *resources, GError **error) { UfoAnkaBackprojectTaskPrivate *priv; cl_int cl_error; priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task); priv->context = ufo_resources_get_context (resources); priv->bp_kernel = ufo_resources_get_kernel (resources, "ankabackproject.cl", "backproject", error); priv->sampler = clCreateSampler (priv->context, (cl_bool) FALSE, CL_ADDRESS_CLAMP, CL_FILTER_LINEAR, &cl_error); UFO_RESOURCES_CHECK_CLERR (clRetainContext (priv->context)); UFO_RESOURCES_CHECK_CLERR (cl_error); if (priv->bp_kernel) { UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->bp_kernel)); } } static void ufo_anka_backproject_task_get_requisition (UfoTask *task, UfoBuffer **inputs, UfoRequisition *requisition) { UfoAnkaBackprojectTaskPrivate *priv; priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task); requisition->n_dims = 3; requisition->dims[0] = REGION_SIZE (priv->x_region); requisition->dims[1] = REGION_SIZE (priv->y_region); requisition->dims[2] = REGION_SIZE (priv->z_region); } static guint ufo_anka_backproject_task_get_num_inputs (UfoTask *task) { return 1; } static guint ufo_anka_backproject_task_get_num_dimensions (UfoTask *task, guint input) { g_return_val_if_fail (input == 0, 0); return 3; } static gboolean ufo_anka_backproject_task_equal_real (UfoNode *n1, UfoNode *n2) { g_return_val_if_fail (UFO_IS_ANKA_BACKPROJECT_TASK (n1) && UFO_IS_ANKA_BACKPROJECT_TASK (n2), FALSE); return UFO_ANKA_BACKPROJECT_TASK (n1)->priv->bp_kernel == UFO_ANKA_BACKPROJECT_TASK (n2)->priv->bp_kernel; } static UfoTaskMode ufo_anka_backproject_task_get_mode (UfoTask *task) { return UFO_TASK_MODE_REDUCTOR | UFO_TASK_MODE_GPU; } static gboolean ufo_anka_backproject_task_process (UfoTask *task, UfoBuffer **inputs, UfoBuffer *output, UfoRequisition *requisition) { UfoAnkaBackprojectTaskPrivate *priv; UfoGpuNode *node; UfoProfiler *profiler; gfloat tomo_angle; /* regions stripped off the "to" value */ gint x_region[2], y_region[2], z_region[2], proj_offset[2]; cl_command_queue cmd_queue; cl_mem image; cl_mem out_mem; priv = UFO_ANKA_BACKPROJECT_TASK (task)->priv; 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); image = ufo_buffer_get_device_image (inputs[0], cmd_queue); x_region[0] = EXTRACT_INT (priv->x_region, 0); x_region[1] = EXTRACT_INT (priv->x_region, 2); y_region[0] = EXTRACT_INT (priv->y_region, 0); y_region[1] = EXTRACT_INT (priv->y_region, 2); z_region[0] = EXTRACT_INT (priv->z_region, 0); z_region[1] = EXTRACT_INT (priv->z_region, 2); proj_offset[0] = EXTRACT_INT (priv->projection_offset, 0); proj_offset[1] = EXTRACT_INT (priv->projection_offset, 1); tomo_angle = priv->tomo_angle_is_absolute ? priv->tomo_angle : priv->tomo_angle * priv->count; create_transformation_matrix (priv, tomo_angle); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 0, sizeof (cl_mem), &out_mem)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 1, sizeof (cl_mem), &image)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 2, sizeof (cl_sampler), &priv->sampler)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 3, sizeof (cl_int2), x_region)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 4, sizeof (cl_int2), y_region)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 5, sizeof (cl_int2), z_region)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 6, sizeof (cl_float8), priv->tmatrix)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 7, sizeof (cl_int2), proj_offset)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 8, sizeof (cl_uint), (cl_uint *) &priv->count)); profiler = ufo_task_node_get_profiler (UFO_TASK_NODE (task)); ufo_profiler_call (profiler, cmd_queue, priv->bp_kernel, 3, requisition->dims, NULL); priv->count++; return TRUE; } static gboolean ufo_anka_backproject_task_generate (UfoTask *task, UfoBuffer *output, UfoRequisition *requisition) { UfoAnkaBackprojectTaskPrivate *priv; priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task); if (priv->generated) { return FALSE; } priv->generated = TRUE; return TRUE; } static void ufo_anka_backproject_task_finalize (GObject *object) { UfoAnkaBackprojectTaskPrivate *priv; priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object); g_value_array_free (priv->x_region); g_value_array_free (priv->y_region); g_value_array_free (priv->z_region); g_value_array_free (priv->projection_offset); g_value_array_free (priv->center); if (priv->bp_kernel) { UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->bp_kernel)); priv->bp_kernel = NULL; } if (priv->context) { UFO_RESOURCES_CHECK_CLERR (clReleaseContext (priv->context)); priv->context = NULL; } if (priv->sampler) { UFO_RESOURCES_CHECK_CLERR (clReleaseSampler (priv->sampler)); priv->sampler = NULL; } G_OBJECT_CLASS (ufo_anka_backproject_task_parent_class)->finalize (object); } static void ufo_task_interface_init (UfoTaskIface *iface) { iface->setup = ufo_anka_backproject_task_setup; iface->get_requisition = ufo_anka_backproject_task_get_requisition; iface->get_num_inputs = ufo_anka_backproject_task_get_num_inputs; iface->get_num_dimensions = ufo_anka_backproject_task_get_num_dimensions; iface->get_mode = ufo_anka_backproject_task_get_mode; iface->process = ufo_anka_backproject_task_process; iface->generate = ufo_anka_backproject_task_generate; } static void ufo_anka_backproject_task_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { UfoAnkaBackprojectTaskPrivate *priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object); GValueArray *array; switch (property_id) { case PROP_X_REGION: array = (GValueArray *) g_value_get_boxed (value); g_value_array_free (priv->x_region); priv->x_region = g_value_array_copy (array); break; case PROP_Y_REGION: array = (GValueArray *) g_value_get_boxed (value); g_value_array_free (priv->y_region); priv->y_region = g_value_array_copy (array); break; case PROP_Z_REGION: array = (GValueArray *) g_value_get_boxed (value); g_value_array_free (priv->z_region); priv->z_region = g_value_array_copy (array); break; case PROP_PROJECTION_OFFSET: array = (GValueArray *) g_value_get_boxed (value); g_value_array_free (priv->projection_offset); priv->projection_offset = g_value_array_copy (array); break; case PROP_CENTER: array = (GValueArray *) g_value_get_boxed (value); g_value_array_free (priv->center); priv->center = g_value_array_copy (array); break; case PROP_TOMO_ANGLE_IS_ABSOLUTE: priv->tomo_angle_is_absolute = g_value_get_boolean (value); break; case PROP_TOMO_ANGLE: priv->tomo_angle = g_value_get_float (value); break; case PROP_LAMINO_ANGLE: priv->lamino_angle = g_value_get_float (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ufo_anka_backproject_task_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { UfoAnkaBackprojectTaskPrivate *priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object); switch (property_id) { case PROP_X_REGION: g_value_set_boxed (value, priv->x_region); break; case PROP_Y_REGION: g_value_set_boxed (value, priv->y_region); break; case PROP_Z_REGION: g_value_set_boxed (value, priv->z_region); break; case PROP_PROJECTION_OFFSET: g_value_set_boxed (value, priv->projection_offset); break; case PROP_CENTER: g_value_set_boxed (value, priv->center); break; case PROP_TOMO_ANGLE_IS_ABSOLUTE: g_value_set_boolean (value, priv->tomo_angle_is_absolute); break; case PROP_TOMO_ANGLE: g_value_set_float (value, priv->tomo_angle); break; case PROP_LAMINO_ANGLE: g_value_set_float (value, priv->lamino_angle); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ufo_anka_backproject_task_class_init (UfoAnkaBackprojectTaskClass *klass) { GObjectClass *oclass; UfoNodeClass *node_class; oclass = G_OBJECT_CLASS (klass); node_class = UFO_NODE_CLASS (klass); oclass->finalize = ufo_anka_backproject_task_finalize; oclass->set_property = ufo_anka_backproject_task_set_property; oclass->get_property = ufo_anka_backproject_task_get_property; GParamSpec *region_vals = g_param_spec_int ("region_values", "Region values", "Elements in regions", G_MININT, G_MAXINT, (gint) 0, G_PARAM_READWRITE); GParamSpec *float_region_vals = g_param_spec_float ("float_region_values", "Float Region values", "Elements in float regions", -G_MAXFLOAT, G_MAXFLOAT, 0.0f, G_PARAM_READWRITE); properties[PROP_X_REGION] = g_param_spec_value_array ("x_region", "X region for reconstruction as (from, to, step)", "X region for reconstruction as (from, to, step)", region_vals, G_PARAM_READWRITE); properties[PROP_Y_REGION] = g_param_spec_value_array ("y_region", "Y region for reconstruction as (from, to, step)", "Y region for reconstruction as (from, to, step)", region_vals, G_PARAM_READWRITE); properties[PROP_Z_REGION] = g_param_spec_value_array ("z_region", "Z region for reconstruction as (from, to, step)", "Z region for reconstruction as (from, to, step)", region_vals, G_PARAM_READWRITE); properties[PROP_PROJECTION_OFFSET] = g_param_spec_value_array ("projection-offset", "Offset to projection data as (x, y)", "Offset to projection data as (x, y) for the case input data \ is cropped to the necessary range of interest", region_vals, G_PARAM_READWRITE); properties[PROP_CENTER] = g_param_spec_value_array ("center", "Center of the volume with respect to projections (x, y)", "Center of the volume with respect to projections (x, y), (rotation axes)", float_region_vals, G_PARAM_READWRITE); properties[PROP_TOMO_ANGLE_IS_ABSOLUTE] = g_param_spec_boolean ("tomo-angle-is-absolute", "Tomographic angle is absolute", "If TRUE, the value stored in tomo-angle property represents \ an absolute angle, relative otherwise", FALSE, G_PARAM_READWRITE); properties[PROP_TOMO_ANGLE] = g_param_spec_float ("tomo-angle", "Tomographic rotation angle in radians", "Tomographic rotation angle in radians (used for acquiring projections)", -G_MAXFLOAT, G_MAXFLOAT, 0.0f, G_PARAM_READWRITE); properties[PROP_LAMINO_ANGLE] = g_param_spec_float ("lamino-angle", "Absolute laminogrpahic angle in radians", "Absolute laminogrpahic angle in radians determining the sample tilt", 0.0f, (float) G_PI / 2, 0.0f, G_PARAM_READWRITE); for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++) g_object_class_install_property (oclass, i, properties[i]); node_class->equal = ufo_anka_backproject_task_equal_real; g_type_class_add_private (klass, sizeof(UfoAnkaBackprojectTaskPrivate)); } static void ufo_anka_backproject_task_init(UfoAnkaBackprojectTask *self) { UfoAnkaBackprojectTaskPrivate *priv; self->priv = priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE(self); guint i; GValue int_zero = G_VALUE_INIT; GValue float_zero = G_VALUE_INIT; g_value_init (&int_zero, G_TYPE_INT); g_value_init (&float_zero, G_TYPE_FLOAT); g_value_set_int (&int_zero, 0); g_value_set_float (&float_zero, 0.0f); self->priv->x_region = g_value_array_new (3); self->priv->y_region = g_value_array_new (3); self->priv->z_region = g_value_array_new (3); self->priv->projection_offset = g_value_array_new (2); self->priv->center = g_value_array_new (2); for (i = 0; i < 3; i++) { g_value_array_insert (self->priv->x_region, i, &int_zero); g_value_array_insert (self->priv->y_region, i, &int_zero); g_value_array_insert (self->priv->z_region, i, &int_zero); if (i < 2) { g_value_array_insert (self->priv->projection_offset, i, &int_zero); g_value_array_insert (self->priv->center, i, &float_zero); } } self->priv->tomo_angle_is_absolute = FALSE; self->priv->tomo_angle = 0.0f; self->priv->lamino_angle = 0.0f; self->priv->count = 0; self->priv->generated = FALSE; }