PageRenderTime 73ms CodeModel.GetById 48ms RepoModel.GetById 1ms app.codeStats 0ms

/src/plastimatch/cli/pcmd_lm_warp.cxx

https://gitlab.com/plastimatch/plastimatch
C++ | 354 lines | 283 code | 41 blank | 30 comment | 47 complexity | 78e08ebf0db315a28b770d7c6709818e MD5 | raw file
  1. /* -----------------------------------------------------------------------
  2. See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information
  3. ----------------------------------------------------------------------- */
  4. #include "plmcli_config.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <math.h>
  9. #include <time.h>
  10. #include "itk_tps.h"
  11. #include "landmark_warp.h"
  12. #include "path_util.h"
  13. #include "plm_clp.h"
  14. #include "plm_image.h"
  15. #include "plm_math.h"
  16. #include "print_and_exit.h"
  17. #include "raw_pointset.h"
  18. #include "rbf_gauss.h"
  19. #include "rbf_wendland.h"
  20. #include "string_util.h"
  21. #include "volume.h"
  22. #include "xform.h"
  23. class Landmark_warp_parms {
  24. public:
  25. std::string fixed_lm_fn;
  26. std::string moving_lm_fn;
  27. std::string input_vf_fn;
  28. std::string input_img_fn;
  29. std::string output_img_fn;
  30. std::string output_vf_fn;
  31. std::string output_lm_fn;
  32. std::string fixed_img_fn;
  33. bool have_dim;
  34. plm_long dim[3];
  35. bool have_origin;
  36. float origin[3];
  37. bool have_spacing;
  38. float spacing[3];
  39. bool have_direction_cosines;
  40. float direction_cosines[9];
  41. std::string algorithm;
  42. Landmark_warp lw;
  43. public:
  44. Landmark_warp_parms () {
  45. have_dim = 0;
  46. have_origin = 0;
  47. have_spacing = 0;
  48. have_direction_cosines = 0;
  49. }
  50. };
  51. static void
  52. do_landmark_warp_itk_tps (Landmark_warp *lw)
  53. {
  54. itk_tps_warp (lw);
  55. }
  56. static void
  57. do_landmark_warp_wendland (Landmark_warp *lw)
  58. {
  59. rbf_wendland_warp (lw);
  60. }
  61. static void
  62. do_landmark_warp_gauss (Landmark_warp *lw)
  63. {
  64. rbf_gauss_warp (lw);
  65. }
  66. static void
  67. load_input_files (Landmark_warp_parms *parms)
  68. {
  69. Landmark_warp *lw = &parms->lw;
  70. /* Load the pointsets */
  71. lw->load_pointsets (parms->fixed_lm_fn.c_str(),
  72. parms->moving_lm_fn.c_str());
  73. if (!lw) {
  74. print_and_exit ("Error, landmarks were not loaded successfully.\n");
  75. }
  76. /* Load the input image */
  77. if (parms->input_img_fn != "") {
  78. lw->m_input_img = plm_image_load_native (parms->input_img_fn);
  79. if (!lw->m_input_img) {
  80. print_and_exit ("Error reading input image: %s\n",
  81. parms->input_img_fn.c_str());
  82. }
  83. /* Default geometry, if unknown, comes from moving image */
  84. lw->m_pih.set_from_plm_image (lw->m_input_img);
  85. }
  86. /* Set the output geometry.
  87. Note: --offset, --spacing, and --dim get priority over --fixed.
  88. Therefore, if these options are completely specified, we don't need
  89. to load the fixed image.
  90. */
  91. if (!parms->have_dim || !parms->have_origin
  92. || !parms->have_spacing || !parms->have_direction_cosines)
  93. {
  94. if (parms->fixed_img_fn != "") {
  95. Plm_image::Pointer pli
  96. = plm_image_load_native (parms->fixed_img_fn);
  97. if (!pli) {
  98. print_and_exit ("Error loading fixed image: %s\n",
  99. parms->fixed_img_fn.c_str());
  100. }
  101. lw->m_pih.set_from_plm_image (pli);
  102. }
  103. }
  104. if (parms->have_dim) {
  105. lw->m_pih.set_dim (parms->dim);
  106. }
  107. if (parms->have_origin) {
  108. lw->m_pih.set_origin (parms->origin);
  109. }
  110. if (parms->have_spacing) {
  111. lw->m_pih.set_spacing (parms->spacing);
  112. }
  113. // if (parms->have_direction_cosines) {
  114. // lw->m_pih.set_direction_cosines (parms->direction_cosines);
  115. // }
  116. }
  117. #if defined (commentout)
  118. void
  119. pointset_save_fcsv_by_cluster (Raw_pointset* ps, int *clust_id, int which_cluster, const char *fn)
  120. {
  121. int i;
  122. int symbol;
  123. FILE *fp;
  124. // symbolType, see
  125. //http://www.slicer.org/slicerWiki/index.php/Modules:Fiducials-Documentation-3.4
  126. symbol =which_cluster+2;
  127. if (symbol > 13) symbol -=13;
  128. fp = fopen (fn, "w");
  129. if (!fp) return;
  130. int num_points_in_cluster=0;
  131. for (i = 0; i < ps->num_points; i++) {
  132. if (clust_id[i] == which_cluster) num_points_in_cluster++;
  133. }
  134. fprintf (fp,
  135. "# Fiducial List file %s\n"
  136. "# version = 2\n"
  137. "# name = plastimatch-fiducials\n"
  138. "# numPoints = %d\n"
  139. "# symbolScale = 5\n"
  140. "# symbolType = %d\n"
  141. "# visibility = 1\n"
  142. "# textScale = 4.5\n"
  143. "# color = 0.4,1,1\n"
  144. "# selectedColor = 1,0.5,0.5\n"
  145. "# opacity = 1\n"
  146. "# ambient = 0\n"
  147. "# diffuse = 1\n"
  148. "# specular = 0\n"
  149. "# power = 1\n"
  150. "# locked = 0\n"
  151. "# numberingScheme = 0\n"
  152. "# columns = label,x,y,z,sel,vis\n",
  153. fn,
  154. num_points_in_cluster,
  155. symbol);
  156. for (i = 0; i < ps->num_points; i++) {
  157. if (clust_id[i] == which_cluster)
  158. fprintf (fp, "p-%03d-c%02d,%f,%f,%f,1,1\n",
  159. i, clust_id[i],
  160. - ps->points[i*3+0],
  161. - ps->points[i*3+1],
  162. ps->points[i*3+2]);
  163. }
  164. fclose (fp);
  165. }
  166. #endif
  167. static void
  168. save_output_files (Landmark_warp_parms *parms)
  169. {
  170. Landmark_warp *lw = &parms->lw;
  171. /* GCS FIX: float output only, and no dicom. */
  172. if (lw->m_warped_img && parms->output_img_fn != "") {
  173. lw->m_warped_img->save_image (parms->output_img_fn);
  174. }
  175. if (lw->m_vf && parms->output_vf_fn != "") {
  176. xform_save (lw->m_vf, parms->output_vf_fn);
  177. }
  178. if (lw->m_vf && parms->output_lm_fn != "")
  179. {
  180. if ( lw->num_clusters > 0 ) {
  181. /* GCS FIX 2015-06-23: If this is ever needed, it can be
  182. re-implemented e.g. by specifying a selection mask.
  183. N.b. see above code for reference. */
  184. #if defined (commentout)
  185. // if clustering required, save each cluster to a separate fcsv
  186. for( int ii = 0; ii<lw->num_clusters; ii++) {
  187. std::string fn_base = strip_extension (parms->output_lm_fn);
  188. std::string fn_out = string_format ("%s_cl_%d.fcsv",
  189. fn_base.c_str(), ii);
  190. //write FIXED landmarks to check for clustering issues
  191. pointset_save_fcsv_by_cluster(lw->m_fixed_landmarks,
  192. lw->cluster_id, ii, fn_out.c_str());
  193. }
  194. #endif
  195. }
  196. else {
  197. lw->m_warped_landmarks.save (parms->output_lm_fn.c_str());
  198. }
  199. }
  200. }
  201. static void
  202. do_landmark_warp (Landmark_warp_parms *parms)
  203. {
  204. Landmark_warp *lw = &parms->lw;
  205. load_input_files (parms);
  206. if (parms->algorithm == "tps") {
  207. do_landmark_warp_itk_tps (lw);
  208. }
  209. else if (parms->algorithm == "gauss") {
  210. do_landmark_warp_gauss (lw);
  211. }
  212. else if (parms->algorithm == "wendland") {
  213. do_landmark_warp_wendland (lw);
  214. }
  215. if (parms->output_lm_fn != "") {
  216. calculate_warped_landmarks (lw);
  217. }
  218. save_output_files (parms);
  219. }
  220. static void
  221. usage_fn (dlib::Plm_clp* parser, int argc, char *argv[])
  222. {
  223. printf ("Usage: plastimatch %s [options]\n", argv[1]);
  224. parser->print_options (std::cout);
  225. std::cout << std::endl;
  226. }
  227. static void
  228. parse_fn (
  229. Landmark_warp_parms *parms,
  230. dlib::Plm_clp *parser,
  231. int argc,
  232. char* argv[]
  233. )
  234. {
  235. Landmark_warp *lw = &parms->lw;
  236. /* Add --help, --version */
  237. parser->add_default_options ();
  238. /* Basic options */
  239. parser->add_long_option ("f", "fixed-landmarks",
  240. "Input fixed landmarks", 1, "");
  241. parser->add_long_option ("m", "moving-landmarks",
  242. "Output moving landmarks", 1, "");
  243. parser->add_long_option ("v", "input-vf",
  244. "Input vector field (applied prior to landmark warping)", 1, "");
  245. parser->add_long_option ("I", "input-image",
  246. "Input image to warp", 1, "");
  247. parser->add_long_option ("O", "output-image",
  248. "Output warped image", 1, "");
  249. parser->add_long_option ("V", "output-vf",
  250. "Output vector field", 1, "");
  251. parser->add_long_option ("L", "output-landmarks",
  252. "Output warped landmarks", 1, "");
  253. /* Output geometry options */
  254. parser->add_long_option ("", "origin",
  255. "Location of first image voxel in mm \"x y z\"", 1, "");
  256. parser->add_long_option ("", "spacing",
  257. "Voxel spacing in mm \"x [y z]\"", 1, "");
  258. parser->add_long_option ("", "dim",
  259. "Size of output image in voxels \"x [y z]\"", 1, "");
  260. parser->add_long_option ("F", "fixed",
  261. "Fixed image (match output size to this image)", 1, "");
  262. /* Algorithm options */
  263. parser->add_long_option ("a", "algorithm",
  264. "RBF warping algorithm {tps,gauss,wendland}", 1, "gauss");
  265. parser->add_long_option ("r", "radius",
  266. "Radius of radial basis function (in mm)", 1, "50.0");
  267. parser->add_long_option ("Y", "stiffness",
  268. "Young modulus (default = 0.0)", 1, "0.0");
  269. parser->add_long_option ("d", "default-value",
  270. "Value to set for pixels with unknown value", 1, "-1000");
  271. parser->add_long_option ("N", "numclusters",
  272. "Number of clusters of landmarks", 1, "0");
  273. /* Parse the command line arguments */
  274. parser->parse (argc,argv);
  275. /* Handle --help, --version */
  276. parser->check_default_options ();
  277. /* Check that required inputs were given */
  278. parser->check_required ("fixed-landmarks");
  279. parser->check_required ("moving-landmarks");
  280. /* Copy values into output struct */
  281. parms->fixed_lm_fn = parser->get_string("fixed-landmarks");
  282. parms->moving_lm_fn = parser->get_string("moving-landmarks");
  283. parms->input_vf_fn = parser->get_string("input-vf");
  284. parms->input_img_fn = parser->get_string("input-image");
  285. parms->output_img_fn = parser->get_string("output-image");
  286. parms->output_vf_fn = parser->get_string("output-vf");
  287. parms->output_lm_fn = parser->get_string("output-landmarks");
  288. if (parser->option ("origin")) {
  289. parms->have_origin = 1;
  290. parser->assign_float_13 (parms->origin, "origin");
  291. }
  292. if (parser->option ("spacing")) {
  293. parms->have_spacing = 1;
  294. parser->assign_float_13 (parms->spacing, "spacing");
  295. }
  296. if (parser->option ("dim")) {
  297. parms->have_dim = 1;
  298. parser->assign_plm_long_13 (parms->dim, "dim");
  299. }
  300. parms->fixed_img_fn = parser->get_string("fixed");
  301. parms->algorithm = parser->get_string("algorithm");
  302. lw->rbf_radius = parser->get_float("radius");
  303. lw->young_modulus = parser->get_float("stiffness");
  304. lw->default_val = parser->get_float("default-value");
  305. lw->num_clusters = parser->get_float("numclusters");
  306. }
  307. void
  308. do_command_lm_warp (int argc, char *argv[])
  309. {
  310. Landmark_warp_parms parms;
  311. plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv);
  312. do_landmark_warp (&parms);
  313. }