ufo-anka-backproject-task.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /*
  2. * Copyright (C) 2011-2014 Karlsruhe Institute of Technology
  3. *
  4. * This file is part of Ufo.
  5. *
  6. * This library is free software: you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation, either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <math.h>
  20. #include <string.h>
  21. #ifdef __APPLE__
  22. #include <OpenCL/cl.h>
  23. #else
  24. #include <CL/cl.h>
  25. #endif
  26. #include "ufo-anka-backproject-task.h"
  27. #define EXTRACT_INT(region, index) g_value_get_int (g_value_array_get_nth ((region), (index)))
  28. #define EXTRACT_FLOAT(region, index) g_value_get_float (g_value_array_get_nth ((region), (index)))
  29. #define REGION_SIZE(region) ((EXTRACT_INT ((region), 2)) == 0) ? 0 : \
  30. ((EXTRACT_INT ((region), 1) - EXTRACT_INT ((region), 0) - 1) /\
  31. EXTRACT_INT ((region), 2) + 1)
  32. /**
  33. * SECTION:ufo-anka-backproject-task
  34. * @Short_description: Backproject projection by projection
  35. * @Title: anka_backproject
  36. *
  37. */
  38. struct _UfoAnkaBackprojectTaskPrivate {
  39. /* private */
  40. gboolean generated;
  41. guint count;
  42. float tmatrix[8];
  43. /* OpenCL */
  44. cl_context context;
  45. cl_kernel bp_kernel;
  46. cl_sampler sampler;
  47. /* properties */
  48. GValueArray *x_region;
  49. GValueArray *y_region;
  50. GValueArray *z_region;
  51. GValueArray *center;
  52. GValueArray *projection_offset;
  53. gboolean tomo_angle_is_absolute;
  54. gfloat tomo_angle;
  55. gfloat lamino_angle;
  56. };
  57. static void ufo_task_interface_init (UfoTaskIface *iface);
  58. G_DEFINE_TYPE_WITH_CODE (UfoAnkaBackprojectTask, ufo_anka_backproject_task, UFO_TYPE_TASK_NODE,
  59. G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
  60. ufo_task_interface_init))
  61. #define UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_ANKA_BACKPROJECT_TASK, UfoAnkaBackprojectTaskPrivate))
  62. enum {
  63. PROP_0,
  64. PROP_X_REGION,
  65. PROP_Y_REGION,
  66. PROP_Z_REGION,
  67. PROP_PROJECTION_OFFSET,
  68. PROP_CENTER,
  69. PROP_TOMO_ANGLE_IS_ABSOLUTE,
  70. PROP_TOMO_ANGLE,
  71. PROP_LAMINO_ANGLE,
  72. N_PROPERTIES
  73. };
  74. static GParamSpec *properties[N_PROPERTIES] = { NULL, };
  75. static void
  76. create_transformation_matrix (UfoAnkaBackprojectTaskPrivate *priv, float tomo_angle)
  77. {
  78. priv->tmatrix[0] = cos (tomo_angle);
  79. priv->tmatrix[1] = sin (tomo_angle);
  80. priv->tmatrix[2] = 0.0f;
  81. priv->tmatrix[3] = EXTRACT_FLOAT (priv->center, 0);
  82. priv->tmatrix[4] = cos (priv->lamino_angle) * sin (tomo_angle);
  83. priv->tmatrix[5] = -cos (priv->lamino_angle) * cos(tomo_angle);
  84. priv->tmatrix[6] = sin(priv->lamino_angle);
  85. priv->tmatrix[7] = EXTRACT_FLOAT (priv->center, 1);
  86. }
  87. UfoNode *
  88. ufo_anka_backproject_task_new (void)
  89. {
  90. return UFO_NODE (g_object_new (UFO_TYPE_ANKA_BACKPROJECT_TASK, NULL));
  91. }
  92. static void
  93. ufo_anka_backproject_task_setup (UfoTask *task,
  94. UfoResources *resources,
  95. GError **error)
  96. {
  97. UfoAnkaBackprojectTaskPrivate *priv;
  98. cl_int cl_error;
  99. priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task);
  100. priv->context = ufo_resources_get_context (resources);
  101. priv->bp_kernel = ufo_resources_get_kernel (resources, "ankabackproject.cl", "backproject", error);
  102. priv->sampler = clCreateSampler (priv->context,
  103. (cl_bool) FALSE,
  104. CL_ADDRESS_CLAMP,
  105. CL_FILTER_LINEAR,
  106. &cl_error);
  107. UFO_RESOURCES_CHECK_CLERR (clRetainContext (priv->context));
  108. UFO_RESOURCES_CHECK_CLERR (cl_error);
  109. if (priv->bp_kernel) {
  110. UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->bp_kernel));
  111. }
  112. }
  113. static void
  114. ufo_anka_backproject_task_get_requisition (UfoTask *task,
  115. UfoBuffer **inputs,
  116. UfoRequisition *requisition)
  117. {
  118. UfoAnkaBackprojectTaskPrivate *priv;
  119. priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task);
  120. requisition->n_dims = 3;
  121. requisition->dims[0] = REGION_SIZE (priv->x_region);
  122. requisition->dims[1] = REGION_SIZE (priv->y_region);
  123. requisition->dims[2] = REGION_SIZE (priv->z_region);
  124. }
  125. static guint
  126. ufo_anka_backproject_task_get_num_inputs (UfoTask *task)
  127. {
  128. return 1;
  129. }
  130. static guint
  131. ufo_anka_backproject_task_get_num_dimensions (UfoTask *task,
  132. guint input)
  133. {
  134. g_return_val_if_fail (input == 0, 0);
  135. return 3;
  136. }
  137. static gboolean
  138. ufo_anka_backproject_task_equal_real (UfoNode *n1,
  139. UfoNode *n2)
  140. {
  141. g_return_val_if_fail (UFO_IS_ANKA_BACKPROJECT_TASK (n1) && UFO_IS_ANKA_BACKPROJECT_TASK (n2), FALSE);
  142. return UFO_ANKA_BACKPROJECT_TASK (n1)->priv->bp_kernel == UFO_ANKA_BACKPROJECT_TASK (n2)->priv->bp_kernel;
  143. }
  144. static UfoTaskMode
  145. ufo_anka_backproject_task_get_mode (UfoTask *task)
  146. {
  147. return UFO_TASK_MODE_REDUCTOR | UFO_TASK_MODE_GPU;
  148. }
  149. static gboolean
  150. ufo_anka_backproject_task_process (UfoTask *task,
  151. UfoBuffer **inputs,
  152. UfoBuffer *output,
  153. UfoRequisition *requisition)
  154. {
  155. UfoAnkaBackprojectTaskPrivate *priv;
  156. UfoGpuNode *node;
  157. UfoProfiler *profiler;
  158. gfloat tomo_angle;
  159. /* regions stripped off the "to" value */
  160. gint x_region[2], y_region[2], z_region[2], proj_offset[2];
  161. cl_command_queue cmd_queue;
  162. cl_mem image;
  163. cl_mem out_mem;
  164. priv = UFO_ANKA_BACKPROJECT_TASK (task)->priv;
  165. node = UFO_GPU_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (task)));
  166. cmd_queue = ufo_gpu_node_get_cmd_queue (node);
  167. out_mem = ufo_buffer_get_device_array (output, cmd_queue);
  168. image = ufo_buffer_get_device_image (inputs[0], cmd_queue);
  169. x_region[0] = EXTRACT_INT (priv->x_region, 0);
  170. x_region[1] = EXTRACT_INT (priv->x_region, 2);
  171. y_region[0] = EXTRACT_INT (priv->y_region, 0);
  172. y_region[1] = EXTRACT_INT (priv->y_region, 2);
  173. z_region[0] = EXTRACT_INT (priv->z_region, 0);
  174. z_region[1] = EXTRACT_INT (priv->z_region, 2);
  175. proj_offset[0] = EXTRACT_INT (priv->projection_offset, 0);
  176. proj_offset[1] = EXTRACT_INT (priv->projection_offset, 1);
  177. tomo_angle = priv->tomo_angle_is_absolute ? priv->tomo_angle : priv->tomo_angle * priv->count;
  178. create_transformation_matrix (priv, tomo_angle);
  179. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 0, sizeof (cl_mem), &out_mem));
  180. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 1, sizeof (cl_mem), &image));
  181. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 2, sizeof (cl_sampler), &priv->sampler));
  182. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 3, sizeof (cl_int2), x_region));
  183. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 4, sizeof (cl_int2), y_region));
  184. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 5, sizeof (cl_int2), z_region));
  185. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 6, sizeof (cl_float8), priv->tmatrix));
  186. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 7, sizeof (cl_int2), proj_offset));
  187. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->bp_kernel, 8, sizeof (cl_uint), (cl_uint *) &priv->count));
  188. profiler = ufo_task_node_get_profiler (UFO_TASK_NODE (task));
  189. ufo_profiler_call (profiler, cmd_queue, priv->bp_kernel, 3, requisition->dims, NULL);
  190. priv->count++;
  191. return TRUE;
  192. }
  193. static gboolean
  194. ufo_anka_backproject_task_generate (UfoTask *task,
  195. UfoBuffer *output,
  196. UfoRequisition *requisition)
  197. {
  198. UfoAnkaBackprojectTaskPrivate *priv;
  199. priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task);
  200. if (priv->generated) {
  201. return FALSE;
  202. }
  203. priv->generated = TRUE;
  204. return TRUE;
  205. }
  206. static void
  207. ufo_anka_backproject_task_finalize (GObject *object)
  208. {
  209. UfoAnkaBackprojectTaskPrivate *priv;
  210. priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object);
  211. g_value_array_free (priv->x_region);
  212. g_value_array_free (priv->y_region);
  213. g_value_array_free (priv->z_region);
  214. g_value_array_free (priv->projection_offset);
  215. g_value_array_free (priv->center);
  216. if (priv->bp_kernel) {
  217. UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->bp_kernel));
  218. priv->bp_kernel = NULL;
  219. }
  220. if (priv->context) {
  221. UFO_RESOURCES_CHECK_CLERR (clReleaseContext (priv->context));
  222. priv->context = NULL;
  223. }
  224. if (priv->sampler) {
  225. UFO_RESOURCES_CHECK_CLERR (clReleaseSampler (priv->sampler));
  226. priv->sampler = NULL;
  227. }
  228. G_OBJECT_CLASS (ufo_anka_backproject_task_parent_class)->finalize (object);
  229. }
  230. static void
  231. ufo_task_interface_init (UfoTaskIface *iface)
  232. {
  233. iface->setup = ufo_anka_backproject_task_setup;
  234. iface->get_requisition = ufo_anka_backproject_task_get_requisition;
  235. iface->get_num_inputs = ufo_anka_backproject_task_get_num_inputs;
  236. iface->get_num_dimensions = ufo_anka_backproject_task_get_num_dimensions;
  237. iface->get_mode = ufo_anka_backproject_task_get_mode;
  238. iface->process = ufo_anka_backproject_task_process;
  239. iface->generate = ufo_anka_backproject_task_generate;
  240. }
  241. static void
  242. ufo_anka_backproject_task_set_property (GObject *object,
  243. guint property_id,
  244. const GValue *value,
  245. GParamSpec *pspec)
  246. {
  247. UfoAnkaBackprojectTaskPrivate *priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object);
  248. GValueArray *array;
  249. switch (property_id) {
  250. case PROP_X_REGION:
  251. array = (GValueArray *) g_value_get_boxed (value);
  252. g_value_array_free (priv->x_region);
  253. priv->x_region = g_value_array_copy (array);
  254. break;
  255. case PROP_Y_REGION:
  256. array = (GValueArray *) g_value_get_boxed (value);
  257. g_value_array_free (priv->y_region);
  258. priv->y_region = g_value_array_copy (array);
  259. break;
  260. case PROP_Z_REGION:
  261. array = (GValueArray *) g_value_get_boxed (value);
  262. g_value_array_free (priv->z_region);
  263. priv->z_region = g_value_array_copy (array);
  264. break;
  265. case PROP_PROJECTION_OFFSET:
  266. array = (GValueArray *) g_value_get_boxed (value);
  267. g_value_array_free (priv->projection_offset);
  268. priv->projection_offset = g_value_array_copy (array);
  269. break;
  270. case PROP_CENTER:
  271. array = (GValueArray *) g_value_get_boxed (value);
  272. g_value_array_free (priv->center);
  273. priv->center = g_value_array_copy (array);
  274. break;
  275. case PROP_TOMO_ANGLE_IS_ABSOLUTE:
  276. priv->tomo_angle_is_absolute = g_value_get_boolean (value);
  277. break;
  278. case PROP_TOMO_ANGLE:
  279. priv->tomo_angle = g_value_get_float (value);
  280. break;
  281. case PROP_LAMINO_ANGLE:
  282. priv->lamino_angle = g_value_get_float (value);
  283. break;
  284. default:
  285. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  286. break;
  287. }
  288. }
  289. static void
  290. ufo_anka_backproject_task_get_property (GObject *object,
  291. guint property_id,
  292. GValue *value,
  293. GParamSpec *pspec)
  294. {
  295. UfoAnkaBackprojectTaskPrivate *priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object);
  296. switch (property_id) {
  297. case PROP_X_REGION:
  298. g_value_set_boxed (value, priv->x_region);
  299. break;
  300. case PROP_Y_REGION:
  301. g_value_set_boxed (value, priv->y_region);
  302. break;
  303. case PROP_Z_REGION:
  304. g_value_set_boxed (value, priv->z_region);
  305. break;
  306. case PROP_PROJECTION_OFFSET:
  307. g_value_set_boxed (value, priv->projection_offset);
  308. break;
  309. case PROP_CENTER:
  310. g_value_set_boxed (value, priv->center);
  311. break;
  312. case PROP_TOMO_ANGLE_IS_ABSOLUTE:
  313. g_value_set_boolean (value, priv->tomo_angle_is_absolute);
  314. break;
  315. case PROP_TOMO_ANGLE:
  316. g_value_set_float (value, priv->tomo_angle);
  317. break;
  318. case PROP_LAMINO_ANGLE:
  319. g_value_set_float (value, priv->lamino_angle);
  320. break;
  321. default:
  322. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  323. break;
  324. }
  325. }
  326. static void
  327. ufo_anka_backproject_task_class_init (UfoAnkaBackprojectTaskClass *klass)
  328. {
  329. GObjectClass *oclass;
  330. UfoNodeClass *node_class;
  331. oclass = G_OBJECT_CLASS (klass);
  332. node_class = UFO_NODE_CLASS (klass);
  333. oclass->finalize = ufo_anka_backproject_task_finalize;
  334. oclass->set_property = ufo_anka_backproject_task_set_property;
  335. oclass->get_property = ufo_anka_backproject_task_get_property;
  336. GParamSpec *region_vals = g_param_spec_int ("region_values",
  337. "Region values",
  338. "Elements in regions",
  339. G_MININT,
  340. G_MAXINT,
  341. (gint) 0,
  342. G_PARAM_READWRITE);
  343. GParamSpec *float_region_vals = g_param_spec_float ("float_region_values",
  344. "Float Region values",
  345. "Elements in float regions",
  346. -G_MAXFLOAT,
  347. G_MAXFLOAT,
  348. 0.0f,
  349. G_PARAM_READWRITE);
  350. properties[PROP_X_REGION] =
  351. g_param_spec_value_array ("x_region",
  352. "X region for reconstruction as (from, to, step)",
  353. "X region for reconstruction as (from, to, step)",
  354. region_vals,
  355. G_PARAM_READWRITE);
  356. properties[PROP_Y_REGION] =
  357. g_param_spec_value_array ("y_region",
  358. "Y region for reconstruction as (from, to, step)",
  359. "Y region for reconstruction as (from, to, step)",
  360. region_vals,
  361. G_PARAM_READWRITE);
  362. properties[PROP_Z_REGION] =
  363. g_param_spec_value_array ("z_region",
  364. "Z region for reconstruction as (from, to, step)",
  365. "Z region for reconstruction as (from, to, step)",
  366. region_vals,
  367. G_PARAM_READWRITE);
  368. properties[PROP_PROJECTION_OFFSET] =
  369. g_param_spec_value_array ("projection-offset",
  370. "Offset to projection data as (x, y)",
  371. "Offset to projection data as (x, y) for the case input data \
  372. is cropped to the necessary range of interest",
  373. region_vals,
  374. G_PARAM_READWRITE);
  375. properties[PROP_CENTER] =
  376. g_param_spec_value_array ("center",
  377. "Center of the volume with respect to projections (x, y)",
  378. "Center of the volume with respect to projections (x, y), (rotation axes)",
  379. float_region_vals,
  380. G_PARAM_READWRITE);
  381. properties[PROP_TOMO_ANGLE_IS_ABSOLUTE] =
  382. g_param_spec_boolean ("tomo-angle-is-absolute",
  383. "Tomographic angle is absolute",
  384. "If TRUE, the value stored in tomo-angle property represents \
  385. an absolute angle, relative otherwise",
  386. FALSE,
  387. G_PARAM_READWRITE);
  388. properties[PROP_TOMO_ANGLE] =
  389. g_param_spec_float ("tomo-angle",
  390. "Tomographic rotation angle in radians",
  391. "Tomographic rotation angle in radians (used for acquiring projections)",
  392. -G_MAXFLOAT,
  393. G_MAXFLOAT,
  394. 0.0f,
  395. G_PARAM_READWRITE);
  396. properties[PROP_LAMINO_ANGLE] =
  397. g_param_spec_float ("lamino-angle",
  398. "Absolute laminogrpahic angle in radians",
  399. "Absolute laminogrpahic angle in radians determining the sample tilt",
  400. 0.0f,
  401. (float) G_PI / 2,
  402. 0.0f,
  403. G_PARAM_READWRITE);
  404. for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
  405. g_object_class_install_property (oclass, i, properties[i]);
  406. node_class->equal = ufo_anka_backproject_task_equal_real;
  407. g_type_class_add_private (klass, sizeof(UfoAnkaBackprojectTaskPrivate));
  408. }
  409. static void
  410. ufo_anka_backproject_task_init(UfoAnkaBackprojectTask *self)
  411. {
  412. UfoAnkaBackprojectTaskPrivate *priv;
  413. self->priv = priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE(self);
  414. guint i;
  415. GValue int_zero = G_VALUE_INIT;
  416. GValue float_zero = G_VALUE_INIT;
  417. g_value_init (&int_zero, G_TYPE_INT);
  418. g_value_init (&float_zero, G_TYPE_FLOAT);
  419. g_value_set_int (&int_zero, 0);
  420. g_value_set_float (&float_zero, 0.0f);
  421. self->priv->x_region = g_value_array_new (3);
  422. self->priv->y_region = g_value_array_new (3);
  423. self->priv->z_region = g_value_array_new (3);
  424. self->priv->projection_offset = g_value_array_new (2);
  425. self->priv->center = g_value_array_new (2);
  426. for (i = 0; i < 3; i++) {
  427. g_value_array_insert (self->priv->x_region, i, &int_zero);
  428. g_value_array_insert (self->priv->y_region, i, &int_zero);
  429. g_value_array_insert (self->priv->z_region, i, &int_zero);
  430. if (i < 2) {
  431. g_value_array_insert (self->priv->projection_offset, i, &int_zero);
  432. g_value_array_insert (self->priv->center, i, &float_zero);
  433. }
  434. }
  435. self->priv->tomo_angle_is_absolute = FALSE;
  436. self->priv->tomo_angle = 0.0f;
  437. self->priv->lamino_angle = 0.0f;
  438. self->priv->count = 0;
  439. self->priv->generated = FALSE;
  440. }