Created
December 7, 2021 17:18
-
-
Save dokato/3c1f5d322b4cfad8332836f10a675dac to your computer and use it in GitHub Desktop.
precomputed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| library(nat) | |
| library(jsonlite) | |
| library(float) | |
| #' Based on specification | |
| #' https://github.com/google/neuroglancer/tree/master/src/neuroglancer/datasource/precomputed | |
| # write mesh to single res precomputed format | |
| #meshes = read.neurons("../registration/dns_objs21_reg/") | |
| #n_mesh = length(meshes) | |
| save_single_res_info <- function(output_info) { | |
| jsonlite::write_json( | |
| list("@type" = "neuroglancer_legacy_mesh", | |
| "spatial_index"= NA, | |
| "segment_name_map"="segment_names", | |
| "segment_properties"="segment_properties"), | |
| output_info, | |
| auto_unbox = TRUE, | |
| ) | |
| } | |
| save_single_res_mesh <- function(mesh, output_path, name) { | |
| fc = file(file.path(output_path, name), "wb") | |
| writeBin(as.integer(dim(mesh$vb)[[2]]), fc) | |
| writeBin(as.vector(mesh$vb[1:3,]), fc, size = 4L) | |
| writeBin(as.integer(mesh$it-1), fc, size = 4L) | |
| close(fc) | |
| } | |
| save_single_res_manifest <- function(output_path, name) { | |
| jsonlite::write_json( | |
| list("fragments" = as.character(name)), | |
| file.path(output_path, paste0(name, ":0")), | |
| auto_unbox = FALSE, | |
| ) | |
| } | |
| write_meshes_info <- function(meshes, start_idx, | |
| output_seg_names, output_seg_prop) { | |
| volids <- as.character( | |
| start_idx:(start_idx + length(meshes) - 1) | |
| ) | |
| if (is.null(names(meshes))) | |
| map_ids <- as.list(1:length(meshes)) | |
| else | |
| map_ids <- as.list(names(meshes)) | |
| names(map_ids) <- volids | |
| # segment properties | |
| info <- list( | |
| "@type"=jsonlite::unbox("neuroglancer_segment_properties") | |
| ) | |
| mesh_properties = list("id" = jsonlite::unbox("label"), | |
| "type"= jsonlite::unbox("label"), | |
| "values"= names(map_ids) | |
| ) | |
| info$inline = list( | |
| "ids" = volids, | |
| "properties" = list(mesh_properties) | |
| ) | |
| jsonlite::write_json( | |
| info, | |
| file.path(output_seg_prop, "info"), | |
| auto_unbox = FALSE, | |
| ) | |
| # segment names | |
| info <- list( | |
| "@type"="neuroglancer_segment_name_map", | |
| "map" = map_ids | |
| ) | |
| jsonlite::write_json( | |
| info, | |
| file.path(output_seg_names, "info"), | |
| auto_unbox = TRUE, | |
| ) | |
| } | |
| save_single_res_meshes <- function(mesh_list, output_path, start_index = 1) { | |
| #' TODO check if mesh_list is a nat::neuronlist | |
| output_meshes = file.path(output_path, "mesh") | |
| output_info = file.path(output_meshes, "info") | |
| output_seg_names = file.path(output_meshes, "segment_names") | |
| output_seg_prop = file.path(output_meshes, "segment_properties") | |
| # save meshes | |
| if (!dir.exists(output_path)) | |
| dir.create(output_path) | |
| if (!dir.exists(output_meshes)) | |
| dir.create(output_meshes) | |
| idx <- start_index | |
| for (msh in mesh_list){ | |
| save_single_res_mesh(msh, output_path = output_meshes, name = as.character(idx)) | |
| save_single_res_manifest(output_path = output_meshes, name = as.character(idx)) | |
| idx <- idx + 1 | |
| } | |
| # save annotations | |
| if (!dir.exists(output_seg_names)) | |
| dir.create(output_seg_names) | |
| if (!dir.exists(output_seg_prop)) | |
| dir.create(output_seg_prop) | |
| save_single_res_info(output_info) | |
| write_meshes_info(mesh_list, | |
| start_idx = start_index, | |
| output_seg_names = output_seg_names, | |
| output_seg_prop = output_seg_prop) | |
| } | |
| # ---- Skeletons | |
| save_skel_info <- function(output_info, radius = TRUE) { | |
| info_dict <- list( | |
| "@type" = "neuroglancer_skeletons", | |
| "transform": c(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0), | |
| "segment_properties"= "seg_props" | |
| ) | |
| if (isTRUE(radius)) | |
| info_dict["vertex_attributes"] <- c( | |
| list("id"= "radius", "data_type"="float32", "num_components"=1) | |
| ) | |
| jsonlite::write_json( | |
| info_dict, | |
| output_info, | |
| auto_unbox = TRUE, | |
| ) | |
| } | |
| save_skel_props <- function(skels, output_skels, start_idx) { | |
| idcs <- start_idx:(start_idx+length(skels)) | |
| properties <- list( | |
| "@type" = "neuroglancer_segment_properties", | |
| "inline" = list( | |
| "ids" = idcs, | |
| "properties" = c( | |
| lapply(idcs, function(x) list(id = idcs[[x]], type='label', | |
| values=names(skels)[[x]])) | |
| ) | |
| ) | |
| ) | |
| jsonlite::write_json( | |
| properties, | |
| file.path(output_skels, "seg_props", "info"), | |
| auto_unbox = TRUE, | |
| ) | |
| } | |
| save_single_res_skel <- function(skel, output_path, name) { | |
| vertex_positions <- xyzmatrix(skel) | |
| edges <- cbind(skel$d$PointNo[skel$d$Parent!=-1], | |
| skel$d$Parent[skel$d$Parent!=-1]) | |
| fc = file(file.path(output_path, name), "wb") | |
| writeBin(as.integer(dim(vertex_positions)[[1]]), fc) | |
| writeBin(as.integer(floor(dim(edges)[[1]]/2)), fc) | |
| writeBin(as.vector(t(vertex_positions)), fc, size = 4L) | |
| writeBin(as.integer(t(edges)), fc, size = 4L) | |
| close(fc) | |
| } | |
| read_single_res_mesh <- function(filename) { | |
| # read from binary | |
| fc <- file(filename, "rb") | |
| num_nodes <- readBin(fc, integer(), n = 1, size = 4L) | |
| nodes_pos = readBin(fc, double(), n = 3 * num_nodes, size = 4L) | |
| nodes_pos = matrix(nodes_pos, ncol = 3, byrow=T) | |
| ee <- readBin(fc, integer(), n = 1024, size = 4L) | |
| edges <- c(ee) | |
| while (length(ee) > 0) { # TODO optimize | |
| ee <- readBin(fc, integer(), n = 1024, size = 4L) | |
| edges <- c(edges, ee) | |
| } | |
| edges = matrix(edges, ncol = 3, byrow=T) | |
| edges = edges + 1 | |
| close(fc) | |
| # create mesh | |
| mesh <- list(vb = vertices <- t(cbind(nodes_pos, 1)), | |
| it = t(edges), | |
| primitivetype = "triangle") | |
| class(mesh) <- c("mesh3d", "shape3d") | |
| mesh | |
| } | |
| read_skeleton <- function(filename) { | |
| # read from binary | |
| fc <- file(filename, "rb") | |
| num_nodes <- readBin(fc, integer(), n = 1, size = 4L) | |
| num_edges <- readBin(fc, integer(), n = 1, size = 4L) | |
| nodes_pos = readBin(fc, double(), n = 3 * num_nodes, size = 4L) | |
| nodes_pos = matrix(nodes_pos, ncol = 3, byrow=T) | |
| edges = readBin(fc, integer(), n = 2 * num_edges, size = 4L) | |
| edges = matrix(edges, ncol = 2, byrow=T) | |
| edges = edges + 1 | |
| close(fc) | |
| # create a neuron | |
| d <- data.frame( | |
| PointNo = 1:num_nodes, | |
| X = nodes_pos[,1], | |
| Y = nodes_pos[,2], | |
| Z = nodes_pos[,3] | |
| ) | |
| parent_mapping <- as.list(edges[,2]) | |
| names(parent_mapping) <- as.character(edges[,1]) | |
| d$Parent <- sapply(1:num_nodes, function(x) { | |
| m <- parent_mapping[[as.character(x)]] | |
| if (is.null(m)) -1 else m | |
| }) | |
| as.neuron(d) | |
| } | |
| read_skeletons <- function(in_path) { | |
| if (!dir.exists(in_path)) | |
| stop("This folder doesn't exist!") | |
| sk_fns <- list.files(in_path, pattern = "[0-9]+") | |
| sk_paths <- sapply(sk_fns, function(x) file.path(in_path, x)) | |
| nl <- as.neuronlist(lapply(pps, read_skeleton)) | |
| #if (file.exists()) #TODO check neuron names from seg_prop | |
| nl | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment