Developer documentation
Version 3.0.3-105-gd3941f44
mrtrix_utils.h
Go to the documentation of this file.
1/* Copyright (c) 2008-2022 the MRtrix3 contributors.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 *
7 * Covered Software is provided under this License on an "as is"
8 * basis, without warranty of any kind, either expressed, implied, or
9 * statutory, including, without limitation, warranties that the
10 * Covered Software is free of defects, merchantable, fit for a
11 * particular purpose or non-infringing.
12 * See the Mozilla Public License v. 2.0 for more details.
13 *
14 * For more details, see http://www.mrtrix.org/.
15 */
16
17#ifndef __formats_mrtrix_utils_h__
18#define __formats_mrtrix_utils_h__
19
20#include "header.h"
21#include "types.h"
22
23#include "file/gz.h"
24#include "file/key_value.h"
25#include "file/ofstream.h"
26#include "file/path.h"
27#include "file/utils.h"
28
29
30
31namespace MR
32{
33 namespace Formats
34 {
35
36
37 // Read generic image header information - common between conventional, compressed and sparse formats
38 template <class SourceType>
39 void read_mrtrix_header (Header&, SourceType&);
40
41 // These are helper functiosn for reading key/value pairs from either a File::KeyValue construct,
42 // or from a GZipped file (where the getline() function must be used explicitly)
43 bool next_keyvalue (File::KeyValue::Reader&, std::string&, std::string&);
44 bool next_keyvalue (File::GZ&, std::string&, std::string&);
45
46 // Get the path to a file - use same function for image data and sparse data
47 // Note that the 'file' and 'sparse_file' fields are read in as entries in the map<string, string>
48 // by read_mrtrix_header(), and are therefore erased by this function so that they do not propagate
49 // into new images created using this header
50 void get_mrtrix_file_path (Header&, const std::string&, std::string&, size_t&);
51
52 // Write generic image header information to a stream -
53 // this could be an ofstream in the case of .mif, or a stringstream in the case of .mif.gz
54 template <class StreamType>
55 void write_mrtrix_header (const Header&, StreamType&);
56
57
58 vector<ssize_t> parse_axes (size_t ndim, const std::string& specifier);
59
60
61
62
63 template <class SourceType>
64 void read_mrtrix_header (Header& H, SourceType& kv)
65 {
66 std::string dtype, layout;
68 vector<default_type> vox, scaling;
70
71 std::string key, value;
72 while (next_keyvalue (kv, key, value)) {
73 const std::string lkey = lowercase (key);
74 if (lkey == "dim") dim = parse_ints<uint64_t> (value);
75 else if (lkey == "vox") vox = parse_floats (value);
76 else if (lkey == "layout") layout = value;
77 else if (lkey == "datatype") dtype = value;
78 else if (lkey == "scaling") scaling = parse_floats (value);
79 else if (lkey == "transform")
80 transform.push_back (parse_floats (value));
81 else if (key.size() && value.size())
82 add_line (H.keyval()[key], value); // Preserve capitalization if not a compulsory key
83 }
84
85 if (dim.empty())
86 throw Exception ("missing \"dim\" specification for MRtrix image \"" + H.name() + "\"");
87 H.ndim() = dim.size();
88 for (size_t n = 0; n < dim.size(); n++) {
89 if (dim[n] < 1)
90 throw Exception ("invalid dimensions for MRtrix image \"" + H.name() + "\"");
91 H.size(n) = dim[n];
92 }
93
94 if (vox.empty())
95 throw Exception ("missing \"vox\" specification for MRtrix image \"" + H.name() + "\"");
96 if (vox.size() < std::min (size_t(3), dim.size()))
97 throw Exception ("too few entries in \"vox\" specification for MRtrix image \"" + H.name() + "\"");
98 for (size_t n = 0; n < std::min<size_t> (vox.size(), H.ndim()); n++) {
99 if (vox[n] < 0.0)
100 throw Exception ("invalid voxel size for MRtrix image \"" + H.name() + "\"");
101 H.spacing(n) = vox[n];
102 }
103
104
105 if (dtype.empty())
106 throw Exception ("missing \"datatype\" specification for MRtrix image \"" + H.name() + "\"");
107 H.datatype() = DataType::parse (dtype);
108
109
110 if (layout.empty())
111 throw Exception ("missing \"layout\" specification for MRtrix image \"" + H.name() + "\"");
112 auto ax = parse_axes (H.ndim(), layout);
113 for (size_t i = 0; i < ax.size(); ++i)
114 H.stride(i) = ax[i];
115
116 if (transform.size()) {
117
118 auto check_transform = [&transform]() {
119 if (transform.size() < 3) return false;
120 for (auto row : transform)
121 if (row.size() != 4)
122 return false;
123 return true;
124 };
125 if (!check_transform())
126 throw Exception ("invalid \"transform\" specification for MRtrix image \"" + H.name() + "\"");
127
128 for (int row = 0; row < 3; ++row)
129 for (int col = 0; col < 4; ++col)
130 H.transform() (row,col) = transform[row][col];
131 }
132
133
134 if (scaling.size()) {
135 if (scaling.size() != 2)
136 throw Exception ("invalid \"scaling\" specification for MRtrix image \"" + H.name() + "\"");
137 H.set_intensity_scaling (scaling[1], scaling[0]);
138 }
139
140 }
141
142
143
144
145
146
147
148 template <class StreamType>
149 void write_mrtrix_header (const Header& H, StreamType& out)
150 {
151 out << "dim: " << H.size (0);
152 for (size_t n = 1; n < H.ndim(); ++n)
153 out << "," << H.size (n);
154
155 out << "\nvox: " << H.spacing (0);
156 for (size_t n = 1; n < H.ndim(); ++n)
157 out << "," << H.spacing (n);
158
159 auto stride = Stride::get (H);
160 Stride::symbolise (stride);
161
162 out << "\nlayout: " << (stride[0] >0 ? "+" : "-") << abs (stride[0])-1;
163 for (size_t n = 1; n < H.ndim(); ++n)
164 out << "," << (stride[n] >0 ? "+" : "-") << abs (stride[n])-1;
165
166 DataType dt = H.datatype();
168 out << "\ndatatype: " << dt.specifier();
169
170 Eigen::IOFormat fmt(Eigen::FullPrecision, Eigen::DontAlignCols, ", ", "\ntransform: ", "", "", "\ntransform: ", "");
171 out << H.transform().matrix().topLeftCorner(3,4).format(fmt);
172
173 if (H.intensity_offset() != 0.0 || H.intensity_scale() != 1.0)
174 out << "\nscaling: " << H.intensity_offset() << "," << H.intensity_scale();
175
176 for (const auto& i : H.keyval())
177 for (const auto& line : split_lines (i.second))
178 out << "\n" << i.first << ": " << line;
179
180
181 out << "\n";
182 }
183
184
185
186
187
188 }
189}
190
191#endif
192
static DataType parse(const std::string &spec)
const char * specifier() const
void set_byte_order_native()
Definition: datatype.h:96
VectorType::Scalar value(const VectorType &coefs, typename VectorType::Scalar cos_elevation, typename VectorType::Scalar cos_azimuth, typename VectorType::Scalar sin_azimuth, int lmax)
Definition: SH.h:233
void get_mrtrix_file_path(Header &, const std::string &, std::string &, size_t &)
bool next_keyvalue(File::KeyValue::Reader &, std::string &, std::string &)
vector< ssize_t > parse_axes(size_t ndim, const std::string &specifier)
void write_mrtrix_header(const Header &, StreamType &)
Definition: mrtrix_utils.h:149
void read_mrtrix_header(Header &, SourceType &)
Definition: mrtrix_utils.h:64
void symbolise(HeaderType &header)
convert strides from actual to symbolic strides
Definition: stride.h:281
List get(const HeaderType &header)
return the strides of header as a vector<ssize_t>
Definition: stride.h:125
Definition: base.h:24
vector< default_type > parse_floats(const std::string &spec)
constexpr std::enable_if< std::is_arithmetic< X >::value &&std::is_unsigned< X >::value, X >::type abs(X x)
Definition: types.h:297
std::string lowercase(const std::string &string)
return lowercase version of string
Definition: mrtrix.h:98
vector< std::string > split_lines(const std::string &string, bool ignore_empty_fields=true, size_t num=std::numeric_limits< size_t >::max())
Definition: mrtrix.h:179
std::string & add_line(std::string &original, const std::string &new_line)
add a line to a string, taking care of inserting a newline if needed
Definition: mrtrix.h:81
Eigen::MatrixXd H