lamino.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. #include <stdlib.h>
  2. #include <readline/readline.h>
  3. #include <readline/history.h>
  4. #include <ufo/ufo.h>
  5. typedef struct {
  6. gboolean interactive;
  7. gchar *radios;
  8. gchar *darks;
  9. gchar *flats;
  10. gchar *output;
  11. gint width;
  12. gint height;
  13. guint num_radios;
  14. guint num_darks;
  15. gdouble dark_scale;
  16. gdouble theta;
  17. gdouble tau;
  18. gdouble psi;
  19. gdouble px;
  20. gdouble py;
  21. gdouble px_variation;
  22. gdouble v_origin[3];
  23. guint v_size[3];
  24. GOptionEntry *entries;
  25. } Params;
  26. typedef void (*CommandFunction)(Params *, gchar **argv);
  27. typedef struct {
  28. const gchar *command;
  29. CommandFunction func;
  30. } CommandMap;
  31. const int COLOR_RED = 31;
  32. const int COLOR_GREEN = 32;
  33. const int COLOR_YELLOW = 33;
  34. static void
  35. check (GError *error)
  36. {
  37. if (error != NULL) {
  38. if (error->message != NULL)
  39. g_printerr ("%s", error->message);
  40. exit (1);
  41. }
  42. }
  43. static UfoTaskNode *
  44. make_task (UfoPluginManager *pm, const gchar *name)
  45. {
  46. GError *error = NULL;
  47. UfoTaskNode *task;
  48. task = ufo_plugin_manager_get_task (pm, name, &error);
  49. check (error);
  50. return task;
  51. }
  52. static guint
  53. next_power_of_two (guint32 x)
  54. {
  55. --x;
  56. x |= x >> 1;
  57. x |= x >> 2;
  58. x |= x >> 4;
  59. x |= x >> 8;
  60. x |= x >> 16;
  61. return x + 1;
  62. }
  63. static void
  64. colored_print (gint color, const gchar *fmt, va_list args)
  65. {
  66. gchar *s;
  67. s = g_strdup_vprintf (fmt, args);
  68. g_print ("%c[%d;%dm%s%c[%dm", 0x1B, 1, color, s, 0x1b, 0);
  69. g_free (s);
  70. }
  71. static void
  72. warn (const gchar *fmt, ...)
  73. {
  74. va_list args;
  75. va_start (args, fmt);
  76. colored_print (COLOR_YELLOW, fmt, args);
  77. va_end (args);
  78. }
  79. static void
  80. err (const gchar *fmt, ...)
  81. {
  82. va_list args;
  83. va_start (args, fmt);
  84. colored_print (COLOR_RED, fmt, args);
  85. va_end (args);
  86. }
  87. static void
  88. info (const gchar *fmt, ...)
  89. {
  90. va_list args;
  91. gchar *s;
  92. va_start (args, fmt);
  93. g_print ("%c[%d;%dm>%c[%dm ", 0x1B, 1, COLOR_GREEN, 0x1b, 0);
  94. s = g_strdup_vprintf (fmt, args);
  95. g_print ("%s", s);
  96. va_end (args);
  97. g_free (s);
  98. }
  99. static void
  100. print_dots (gpointer user)
  101. {
  102. static int n = 0;
  103. if ((n++ % 10) == 0)
  104. g_print (".");
  105. }
  106. static gboolean
  107. params_okay (Params *params)
  108. {
  109. return params->width != 0 &&
  110. params->height != 0 &&
  111. params->num_radios != 0 &&
  112. params->radios != NULL &&
  113. params->theta < G_MAXDOUBLE &&
  114. params->px < G_MAXDOUBLE &&
  115. params->py < G_MAXDOUBLE;
  116. }
  117. static void
  118. run_reconstruction (Params *params, gchar **argv)
  119. {
  120. guint xl, xr, yt, yb;
  121. guint padded_width;
  122. guint padded_height;
  123. gdouble theta_rad;
  124. gdouble angle_step;
  125. guint fwidth;
  126. gdouble time = 0.0;
  127. UfoPluginManager *pm = NULL;
  128. UfoTaskGraph *graph = NULL;
  129. UfoBaseScheduler *sched = NULL;
  130. UfoTaskNode *radio_reader = NULL;
  131. UfoTaskNode *dark_reader = NULL;
  132. UfoTaskNode *flat_reader = NULL;
  133. UfoTaskNode *ffc = NULL;
  134. UfoTaskNode *pad = NULL;
  135. UfoTaskNode *ramp = NULL;
  136. UfoTaskNode *fft1 = NULL;
  137. UfoTaskNode *fft2 = NULL;
  138. UfoTaskNode *ifft = NULL;
  139. UfoTaskNode *conv = NULL;
  140. UfoTaskNode *reco = NULL;
  141. UfoTaskNode *writer = NULL;
  142. GError *error = NULL;
  143. if (!params_okay (params)) {
  144. err ("Parameters missing.\n");
  145. return;
  146. }
  147. pm = ufo_plugin_manager_new (NULL);
  148. graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
  149. radio_reader = make_task (pm, "reader");
  150. pad = make_task (pm, "padding-2d");
  151. ramp = make_task (pm, "lamino-ramp");
  152. fft1 = make_task (pm, "fft");
  153. fft2 = make_task (pm, "fft");
  154. ifft = make_task (pm, "ifft");
  155. conv = make_task (pm, "lamino-conv");
  156. reco = make_task (pm, "lamino-bp");
  157. writer = make_task (pm, "writer");
  158. g_object_set (radio_reader,
  159. "path", params->radios,
  160. "end", params->num_radios - 1,
  161. NULL);
  162. g_object_set (fft1, "dimensions", 2, NULL);
  163. g_object_set (fft2, "dimensions", 2, NULL);
  164. g_object_set (ifft, "dimensions", 2, NULL);
  165. fwidth = ((guint) params->px) * 2;
  166. padded_width = next_power_of_two (fwidth) * 2;
  167. padded_height = next_power_of_two ((guint32) params->height + 1);
  168. xl = params->px - params->width / 2;
  169. xr = padded_width - params->width - xl;
  170. yt = params->py - params->height / 2;
  171. yb = padded_height - params->height - yt;
  172. angle_step = (G_PI * 2.0) / params->num_radios;
  173. theta_rad = params->theta / 360. * G_PI * 2;
  174. info ("Axis: x=%.1f y=%.1f variation=%.1f\n",
  175. params->px, params->py, params->px_variation);
  176. info ("Lamino: theta=%.3f tau=%.3f step=%.5f fwidth=%d\n",
  177. theta_rad, params->tau, angle_step, fwidth);
  178. info ("Padding: size=[%d %d] (xl=%d xr=%d yt=%d yb=%d)\n",
  179. padded_width, padded_height, xl, xr, yt, yb);
  180. info ("Volume: origin=[%.1f %.1f %.1f] size=[%d %d %d]\n",
  181. params->v_origin[0], params->v_origin[1], params->v_origin[2],
  182. params->v_size[0], params->v_size[1], params->v_size[2]);
  183. g_object_set (pad,
  184. "xl", xl, "xr", xr,
  185. "yt", yt, "yb", yb,
  186. "mode", "brep",
  187. NULL);
  188. g_object_set (ramp,
  189. "width", padded_width,
  190. "height", padded_height,
  191. "theta", theta_rad,
  192. "tau", params->tau,
  193. "fwidth", fwidth,
  194. NULL);
  195. g_object_set (reco,
  196. "angle-step", angle_step,
  197. "theta", theta_rad,
  198. "psi", params->psi,
  199. "proj-ox", params->px,
  200. "proj-oy", params->py,
  201. "proj-ox-variation", params->px_variation,
  202. "vol-ox", params->v_size[0] / 2 + params->v_origin[0],
  203. "vol-oy", params->v_size[1] / 2 + params->v_origin[1],
  204. "vol-oz", params->v_size[2] / 2 + params->v_origin[2],
  205. "vol-sx", params->v_size[0],
  206. "vol-sy", params->v_size[1],
  207. "vol-sz", params->v_size[2],
  208. NULL);
  209. g_object_set (writer,
  210. "filename", params->output,
  211. NULL);
  212. if (params->darks != NULL && params->flats != NULL) {
  213. flat_reader = make_task (pm, "reader");
  214. dark_reader = make_task (pm, "reader");
  215. ffc = make_task (pm, "flat-field-correction");
  216. g_object_set (ffc, "dark-scale", params->dark_scale, NULL);
  217. g_object_set (flat_reader, "path", params->flats, NULL);
  218. g_object_set (dark_reader, "path", params->darks, NULL);
  219. ufo_task_graph_connect_nodes_full (graph, radio_reader, ffc, 0);
  220. ufo_task_graph_connect_nodes_full (graph, dark_reader, ffc, 1);
  221. ufo_task_graph_connect_nodes_full (graph, flat_reader, ffc, 2);
  222. ufo_task_graph_connect_nodes (graph, ffc, pad);
  223. }
  224. else {
  225. warn ("> No flat/dark field correction\n");
  226. ufo_task_graph_connect_nodes (graph, radio_reader, pad);
  227. }
  228. ufo_task_graph_connect_nodes (graph, pad, fft1);
  229. ufo_task_graph_connect_nodes (graph, ramp, fft2);
  230. ufo_task_graph_connect_nodes_full (graph, fft1, conv, 0);
  231. ufo_task_graph_connect_nodes_full (graph, fft2, conv, 1);
  232. ufo_task_graph_connect_nodes (graph, conv, ifft);
  233. ufo_task_graph_connect_nodes (graph, ifft, reco);
  234. ufo_task_graph_connect_nodes (graph, reco, writer);
  235. g_signal_connect (reco, "processed", G_CALLBACK (print_dots), NULL);
  236. sched = UFO_BASE_SCHEDULER (ufo_scheduler_new (NULL, NULL));
  237. ufo_base_scheduler_run (sched, graph, &error);
  238. check (error);
  239. g_object_get (sched, "time", &time, NULL);
  240. g_print ("\n");
  241. info("Finished in %3.3fs\n", time);
  242. g_object_unref (pm);
  243. g_object_unref (graph);
  244. g_object_unref (sched);
  245. g_object_unref (radio_reader);
  246. g_object_unref (pad);
  247. g_object_unref (fft1);
  248. g_object_unref (fft2);
  249. /* g_object_unref (conv); */
  250. g_object_unref (reco);
  251. g_object_unref (writer);
  252. if (params->darks != NULL && params->flats != NULL) {
  253. g_object_unref (ffc);
  254. g_object_unref (flat_reader);
  255. g_object_unref (dark_reader);
  256. }
  257. }
  258. static void
  259. print (Params *params, gchar **argv)
  260. {
  261. for (gint i = 0; params->entries[i].long_name != NULL; i++) {
  262. GOptionEntry *entry;
  263. entry = &params->entries[i];
  264. if (argv[0] == NULL || g_strcmp0 (entry->long_name, argv[0]) == 0) {
  265. switch (entry->arg) {
  266. case G_OPTION_ARG_STRING:
  267. info ("%-15s%s\n", entry->long_name, *((gchar **) entry->arg_data));
  268. break;
  269. case G_OPTION_ARG_INT:
  270. info ("%-15s%i\n", entry->long_name, *((gint *) entry->arg_data));
  271. break;
  272. case G_OPTION_ARG_DOUBLE:
  273. info ("%-15s%f\n", entry->long_name, *((gdouble *) entry->arg_data));
  274. break;
  275. default:
  276. break;
  277. }
  278. }
  279. }
  280. }
  281. static void
  282. set (Params *params, gchar **argv)
  283. {
  284. if (argv[0] == NULL) {
  285. warn ("No parameter given\n");
  286. return;
  287. }
  288. if (argv[1] == NULL) {
  289. warn ("No value given\n");
  290. return;
  291. }
  292. for (gint i = 0; params->entries[i].long_name != NULL; i++) {
  293. GOptionEntry *entry;
  294. entry = &params->entries[i];
  295. if (g_strcmp0 (entry->long_name, argv[0]) == 0) {
  296. switch (entry->arg) {
  297. case G_OPTION_ARG_STRING:
  298. {
  299. gchar *s;
  300. s = *((gchar **) entry->arg_data);
  301. g_free (s);
  302. *(gchar **) entry->arg_data = g_strjoinv (" ", &argv[1]);
  303. }
  304. break;
  305. case G_OPTION_ARG_INT:
  306. *(gint *) entry->arg_data = atoi (argv[1]);
  307. break;
  308. case G_OPTION_ARG_DOUBLE:
  309. *(gdouble *) entry->arg_data = atof (argv[1]);
  310. break;
  311. default:
  312. break;
  313. }
  314. /* print (params, arg); */
  315. break;
  316. }
  317. }
  318. }
  319. static void
  320. quit (Params *params, gchar **argv)
  321. {
  322. exit (0);
  323. }
  324. static void
  325. start_shell (Params *params)
  326. {
  327. static CommandMap map[] = {
  328. { "run", run_reconstruction },
  329. { "print", print },
  330. { "set", set },
  331. { "quit", quit },
  332. { NULL },
  333. };
  334. while (1) {
  335. gchar *line;
  336. gint i;
  337. gchar **split = NULL;
  338. line = readline ("> ");
  339. if (line && *line && (g_strchomp (line) == g_strchug (line))) {
  340. add_history (line);
  341. }
  342. else {
  343. goto cleanup_line;
  344. }
  345. split = g_strsplit (line, " ", 0);
  346. for (i = 0; map[i].command != NULL; i++) {
  347. /* Run command even if only partially written out */
  348. if (g_str_has_prefix (map[i].command, split[0])) {
  349. map[i].func (params, &split[1]);
  350. break;
  351. }
  352. }
  353. if (map[i].command == NULL)
  354. warn ("Unknown command `%s'\n", split[0]);
  355. cleanup_line:
  356. g_free (line);
  357. g_strfreev (split);
  358. }
  359. }
  360. static void
  361. parse_params (Params *params, int argc, char **argv)
  362. {
  363. GOptionContext *context;
  364. GError *error = NULL;
  365. GOptionEntry entries[] = {
  366. { "width", 0, 0, G_OPTION_ARG_INT, &params->width, "Width", "[int]" },
  367. { "height", 0, 0, G_OPTION_ARG_INT, &params->height, "Height", "[int]" },
  368. { "num-radios", 0, 0, G_OPTION_ARG_INT, &params->num_radios, "Number of radios", "[int]" },
  369. { "num-darks", 0, 0, G_OPTION_ARG_INT, &params->num_darks, "Number of darks", "[int]" },
  370. { "radios", 0, 0, G_OPTION_ARG_STRING, &params->radios, "Radios", "[path|glob]" },
  371. { "darks", 0, 0, G_OPTION_ARG_STRING, &params->darks, "Darks", "[path|glob]" },
  372. { "flats", 0, 0, G_OPTION_ARG_STRING, &params->flats, "Flats", "[path|glob]" },
  373. { "dark-scale", 0, 0, G_OPTION_ARG_DOUBLE, &params->dark_scale, "Dark scale", "[float]" },
  374. { "output", 0, 0, G_OPTION_ARG_STRING, &params->output, "Output", "[path]" },
  375. { "theta", 0, 0, G_OPTION_ARG_DOUBLE, &params->theta, "Tilt (theta)", "[float]" },
  376. { "tau", 0, 0, G_OPTION_ARG_DOUBLE, &params->tau, "Pixel size (theta)", "[float]" },
  377. { "psi", 0, 0, G_OPTION_ARG_DOUBLE, &params->psi, "Misalignment (psi)", "[float]" },
  378. { "px", 0, 0, G_OPTION_ARG_DOUBLE, &params->px, "X coordinate of axis", "[float]" },
  379. { "py", 0, 0, G_OPTION_ARG_DOUBLE, &params->py, "Y coordinate of axis", "[float]" },
  380. { "px-variation", 0, 0, G_OPTION_ARG_DOUBLE, &params->px_variation, "X axis variation", "[float]" },
  381. { "vx", 0, 0, G_OPTION_ARG_DOUBLE, &params->v_origin[0], "X coordinate of box origin", "[float]" },
  382. { "vy", 0, 0, G_OPTION_ARG_DOUBLE, &params->v_origin[1], "Y coordinate of box origin", "[float]" },
  383. { "vz", 0, 0, G_OPTION_ARG_DOUBLE, &params->v_origin[2], "Z coordinate of box origin", "[float]" },
  384. { "vw", 0, 0, G_OPTION_ARG_INT, &params->v_size[0], "Width of box", "[int]" },
  385. { "vh", 0, 0, G_OPTION_ARG_INT, &params->v_size[1], "Height of box", "[int]" },
  386. { "vd", 0, 0, G_OPTION_ARG_INT, &params->v_size[2], "Depth of box", "[int]" },
  387. { "interactive", 0, 0, G_OPTION_ARG_NONE, &params->interactive, "Start interactive mode", "" },
  388. { NULL }
  389. };
  390. context = g_option_context_new ("- laminographic reconstruction");
  391. g_option_context_add_main_entries (context, entries, NULL);
  392. if (!g_option_context_parse (context, &argc, &argv, &error)) {
  393. g_print ("option parsing failed: %s\n", error->message);
  394. exit (1);
  395. }
  396. /* Copy entry information for later reference */
  397. params->entries = g_memdup (entries, sizeof (entries));
  398. if (params->interactive)
  399. goto parse_params_cleanup;
  400. if (!params_okay (params)) {
  401. err ("Parameters missing.\n\n");
  402. g_print ("%s\n", g_option_context_get_help (context, TRUE, NULL));
  403. exit (1);
  404. }
  405. parse_params_cleanup:
  406. g_option_context_free (context);
  407. }
  408. int
  409. main (int argc, char **argv)
  410. {
  411. Params params = {
  412. .interactive = FALSE,
  413. .radios = NULL,
  414. .darks = NULL,
  415. .flats = NULL,
  416. .output = "volume-%i.tif",
  417. .width = 0,
  418. .height = 0,
  419. .num_radios = 0,
  420. .num_darks = 1,
  421. .theta = G_MAXDOUBLE,
  422. .dark_scale = 1.0,
  423. .tau = 1.0,
  424. .psi = 0.0,
  425. .px = G_MAXDOUBLE,
  426. .py = G_MAXDOUBLE,
  427. .px_variation = 0.0,
  428. .v_size = {256, 256, 256},
  429. .v_origin = {0.0, 0.0, 0.0},
  430. };
  431. #if !(GLIB_CHECK_VERSION (2, 36, 0))
  432. g_type_init ();
  433. #endif
  434. parse_params (&params, argc, argv);
  435. if (params.interactive)
  436. start_shell (&params);
  437. else
  438. run_reconstruction (&params, NULL);
  439. return 0;
  440. }