reco.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <ufo/ufo.h>
  5. #include "reco.h"
  6. #include "io.h"
  7. typedef struct {
  8. UfoPluginManager *pm;
  9. UfoTaskGraph *graph;
  10. UfoTaskNode *pad;
  11. UfoTaskNode *ramp;
  12. UfoTaskNode *fft1;
  13. UfoTaskNode *fft2;
  14. UfoTaskNode *ifft;
  15. UfoTaskNode *conv;
  16. UfoTaskNode *reco;
  17. UfoTaskNode *slice;
  18. UfoTaskNode *stats;
  19. UfoTaskNode *writer;
  20. /* interactive */
  21. guint current;
  22. UfoTaskNode *output;
  23. UfoTaskNode *input;
  24. Params *params;
  25. /* stats file */
  26. FILE *stats_fp;
  27. } LaminoData;
  28. static void
  29. print_dots (gpointer user)
  30. {
  31. static int n = 0;
  32. if ((n++ % 10) == 0)
  33. g_print (".");
  34. }
  35. static void
  36. check (GError *error)
  37. {
  38. if (error != NULL) {
  39. if (error->message != NULL)
  40. g_printerr ("%s", error->message);
  41. exit (1);
  42. }
  43. }
  44. static UfoTaskNode *
  45. make_task (UfoPluginManager *pm, const gchar *name)
  46. {
  47. GError *error = NULL;
  48. UfoTaskNode *task;
  49. task = ufo_plugin_manager_get_task (pm, name, &error);
  50. check (error);
  51. return task;
  52. }
  53. static guint
  54. next_power_of_two (guint32 x)
  55. {
  56. --x;
  57. x |= x >> 1;
  58. x |= x >> 2;
  59. x |= x >> 4;
  60. x |= x >> 8;
  61. x |= x >> 16;
  62. return x + 1;
  63. }
  64. gboolean
  65. params_okay (Params *params)
  66. {
  67. return params->width != 0 &&
  68. params->height != 0 &&
  69. params->num_radios != 0 &&
  70. params->radios != NULL &&
  71. params->theta < G_MAXDOUBLE &&
  72. params->px < G_MAXDOUBLE &&
  73. params->py < G_MAXDOUBLE;
  74. }
  75. static gboolean
  76. with_flat_field_correction (Params *params)
  77. {
  78. return params->darks != NULL && params->flats != NULL;
  79. }
  80. static void
  81. stats_finished (UfoTaskNode *stats, UfoBuffer *result, LaminoData *user)
  82. {
  83. gfloat *data;
  84. gchar buffer[128];
  85. data = ufo_buffer_get_host_array (result, NULL);
  86. g_snprintf (buffer, 128, "%.12f\n", data[0]);
  87. fwrite (buffer, 1, strlen (buffer), user->stats_fp);
  88. }
  89. static LaminoData *
  90. reco_graph_new (Params *params)
  91. {
  92. LaminoData *data;
  93. guint xl, xr, yt, yb;
  94. guint padded_width;
  95. guint padded_height;
  96. gdouble theta_rad;
  97. gdouble angle_step;
  98. guint fwidth;
  99. gchar *stats_name;
  100. data = g_malloc0 (sizeof (LaminoData));
  101. data->params = params;
  102. data->pm = ufo_plugin_manager_new ();
  103. data->graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
  104. data->pad = make_task (data->pm, "padding-2d");
  105. data->ramp = make_task (data->pm, "lamino-ramp");
  106. data->fft1 = make_task (data->pm, "fft");
  107. data->fft2 = make_task (data->pm, "fft");
  108. data->ifft = make_task (data->pm, "ifft");
  109. data->conv = make_task (data->pm, "lamino-conv");
  110. data->reco = make_task (data->pm, "lamino-bp");
  111. data->slice = make_task (data->pm, "slice");
  112. data->stats = make_task (data->pm, "measure");
  113. data->writer = make_task (data->pm, "write");
  114. fwidth = ((guint) params->px) * 2;
  115. padded_width = next_power_of_two ((guint32) params->width + 1);
  116. padded_height = next_power_of_two ((guint32) params->height + 1);
  117. xl = xr = (padded_width - params->width) / 2;
  118. yt = yb = (padded_height - params->height) / 2;
  119. angle_step = (G_PI * 2.0) / params->num_radios * params->radio_step;
  120. theta_rad = params->theta / 360. * G_PI * 2;
  121. info ("Axis x=%.1f y=%.1f variation=%.1f\n",
  122. params->px, params->py, params->px_variation);
  123. info ("Lamino theta=%.3f tau=%.3f step=%.5f\n",
  124. theta_rad, params->tau, angle_step);
  125. info ("Padding size=[%d %d] (xl=%d xr=%d yt=%d yb=%d)\n",
  126. padded_width, padded_height, xl, xr, yt, yb);
  127. info ("Volume origin=[%.1f %.1f %.1f] size=[%d %d %d]\n",
  128. params->v_origin[0], params->v_origin[1], params->v_origin[2],
  129. params->v_size[0], params->v_size[1], params->v_size[2]);
  130. g_object_set (data->fft1, "dimensions", 2, NULL);
  131. g_object_set (data->fft2, "dimensions", 2, NULL);
  132. g_object_set (data->ifft, "dimensions", 2, NULL);
  133. g_object_set (data->pad,
  134. "xl", xl, "xr", xr,
  135. "yt", yt, "yb", yb,
  136. "mode", "brep",
  137. NULL);
  138. g_object_set (data->ramp,
  139. "width", padded_width,
  140. "height", padded_height,
  141. "theta", theta_rad,
  142. "tau", params->tau,
  143. "fwidth", fwidth,
  144. NULL);
  145. g_object_set (data->reco,
  146. "angle-step", angle_step,
  147. "theta", theta_rad,
  148. "psi", params->psi,
  149. "proj-ox", params->px + xl,
  150. "proj-oy", params->py + yt,
  151. "proj-ox-variation", params->px_variation,
  152. "vol-ox", params->v_size[0] / 2 + params->v_origin[0],
  153. "vol-oy", params->v_size[1] / 2 + params->v_origin[1],
  154. "vol-oz", params->v_size[2] / 2 + params->v_origin[2],
  155. "vol-sx", params->v_size[0],
  156. "vol-sy", params->v_size[1],
  157. "vol-sz", params->v_size[2],
  158. "vol-z-spacing", params->z_spacing,
  159. NULL);
  160. g_object_set (data->stats,
  161. "pass-through", TRUE,
  162. NULL);
  163. g_object_set (data->writer,
  164. "filename", params->output,
  165. "single-file", TRUE,
  166. NULL);
  167. g_signal_connect (data->stats, "result", G_CALLBACK (stats_finished), data);
  168. ufo_task_graph_connect_nodes (data->graph, data->pad, data->fft1);
  169. ufo_task_graph_connect_nodes (data->graph, data->ramp, data->fft2);
  170. ufo_task_graph_connect_nodes_full (data->graph, data->fft1, data->conv, 0);
  171. ufo_task_graph_connect_nodes_full (data->graph, data->fft2, data->conv, 1);
  172. ufo_task_graph_connect_nodes (data->graph, data->conv, data->ifft);
  173. ufo_task_graph_connect_nodes (data->graph, data->ifft, data->reco);
  174. ufo_task_graph_connect_nodes (data->graph, data->reco, data->slice);
  175. ufo_task_graph_connect_nodes (data->graph, data->slice, data->stats);
  176. ufo_task_graph_connect_nodes (data->graph, data->stats, data->writer);
  177. stats_name = g_strdup_printf ("%s.stats", params->output);
  178. data->stats_fp = fopen (stats_name, "wb");
  179. g_free (stats_name);
  180. return data;
  181. }
  182. static void
  183. reco_graph_free (LaminoData *data)
  184. {
  185. g_object_unref (data->pm);
  186. g_object_unref (data->graph);
  187. g_object_unref (data->pad);
  188. g_object_unref (data->fft1);
  189. g_object_unref (data->fft2);
  190. /* g_object_unref (conv); */
  191. g_object_unref (data->reco);
  192. g_object_unref (data->slice);
  193. g_object_unref (data->stats);
  194. g_object_unref (data->writer);
  195. fclose (data->stats_fp);
  196. }
  197. static void
  198. update_reader (UfoTaskNode *reader, Params *params)
  199. {
  200. g_object_set (reader,
  201. "path", params->radios,
  202. "number", params->num_radios - 1,
  203. "step", params->radio_step,
  204. NULL);
  205. }
  206. static void
  207. show_time (UfoBaseScheduler *sched)
  208. {
  209. gdouble time = 0.0;
  210. g_object_get (sched, "time", &time, NULL);
  211. g_print ("\n");
  212. info ("Finished in %3.3fs\n", time);
  213. }
  214. void
  215. run_simple_reconstruction (Params *params, gchar **argv)
  216. {
  217. LaminoData *data;
  218. UfoBaseScheduler *sched = NULL;
  219. UfoTaskNode *radio_reader = NULL;
  220. UfoTaskNode *dark_reader = NULL;
  221. UfoTaskNode *flat_before_reader = NULL;
  222. UfoTaskNode *flat_before_stack = NULL;
  223. UfoTaskNode *flat_before_median = NULL;
  224. UfoTaskNode *flat_after_reader = NULL;
  225. UfoTaskNode *flat_after_stack = NULL;
  226. UfoTaskNode *flat_after_median = NULL;
  227. UfoTaskNode *flat_interpolate = NULL;
  228. UfoTaskNode *ffc = NULL;
  229. UfoTaskNode *copy = NULL;
  230. UfoTaskNode *sum = NULL;
  231. UfoTaskNode *sum_writer = NULL;
  232. GError *error = NULL;
  233. if (!params_okay (params)) {
  234. err ("Parameters missing.\n");
  235. return;
  236. }
  237. data = reco_graph_new (params);
  238. g_signal_connect (data->reco, "processed", G_CALLBACK (print_dots), NULL);
  239. /* Set up input */
  240. radio_reader = make_task (data->pm, "read");
  241. update_reader (radio_reader, params);
  242. if (with_flat_field_correction (params)) {
  243. flat_before_reader = make_task (data->pm, "read");
  244. flat_before_stack = make_task (data->pm, "stack");
  245. flat_before_median = make_task (data->pm, "flatten");
  246. dark_reader = make_task (data->pm, "read");
  247. ffc = make_task (data->pm, "flat-field-correction");
  248. copy = UFO_TASK_NODE (ufo_copy_task_new ());
  249. sum = make_task (data->pm, "flatten-inplace");
  250. sum_writer = make_task (data->pm, "writer");
  251. g_object_set (flat_before_reader, "path", params->flats, NULL);
  252. g_object_set (flat_before_stack, "number", params->num_flats, NULL);
  253. g_object_set (dark_reader, "path", params->darks, NULL);
  254. g_object_set (ffc, "dark-scale", params->dark_scale,
  255. "absorption-correction", TRUE,
  256. NULL);
  257. ufo_task_graph_connect_nodes (data->graph, flat_before_reader, flat_before_stack);
  258. ufo_task_graph_connect_nodes (data->graph, flat_before_stack, flat_before_median);
  259. ufo_task_graph_connect_nodes_full (data->graph, radio_reader, ffc, 0);
  260. ufo_task_graph_connect_nodes_full (data->graph, dark_reader, ffc, 1);
  261. if (params->write_summed) {
  262. gchar *sum_name = g_strdup_printf ("%s.sum.tif", params->output);
  263. info ("Write sum image to `%s'\n", sum_name);
  264. g_object_set (sum_writer, "filename", sum_name, NULL);
  265. ufo_task_graph_connect_nodes (data->graph, ffc, copy);
  266. ufo_task_graph_connect_nodes_full (data->graph, copy, sum, 0);
  267. ufo_task_graph_connect_nodes_full (data->graph, copy, data->pad, 0);
  268. ufo_task_graph_connect_nodes (data->graph, sum, sum_writer);
  269. g_free (sum_name);
  270. }
  271. else {
  272. ufo_task_graph_connect_nodes (data->graph, ffc, data->pad);
  273. }
  274. if (params->flats_after != NULL) {
  275. flat_after_reader = make_task (data->pm, "read");
  276. flat_after_stack = make_task (data->pm, "stack");
  277. flat_after_median = make_task (data->pm, "flatten");
  278. flat_interpolate = make_task (data->pm, "interpolate");
  279. g_object_set (flat_after_reader, "path", params->flats_after, NULL);
  280. g_object_set (flat_after_stack, "number", params->num_flats, NULL);
  281. ufo_task_graph_connect_nodes (data->graph, flat_after_reader, flat_after_stack);
  282. ufo_task_graph_connect_nodes (data->graph, flat_after_stack, flat_after_median);
  283. ufo_task_graph_connect_nodes_full (data->graph, flat_before_median, flat_interpolate, 0);
  284. ufo_task_graph_connect_nodes_full (data->graph, flat_after_median, flat_interpolate, 1);
  285. ufo_task_graph_connect_nodes_full (data->graph, flat_interpolate, ffc, 2);
  286. }
  287. else {
  288. ufo_task_graph_connect_nodes_full (data->graph, flat_before_median, ffc, 2);
  289. }
  290. }
  291. else {
  292. warn ("> No flat/dark field correction\n");
  293. ufo_task_graph_connect_nodes (data->graph, radio_reader, data->pad);
  294. }
  295. /* Run reconstruction */
  296. info ("Processing ");
  297. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  298. ufo_base_scheduler_run (sched, data->graph, &error);
  299. check (error);
  300. show_time (sched);
  301. /* Clean up */
  302. reco_graph_free (data);
  303. g_object_unref (sched);
  304. g_object_unref (radio_reader);
  305. if (with_flat_field_correction (params)) {
  306. g_object_unref (ffc);
  307. g_object_unref (flat_before_reader);
  308. g_object_unref (flat_before_stack);
  309. g_object_unref (flat_before_median);
  310. g_object_unref (dark_reader);
  311. g_object_unref (copy);
  312. g_object_unref (sum);
  313. g_object_unref (sum_writer);
  314. if (params->flats_after) {
  315. g_object_unref (flat_after_reader);
  316. g_object_unref (flat_after_stack);
  317. g_object_unref (flat_after_median);
  318. }
  319. }
  320. }
  321. static void
  322. move_data (UfoTaskNode *reader, LaminoData *data)
  323. {
  324. UfoBuffer *buffer;
  325. gfloat *mem;
  326. gsize size;
  327. static int n = 0;
  328. /* FIXME: we miss one projection */
  329. /* We will block here, even though reader sent the "generated" signal */
  330. if (data->current == 0) {
  331. data->current++;
  332. return;
  333. }
  334. buffer = ufo_output_task_get_output_buffer (UFO_OUTPUT_TASK (data->output));
  335. mem = ufo_buffer_get_host_array (buffer, NULL);
  336. size = ufo_buffer_get_size (buffer);
  337. memcpy (data->params->cache + (data->current - 1) * size, mem, size);
  338. ufo_output_task_release_output_buffer (UFO_OUTPUT_TASK (data->output), buffer);
  339. data->current++;
  340. if ((n++ % 10) == 0)
  341. g_print (".");
  342. }
  343. static gpointer
  344. input_thread (LaminoData *data)
  345. {
  346. UfoBuffer *buffer;
  347. UfoRequisition req;
  348. guint current;
  349. guint num_radios;
  350. current = 0;
  351. req.n_dims = 2;
  352. req.dims[0] = data->params->width;
  353. req.dims[1] = data->params->height;
  354. buffer = ufo_buffer_new (&req, NULL);
  355. num_radios = data->params->num_radios / data->params->radio_step;
  356. while (current < num_radios) {
  357. gfloat *mem;
  358. gsize size;
  359. mem = ufo_buffer_get_host_array (buffer, NULL);
  360. size = ufo_buffer_get_size (buffer);
  361. memcpy (mem, data->params->cache + current * size, size);
  362. ufo_input_task_release_input_buffer (UFO_INPUT_TASK (data->input), buffer);
  363. current++;
  364. buffer = ufo_input_task_get_input_buffer (UFO_INPUT_TASK (data->input));
  365. if ((current % 10) == 0)
  366. g_print (".");
  367. }
  368. ufo_input_task_stop (UFO_INPUT_TASK (data->input));
  369. return NULL;
  370. }
  371. void
  372. run_cached_reconstruction (Params *params, gchar **argv)
  373. {
  374. LaminoData *data;
  375. GThread *thread;
  376. UfoBaseScheduler *sched = NULL;
  377. GError *error = NULL;
  378. data = reco_graph_new (params);
  379. if (params->cache == NULL) {
  380. UfoTaskGraph *read_graph;
  381. UfoTaskNode *radio_reader;
  382. UfoBaseScheduler *sched;
  383. GError *error = NULL;
  384. UfoTaskNode *dark_reader = NULL;
  385. UfoTaskNode *flat_before_reader = NULL;
  386. UfoTaskNode *flat_before_stack = NULL;
  387. UfoTaskNode *flat_before_median = NULL;
  388. UfoTaskNode *flat_after_reader = NULL;
  389. UfoTaskNode *flat_after_stack = NULL;
  390. UfoTaskNode *flat_after_median = NULL;
  391. UfoTaskNode *flat_interpolate = NULL;
  392. UfoTaskNode *ffc = NULL;
  393. params->cache = g_malloc (((gsize) params->num_radios) * ((gsize) params->width) * ((gsize) params->height) * sizeof (gfloat));
  394. /* fill the cache and reconstruct simultaneously */
  395. read_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
  396. radio_reader = make_task (data->pm, "read");
  397. update_reader (radio_reader, params);
  398. data->output = UFO_TASK_NODE (ufo_output_task_new (2));
  399. if (with_flat_field_correction (params)) {
  400. flat_before_reader = make_task (data->pm, "read");
  401. flat_before_stack = make_task (data->pm, "stack");
  402. flat_before_median = make_task (data->pm, "flatten");
  403. dark_reader = make_task (data->pm, "read");
  404. ffc = make_task (data->pm, "flat-field-correction");
  405. g_object_set (dark_reader, "path", params->darks, NULL);
  406. g_object_set (flat_before_reader, "path", params->flats, NULL);
  407. g_object_set (flat_before_stack, "number", params->num_flats, NULL);
  408. g_object_set (ffc,
  409. "dark-scale", params->dark_scale,
  410. "absorption-correction", TRUE,
  411. NULL);
  412. ufo_task_graph_connect_nodes (read_graph, flat_before_reader, flat_before_stack);
  413. ufo_task_graph_connect_nodes (read_graph, flat_before_stack, flat_before_median);
  414. ufo_task_graph_connect_nodes_full (read_graph, radio_reader, ffc, 0);
  415. ufo_task_graph_connect_nodes_full (read_graph, dark_reader, ffc, 1);
  416. ufo_task_graph_connect_nodes (read_graph, ffc, data->output);
  417. if (params->flats_after) {
  418. flat_after_reader = make_task (data->pm, "read");
  419. flat_after_stack = make_task (data->pm, "stack");
  420. flat_after_median = make_task (data->pm, "flatten");
  421. flat_interpolate = make_task (data->pm, "interpolate");
  422. g_object_set (flat_after_stack, "number", params->num_flats, NULL);
  423. g_object_set (flat_after_reader, "path", params->flats_after, NULL);
  424. ufo_task_graph_connect_nodes (read_graph, flat_after_reader, flat_after_stack);
  425. ufo_task_graph_connect_nodes (read_graph, flat_after_stack, flat_after_median);
  426. ufo_task_graph_connect_nodes_full (read_graph, flat_before_median, flat_interpolate, 0);
  427. ufo_task_graph_connect_nodes_full (read_graph, flat_after_median, flat_interpolate, 1);
  428. ufo_task_graph_connect_nodes_full (read_graph, flat_interpolate, ffc, 2);
  429. }
  430. else {
  431. ufo_task_graph_connect_nodes_full (read_graph, flat_before_median, ffc, 2);
  432. }
  433. }
  434. else {
  435. warn ("> No flat/dark field correction\n");
  436. ufo_task_graph_connect_nodes (read_graph, radio_reader, data->output);
  437. }
  438. g_signal_connect (radio_reader, "generated", G_CALLBACK (move_data), data);
  439. data->current = 0;
  440. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  441. info ("Reading ");
  442. ufo_base_scheduler_run (sched, read_graph, &error);
  443. check (error);
  444. g_print ("\n");
  445. g_object_unref (radio_reader);
  446. g_object_unref (read_graph);
  447. g_object_unref (data->output);
  448. if (with_flat_field_correction (params)) {
  449. g_object_unref (ffc);
  450. g_object_unref (flat_before_reader);
  451. g_object_unref (flat_before_stack);
  452. g_object_unref (flat_before_median);
  453. g_object_unref (dark_reader);
  454. if (params->flats_after) {
  455. g_object_unref (flat_after_reader);
  456. g_object_unref (flat_after_stack);
  457. g_object_unref (flat_after_median);
  458. }
  459. }
  460. }
  461. data->current = 0;
  462. data->input = UFO_TASK_NODE (ufo_input_task_new ());
  463. ufo_task_graph_connect_nodes (data->graph, data->input, data->pad);
  464. /* Run reconstruction */
  465. info ("Processing ");
  466. thread = g_thread_new (NULL, (GThreadFunc) input_thread, data);
  467. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  468. ufo_base_scheduler_run (sched, data->graph, &error);
  469. check (error);
  470. show_time (sched);
  471. g_thread_unref (thread);
  472. g_object_unref (data->input);
  473. reco_graph_free (data);
  474. }