reco.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <ufo/ufo.h>
  4. #include "reco.h"
  5. #include "io.h"
  6. typedef struct {
  7. UfoPluginManager *pm;
  8. UfoTaskGraph *graph;
  9. UfoTaskNode *pad;
  10. UfoTaskNode *ramp;
  11. UfoTaskNode *fft1;
  12. UfoTaskNode *fft2;
  13. UfoTaskNode *ifft;
  14. UfoTaskNode *conv;
  15. UfoTaskNode *reco;
  16. UfoTaskNode *writer;
  17. /* interactive */
  18. guint current;
  19. UfoTaskNode *output;
  20. UfoTaskNode *input;
  21. Params *params;
  22. } LaminoData;
  23. static void
  24. print_dots (gpointer user)
  25. {
  26. static int n = 0;
  27. if ((n++ % 10) == 0)
  28. g_print (".");
  29. }
  30. static void
  31. check (GError *error)
  32. {
  33. if (error != NULL) {
  34. if (error->message != NULL)
  35. g_printerr ("%s", error->message);
  36. exit (1);
  37. }
  38. }
  39. static UfoTaskNode *
  40. make_task (UfoPluginManager *pm, const gchar *name)
  41. {
  42. GError *error = NULL;
  43. UfoTaskNode *task;
  44. task = ufo_plugin_manager_get_task (pm, name, &error);
  45. check (error);
  46. return task;
  47. }
  48. static guint
  49. next_power_of_two (guint32 x)
  50. {
  51. --x;
  52. x |= x >> 1;
  53. x |= x >> 2;
  54. x |= x >> 4;
  55. x |= x >> 8;
  56. x |= x >> 16;
  57. return x + 1;
  58. }
  59. gboolean
  60. params_okay (Params *params)
  61. {
  62. return params->width != 0 &&
  63. params->height != 0 &&
  64. params->num_radios != 0 &&
  65. params->radios != NULL &&
  66. params->theta < G_MAXDOUBLE &&
  67. params->px < G_MAXDOUBLE &&
  68. params->py < G_MAXDOUBLE;
  69. }
  70. gboolean
  71. with_flat_field_correction (Params *params)
  72. {
  73. return params->darks != NULL && params->flats != NULL;
  74. }
  75. static LaminoData *
  76. reco_graph_new (Params *params)
  77. {
  78. LaminoData *data;
  79. guint xl, xr, yt, yb;
  80. guint padded_width;
  81. guint padded_height;
  82. gdouble theta_rad;
  83. gdouble angle_step;
  84. guint fwidth;
  85. data = g_malloc0 (sizeof (LaminoData));
  86. data->params = params;
  87. data->pm = ufo_plugin_manager_new ();
  88. data->graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
  89. data->pad = make_task (data->pm, "padding-2d");
  90. data->ramp = make_task (data->pm, "lamino-ramp");
  91. data->fft1 = make_task (data->pm, "fft");
  92. data->fft2 = make_task (data->pm, "fft");
  93. data->ifft = make_task (data->pm, "ifft");
  94. data->conv = make_task (data->pm, "lamino-conv");
  95. data->reco = make_task (data->pm, "lamino-bp");
  96. data->writer = make_task (data->pm, "writer");
  97. fwidth = ((guint) params->px) * 2;
  98. padded_width = next_power_of_two ((guint32) params->width + 1);
  99. padded_height = next_power_of_two ((guint32) params->height + 1);
  100. xl = xr = (padded_width - params->width) / 2;
  101. yt = yb = (padded_height - params->height) / 2;
  102. angle_step = (G_PI * 2.0) / params->num_radios * params->radio_step;
  103. theta_rad = params->theta / 360. * G_PI * 2;
  104. info ("Axis x=%.1f y=%.1f variation=%.1f\n",
  105. params->px, params->py, params->px_variation);
  106. info ("Lamino theta=%.3f tau=%.3f step=%.5f\n",
  107. theta_rad, params->tau, angle_step);
  108. info ("Padding size=[%d %d] (xl=%d xr=%d yt=%d yb=%d)\n",
  109. padded_width, padded_height, xl, xr, yt, yb);
  110. info ("Volume origin=[%.1f %.1f %.1f] size=[%d %d %d]\n",
  111. params->v_origin[0], params->v_origin[1], params->v_origin[2],
  112. params->v_size[0], params->v_size[1], params->v_size[2]);
  113. g_object_set (data->fft1, "dimensions", 2, NULL);
  114. g_object_set (data->fft2, "dimensions", 2, NULL);
  115. g_object_set (data->ifft, "dimensions", 2, NULL);
  116. g_object_set (data->pad,
  117. "xl", xl, "xr", xr,
  118. "yt", yt, "yb", yb,
  119. "mode", "brep",
  120. NULL);
  121. g_object_set (data->ramp,
  122. "width", padded_width,
  123. "height", padded_height,
  124. "theta", theta_rad,
  125. "tau", params->tau,
  126. "fwidth", fwidth,
  127. NULL);
  128. g_object_set (data->reco,
  129. "angle-step", angle_step,
  130. "theta", theta_rad,
  131. "psi", params->psi,
  132. "proj-ox", params->px + xl,
  133. "proj-oy", params->py + yt,
  134. "proj-ox-variation", params->px_variation,
  135. "vol-ox", params->v_size[0] / 2 + params->v_origin[0],
  136. "vol-oy", params->v_size[1] / 2 + params->v_origin[1],
  137. "vol-oz", params->v_size[2] / 2 + params->v_origin[2],
  138. "vol-sx", params->v_size[0],
  139. "vol-sy", params->v_size[1],
  140. "vol-sz", params->v_size[2],
  141. "vol-z-spacing", params->z_spacing,
  142. NULL);
  143. g_object_set (data->writer,
  144. "filename", params->output,
  145. NULL);
  146. ufo_task_graph_connect_nodes (data->graph, data->pad, data->fft1);
  147. ufo_task_graph_connect_nodes (data->graph, data->ramp, data->fft2);
  148. ufo_task_graph_connect_nodes_full (data->graph, data->fft1, data->conv, 0);
  149. ufo_task_graph_connect_nodes_full (data->graph, data->fft2, data->conv, 1);
  150. ufo_task_graph_connect_nodes (data->graph, data->conv, data->ifft);
  151. ufo_task_graph_connect_nodes (data->graph, data->ifft, data->reco);
  152. ufo_task_graph_connect_nodes (data->graph, data->reco, data->writer);
  153. return data;
  154. }
  155. static void
  156. reco_graph_free (LaminoData *data)
  157. {
  158. g_object_unref (data->pm);
  159. g_object_unref (data->graph);
  160. g_object_unref (data->pad);
  161. g_object_unref (data->fft1);
  162. g_object_unref (data->fft2);
  163. /* g_object_unref (conv); */
  164. g_object_unref (data->reco);
  165. g_object_unref (data->writer);
  166. }
  167. static void
  168. update_reader (UfoTaskNode *reader, Params *params)
  169. {
  170. g_object_set (reader,
  171. "path", params->radios,
  172. "end", params->num_radios - 1,
  173. "step", params->radio_step,
  174. NULL);
  175. }
  176. static void
  177. show_time (UfoBaseScheduler *sched)
  178. {
  179. gdouble time = 0.0;
  180. g_object_get (sched, "time", &time, NULL);
  181. g_print ("\n");
  182. info ("Finished in %3.3fs\n", time);
  183. }
  184. void
  185. run_simple_reconstruction (Params *params, gchar **argv)
  186. {
  187. LaminoData *data;
  188. UfoBaseScheduler *sched = NULL;
  189. UfoTaskNode *radio_reader = NULL;
  190. UfoTaskNode *dark_reader = NULL;
  191. UfoTaskNode *flat_reader = NULL;
  192. UfoTaskNode *flat_avg = NULL;
  193. UfoTaskNode *ffc = NULL;
  194. GError *error = NULL;
  195. if (!params_okay (params)) {
  196. err ("Parameters missing.\n");
  197. return;
  198. }
  199. data = reco_graph_new (params);
  200. g_signal_connect (data->reco, "processed", G_CALLBACK (print_dots), NULL);
  201. /* Set up input */
  202. radio_reader = make_task (data->pm, "reader");
  203. update_reader (radio_reader, params);
  204. if (with_flat_field_correction (params)) {
  205. flat_avg = make_task (data->pm, "averager");
  206. flat_reader = make_task (data->pm, "reader");
  207. dark_reader = make_task (data->pm, "reader");
  208. ffc = make_task (data->pm, "flat-field-correction");
  209. g_object_set (ffc,
  210. "dark-scale", params->dark_scale,
  211. "absorption-correction", TRUE,
  212. NULL);
  213. g_object_set (flat_reader, "path", params->flats, NULL);
  214. g_object_set (dark_reader, "path", params->darks, NULL);
  215. ufo_task_graph_connect_nodes (data->graph, flat_reader, flat_avg);
  216. ufo_task_graph_connect_nodes_full (data->graph, radio_reader, ffc, 0);
  217. ufo_task_graph_connect_nodes_full (data->graph, dark_reader, ffc, 1);
  218. ufo_task_graph_connect_nodes_full (data->graph, flat_avg, ffc, 2);
  219. ufo_task_graph_connect_nodes (data->graph, ffc, data->pad);
  220. }
  221. else {
  222. warn ("> No flat/dark field correction\n");
  223. ufo_task_graph_connect_nodes (data->graph, radio_reader, data->pad);
  224. }
  225. /* Run reconstruction */
  226. info ("Processing ");
  227. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  228. ufo_base_scheduler_run (sched, data->graph, &error);
  229. check (error);
  230. show_time (sched);
  231. /* Clean up */
  232. reco_graph_free (data);
  233. g_object_unref (sched);
  234. g_object_unref (radio_reader);
  235. if (with_flat_field_correction (params)) {
  236. g_object_unref (ffc);
  237. g_object_unref (flat_avg);
  238. g_object_unref (flat_reader);
  239. g_object_unref (dark_reader);
  240. }
  241. }
  242. static void
  243. move_data (UfoTaskNode *reader, LaminoData *data)
  244. {
  245. UfoBuffer *buffer;
  246. gfloat *mem;
  247. gsize size;
  248. static int n = 0;
  249. /* FIXME: we miss one projection */
  250. /* We will block here, even though reader sent the "generated" signal */
  251. if (data->current == 0) {
  252. data->current++;
  253. return;
  254. }
  255. buffer = ufo_output_task_get_output_buffer (UFO_OUTPUT_TASK (data->output));
  256. mem = ufo_buffer_get_host_array (buffer, NULL);
  257. size = ufo_buffer_get_size (buffer);
  258. memcpy (data->params->cache + (data->current - 1) * size, mem, size);
  259. ufo_output_task_release_output_buffer (UFO_OUTPUT_TASK (data->output), buffer);
  260. data->current++;
  261. if ((n++ % 10) == 0)
  262. g_print (".");
  263. }
  264. static gpointer
  265. input_thread (LaminoData *data)
  266. {
  267. UfoBuffer *buffer;
  268. UfoRequisition req;
  269. guint current;
  270. guint num_radios;
  271. current = 0;
  272. req.n_dims = 2;
  273. req.dims[0] = data->params->width;
  274. req.dims[1] = data->params->height;
  275. buffer = ufo_buffer_new (&req, NULL);
  276. num_radios = data->params->num_radios / data->params->radio_step;
  277. while (current < num_radios) {
  278. gfloat *mem;
  279. gsize size;
  280. mem = ufo_buffer_get_host_array (buffer, NULL);
  281. size = ufo_buffer_get_size (buffer);
  282. memcpy (mem, data->params->cache + current * size, size);
  283. ufo_input_task_release_input_buffer (UFO_INPUT_TASK (data->input), buffer);
  284. current++;
  285. buffer = ufo_input_task_get_input_buffer (UFO_INPUT_TASK (data->input));
  286. if ((current % 10) == 0)
  287. g_print (".");
  288. }
  289. ufo_input_task_stop (UFO_INPUT_TASK (data->input));
  290. return NULL;
  291. }
  292. void
  293. run_cached_reconstruction (Params *params, gchar **argv)
  294. {
  295. LaminoData *data;
  296. GThread *thread;
  297. UfoBaseScheduler *sched = NULL;
  298. GError *error = NULL;
  299. data = reco_graph_new (params);
  300. if (params->cache == NULL) {
  301. UfoTaskGraph *read_graph;
  302. UfoTaskNode *radio_reader;
  303. UfoBaseScheduler *sched;
  304. GError *error = NULL;
  305. UfoTaskNode *dark_reader = NULL;
  306. UfoTaskNode *flat_reader = NULL;
  307. UfoTaskNode *flat_avg = NULL;
  308. UfoTaskNode *ffc = NULL;
  309. params->cache = g_malloc (((gsize) params->num_radios) * ((gsize) params->width) * ((gsize) params->height) * sizeof (gfloat));
  310. /* fill the cache and reconstruct simultaneously */
  311. read_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
  312. radio_reader = make_task (data->pm, "reader");
  313. update_reader (radio_reader, params);
  314. data->output = UFO_TASK_NODE (ufo_output_task_new (2));
  315. if (with_flat_field_correction (params)) {
  316. flat_avg = make_task (data->pm, "averager");
  317. flat_reader = make_task (data->pm, "reader");
  318. dark_reader = make_task (data->pm, "reader");
  319. ffc = make_task (data->pm, "flat-field-correction");
  320. g_object_set (ffc,
  321. "dark-scale", params->dark_scale,
  322. "absorption-correction", TRUE,
  323. NULL);
  324. g_object_set (flat_reader, "path", params->flats, NULL);
  325. g_object_set (dark_reader, "path", params->darks, NULL);
  326. ufo_task_graph_connect_nodes (read_graph, flat_reader, flat_avg);
  327. ufo_task_graph_connect_nodes_full (read_graph, radio_reader, ffc, 0);
  328. ufo_task_graph_connect_nodes_full (read_graph, dark_reader, ffc, 1);
  329. ufo_task_graph_connect_nodes_full (read_graph, flat_avg, ffc, 2);
  330. ufo_task_graph_connect_nodes (read_graph, ffc, data->output);
  331. }
  332. else {
  333. warn ("> No flat/dark field correction\n");
  334. ufo_task_graph_connect_nodes (read_graph, radio_reader, data->output);
  335. }
  336. g_signal_connect (radio_reader, "generated", G_CALLBACK (move_data), data);
  337. data->current = 0;
  338. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  339. info ("Reading ");
  340. ufo_base_scheduler_run (sched, read_graph, &error);
  341. check (error);
  342. g_print ("\n");
  343. g_object_unref (radio_reader);
  344. g_object_unref (read_graph);
  345. g_object_unref (data->output);
  346. if (with_flat_field_correction (params)) {
  347. g_object_unref (ffc);
  348. g_object_unref (flat_avg);
  349. g_object_unref (flat_reader);
  350. g_object_unref (dark_reader);
  351. }
  352. }
  353. data->current = 0;
  354. data->input = UFO_TASK_NODE (ufo_input_task_new ());
  355. ufo_task_graph_connect_nodes (data->graph, data->input, data->pad);
  356. /* Run reconstruction */
  357. info ("Processing ");
  358. thread = g_thread_new (NULL, (GThreadFunc) input_thread, data);
  359. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  360. ufo_base_scheduler_run (sched, data->graph, &error);
  361. check (error);
  362. show_time (sched);
  363. g_thread_unref (thread);
  364. g_object_unref (data->input);
  365. reco_graph_free (data);
  366. }