12 #include <unordered_set> 13 #include <unordered_map> 19 #define LIBFS_VERSION "0.3.4" 20 #define LIBFS_VERISION_MAJOR 0 21 #define LIBFS_VERISION_MINOR 3 22 #define LIBFS_VERISION_PATCH 4 89 #define LIBFS_APPTAG "[libfs] " 93 #define LIBFS_DBG_WARNING 97 #undef LIBFS_DBG_WARNING 100 #ifdef LIBFS_DBG_CRITICAL 101 #undef LIBFS_DBG_WARNING 104 #ifdef LIBFS_DBG_ERROR 105 #undef LIBFS_DBG_WARNING 110 #ifdef LIBFS_DBG_EXCESSIVE 111 #define LIBFS_DBG_VERBOSE 114 #ifdef LIBFS_DBG_VERBOSE 115 #define LIBFS_DBG_INFO 118 #ifdef LIBFS_DBG_INFO 119 #define LIBFS_DBG_WARNING 122 #ifdef LIBFS_DBG_WARNING 123 #define LIBFS_DBG_ERROR 126 #ifdef LIBFS_DBG_ERROR 127 #define LIBFS_DBG_CRITICAL 141 tm _localtime(
const std::time_t &time)
144 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) 145 ::localtime_s(&tm_snapshot, &time);
147 ::localtime_r(&time, &tm_snapshot);
160 std::string
time_tag(std::chrono::system_clock::time_point t)
162 auto as_time_t = std::chrono::system_clock::to_time_t(t);
164 char time_buffer[64];
166 tm = _localtime(as_time_t);
167 if (std::strftime(time_buffer,
sizeof(time_buffer),
"%F %T", &tm))
169 return std::string{time_buffer};
171 throw std::runtime_error(
"Failed to get current date as string");
195 inline void log(std::string
const &message, std::string
const loglevel =
"INFO")
197 std::cout << LIBFS_APPTAG <<
"[" << loglevel <<
"] [" <<
fs::util::time_tag(std::chrono::system_clock::now()) <<
"] " << message <<
"\n";
208 inline bool ends_with(std::string
const &value, std::string
const &suffix)
210 if (suffix.size() > value.size())
212 return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin());
223 inline bool ends_with(std::string
const &value, std::initializer_list<std::string> suffixes)
225 for (
auto suffix : suffixes)
227 if (ends_with(value, suffix))
247 template <
typename T>
248 std::vector<std::vector<T>> v2d(std::vector<T> values,
size_t num_cols)
250 std::vector<std::vector<T>> result;
251 for (std::size_t i = 0; i < values.size(); ++i)
253 if (i % num_cols == 0)
255 result.resize(result.size() + 1);
257 result[i / num_cols].push_back(values[i]);
272 template <
typename T>
273 std::vector<T>
vflatten(std::vector<std::vector<T>> values)
275 size_t total_size = 0;
276 for (std::size_t i = 0; i < values.size(); i++)
278 total_size += values[i].size();
281 std::vector<T> result = std::vector<T>(total_size);
283 for (std::size_t i = 0; i < values.size(); i++)
285 for (std::size_t j = 0; j < values[i].size(); j++)
287 result[cur_idx] = values[i][j];
304 inline bool starts_with(std::string
const &value, std::string
const &prefix)
306 if (prefix.length() > value.length())
308 return value.rfind(prefix, 0) == 0;
321 inline bool starts_with(std::string
const &value, std::initializer_list<std::string> prefixes)
323 for (
auto prefix : prefixes)
325 if (starts_with(value, prefix))
346 if (FILE *file = fopen(name.c_str(),
"r"))
372 std::string
fullpath(std::initializer_list<std::string> path_components, std::string path_sep = std::string(
"/"))
375 if (path_components.size() == 0)
377 throw std::invalid_argument(
"The 'path_components' must not be empty.");
381 std::string comp_mod;
383 for (
auto comp : path_components)
388 if (starts_with(comp, path_sep))
390 comp_mod = comp.substr(1, comp.size() - 1);
394 if (ends_with(comp_mod, path_sep))
396 comp_mod = comp_mod.substr(0, comp_mod.size() - 1);
400 if (idx < path_components.size() - 1)
419 void str_to_file(
const std::string &filename,
const std::string rep)
422 ofs.open(filename, std::ofstream::out);
423 #ifdef LIBFS_DBG_VERBOSE 424 std::cout << LIBFS_APPTAG <<
"Opening file '" << filename <<
"' for writing.\n";
433 throw std::runtime_error(
"Unable to open file '" + filename +
"' for writing.\n");
454 int _fread3(std::istream &);
455 template <
typename T>
456 T _freadt(std::istream &);
457 std::string _freadstringnewline(std::istream &);
458 std::string _freadfixedlengthstring(std::istream &,
size_t,
bool);
459 bool _ends_with(std::string
const &fullString, std::string
const &ending);
460 size_t _vidx_2d(
size_t,
size_t,
size_t);
484 Mesh(std::vector<float> cvertices, std::vector<int32_t> cfaces)
486 vertices = cvertices;
491 Mesh(std::vector<std::vector<float>> cvertices, std::vector<std::vector<int32_t>> cfaces)
493 vertices = util::vflatten(cvertices);
494 faces = util::vflatten(cfaces);
524 mesh.
faces = {0, 2, 3,
558 mesh.
faces = {0, 2, 1,
583 static fs::Mesh construct_grid(
const size_t nx = 4,
const size_t ny = 5,
const float distx = 1.0,
const float disty = 1.0)
585 if (nx < 2 || ny < 2)
587 throw std::runtime_error(
"Parameters nx and ny must be at least 2.");
590 size_t num_vertices = nx * ny;
591 size_t num_faces = ((nx - 1) * (ny - 1)) * 2;
592 std::vector<float> vertices;
593 vertices.reserve(num_vertices * 3);
594 std::vector<int> faces;
595 faces.reserve(num_faces * 3);
598 float cur_x, cur_y, cur_z;
599 cur_x = cur_y = cur_z = 0.0;
600 for (
size_t i = 0; i < nx; i++)
602 for (
size_t j = 0; j < ny; j++)
604 vertices.push_back(cur_x);
605 vertices.push_back(cur_y);
606 vertices.push_back(cur_z);
613 for (
size_t i = 0; i < num_vertices; i++)
615 if ((i + 1) % ny == 0 || i >= num_vertices - ny)
621 faces.push_back(
int(i));
622 faces.push_back(
int(i + ny + 1));
623 faces.push_back(
int(i + 1));
625 faces.push_back(
int(i));
626 faces.push_back(
int(i + ny + 1));
627 faces.push_back(
int(i + ny));
647 std::stringstream objs;
648 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
650 objs <<
"v " << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2] <<
"\n";
652 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
654 objs <<
"f " << faces[fidx] + 1 <<
" " << faces[fidx + 1] + 1 <<
" " << faces[fidx + 2] + 1 <<
"\n";
672 std::vector<std::vector<bool>> adjm = std::vector<std::vector<bool>>(this->num_vertices(), std::vector<bool>(this->num_vertices(),
false));
673 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
675 adjm[faces[fidx]][faces[fidx + 1]] =
true;
676 adjm[faces[fidx + 1]][faces[fidx]] =
true;
677 adjm[faces[fidx + 1]][faces[fidx + 2]] =
true;
678 adjm[faces[fidx + 2]][faces[fidx + 1]] =
true;
679 adjm[faces[fidx + 2]][faces[fidx]] =
true;
680 adjm[faces[fidx]][faces[fidx + 2]] =
true;
686 struct _tupleHashFunction
688 size_t operator()(
const std::tuple<size_t, size_t> &x)
const 690 return std::get<0>(x) ^ std::get<1>(x);
696 typedef std::unordered_set<std::tuple<size_t, size_t>, _tupleHashFunction>
edge_set;
712 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
714 edges.insert(std::make_tuple(faces[fidx], faces[fidx + 1]));
715 edges.insert(std::make_tuple(faces[fidx + 1], faces[fidx]));
717 edges.insert(std::make_tuple(faces[fidx + 1], faces[fidx + 2]));
718 edges.insert(std::make_tuple(faces[fidx + 2], faces[fidx + 1]));
720 edges.insert(std::make_tuple(faces[fidx], faces[fidx + 2]));
721 edges.insert(std::make_tuple(faces[fidx + 2], faces[fidx]));
738 std::vector<std::vector<size_t>>
as_adjlist(
const bool via_matrix =
true)
const 742 return (this->_as_adjlist_via_edgeset());
744 std::vector<std::vector<bool>> adjm = this->as_adjmatrix();
745 std::vector<std::vector<size_t>> adjl = std::vector<std::vector<size_t>>(this->num_vertices(), std::vector<size_t>());
746 size_t nv = adjm.size();
747 for (
size_t i = 0; i < nv; i++)
749 for (
size_t j = i + 1; j < nv; j++)
751 if (adjm[i][j] ==
true)
753 adjl[i].push_back(j);
754 adjl[j].push_back(i);
771 std::vector<std::vector<size_t>> _as_adjlist_via_edgeset()
const 773 edge_set edges = this->as_edgelist();
774 std::vector<std::vector<size_t>> adjl = std::vector<std::vector<size_t>>(this->num_vertices(), std::vector<size_t>());
775 for (
const std::tuple<size_t, size_t> &e : edges)
777 adjl[std::get<0>(e)].push_back(std::get<1>(e));
797 std::vector<float>
smooth_pvd_nn(
const std::vector<float> pvd,
const size_t num_iter = 1,
const bool via_matrix =
true,
const bool with_nan =
true,
const bool detect_nan =
true)
const 800 const std::vector<std::vector<size_t>> adjlist = this->as_adjlist(via_matrix);
820 static std::vector<float>
smooth_pvd_nn(
const std::vector<std::vector<size_t>> mesh_adj,
const std::vector<float> pvd,
const size_t num_iter = 1,
const bool with_nan =
true,
const bool detect_nan =
true)
822 assert(pvd.size() == mesh_adj.size());
823 bool final_with_nan = with_nan;
826 final_with_nan =
false;
827 for (
size_t i = 0; i < pvd.size(); i++)
829 if (std::isnan(pvd[i]))
831 final_with_nan =
true;
838 return fs::Mesh::_smooth_pvd_nn_nan(mesh_adj, pvd, num_iter);
840 std::vector<float> current_pvd_source;
841 std::vector<float> current_pvd_smoothed = std::vector<float>(pvd.size());
845 for (
size_t i = 0; i < num_iter; i++)
849 current_pvd_source = pvd;
853 current_pvd_source = current_pvd_smoothed;
855 for (
size_t v_idx = 0; v_idx < mesh_adj.size(); v_idx++)
857 num_neigh = mesh_adj[v_idx].size();
858 val_sum = current_pvd_source[v_idx] / (num_neigh + 1);
859 for (
size_t neigh_rel_idx = 0; neigh_rel_idx < num_neigh; neigh_rel_idx++)
861 val_sum += current_pvd_source[mesh_adj[v_idx][neigh_rel_idx]] / (num_neigh + 1);
863 current_pvd_smoothed[v_idx] = val_sum;
866 return current_pvd_smoothed;
885 static std::vector<float> _smooth_pvd_nn_nan(
const std::vector<std::vector<size_t>> mesh_adj,
const std::vector<float> pvd,
const size_t num_iter = 1)
887 std::vector<float> current_pvd_source;
888 std::vector<float> current_pvd_smoothed = std::vector<float>(pvd.size());
892 size_t num_non_nan_values;
894 for (
size_t i = 0; i < num_iter; i++)
899 current_pvd_source = pvd;
903 current_pvd_source = current_pvd_smoothed;
906 for (
size_t v_idx = 0; v_idx < mesh_adj.size(); v_idx++)
908 if (std::isnan(current_pvd_source[v_idx]))
910 current_pvd_smoothed[v_idx] = NAN;
913 val_sum = current_pvd_source[v_idx];
914 num_non_nan_values = 1;
915 num_neigh = mesh_adj[v_idx].size();
916 for (
size_t neigh_rel_idx = 0; neigh_rel_idx < num_neigh; neigh_rel_idx++)
918 neigh_val = current_pvd_source[mesh_adj[v_idx][neigh_rel_idx]];
919 if (std::isnan(neigh_val))
925 val_sum += neigh_val;
926 num_non_nan_values++;
929 current_pvd_smoothed[v_idx] = val_sum / (float)num_non_nan_values;
932 return current_pvd_smoothed;
941 static std::vector<std::vector<size_t>>
extend_adj(
const std::vector<std::vector<size_t>> mesh_adj,
const size_t extend_by = 1, std::vector<std::vector<size_t>> mesh_adj_ext = std::vector<std::vector<size_t>>())
943 size_t num_vertices = mesh_adj.size();
944 if (mesh_adj_ext.size() == 0)
946 mesh_adj_ext = mesh_adj;
948 std::vector<size_t> neighborhood;
949 std::vector<size_t> ext_neighborhood;
950 for (
size_t ext_idx = 0; ext_idx < extend_by; ext_idx++)
952 for (
size_t source_vert_idx = 0; source_vert_idx < num_vertices; source_vert_idx++)
954 neighborhood = mesh_adj_ext[source_vert_idx];
956 for (
size_t neigh_vert_rel_idx = 0; neigh_vert_rel_idx < neighborhood.size(); neigh_vert_rel_idx++)
958 for (
size_t canidate_rel_idx = 0; canidate_rel_idx < mesh_adj[neighborhood[neigh_vert_rel_idx]].size(); canidate_rel_idx++)
960 if (mesh_adj[neighborhood[neigh_vert_rel_idx]][canidate_rel_idx] != source_vert_idx)
962 mesh_adj_ext[source_vert_idx].push_back(mesh_adj[neighborhood[neigh_vert_rel_idx]][canidate_rel_idx]);
967 std::sort(mesh_adj_ext[source_vert_idx].begin(), mesh_adj_ext[source_vert_idx].end());
968 mesh_adj_ext[source_vert_idx].erase(std::unique(mesh_adj_ext[source_vert_idx].begin(), mesh_adj_ext[source_vert_idx].end()), mesh_adj_ext[source_vert_idx].end());
988 fs::util::str_to_file(filename, this->to_obj());
1007 std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh>
submesh_vertex(
const std::vector<int32_t> &old_vertex_indices,
const bool mapdir_fulltosubmesh =
false)
const 1010 std::vector<float> new_vertices;
1011 std::vector<int> new_faces;
1012 std::unordered_map<int32_t, int32_t> vertex_index_map_full2submesh;
1013 int32_t new_vertex_idx = 0;
1014 for (
size_t i = 0; i < old_vertex_indices.size(); i++)
1016 vertex_index_map_full2submesh[old_vertex_indices[i]] = new_vertex_idx;
1017 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3]);
1018 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3 + 1]);
1019 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3 + 2]);
1025 for (
size_t i = 0; i < this->num_faces(); i++)
1027 face_v0 = this->faces[i * 3];
1028 face_v1 = this->faces[i * 3 + 1];
1029 face_v2 = this->faces[i * 3 + 2];
1030 if ((vertex_index_map_full2submesh.find(face_v0) != vertex_index_map_full2submesh.end()) && (vertex_index_map_full2submesh.find(face_v1) != vertex_index_map_full2submesh.end()) && (vertex_index_map_full2submesh.find(face_v2) != vertex_index_map_full2submesh.end()))
1032 new_faces.push_back(vertex_index_map_full2submesh[face_v0]);
1033 new_faces.push_back(vertex_index_map_full2submesh[face_v1]);
1034 new_faces.push_back(vertex_index_map_full2submesh[face_v2]);
1038 submesh.
faces = new_faces;
1040 std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh> result;
1041 if (!mapdir_fulltosubmesh)
1043 std::unordered_map<int32_t, int32_t> vertex_index_map_submesh2full;
1044 for (
auto const &pair : vertex_index_map_full2submesh)
1046 vertex_index_map_submesh2full[pair.second] = pair.first;
1048 result = std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh>(vertex_index_map_submesh2full, submesh);
1052 result = std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh>(vertex_index_map_full2submesh, submesh);
1064 static std::vector<float>
curv_data_for_orig_mesh(
const std::vector<float> data_submesh,
const std::unordered_map<int32_t, int32_t> submesh_to_orig_mapping,
const int32_t orig_mesh_num_vertices,
const float fill_value = std::numeric_limits<float>::quiet_NaN())
1067 if (submesh_to_orig_mapping.size() != data_submesh.size())
1069 throw std::domain_error(
"The number of vertices of the submesh and the number of values in the submesh_to_orig_mapping do not match: got " + std::to_string(data_submesh.size()) +
" and " + std::to_string(submesh_to_orig_mapping.size()) +
".");
1072 std::vector<float> data_orig_mesh(orig_mesh_num_vertices, fill_value);
1073 for (
size_t i = 0; i < data_submesh.size(); i++)
1075 auto got = submesh_to_orig_mapping.find(
int(i));
1076 if (got != submesh_to_orig_mapping.end())
1078 data_orig_mesh[got->second] = data_submesh[i];
1081 return (data_orig_mesh);
1103 std::vector<float> vertices;
1104 std::vector<int> faces;
1106 #ifdef LIBFS_DBG_INFO 1107 size_t num_lines_ignored = 0;
1110 while (std::getline(*is, line))
1113 std::istringstream iss(line);
1114 if (fs::util::starts_with(line,
"#"))
1120 if (fs::util::starts_with(line,
"v "))
1122 std::string elem_type_identifier;
1124 if (!(iss >> elem_type_identifier >> x >> y >> z))
1126 throw std::domain_error(
"Could not parse vertex line " + std::to_string(line_idx + 1) +
" of OBJ data, invalid format.\n");
1128 assert(elem_type_identifier ==
"v");
1129 vertices.push_back(x);
1130 vertices.push_back(y);
1131 vertices.push_back(z);
1133 else if (fs::util::starts_with(line,
"f "))
1135 std::string elem_type_identifier, v0raw, v1raw, v2raw;
1137 if (!(iss >> elem_type_identifier >> v0raw >> v1raw >> v2raw))
1139 throw std::domain_error(
"Could not parse face line " + std::to_string(line_idx + 1) +
" of OBJ data, invalid format.\n");
1141 assert(elem_type_identifier ==
"f");
1146 std::size_t found_v0 = v0raw.find(
"/");
1147 std::size_t found_v1 = v1raw.find(
"/");
1148 std::size_t found_v2 = v2raw.find(
"/");
1149 if (found_v0 != std::string::npos)
1151 v0raw = v0raw.substr(0, found_v0);
1153 if (found_v1 != std::string::npos)
1155 v1raw = v1raw.substr(0, found_v1);
1157 if (found_v2 != std::string::npos)
1159 v2raw = v0raw.substr(0, found_v2);
1161 v0 = std::stoi(v0raw);
1162 v1 = std::stoi(v1raw);
1163 v2 = std::stoi(v2raw);
1166 faces.push_back(v0 - 1);
1167 faces.push_back(v1 - 1);
1168 faces.push_back(v2 - 1);
1172 #ifdef LIBFS_DBG_INFO 1173 num_lines_ignored++;
1180 #ifdef LIBFS_DBG_INFO 1181 if (num_lines_ignored > 0)
1183 std::cout << LIBFS_APPTAG <<
"Ignored " << num_lines_ignored <<
" lines in Wavefront OBJ format mesh file.\n";
1187 mesh->
faces = faces;
1206 #ifdef LIBFS_DBG_INFO 1207 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from Wavefront object format file " << filename <<
".\n";
1209 std::ifstream input(filename, std::fstream::in);
1210 if (input.is_open())
1217 throw std::runtime_error(
"Could not open Wavefront object format mesh file '" + filename +
"' for reading.\n");
1227 static void from_off(
Mesh *mesh, std::istream *is,
const std::string &source_filename =
"")
1230 std::string msg_source_file_part = source_filename.empty() ?
"" :
"'" + source_filename +
"'";
1234 int noncomment_line_idx = -1;
1236 std::vector<float> vertices;
1237 std::vector<int> faces;
1238 size_t num_vertices = 0;
1239 size_t num_faces = 0;
1240 size_t num_edges = 0;
1241 size_t num_verts_parsed = 0;
1242 size_t num_faces_parsed = 0;
1246 int num_verts_this_face, v0, v1, v2;
1248 while (std::getline(*is, line))
1251 std::istringstream iss(line);
1252 if (fs::util::starts_with(line,
"#"))
1258 noncomment_line_idx++;
1259 if (noncomment_line_idx == 0)
1261 std::string off_header_magic;
1262 if (!(iss >> off_header_magic))
1264 throw std::domain_error(
"Could not parse first header line " + std::to_string(line_idx + 1) +
" of OFF data, invalid format.\n");
1266 if (!(off_header_magic ==
"OFF" || off_header_magic ==
"COFF"))
1268 throw std::domain_error(
"OFF magic string invalid, file " + msg_source_file_part +
" not in OFF format.\n");
1272 else if (noncomment_line_idx == 1)
1274 if (!(iss >> num_vertices >> num_faces >> num_edges))
1276 throw std::domain_error(
"Could not parse element count header line " + std::to_string(line_idx + 1) +
" of OFF data " + msg_source_file_part +
", invalid format.\n");
1282 if (num_verts_parsed < num_vertices)
1284 if (!(iss >> x >> y >> z))
1286 throw std::domain_error(
"Could not parse vertex coordinate line " + std::to_string(line_idx + 1) +
" of OFF data " + msg_source_file_part +
", invalid format.\n");
1288 vertices.push_back(x);
1289 vertices.push_back(y);
1290 vertices.push_back(z);
1295 if (num_faces_parsed < num_faces)
1297 if (!(iss >> num_verts_this_face >> v0 >> v1 >> v2))
1299 throw std::domain_error(
"Could not parse face line " + std::to_string(line_idx + 1) +
" of OFF data " + msg_source_file_part +
", invalid format.\n");
1301 if (num_verts_this_face != 3)
1303 throw std::domain_error(
"At OFF data " + msg_source_file_part +
" line " + std::to_string(line_idx + 1) +
": only triangular meshes supported.\n");
1305 faces.push_back(v0);
1306 faces.push_back(v1);
1307 faces.push_back(v2);
1314 if (num_verts_parsed < num_vertices)
1316 throw std::domain_error(
"Vertex count mismatch between OFF data " + msg_source_file_part +
" header (" + std::to_string(num_vertices) +
") and data (" + std::to_string(num_verts_parsed) +
").\n");
1318 if (num_faces_parsed < num_faces)
1320 throw std::domain_error(
"Face count mismatch between OFF data " + msg_source_file_part +
" header (" + std::to_string(num_faces) +
") and data (" + std::to_string(num_faces_parsed) +
").\n");
1323 mesh->
faces = faces;
1342 #ifdef LIBFS_DBG_INFO 1343 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from OFF format file " << filename <<
".\n";
1345 std::ifstream input(filename, std::fstream::in);
1346 if (input.is_open())
1353 throw std::runtime_error(
"Could not open Object file format (OFF) mesh file '" + filename +
"' for reading.\n");
1366 int noncomment_line_idx = -1;
1368 std::vector<float> vertices;
1369 std::vector<int> faces;
1371 bool in_header =
true;
1374 while (std::getline(*is, line))
1377 std::istringstream iss(line);
1378 if (fs::util::starts_with(line,
"comment"))
1384 noncomment_line_idx++;
1387 if (noncomment_line_idx == 0)
1390 throw std::domain_error(
"Invalid PLY file");
1392 else if (noncomment_line_idx == 1)
1394 if (line !=
"format ascii 1.0")
1395 throw std::domain_error(
"Unsupported PLY file format, only format 'format ascii 1.0' is supported.");
1398 if (line ==
"end_header")
1402 else if (fs::util::starts_with(line,
"element vertex"))
1404 std::string elem, elem_type_identifier;
1405 if (!(iss >> elem >> elem_type_identifier >> num_verts))
1407 throw std::domain_error(
"Could not parse element vertex line of PLY header, invalid format.\n");
1410 else if (fs::util::starts_with(line,
"element face"))
1412 std::string elem, elem_type_identifier;
1413 if (!(iss >> elem >> elem_type_identifier >> num_faces))
1415 throw std::domain_error(
"Could not parse element face line of PLY header, invalid format.\n");
1421 if (num_verts < 1 || num_faces < 1)
1423 throw std::domain_error(
"Invalid PLY file: missing element count lines of header.");
1426 if (vertices.size() < (size_t)num_verts * 3)
1429 if (!(iss >> x >> y >> z))
1431 throw std::domain_error(
"Could not parse vertex line " + std::to_string(line_idx) +
" of PLY data, invalid format.\n");
1433 vertices.push_back(x);
1434 vertices.push_back(y);
1435 vertices.push_back(z);
1439 if (faces.size() < (size_t)num_faces * 3)
1441 int verts_per_face, v0, v1, v2;
1442 if (!(iss >> verts_per_face >> v0 >> v1 >> v2))
1444 throw std::domain_error(
"Could not parse face line " + std::to_string(line_idx) +
" of PLY data, invalid format.\n");
1446 if (verts_per_face != 3)
1448 throw std::domain_error(
"Only triangular meshes are supported: PLY faces lines must contain exactly 3 vertex indices.\n");
1450 faces.push_back(v0);
1451 faces.push_back(v1);
1452 faces.push_back(v2);
1458 if (vertices.size() != (size_t)num_verts * 3)
1460 std::cerr <<
"PLY header mentions " << num_verts <<
" vertices, but found " << vertices.size() / 3 <<
".\n";
1462 if (faces.size() != (size_t)num_faces * 3)
1464 std::cerr <<
"PLY header mentions " << num_faces <<
" faces, but found " << faces.size() / 3 <<
".\n";
1467 mesh->
faces = faces;
1485 #ifdef LIBFS_DBG_INFO 1486 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from PLY format file " << filename <<
".\n";
1488 std::ifstream input(filename, std::fstream::in);
1489 if (input.is_open())
1496 throw std::runtime_error(
"Could not open Stanford PLY format mesh file '" + filename +
"' for reading.\n");
1511 return (this->vertices.size() / 3);
1525 return (this->faces.size() / 3);
1540 const int32_t &
fm_at(
const size_t i,
const size_t j)
const 1542 size_t idx = _vidx_2d(i, j, 3);
1543 if (idx > this->faces.size() - 1)
1545 throw std::range_error(
"Indices (" + std::to_string(i) +
"," + std::to_string(j) +
") into Mesh.faces out of bounds. Hit " + std::to_string(idx) +
" with max valid index " + std::to_string(this->faces.size() - 1) +
".\n");
1547 return (this->faces[idx]);
1563 if (face > this->num_faces() - 1)
1565 throw std::range_error(
"Index " + std::to_string(face) +
" into Mesh.faces out of bounds, max valid index is " + std::to_string(this->num_faces() - 1) +
".\n");
1567 std::vector<int32_t> fv(3);
1568 fv[0] = this->fm_at(face, 0);
1569 fv[1] = this->fm_at(face, 1);
1570 fv[2] = this->fm_at(face, 2);
1587 if (vertex > this->num_vertices() - 1)
1589 throw std::range_error(
"Index " + std::to_string(vertex) +
" into Mesh.vertices out of bounds, max valid index is " + std::to_string(this->num_vertices() - 1) +
".\n");
1591 std::vector<float> vc(3);
1592 vc[0] = this->vm_at(vertex, 0);
1593 vc[1] = this->vm_at(vertex, 1);
1594 vc[2] = this->vm_at(vertex, 2);
1611 const float &
vm_at(
const size_t i,
const size_t j)
const 1613 size_t idx = _vidx_2d(i, j, 3);
1614 if (idx > this->vertices.size() - 1)
1616 throw std::range_error(
"Indices (" + std::to_string(i) +
"," + std::to_string(j) +
") into Mesh.vertices out of bounds. Hit " + std::to_string(idx) +
" with max valid index " + std::to_string(this->vertices.size() - 1) +
".\n");
1618 return (this->vertices[idx]);
1631 std::vector<uint8_t> empty_col;
1632 return (this->to_ply(empty_col));
1645 std::string
to_ply(
const std::vector<uint8_t> col)
const 1647 bool use_vertex_colors = col.size() != 0;
1648 std::stringstream plys;
1649 plys <<
"ply\nformat ascii 1.0\n";
1650 plys <<
"element vertex " << this->num_vertices() <<
"\n";
1651 plys <<
"property float x\nproperty float y\nproperty float z\n";
1652 if (use_vertex_colors)
1654 if (col.size() != this->vertices.size())
1656 throw std::invalid_argument(
"Number of vertex coordinates and vertex colors must match when writing PLY file, but got " + std::to_string(this->vertices.size()) +
" and " + std::to_string(col.size()) +
".");
1658 plys <<
"property uchar red\nproperty uchar green\nproperty uchar blue\n";
1660 plys <<
"element face " << this->num_faces() <<
"\n";
1661 plys <<
"property list uchar int vertex_index\n";
1662 plys <<
"end_header\n";
1664 #ifdef LIBFS_DBG_DEBUG 1665 fs::util::log(
"Writing " + std::to_string(this->vertices.size() / 3) +
" PLY format vertices.",
"INFO");
1668 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
1670 plys << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2];
1671 if (use_vertex_colors)
1673 plys <<
" " << (int)col[vidx] <<
" " << (
int)col[vidx + 1] <<
" " << (int)col[vidx + 2];
1678 #ifdef LIBFS_DBG_DEBUG 1679 fs::util::log(
"Writing " + std::to_string(this->faces.size() / 3) +
" PLY format faces.",
"INFO");
1682 const int num_vertices_per_face = 3;
1683 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
1685 plys << num_vertices_per_face <<
" " << faces[fidx] <<
" " << faces[fidx + 1] <<
" " << faces[fidx + 2] <<
"\n";
1687 return (plys.str());
1701 #ifdef LIBFS_DBG_INFO 1702 fs::util::log(
"Writing mesh to PLY file '" + filename +
"'.",
"INFO");
1704 fs::util::str_to_file(filename, this->to_ply());
1709 void to_ply_file(
const std::string &filename,
const std::vector<uint8_t> col)
const 1711 fs::util::str_to_file(filename, this->to_ply(col));
1724 std::vector<uint8_t> empty_col;
1725 return (this->to_off(empty_col));
1731 std::string
to_off(
const std::vector<uint8_t> col)
const 1733 bool use_vertex_colors = col.size() != 0;
1734 std::stringstream offs;
1735 if (use_vertex_colors)
1737 #ifdef LIBFS_DBG_INFO 1738 fs::util::log(
"Writing OFF representation of mesh with vertex colors.",
"INFO");
1740 if (col.size() != this->vertices.size())
1742 throw std::invalid_argument(
"Number of vertex coordinates and vertex colors must match when writing OFF file but got " + std::to_string(this->vertices.size()) +
" and " + std::to_string(col.size()) +
".");
1748 #ifdef LIBFS_DBG_INFO 1749 fs::util::log(
"Writing OFF representation of mesh without vertex colors.",
"INFO");
1753 offs << this->num_vertices() <<
" " << this->num_faces() <<
" 0\n";
1755 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
1757 offs << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2];
1758 if (use_vertex_colors)
1760 offs <<
" " << (int)col[vidx] <<
" " << (
int)col[vidx + 1] <<
" " << (int)col[vidx + 2] <<
" 255";
1765 const int num_vertices_per_face = 3;
1766 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
1768 offs << num_vertices_per_face <<
" " << faces[fidx] <<
" " << faces[fidx + 1] <<
" " << faces[fidx + 2] <<
"\n";
1770 return (offs.str());
1784 fs::util::str_to_file(filename, this->to_off());
1789 void to_off_file(
const std::string &filename,
const std::vector<uint8_t> col)
const 1791 fs::util::str_to_file(filename, this->to_off(col));
1800 Curv(std::vector<float> curv_data) : num_faces(100000), num_vertices(0), num_values_per_vertex(1)
1803 num_vertices = int(data.size());
1807 Curv() : num_faces(100000), num_vertices(0), num_values_per_vertex(1) {}
1827 std::vector<int32_t>
r;
1828 std::vector<int32_t>
g;
1829 std::vector<int32_t>
b;
1830 std::vector<int32_t>
a;
1836 size_t num_ids = this->
id.size();
1837 if (this->name.size() != num_ids || this->r.size() != num_ids || this->g.size() != num_ids || this->b.size() != num_ids || this->a.size() != num_ids || this->label.size() != num_ids)
1839 std::cerr <<
"Inconsistent Colortable, vector sizes do not match.\n";
1847 for (
size_t i = 0; i < this->num_entries(); i++)
1849 if (this->name[i] == query_name)
1860 for (
size_t i = 0; i < this->num_entries(); i++)
1862 if (this->label[i] == query_label)
1881 int32_t region_idx = this->colortable.
get_region_idx(region_name);
1882 if (region_idx >= 0)
1884 return (this->region_vertices(this->colortable.
label[region_idx]));
1888 std::cerr <<
"No such region in annot, returning empty vector.\n";
1889 std::vector<int32_t> empty;
1897 std::vector<int32_t> reg_verts;
1898 for (
size_t i = 0; i < this->vertex_labels.size(); i++)
1900 if (this->vertex_labels[i] == region_label)
1902 reg_verts.push_back(
int(i));
1912 int num_channels = alpha ? 4 : 3;
1913 std::vector<uint8_t> col;
1914 col.reserve(this->num_vertices() * num_channels);
1915 std::vector<size_t> vertex_region_indices = this->vertex_regions();
1916 for (
size_t i = 0; i < this->num_vertices(); i++)
1918 col.push_back(this->colortable.
r[vertex_region_indices[i]]);
1919 col.push_back(this->colortable.
g[vertex_region_indices[i]]);
1920 col.push_back(this->colortable.
b[vertex_region_indices[i]]);
1923 col.push_back(this->colortable.
a[vertex_region_indices[i]]);
1933 size_t nv = this->vertex_indices.size();
1934 if (this->vertex_labels.size() != nv)
1936 throw std::runtime_error(
"Inconsistent annot, number of vertex indices and labels does not match.\n");
1945 std::vector<size_t> vert_reg;
1946 for (
size_t i = 0; i < this->num_vertices(); i++)
1948 vert_reg.push_back(0);
1950 for (
size_t region_idx = 0; region_idx < this->colortable.
num_entries(); region_idx++)
1952 std::vector<int32_t> reg_vertices = this->region_vertices(this->colortable.
label[region_idx]);
1953 for (
size_t region_vert_local_idx = 0; region_vert_local_idx < reg_vertices.size(); region_vert_local_idx++)
1955 int32_t region_vert_idx = reg_vertices[region_vert_local_idx];
1956 vert_reg[region_vert_idx] = region_idx;
1965 std::vector<std::string> region_names;
1966 std::vector<size_t> vertex_region_indices = this->vertex_regions();
1967 for (
size_t i = 0; i < this->num_vertices(); i++)
1969 region_names.push_back(this->colortable.
name[vertex_region_indices[i]]);
1971 return (region_names);
1981 dim1length = curv.
data.size();
1989 dim1length = curv_data.size();
1995 int32_t dim1length = 0;
1996 int32_t dim2length = 0;
1997 int32_t dim3length = 0;
1998 int32_t dim4length = 0;
2002 int16_t ras_good_flag = 0;
2007 return ((
size_t)dim1length * dim2length * dim3length * dim4length);
2021 MghData(std::vector<int32_t> curv_data) { data_mri_int = curv_data; }
2022 explicit MghData(std::vector<uint8_t> curv_data) { data_mri_uchar = curv_data; }
2023 explicit MghData(std::vector<short> curv_data) { data_mri_short = curv_data; }
2024 MghData(std::vector<float> curv_data) { data_mri_float = curv_data; }
2043 Mgh(std::vector<float> curv_data)
2056 Array4D(
unsigned int d1,
unsigned int d2,
unsigned int d3,
unsigned int d4) : d1(d1), d2(d2), d3(d3), d4(d4), data(d1 * d2 * d3 * d4) {}
2059 Array4D(
MghHeader *mgh_header) : d1(mgh_header->dim1length), d2(mgh_header->dim2length), d3(mgh_header->dim3length), d4(mgh_header->dim4length), data(d1 * d2 * d3 * d4) {}
2063 d1(mgh->header.dim1length), d2(mgh->header.dim2length), d3(mgh->header.dim3length), d4(mgh->header.dim4length), data(d1 * d2 * d3 * d4)
2068 const T &
at(
const unsigned int i1,
const unsigned int i2,
const unsigned int i3,
const unsigned int i4)
const 2070 return data[get_index(i1, i2, i3, i4)];
2074 unsigned int get_index(
const unsigned int i1,
const unsigned int i2,
const unsigned int i3,
const unsigned int i4)
const 2076 assert(i1 >= 0 && i1 < d1);
2077 assert(i2 >= 0 && i2 < d2);
2078 assert(i3 >= 0 && i3 < d3);
2079 assert(i4 >= 0 && i4 < d4);
2080 return (((i1 * d2 + i2) * d3 + i3) * d4 + i4);
2086 return (d1 * d2 * d3 * d4);
2099 template <
typename T>
2100 std::vector<T> _read_mgh_data(
MghHeader *,
const std::string &);
2101 template <
typename T>
2102 std::vector<T> _read_mgh_data(
MghHeader *, std::istream *);
2103 std::vector<int32_t> _read_mgh_data_int(
MghHeader *,
const std::string &);
2104 std::vector<int32_t> _read_mgh_data_int(
MghHeader *, std::istream *);
2105 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *,
const std::string &);
2106 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *, std::istream *);
2107 std::vector<short> _read_mgh_data_short(
MghHeader *,
const std::string &);
2108 std::vector<short> _read_mgh_data_short(
MghHeader *, std::istream *);
2109 std::vector<float> _read_mgh_data_float(
MghHeader *,
const std::string &);
2110 std::vector<float> _read_mgh_data_float(
MghHeader *, std::istream *);
2128 mgh->
header = mgh_header;
2131 std::vector<int32_t> data = _read_mgh_data_int(&mgh_header, filename);
2136 std::vector<uint8_t> data = _read_mgh_data_uchar(&mgh_header, filename);
2141 std::vector<float> data = _read_mgh_data_float(&mgh_header, filename);
2146 std::vector<short> data = _read_mgh_data_short(&mgh_header, filename);
2151 #ifdef LIBFS_DBG_INFO 2152 if (fs::util::ends_with(filename,
".mgz"))
2154 std::cout << LIBFS_APPTAG <<
"Note: your MGH filename ends with '.mgz'. Keep in mind that MGZ format is not supported directly. You can ignore this message if you wrapped a gz stream.\n";
2157 throw std::runtime_error(
"Not reading MGH data from file '" + filename +
"', data type " + std::to_string(mgh->
header.
dtype) +
" not supported yet.\n");
2172 std::vector<std::string> subjects;
2173 std::ifstream input(filename, std::fstream::in);
2176 if (!input.is_open())
2178 throw std::runtime_error(
"Could not open subjects file '" + filename +
"'.\n");
2181 while (std::getline(input, line))
2183 subjects.push_back(line);
2197 mgh->
header = mgh_header;
2200 std::vector<int32_t> data = _read_mgh_data_int(&mgh_header, is);
2205 std::vector<uint8_t> data = _read_mgh_data_uchar(&mgh_header, is);
2210 std::vector<float> data = _read_mgh_data_float(&mgh_header, is);
2215 std::vector<short> data = _read_mgh_data_short(&mgh_header, is);
2220 throw std::runtime_error(
"Not reading data from MGH stream, data type " + std::to_string(mgh->
header.
dtype) +
" not supported yet.\n");
2231 const int MGH_VERSION = 1;
2233 int format_version = _freadt<int32_t>(*is);
2234 if (format_version != MGH_VERSION)
2236 throw std::runtime_error(
"Invalid MGH file or unsupported file format version: expected version " + std::to_string(MGH_VERSION) +
", found " + std::to_string(format_version) +
".\n");
2238 mgh_header->
dim1length = _freadt<int32_t>(*is);
2239 mgh_header->
dim2length = _freadt<int32_t>(*is);
2240 mgh_header->
dim3length = _freadt<int32_t>(*is);
2241 mgh_header->
dim4length = _freadt<int32_t>(*is);
2243 mgh_header->
dtype = _freadt<int32_t>(*is);
2244 mgh_header->
dof = _freadt<int32_t>(*is);
2246 int unused_header_space_size_left = 256;
2248 unused_header_space_size_left -= 2;
2253 mgh_header->
xsize = _freadt<float>(*is);
2254 mgh_header->
ysize = _freadt<float>(*is);
2255 mgh_header->
zsize = _freadt<float>(*is);
2257 for (
int i = 0; i < 9; i++)
2259 mgh_header->
Mdc.push_back(_freadt<float>(*is));
2261 for (
int i = 0; i < 3; i++)
2263 mgh_header->
Pxyz_c.push_back(_freadt<float>(*is));
2265 unused_header_space_size_left -= 60;
2271 while (unused_header_space_size_left > 0)
2273 discarded = _freadt<uint8_t>(*is);
2274 unused_header_space_size_left -= 1;
2283 std::vector<int32_t> _read_mgh_data_int(
MghHeader *mgh_header,
const std::string &filename)
2285 if (mgh_header->
dtype != MRI_INT)
2287 std::cerr <<
"Expected MRI data type " << MRI_INT <<
", but found " << mgh_header->
dtype <<
".\n";
2289 return (_read_mgh_data<int32_t>(mgh_header, filename));
2296 std::vector<int32_t> _read_mgh_data_int(
MghHeader *mgh_header, std::istream *is)
2298 if (mgh_header->
dtype != MRI_INT)
2300 std::cerr <<
"Expected MRI data type " << MRI_INT <<
", but found " << mgh_header->
dtype <<
".\n";
2302 return (_read_mgh_data<int32_t>(mgh_header, is));
2309 std::vector<short> _read_mgh_data_short(
MghHeader *mgh_header,
const std::string &filename)
2311 if (mgh_header->
dtype != MRI_SHORT)
2313 std::cerr <<
"Expected MRI data type " << MRI_SHORT <<
", but found " << mgh_header->
dtype <<
".\n";
2315 return (_read_mgh_data<short>(mgh_header, filename));
2322 std::vector<short> _read_mgh_data_short(
MghHeader *mgh_header, std::istream *is)
2324 if (mgh_header->
dtype != MRI_SHORT)
2326 std::cerr <<
"Expected MRI data type " << MRI_SHORT <<
", but found " << mgh_header->
dtype <<
".\n";
2328 return (_read_mgh_data<short>(mgh_header, is));
2340 ifs.open(filename, std::ios_base::in | std::ios::binary);
2348 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"'.\n");
2357 template <
typename T>
2358 std::vector<T> _read_mgh_data(
MghHeader *mgh_header,
const std::string &filename)
2361 ifs.open(filename, std::ios_base::in | std::ios::binary);
2364 ifs.seekg(284, ifs.beg);
2366 int num_values = int(mgh_header->
num_values());
2367 std::vector<T> data;
2368 for (
int i = 0; i < num_values; i++)
2370 data.push_back(_freadt<T>(ifs));
2377 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"'.\n");
2385 template <
typename T>
2386 std::vector<T> _read_mgh_data(
MghHeader *mgh_header, std::istream *is)
2388 int num_values = int(mgh_header->
num_values());
2389 std::vector<T> data;
2390 for (
int i = 0; i < num_values; i++)
2392 data.push_back(_freadt<T>(*is));
2401 std::vector<float> _read_mgh_data_float(
MghHeader *mgh_header,
const std::string &filename)
2403 if (mgh_header->
dtype != MRI_FLOAT)
2405 std::cerr <<
"Expected MRI data type " << MRI_FLOAT <<
", but found " << mgh_header->
dtype <<
".\n";
2407 return (_read_mgh_data<float>(mgh_header, filename));
2414 std::vector<float> _read_mgh_data_float(
MghHeader *mgh_header, std::istream *is)
2416 if (mgh_header->
dtype != MRI_FLOAT)
2418 std::cerr <<
"Expected MRI data type " << MRI_FLOAT <<
", but found " << mgh_header->
dtype <<
".\n";
2420 return (_read_mgh_data<float>(mgh_header, is));
2427 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *mgh_header,
const std::string &filename)
2429 if (mgh_header->
dtype != MRI_UCHAR)
2431 std::cerr <<
"Expected MRI data type " << MRI_UCHAR <<
", but found " << mgh_header->
dtype <<
".\n";
2433 return (_read_mgh_data<uint8_t>(mgh_header, filename));
2440 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *mgh_header, std::istream *is)
2442 if (mgh_header->
dtype != MRI_UCHAR)
2444 std::cerr <<
"Expected MRI data type " << MRI_UCHAR <<
", but found " << mgh_header->
dtype <<
".\n";
2446 return (_read_mgh_data<uint8_t>(mgh_header, is));
2464 const int SURF_TRIS_MAGIC = 16777214;
2466 is.open(filename, std::ios_base::in | std::ios::binary);
2469 int magic = _fread3(is);
2470 if (magic != SURF_TRIS_MAGIC)
2472 throw std::domain_error(
"Surf file '" + filename +
"' magic code in header did not match: expected " + std::to_string(SURF_TRIS_MAGIC) +
", found " + std::to_string(magic) +
".\n");
2474 std::string created_line = _freadstringnewline(is);
2475 std::string comment_line = _freadstringnewline(is);
2476 int num_verts = _freadt<int32_t>(is);
2477 int num_faces = _freadt<int32_t>(is);
2478 #ifdef LIBFS_DBG_INFO 2479 std::cout << LIBFS_APPTAG <<
"Read surface file with " << num_verts <<
" vertices, " << num_faces <<
" faces.\n";
2481 std::vector<float> vdata;
2482 for (
int i = 0; i < (num_verts * 3); i++)
2484 vdata.push_back(_freadt<float>(is));
2486 std::vector<int> fdata;
2487 for (
int i = 0; i < (num_faces * 3); i++)
2489 fdata.push_back(_freadt<int32_t>(is));
2493 surface->
faces = fdata;
2497 throw std::runtime_error(
"Unable to open surface file '" + filename +
"'.\n");
2515 if (fs::util::ends_with(filename,
".obj"))
2519 else if (fs::util::ends_with(filename,
".ply"))
2523 else if (fs::util::ends_with(filename,
".off"))
2538 bool _is_bigendian()
2540 short int number = 0x1;
2541 char *numPtr = (
char *)&number;
2543 return (numPtr[0] != 1);
2551 void read_curv(
Curv *curv, std::istream *is,
const std::string &source_filename =
"")
2553 const std::string msg_source_file_part = source_filename.empty() ?
"" :
"'" + source_filename +
"' ";
2554 const int CURV_MAGIC = 16777215;
2555 int magic = _fread3(*is);
2556 if (magic != CURV_MAGIC)
2558 throw std::domain_error(
"Curv file " + msg_source_file_part +
"header magic did not match: expected " + std::to_string(CURV_MAGIC) +
", found " + std::to_string(magic) +
".\n");
2561 curv->
num_faces = _freadt<int32_t>(*is);
2563 #ifdef LIBFS_DBG_INFO 2568 throw std::domain_error(
"Curv file " + msg_source_file_part +
"must contain exactly 1 value per vertex, found " + std::to_string(curv->
num_values_per_vertex) +
".\n");
2570 std::vector<float> data;
2573 data.push_back(_freadt<float>(*is));
2592 std::ifstream is(filename, std::fstream::in | std::fstream::binary);
2600 throw std::runtime_error(
"Could not open curv file '" + filename +
"' for reading.\n");
2606 void _read_annot_colortable(
Colortable *colortable, std::istream *is, int32_t num_entries)
2608 int32_t num_chars_orig_filename = _freadt<int32_t>(*is);
2612 for (int32_t i = 0; i < num_chars_orig_filename; i++)
2614 discarded = _freadt<uint8_t>(*is);
2618 int32_t num_entries_duplicated = _freadt<int32_t>(*is);
2619 if (num_entries != num_entries_duplicated)
2621 std::cerr <<
"Warning: the two num_entries header fields of this annotation do not match. Use with care.\n";
2624 int32_t entry_num_chars;
2625 for (int32_t i = 0; i < num_entries; i++)
2627 colortable->
id.push_back(_freadt<int32_t>(*is));
2628 entry_num_chars = _freadt<int32_t>(*is);
2629 colortable->
name.push_back(_freadfixedlengthstring(*is, entry_num_chars,
true));
2630 colortable->
r.push_back(_freadt<int32_t>(*is));
2631 colortable->
g.push_back(_freadt<int32_t>(*is));
2632 colortable->
b.push_back(_freadt<int32_t>(*is));
2633 colortable->
a.push_back(_freadt<int32_t>(*is));
2634 colortable->
label.push_back(colortable->
r[i] + colortable->
g[i] * 256 + colortable->
b[i] * 65536 + colortable->
a[i] * 16777216);
2640 size_t _vidx_2d(
size_t row,
size_t column,
size_t row_length = 3)
2642 return (row + 1) * row_length - row_length + column;
2653 int32_t num_vertices = _freadt<int32_t>(*is);
2654 std::vector<int32_t> vertices;
2655 std::vector<int32_t> labels;
2656 for (int32_t i = 0; i < (num_vertices * 2); i++)
2660 vertices.push_back(_freadt<int32_t>(*is));
2664 labels.push_back(_freadt<int32_t>(*is));
2669 int32_t has_colortable = _freadt<int32_t>(*is);
2670 if (has_colortable == 1)
2672 int32_t num_colortable_entries_old_format = _freadt<int32_t>(*is);
2673 if (num_colortable_entries_old_format > 0)
2675 throw std::domain_error(
"Reading annotation in old format not supported. Please open an issue and supply an example file if you need this.\n");
2679 int32_t colortable_format_version = -num_colortable_entries_old_format;
2680 if (colortable_format_version == 2)
2682 int32_t num_colortable_entries = _freadt<int32_t>(*is);
2683 _read_annot_colortable(&annot->
colortable, is, num_colortable_entries);
2687 throw std::domain_error(
"Reading annotation in new format version !=2 not supported. Please open an issue and supply an example file if you need this.\n");
2693 throw std::domain_error(
"Reading annotation without colortable not supported. Maybe invalid annotation file?\n");
2712 std::ifstream is(filename, std::fstream::in | std::fstream::binary);
2720 throw std::runtime_error(
"Could not open annot file '" + filename +
"' for reading.\n");
2758 if (fs::util::ends_with(filename, {
".MGH",
".mgh"}))
2765 for (
size_t i = 0; i < dims.size(); i++)
2774 std::cerr <<
"MGH file '" << filename <<
"' contains more than one non-empty dimension. Returning concatinated data.\n";
2790 template <
typename T>
2794 static_assert(CHAR_BIT == 8,
"CHAR_BIT != 8");
2799 unsigned char u8[
sizeof(T)];
2804 for (
size_t k = 0; k <
sizeof(T); k++)
2805 dest.u8[k] = source.u8[
sizeof(T) - k - 1];
2814 template <
typename T>
2815 T _freadt(std::istream &is)
2818 is.read(reinterpret_cast<char *>(&t),
sizeof(t));
2819 if (!_is_bigendian())
2821 t = _swap_endian<T>(t);
2830 int _fread3(std::istream &is)
2833 is.read(reinterpret_cast<char *>(&i), 3);
2834 if (!_is_bigendian())
2836 i = _swap_endian<std::uint32_t>(i);
2838 i = ((i >> 8) & 0xffffff);
2846 template <
typename T>
2847 void _fwritet(std::ostream &os, T t)
2849 if (!_is_bigendian())
2851 t = _swap_endian<T>(t);
2853 os.write(reinterpret_cast<const char *>(&t),
sizeof(t));
2860 void _fwritei3(std::ostream &os, uint32_t i)
2862 unsigned char b1 = (i >> 16) & 255;
2863 unsigned char b2 = (i >> 8) & 255;
2864 unsigned char b3 = i & 255;
2866 if (!_is_bigendian())
2868 b1 = _swap_endian<unsigned char>(b1);
2869 b2 = _swap_endian<unsigned char>(b2);
2870 b3 = _swap_endian<unsigned char>(b3);
2873 os.write(reinterpret_cast<const char *>(&b1),
sizeof(b1));
2874 os.write(reinterpret_cast<const char *>(&b2),
sizeof(b2));
2875 os.write(reinterpret_cast<const char *>(&b3),
sizeof(b3));
2882 std::string _freadstringnewline(std::istream &is)
2885 std::getline(is, s,
'\n');
2892 std::string _freadfixedlengthstring(std::istream &is,
size_t length,
bool strip_last_char =
true)
2896 is.read(&str[0], length);
2897 if (strip_last_char)
2899 str = str.substr(0, length - 1);
2909 void write_curv(std::ostream &os, std::vector<float> curv_data, int32_t num_faces = 100000)
2911 const uint32_t CURV_MAGIC = 16777215;
2912 _fwritei3(os, CURV_MAGIC);
2913 _fwritet<int32_t>(os, int(curv_data.size()));
2914 _fwritet<int32_t>(os, num_faces);
2915 _fwritet<int32_t>(os, 1);
2916 for (
size_t i = 0; i < curv_data.size(); i++)
2918 _fwritet<float>(os, curv_data[i]);
2936 void write_curv(
const std::string &filename, std::vector<float> curv_data,
const int32_t num_faces = 100000)
2939 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
2947 throw std::runtime_error(
"Unable to open curvature file '" + filename +
"' for writing.\n");
2958 _fwritet<int32_t>(os, 1);
2967 size_t unused_header_space_size_left = 256;
2969 unused_header_space_size_left -= 2;
2978 for (
int i = 0; i < 9; i++)
2982 for (
int i = 0; i < 3; i++)
2987 unused_header_space_size_left -= 60;
2990 for (
size_t i = 0; i < unused_header_space_size_left; i++)
2992 _fwritet<uint8_t>(os, 0);
3001 throw std::logic_error(
"Detected mismatch of MRI_INT data size and MGH header dim length values.\n");
3003 for (
size_t i = 0; i < num_values; i++)
3012 throw std::logic_error(
"Detected mismatch of MRI_FLOAT data size and MGH header dim length values.\n");
3014 for (
size_t i = 0; i < num_values; i++)
3023 throw std::logic_error(
"Detected mismatch of MRI_UCHAR data size and MGH header dim length values.\n");
3025 for (
size_t i = 0; i < num_values; i++)
3034 throw std::logic_error(
"Detected mismatch of MRI_SHORT data size and MGH header dim length values.\n");
3036 for (
size_t i = 0; i < num_values; i++)
3043 throw std::domain_error(
"Unsupported MRI data type " + std::to_string(mgh.
header.
dtype) +
", cannot write MGH data.\n");
3065 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3073 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"' for writing.\n");
3090 Label(std::vector<int> vertices, std::vector<float> values)
3092 assert(vertices.size() == values.size());
3095 coord_x = std::vector<float>(vertices.size(), 0.0f);
3096 coord_y = std::vector<float>(vertices.size(), 0.0f);
3097 coord_z = std::vector<float>(vertices.size(), 0.0f);
3104 value = std::vector<float>(vertices.size(), 0.0f);
3105 coord_x = std::vector<float>(vertices.size(), 0.0f);
3106 coord_y = std::vector<float>(vertices.size(), 0.0f);
3107 coord_z = std::vector<float>(vertices.size(), 0.0f);
3119 if (surface_num_verts < this->vertex.size())
3121 std::cerr <<
"Invalid number of vertices for surface, must be at least " << this->vertex.size() <<
"\n";
3123 std::vector<bool> is_in = std::vector<bool>(surface_num_verts,
false);
3125 for (
size_t i = 0; i < this->vertex.size(); i++)
3127 is_in[this->vertex[i]] =
true;
3135 size_t num_ent = this->vertex.size();
3136 if (this->coord_x.size() != num_ent || this->coord_y.size() != num_ent || this->coord_z.size() != num_ent || this->value.size() != num_ent)
3138 std::cerr <<
"Inconsistent label: sizes of property vectors do not match.\n";
3150 void write_surf(std::vector<float> vertices, std::vector<int32_t> faces, std::ostream &os)
3152 const uint32_t SURF_TRIS_MAGIC = 16777214;
3153 _fwritei3(os, SURF_TRIS_MAGIC);
3154 std::string created_and_comment_lines =
"Created by fslib\n\n";
3155 os << created_and_comment_lines;
3156 _fwritet<int32_t>(os, int(vertices.size() / 3));
3157 _fwritet<int32_t>(os, int(faces.size() / 3));
3158 for (
size_t i = 0; i < vertices.size(); i++)
3160 _fwritet<float>(os, vertices[i]);
3162 for (
size_t i = 0; i < faces.size(); i++)
3164 _fwritet<int32_t>(os, faces[i]);
3181 void write_surf(std::vector<float> vertices, std::vector<int32_t> faces,
const std::string &filename)
3184 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3192 throw std::runtime_error(
"Unable to open surf file '" + filename +
"' for writing.\n");
3211 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3219 throw std::runtime_error(
"Unable to open surf file '" + filename +
"' for writing.\n");
3233 size_t num_entries_header = 0;
3234 size_t num_entries = 0;
3235 while (std::getline(*is, line))
3238 std::istringstream iss(line);
3247 if (!(iss >> num_entries_header))
3249 throw std::domain_error(
"Could not parse entry count from label file, invalid format.\n");
3255 float x, y, z, value;
3256 if (!(iss >> vertex >> x >> y >> z >> value))
3258 throw std::domain_error(
"Could not parse line " + std::to_string(line_idx + 1) +
" of label file, invalid format.\n");
3260 label->
vertex.push_back(vertex);
3264 label->
value.push_back(value);
3269 if (num_entries != num_entries_header)
3271 throw std::domain_error(
"Expected " + std::to_string(num_entries_header) +
" entries from label file header, but found " + std::to_string(num_entries) +
" in file, invalid label file.\n");
3273 if (label->
vertex.size() != num_entries || label->
coord_x.size() != num_entries || label->
coord_y.size() != num_entries || label->
coord_z.size() != num_entries || label->
value.size() != num_entries)
3275 throw std::domain_error(
"Expected " + std::to_string(num_entries) +
" entries in all Label vectors, but some did not match.\n");
3294 std::ifstream infile(filename, std::fstream::in);
3295 if (infile.is_open())
3302 throw std::runtime_error(
"Could not open label file '" + filename +
"' for reading.\n");
3313 os <<
"#!ascii label from subject anonymous\n" 3314 << num_entries <<
"\n";
3315 for (
size_t i = 0; i < num_entries; i++)
3337 ofs.open(filename, std::ofstream::out);
3345 throw std::runtime_error(
"Unable to open label file '" + filename +
"' for writing.\n");
3366 if (fs::util::ends_with(filename, {
".ply",
".PLY"}))
3370 else if (fs::util::ends_with(filename, {
".obj",
".OBJ"}))
3374 else if (fs::util::ends_with(filename, {
".off",
".OFF"}))
void write_curv(std::ostream &os, std::vector< float > curv_data, int32_t num_faces=100000)
Write curv data to a stream.
Definition: libfs.h:2909
std::vector< float > vertices
n x 3 vector of the x,y,z coordinates for the n vertices. The x,y,z coordinates for a single vertex f...
Definition: libfs.h:500
std::vector< int32_t > vertex_indices
Indices of the vertices, these always go from 0 to N-1 (where N is the number of vertices in the resp...
Definition: libfs.h:1874
size_t num_entries() const
Get the number of enties (regions) in this Colortable.
Definition: libfs.h:1834
Mgh(Curv curv)
Definition: libfs.h:2038
std::vector< float > coord_x
x coordinates of the vertices in case of a surface label, or voxels coordinates for a volume label...
Definition: libfs.h:3111
std::string to_off(const std::vector< uint8_t > col) const
Return string representing the mesh in PLY format.
Definition: libfs.h:1731
Models a FreeSurfer curv file that contains per-vertex float data.
Definition: libfs.h:1796
const int MRI_SHORT
MRI data type representing a 16 bit signed integer.
Definition: libfs.h:451
std::vector< float > coord_y
y coordinates of the vertices in case of a surface label, or voxels coordinates for a volume label...
Definition: libfs.h:3112
unsigned int d2
size of data along 2nd dimension
Definition: libfs.h:2090
const std::string LOGTAG_EXCESSIVE
Logging threshold for warning messages.
Definition: libfs.h:190
An annotation, also known as a brain surface parcellation. Assigns to each vertex a region...
Definition: libfs.h:1872
const std::string LOGTAG_VERBOSE
Logging threshold for warning messages.
Definition: libfs.h:187
void read_curv(Curv *curv, std::istream *is, const std::string &source_filename="")
Read per-vertex brain morphometry data from a FreeSurfer curv stream.
Definition: libfs.h:2551
edge_set as_edgelist() const
Return edge list representation of this mesh.
Definition: libfs.h:709
std::vector< int32_t > label
label integer computed from rgba values. Maps to the Annot.vertex_label field.
Definition: libfs.h:1831
Array4D(MghHeader *mgh_header)
Constructor for creating an empty 4D array based on dimensions specified in an fs::MghHeader.
Definition: libfs.h:2059
std::string to_obj() const
Return string representing the mesh in Wavefront Object (.obj) format.
Definition: libfs.h:645
std::string time_tag(std::chrono::system_clock::time_point t)
Get current time as string, e.g. for log messages.
Definition: libfs.h:160
static void from_obj(Mesh *mesh, const std::string &filename)
Read a brainmesh from a Wavefront object format mesh file.
Definition: libfs.h:1204
const std::string LOGTAG_WARNING
Logging threshold for warning messages.
Definition: libfs.h:181
static std::vector< float > smooth_pvd_nn(const std::vector< std::vector< size_t >> mesh_adj, const std::vector< float > pvd, const size_t num_iter=1, const bool with_nan=true, const bool detect_nan=true)
Smooth given per-vertex data using nearest neighbor smoothing based on adjacency list mesh represenat...
Definition: libfs.h:820
bool file_exists(const std::string &name)
Check whether a file exists (can be read) at given path.
Definition: libfs.h:344
const std::string LOGTAG_INFO
Logging threshold for warning messages.
Definition: libfs.h:184
A simple 4D array datastructure, useful for representing volume data.
Definition: libfs.h:2053
std::vector< float > data
The curvature data, one value per vertex. Something like the cortical thickness at each vertex...
Definition: libfs.h:1813
static void from_ply(Mesh *mesh, std::istream *is)
Read a brainmesh from a Stanford PLY format stream.
Definition: libfs.h:1362
const int32_t & fm_at(const size_t i, const size_t j) const
Retrieve a vertex index of a face, treating the faces vector as an nx3 matrix.
Definition: libfs.h:1540
std::vector< T > data
the data, as a 1D vector. Use fs::Array4D::at for easy access in 4D.
Definition: libfs.h:2093
std::vector< int32_t > b
green channel of RGBA color
Definition: libfs.h:1829
static void from_ply(Mesh *mesh, const std::string &filename)
Read a brainmesh from a Stanford PLY format mesh file.
Definition: libfs.h:1483
std::vector< int32_t > g
blue channel of RGBA color
Definition: libfs.h:1828
std::vector< float > read_curv_data(const std::string &filename)
Read per-vertex brain morphometry data from a FreeSurfer curv format file.
Definition: libfs.h:2736
void write_mgh(const Mgh &mgh, std::ostream &os)
Write MGH data to a stream.
Definition: libfs.h:2956
static void from_off(Mesh *mesh, const std::string &filename)
Read a brainmesh from an OFF format mesh file.
Definition: libfs.h:1340
std::vector< bool > vert_in_label(size_t surface_num_verts) const
Compute for each vertex of the surface whether it is inside the label.
Definition: libfs.h:3117
static std::vector< float > curv_data_for_orig_mesh(const std::vector< float > data_submesh, const std::unordered_map< int32_t, int32_t > submesh_to_orig_mapping, const int32_t orig_mesh_num_vertices, const float fill_value=std::numeric_limits< float >::quiet_NaN())
Given per-vertex data for a submesh, add NAN values inbetween to restore the original mesh size...
Definition: libfs.h:1064
Models a triangular mesh, used for brain surface meshes.
Definition: libfs.h:480
const int MRI_UCHAR
MRI data type representing an 8 bit unsigned integer.
Definition: libfs.h:442
size_t num_entries() const
Return the number of entries (vertices/voxels) in this label.
Definition: libfs.h:3133
unsigned int get_index(const unsigned int i1, const unsigned int i2, const unsigned int i3, const unsigned int i4) const
Get the index in the vector for the given 4D position.
Definition: libfs.h:2074
Models the data of an MGH file. Currently these are 1D vectors, but one can compute the 4D array usin...
Definition: libfs.h:2018
void read_label(Label *label, std::istream *is)
Read a FreeSurfer ASCII label from a stream.
Definition: libfs.h:3229
void to_ply_file(const std::string &filename) const
Export this mesh to a file in Stanford PLY format.
Definition: libfs.h:1699
MghData(std::vector< uint8_t > curv_data)
constructor to create MghData from MRI_UCHAR (uint8_t) data.
Definition: libfs.h:2022
Mesh(std::vector< float > cvertices, std::vector< int32_t > cfaces)
Construct a Mesh from the given vertices and faces.
Definition: libfs.h:484
std::vector< size_t > vertex_regions() const
Compute the region indices in the Colortable for all vertices in this brain surface parcellation...
Definition: libfs.h:1943
std::vector< std::vector< bool > > as_adjmatrix() const
Return adjacency matrix representation of this mesh.
Definition: libfs.h:670
const T & at(const unsigned int i1, const unsigned int i2, const unsigned int i3, const unsigned int i4) const
Get the value at the given 4D position.
Definition: libfs.h:2068
Array4D(Mgh *mgh)
Constructor for creating an empty 4D array based on dimensions specified in the header of an fs::Mgh...
Definition: libfs.h:2062
unsigned int d1
size of data along 1st dimension
Definition: libfs.h:2089
std::string to_ply() const
Return string representing the mesh in PLY format. Overload that works without passing a color vector...
Definition: libfs.h:1629
The colortable from an Annot file, can be used for parcellations and integer labels. Typically each index (in all fields) describes a brain region.
Definition: libfs.h:1823
const int MRI_FLOAT
MRI data type representing a 32 bit float.
Definition: libfs.h:448
void write_surf(std::vector< float > vertices, std::vector< int32_t > faces, std::ostream &os)
Write a mesh to a stream in FreeSurfer surf format.
Definition: libfs.h:3150
std::vector< std::vector< size_t > > as_adjlist(const bool via_matrix=true) const
Return adjacency list representation of this mesh.
Definition: libfs.h:738
static fs::Mesh construct_pyramid()
Construct and return a simple pyramidal mesh.
Definition: libfs.h:550
std::vector< float > smooth_pvd_nn(const std::vector< float > pvd, const size_t num_iter=1, const bool via_matrix=true, const bool with_nan=true, const bool detect_nan=true) const
Smooth given per-vertex data using nearest neighbor smoothing.
Definition: libfs.h:797
std::vector< int32_t > id
internal region index
Definition: libfs.h:1825
void write_mesh(const Mesh &mesh, const std::string &filename)
Write a mesh to a file in different formats.
Definition: libfs.h:3364
std::vector< int32_t > region_vertices(int32_t region_label) const
Get all vertices of a region given by label in the brain surface parcellation. Returns an integer vec...
Definition: libfs.h:1895
std::vector< short > data_mri_short
data of type MRI_SHORT, check the dtype to see whether this is relevant for this instance.
Definition: libfs.h:2029
const int MRI_INT
MRI data type representing a 32 bit signed integer.
Definition: libfs.h:445
static void from_obj(Mesh *mesh, std::istream *is)
Read a brainmesh from a Wavefront object format stream.
Definition: libfs.h:1098
Curv(std::vector< float > curv_data)
Construct a Curv instance from the given per-vertex data.
Definition: libfs.h:1800
unsigned int d3
size of data along 3rd dimension
Definition: libfs.h:2091
Models a whole MGH file.
Definition: libfs.h:2033
size_t num_vertices() const
Get the number of vertices of this parcellation (or the associated surface).
Definition: libfs.h:1931
int32_t num_values_per_vertex
The number of values per vertex, stored in this file. Almost all apps (including FreeSurfer itself) o...
Definition: libfs.h:1819
void write_surf(const Mesh &mesh, const std::string &filename)
Write a mesh to a binary file in FreeSurfer surf format.
Definition: libfs.h:3208
void str_to_file(const std::string &filename, const std::string rep)
Write the given text representation (any string) to a file.
Definition: libfs.h:419
void read_annot(Annot *annot, std::istream *is)
Read a FreeSurfer annotation or brain surface parcellation from an annot stream.
Definition: libfs.h:2650
int32_t num_vertices
The number of vertices of the mesh to which this belongs. Can be deduced from length of 'data'...
Definition: libfs.h:1816
std::vector< float > vertex_coords(const size_t vertex) const
Get all coordinates of the vertex, given by its index.
Definition: libfs.h:1585
static void from_off(Mesh *mesh, std::istream *is, const std::string &source_filename="")
Read a brainmesh from an Object File format (OFF) stream.
Definition: libfs.h:1227
std::vector< int32_t > face_vertices(const size_t face) const
Get all vertex indices of the face, given by its index.
Definition: libfs.h:1561
Mgh(std::vector< float > curv_data)
Definition: libfs.h:2043
std::vector< std::string > read_subjectsfile(const std::string &filename)
Read a vector of subject identifiers from a FreeSurfer subjects file.
Definition: libfs.h:2170
std::vector< float > value
the value of the label, can represent continuous data like a p-value, or sometimes simply 1...
Definition: libfs.h:3114
std::vector< int32_t > r
red channel of RGBA color
Definition: libfs.h:1827
void read_mgh(Mgh *mgh, const std::string &filename)
Read a FreeSurfer volume file in MGH format into the given Mgh struct.
Definition: libfs.h:2124
void to_ply_file(const std::string &filename, const std::vector< uint8_t > col) const
Export this mesh to a file in Stanford PLY format with vertex colors.
Definition: libfs.h:1709
std::unordered_set< std::tuple< size_t, size_t >, _tupleHashFunction > edge_set
Datastructure for storing, and quickly querying the existence of, mesh edges.
Definition: libfs.h:696
size_t num_faces() const
Return the number of faces in this mesh.
Definition: libfs.h:1523
void write_label(const Label &label, std::ostream &os)
Write label data to a stream.
Definition: libfs.h:3310
std::vector< int > vertex
vertex indices for the data in this label if it is a surface label. These are indices into the vertic...
Definition: libfs.h:3110
std::string to_ply(const std::vector< uint8_t > col) const
Return string representing the mesh in PLY format.
Definition: libfs.h:1645
std::vector< std::string > vertex_region_names() const
Compute the region names in the Colortable for all vertices in this brain surface parcellation...
Definition: libfs.h:1963
std::vector< uint8_t > vertex_colors(bool alpha=false) const
Get the vertex colors as an array of uchar values, 3 consecutive values are the red, green and blue channel values for a single vertex.
Definition: libfs.h:1910
static fs::Mesh construct_cube()
Construct and return a simple cube mesh.
Definition: libfs.h:513
std::vector< int32_t > data_mri_int
data of type MRI_INT, check the dtype to see whether this is relevant for this instance.
Definition: libfs.h:2026
void read_mgh(Mgh *mgh, std::istream *is)
Read MGH data from a stream.
Definition: libfs.h:2193
MghData(std::vector< float > curv_data)
constructor to create MghData from MRI_FLOAT (float) data.
Definition: libfs.h:2024
MghData(std::vector< short > curv_data)
constructor to create MghData from MRI_SHORT (short) data.
Definition: libfs.h:2023
const std::string LOGTAG_ERROR
Logging threshold for error messages.
Definition: libfs.h:178
Mesh()
Construct an empty Mesh.
Definition: libfs.h:498
std::pair< std::unordered_map< int32_t, int32_t >, fs::Mesh > submesh_vertex(const std::vector< int32_t > &old_vertex_indices, const bool mapdir_fulltosubmesh=false) const
Compute a new mesh that is a submesh of this mesh, based on a subset of the vertices of this mesh...
Definition: libfs.h:1007
std::vector< uint8_t > data_mri_uchar
data of type MRI_UCHAR, check the dtype to see whether this is relevant for this instance.
Definition: libfs.h:2027
Label(std::vector< int > vertices)
Construct a Label from the given vertices / voxel numbers.
Definition: libfs.h:3101
static std::vector< std::vector< size_t > > extend_adj(const std::vector< std::vector< size_t >> mesh_adj, const size_t extend_by=1, std::vector< std::vector< size_t >> mesh_adj_ext=std::vector< std::vector< size_t >>())
Extend mesh neighborhoods based on mesh adjacency representation.
Definition: libfs.h:941
void to_obj_file(const std::string &filename) const
Export this mesh to a file in Wavefront OBJ format.
Definition: libfs.h:986
void read_surf(Mesh *surface, const std::string &filename)
Read a brain mesh from a file in binary FreeSurfer 'surf' format into the given Mesh instance...
Definition: libfs.h:2462
Curv()
Construct an empty Curv instance.
Definition: libfs.h:1807
std::string fullpath(std::initializer_list< std::string > path_components, std::string path_sep=std::string("/"))
Construct a UNIX file system path from the given path_components.
Definition: libfs.h:372
std::vector< int32_t > region_vertices(const std::string ®ion_name) const
Get all vertices of a region given by name in the brain surface parcellation. Returns an integer vect...
Definition: libfs.h:1879
void to_off_file(const std::string &filename, const std::vector< uint8_t > col) const
Export this mesh to a file in OFF format with vertex colors (COFF).
Definition: libfs.h:1789
void read_mesh(Mesh *surface, const std::string &filename)
Read a triangular mesh from a surf, obj, or ply file into the given Mesh instance.
Definition: libfs.h:2513
int32_t get_region_idx(const std::string &query_name) const
Get the index of a region in the Colortable by region name. Returns a negative value if the region is...
Definition: libfs.h:1845
int32_t num_faces
The number of faces of the mesh to which this belongs, typically irrelevant and ignored.
Definition: libfs.h:1810
std::vector< float > data_mri_float
data of type MRI_FLOAT, check the dtype to see whether this is relevant for this instance.
Definition: libfs.h:2028
unsigned int num_values() const
Get number of values/voxels.
Definition: libfs.h:2084
Colortable colortable
A Colortable defining the regions (most importantly, the region name and visualization color)...
Definition: libfs.h:1876
MghHeader header
Header for this MGH instance.
Definition: libfs.h:2035
void log(std::string const &message, std::string const loglevel="INFO")
Log a message, goes to stdout.
Definition: libfs.h:195
const float & vm_at(const size_t i, const size_t j) const
Retrieve a single (x, y, or z) coordinate of a vertex, treating the vertices vector as an nx3 matrix...
Definition: libfs.h:1611
std::vector< T > vflatten(std::vector< std::vector< T >> values)
Flatten 2D vector.
Definition: libfs.h:273
Label(std::vector< int > vertices, std::vector< float > values)
Construct a Label from the given vertices / voxel numbers and values.
Definition: libfs.h:3090
std::vector< int32_t > a
alpha channel of RGBA color
Definition: libfs.h:1830
const std::string LOGTAG_CRITICAL
Logging threshold for critical messages.
Definition: libfs.h:175
int32_t get_region_idx(int32_t query_label) const
Get the index of a region in the Colortable by label. Returns a negative value if the region is not f...
Definition: libfs.h:1858
Label()
Default constructor for a label.
Definition: libfs.h:3087
static fs::Mesh construct_grid(const size_t nx=4, const size_t ny=5, const float distx=1.0, const float disty=1.0)
Construct and return a simple planar grid mesh.
Definition: libfs.h:583
std::vector< int32_t > faces
n x 3 vector of the 3 vertex indices for the n triangles or faces. The 3 vertices of a single face fo...
Definition: libfs.h:501
void to_off_file(const std::string &filename) const
Export this mesh to a file in OFF format.
Definition: libfs.h:1782
std::vector< int32_t > vertex_labels
The label code for each vertex, defining the region it belongs to. Check in the Colortable for a regi...
Definition: libfs.h:1875
MghData(Curv curv)
constructor to create MghData from a Curv instance
Definition: libfs.h:2025
std::vector< float > coord_z
z coordinates of the vertices in case of a surface label, or voxels coordinates for a volume label...
Definition: libfs.h:3113
Array4D(unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4)
Constructor for creating an empty 4D array of the given dimensions.
Definition: libfs.h:2056
MghData(std::vector< int32_t > curv_data)
constructor to create MghData from MRI_INT (int32_t) data.
Definition: libfs.h:2021
std::vector< float > read_desc_data(const std::string &filename)
Read per-vertex brain morphometry data from a FreeSurfer curv format or MGH format file...
Definition: libfs.h:2756
Mgh()
Empty default constuctor.
Definition: libfs.h:2037
std::string to_off() const
Return string representing the mesh in OFF format. Overload that works without passing a color vector...
Definition: libfs.h:1722
std::vector< std::string > name
region name
Definition: libfs.h:1826
MghData data
4D data for this MGH instance.
Definition: libfs.h:2036
unsigned int d4
size of data along 4th dimension
Definition: libfs.h:2092
size_t num_vertices() const
Return the number of vertices in this mesh.
Definition: libfs.h:1509
void read_mgh_header(MghHeader *, const std::string &)
Read the header of a FreeSurfer volume file in MGH format into the given MghHeader struct...
Definition: libfs.h:2337