@@ -27,6 +27,8 @@ namespace MR {
2727 using namespace App ;
2828 const OptionGroup ImportOptions =
2929 OptionGroup (" Options for importing phase-encode tables" )
30+ + Option(" import_pe_table" , " import a phase-encoding table from file" )
31+ + Argument(" file" ).type_file_in()
3032 + Option(" import_pe_topup" , " import a phase-encoding table intended for FSL TOPUP from file" )
3133 + Argument(" file" ).type_file_in()
3234 + Option(" import_pe_eddy" , " import phase-encoding information from an EDDY-style config / index file pair" )
@@ -44,6 +46,8 @@ namespace MR {
4446
4547 const OptionGroup ExportOptions =
4648 OptionGroup (" Options for exporting phase-encode tables" )
49+ + Option(" export_pe_table" , " export phase-encoding table to file" )
50+ + Argument(" file" ).type_file_out()
4751 + Option(" export_pe_topup" , " export phase-encoding table to a file intended for FSL topup" )
4852 + Argument(" file" ).type_file_out()
4953 + Option(" export_pe_eddy" , " export phase-encoding information to an EDDY-style config / index file pair" )
@@ -180,15 +184,18 @@ namespace MR {
180184 DEBUG (" searching for suitable phase encoding data..." );
181185 using namespace App ;
182186
187+ const auto opt_table = get_options (" import_pe_table" );
183188 const auto opt_topup = get_options (" import_pe_topup" );
184189 const auto opt_eddy = get_options (" import_pe_eddy" );
185- if (opt_topup.size () + opt_eddy.size () > 1 )
190+ if (opt_table. size () + opt_topup.size () + opt_eddy.size () > 1 )
186191 throw Exception (" Cannot specify more than one command-line option"
187192 " for importing phase encoding information from external file(s)" );
188193
189194 scheme_type result;
190195 try {
191- if (!opt_topup.empty ())
196+ if (!opt_table.empty ())
197+ result = load_table (opt_table[0 ][0 ], header);
198+ else if (!opt_topup.empty ())
192199 result = load_topup (opt_topup[0 ][0 ], header);
193200 else if (!opt_eddy.empty ())
194201 result = load_eddy (opt_eddy[0 ][0 ], opt_eddy[0 ][1 ], header);
@@ -220,8 +227,13 @@ namespace MR {
220227 try {
221228 pe_scheme = parse_scheme (keyval, H);
222229 } catch (Exception& e) {
223- WARN (" Unable to conform phase encoding information to image realignment "
224- " for image \" " + H.name () + " \" ; erasing" );
230+ if ((keyval.find (" PhaseEncodingDirection" ) != keyval.end ()
231+ && keyval[" PhaseEncodingDirection" ] != " variable" )
232+ || (keyval.find (" pe_scheme" ) != keyval.end ()
233+ && keyval[" pe_scheme" ] != " variable" )) {
234+ WARN (" Unable to conform phase encoding information to image realignment"
235+ " for image \" " + H.name () + " \" ; erasing" );
236+ }
225237 clear_scheme (keyval);
226238 return ;
227239 }
@@ -344,7 +356,11 @@ namespace MR {
344356
345357 auto scheme = parse_scheme (header.keyval (), header);
346358
347- auto opt = get_options (" export_pe_topup" );
359+ auto opt = get_options (" export_pe_table" );
360+ if (!opt.empty ())
361+ save_table (check (scheme), header, opt[0 ][0 ]);
362+
363+ opt = get_options (" export_pe_topup" );
348364 if (!opt.empty ())
349365 save_topup (check (scheme), header, opt[0 ][0 ]);
350366
@@ -355,7 +371,32 @@ namespace MR {
355371
356372
357373
374+ scheme_type load_table (const std::string& path, const Header& header) {
375+ if (Path::has_suffix (header.name (), {" .nii" , " .nii.gz" , " .img" , " .mgh" , " mgz" })) {
376+ WARN (" Note use of -import_pe_table in conjunction with MGH / NIfTI image"
377+ " interprets phase encoding directions as being strictly with respect to image axes,"
378+ " not with respect to the FSL internal convention;"
379+ " consider if -import_pe_topup is more appropriate for your use case"
380+ " (see: mrtrix.readthedocs.org/en/" MRTRIX_BASE_VERSION " /concepts/pe_scheme.html#reference-axes-for-phase-encoding-directions)" );
381+ }
382+ const scheme_type PE = load_matrix (path);
383+ check (PE, header);
384+ // As with JSON import, need to query the header to discover if the
385+ // strides / transform were modified on image load to make the image
386+ // data appear approximately axial, in which case we need to apply the
387+ // same transforms to the phase encoding data on load
388+ return transform_for_image_load (PE, header);
389+ }
390+
391+
392+
358393 scheme_type load_topup (const std::string& path, const Header& header) {
394+ if (!Path::has_suffix (header.name (), {" .nii" , " .nii.gz" , " .img" , " .mgh" , " mgz" })) {
395+ WARN (" Loading FSL topup format phase encoding information"
396+ " accompanying image \" " + header.name () + " \" that is not MGH / NIfTI format"
397+ " may be erroneous due to possible flipping of first image axis"
398+ " (see: mrtrix.readthedocs.org/en/" MRTRIX_BASE_VERSION " /concepts/pe_scheme.html#reference-axes-for-phase-encoding-directions)" );
399+ }
359400 scheme_type PE = load_matrix (path);
360401 check (PE, header);
361402 // Flip of first image axis based on determinant of image transform
@@ -369,6 +410,12 @@ namespace MR {
369410
370411
371412 scheme_type load_eddy (const std::string& config_path, const std::string& index_path, const Header& header) {
413+ if (!Path::has_suffix (header.name (), {" .nii" , " .nii.gz" , " .img" , " .mgh" , " mgz" })) {
414+ WARN (" Loading FSL eddy format phase encoding information"
415+ " accompanying image \" " + header.name () + " \" that is not MGH / NIfTI format"
416+ " may be erroneous due to possible flipping of first image axis"
417+ " (see: mrtrix.readthedocs.org/en/" MRTRIX_BASE_VERSION " /concepts/pe_scheme.html#reference-axes-for-phase-encoding-directions)" );
418+ }
372419 const Eigen::MatrixXd config = load_matrix (config_path);
373420 const Eigen::Array<int , Eigen::Dynamic, 1 > indices = load_vector<int >(index_path);
374421 scheme_type PE = eddy2topup (config, indices);
0 commit comments