reco.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  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, "writer");
  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. "end", 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, "reader");
  241. update_reader (radio_reader, params);
  242. if (with_flat_field_correction (params)) {
  243. gchar *sum_name;
  244. flat_before_reader = make_task (data->pm, "reader");
  245. flat_before_stack = make_task (data->pm, "stack");
  246. flat_before_median = make_task (data->pm, "flatten");
  247. dark_reader = make_task (data->pm, "reader");
  248. ffc = make_task (data->pm, "flat-field-correction");
  249. copy = UFO_TASK_NODE (ufo_copy_task_new ());
  250. sum = make_task (data->pm, "flatten-inplace");
  251. sum_writer = make_task (data->pm, "writer");
  252. sum_name = g_strdup_printf ("%s.sum.tif", params->output);
  253. info ("Write sum image to `%s'", sum_name);
  254. g_object_set (flat_before_reader, "path", params->flats, NULL);
  255. g_object_set (flat_before_stack, "num-items", 21, NULL);
  256. g_object_set (dark_reader, "path", params->darks, NULL);
  257. g_object_set (sum_writer, "filename", sum_name, NULL);
  258. g_object_set (ffc, "dark-scale", params->dark_scale,
  259. "absorption-correction", TRUE,
  260. NULL);
  261. g_free (sum_name);
  262. ufo_task_graph_connect_nodes (data->graph, flat_before_reader, flat_before_stack);
  263. ufo_task_graph_connect_nodes (data->graph, flat_before_stack, flat_before_median);
  264. ufo_task_graph_connect_nodes_full (data->graph, radio_reader, ffc, 0);
  265. ufo_task_graph_connect_nodes_full (data->graph, dark_reader, ffc, 1);
  266. ufo_task_graph_connect_nodes (data->graph, ffc, copy);
  267. ufo_task_graph_connect_nodes_full (data->graph, copy, sum, 0);
  268. ufo_task_graph_connect_nodes_full (data->graph, copy, data->pad, 0);
  269. ufo_task_graph_connect_nodes (data->graph, sum, sum_writer);
  270. if (params->flats_after != NULL) {
  271. flat_after_reader = make_task (data->pm, "reader");
  272. flat_after_stack = make_task (data->pm, "stack");
  273. flat_after_median = make_task (data->pm, "flatten");
  274. flat_interpolate = make_task (data->pm, "interpolate");
  275. g_object_set (flat_after_reader, "path", params->flats_after, NULL);
  276. g_object_set (flat_after_stack, "num-items", params->num_flats, NULL);
  277. ufo_task_graph_connect_nodes (data->graph, flat_after_reader, flat_after_stack);
  278. ufo_task_graph_connect_nodes (data->graph, flat_after_stack, flat_after_median);
  279. ufo_task_graph_connect_nodes_full (data->graph, flat_before_median, flat_interpolate, 0);
  280. ufo_task_graph_connect_nodes_full (data->graph, flat_after_median, flat_interpolate, 1);
  281. ufo_task_graph_connect_nodes_full (data->graph, flat_interpolate, ffc, 2);
  282. }
  283. else {
  284. ufo_task_graph_connect_nodes_full (data->graph, flat_before_median, ffc, 2);
  285. }
  286. }
  287. else {
  288. warn ("> No flat/dark field correction\n");
  289. ufo_task_graph_connect_nodes (data->graph, radio_reader, data->pad);
  290. }
  291. /* Run reconstruction */
  292. info ("Processing ");
  293. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  294. ufo_base_scheduler_run (sched, data->graph, &error);
  295. check (error);
  296. show_time (sched);
  297. /* Clean up */
  298. reco_graph_free (data);
  299. g_object_unref (sched);
  300. g_object_unref (radio_reader);
  301. if (with_flat_field_correction (params)) {
  302. g_object_unref (ffc);
  303. g_object_unref (flat_before_reader);
  304. g_object_unref (flat_before_stack);
  305. g_object_unref (flat_before_median);
  306. g_object_unref (dark_reader);
  307. g_object_unref (copy);
  308. g_object_unref (sum);
  309. g_object_unref (sum_writer);
  310. if (params->flats_after) {
  311. g_object_unref (flat_after_reader);
  312. g_object_unref (flat_after_stack);
  313. g_object_unref (flat_after_median);
  314. }
  315. }
  316. }
  317. static void
  318. move_data (UfoTaskNode *reader, LaminoData *data)
  319. {
  320. UfoBuffer *buffer;
  321. gfloat *mem;
  322. gsize size;
  323. static int n = 0;
  324. /* FIXME: we miss one projection */
  325. /* We will block here, even though reader sent the "generated" signal */
  326. if (data->current == 0) {
  327. data->current++;
  328. return;
  329. }
  330. buffer = ufo_output_task_get_output_buffer (UFO_OUTPUT_TASK (data->output));
  331. mem = ufo_buffer_get_host_array (buffer, NULL);
  332. size = ufo_buffer_get_size (buffer);
  333. memcpy (data->params->cache + (data->current - 1) * size, mem, size);
  334. ufo_output_task_release_output_buffer (UFO_OUTPUT_TASK (data->output), buffer);
  335. data->current++;
  336. if ((n++ % 10) == 0)
  337. g_print (".");
  338. }
  339. static gpointer
  340. input_thread (LaminoData *data)
  341. {
  342. UfoBuffer *buffer;
  343. UfoRequisition req;
  344. guint current;
  345. guint num_radios;
  346. current = 0;
  347. req.n_dims = 2;
  348. req.dims[0] = data->params->width;
  349. req.dims[1] = data->params->height;
  350. buffer = ufo_buffer_new (&req, NULL);
  351. num_radios = data->params->num_radios / data->params->radio_step;
  352. while (current < num_radios) {
  353. gfloat *mem;
  354. gsize size;
  355. mem = ufo_buffer_get_host_array (buffer, NULL);
  356. size = ufo_buffer_get_size (buffer);
  357. memcpy (mem, data->params->cache + current * size, size);
  358. ufo_input_task_release_input_buffer (UFO_INPUT_TASK (data->input), buffer);
  359. current++;
  360. buffer = ufo_input_task_get_input_buffer (UFO_INPUT_TASK (data->input));
  361. if ((current % 10) == 0)
  362. g_print (".");
  363. }
  364. ufo_input_task_stop (UFO_INPUT_TASK (data->input));
  365. return NULL;
  366. }
  367. void
  368. run_cached_reconstruction (Params *params, gchar **argv)
  369. {
  370. LaminoData *data;
  371. GThread *thread;
  372. UfoBaseScheduler *sched = NULL;
  373. GError *error = NULL;
  374. data = reco_graph_new (params);
  375. if (params->cache == NULL) {
  376. UfoTaskGraph *read_graph;
  377. UfoTaskNode *radio_reader;
  378. UfoBaseScheduler *sched;
  379. GError *error = NULL;
  380. UfoTaskNode *dark_reader = NULL;
  381. UfoTaskNode *flat_before_reader = NULL;
  382. UfoTaskNode *flat_before_stack = NULL;
  383. UfoTaskNode *flat_before_median = NULL;
  384. UfoTaskNode *flat_after_reader = NULL;
  385. UfoTaskNode *flat_after_stack = NULL;
  386. UfoTaskNode *flat_after_median = NULL;
  387. UfoTaskNode *flat_interpolate = NULL;
  388. UfoTaskNode *ffc = NULL;
  389. params->cache = g_malloc (((gsize) params->num_radios) * ((gsize) params->width) * ((gsize) params->height) * sizeof (gfloat));
  390. /* fill the cache and reconstruct simultaneously */
  391. read_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
  392. radio_reader = make_task (data->pm, "reader");
  393. update_reader (radio_reader, params);
  394. data->output = UFO_TASK_NODE (ufo_output_task_new (2));
  395. if (with_flat_field_correction (params)) {
  396. flat_before_reader = make_task (data->pm, "reader");
  397. flat_before_stack = make_task (data->pm, "stack");
  398. flat_before_median = make_task (data->pm, "flatten");
  399. dark_reader = make_task (data->pm, "reader");
  400. ffc = make_task (data->pm, "flat-field-correction");
  401. g_object_set (dark_reader, "path", params->darks, NULL);
  402. g_object_set (flat_before_reader, "path", params->flats, NULL);
  403. g_object_set (flat_before_stack, "num-items", 21, NULL);
  404. g_object_set (ffc,
  405. "dark-scale", params->dark_scale,
  406. "absorption-correction", TRUE,
  407. NULL);
  408. ufo_task_graph_connect_nodes (read_graph, flat_before_reader, flat_before_stack);
  409. ufo_task_graph_connect_nodes (read_graph, flat_before_stack, flat_before_median);
  410. ufo_task_graph_connect_nodes_full (read_graph, radio_reader, ffc, 0);
  411. ufo_task_graph_connect_nodes_full (read_graph, dark_reader, ffc, 1);
  412. ufo_task_graph_connect_nodes (read_graph, ffc, data->output);
  413. if (params->flats_after) {
  414. flat_after_reader = make_task (data->pm, "reader");
  415. flat_after_stack = make_task (data->pm, "stack");
  416. flat_after_median = make_task (data->pm, "flatten");
  417. flat_interpolate = make_task (data->pm, "interpolate");
  418. g_object_set (flat_after_stack, "num-items", 21, NULL);
  419. g_object_set (flat_after_reader, "path", params->flats_after, NULL);
  420. ufo_task_graph_connect_nodes (read_graph, flat_after_reader, flat_after_stack);
  421. ufo_task_graph_connect_nodes (read_graph, flat_after_stack, flat_after_median);
  422. ufo_task_graph_connect_nodes_full (read_graph, flat_before_median, flat_interpolate, 0);
  423. ufo_task_graph_connect_nodes_full (read_graph, flat_after_median, flat_interpolate, 1);
  424. ufo_task_graph_connect_nodes_full (read_graph, flat_interpolate, ffc, 2);
  425. }
  426. else {
  427. ufo_task_graph_connect_nodes_full (read_graph, flat_before_median, ffc, 2);
  428. }
  429. }
  430. else {
  431. warn ("> No flat/dark field correction\n");
  432. ufo_task_graph_connect_nodes (read_graph, radio_reader, data->output);
  433. }
  434. g_signal_connect (radio_reader, "generated", G_CALLBACK (move_data), data);
  435. data->current = 0;
  436. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  437. info ("Reading ");
  438. ufo_base_scheduler_run (sched, read_graph, &error);
  439. check (error);
  440. g_print ("\n");
  441. g_object_unref (radio_reader);
  442. g_object_unref (read_graph);
  443. g_object_unref (data->output);
  444. if (with_flat_field_correction (params)) {
  445. g_object_unref (ffc);
  446. g_object_unref (flat_before_reader);
  447. g_object_unref (flat_before_stack);
  448. g_object_unref (flat_before_median);
  449. g_object_unref (dark_reader);
  450. if (params->flats_after) {
  451. g_object_unref (flat_after_reader);
  452. g_object_unref (flat_after_stack);
  453. g_object_unref (flat_after_median);
  454. }
  455. }
  456. }
  457. data->current = 0;
  458. data->input = UFO_TASK_NODE (ufo_input_task_new ());
  459. ufo_task_graph_connect_nodes (data->graph, data->input, data->pad);
  460. /* Run reconstruction */
  461. info ("Processing ");
  462. thread = g_thread_new (NULL, (GThreadFunc) input_thread, data);
  463. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new ());
  464. ufo_base_scheduler_run (sched, data->graph, &error);
  465. check (error);
  466. show_time (sched);
  467. g_thread_unref (thread);
  468. g_object_unref (data->input);
  469. reco_graph_free (data);
  470. }