Documentation ¶
Overview ¶
Provides functions for reading and writing some structural neuroimaging file formats.
The neuro package is intended to be used in neuroimaging, with a focus on structural brain anatomy. Currently it provides functions to access fileformats used by FreeSurfer and some related neuroimaging software packages.
The package can read three-dimensional (3D) and 4D brain scans in MGH and MGZ format, typically produced from the raw DICOM files that are written by magnetic resonance imaging (MRI) hardware. Support for reading brain surface reconstructions (cortical meshes) and the related per-vertex data (like cortical thickness or sulcal depth at each point of the brain surface) are also included.
Index ¶
- Constants
- Variables
- func Export(mesh Mesh, filepath string, format string) (string, error)
- func MeshStats(mesh Mesh) (map[string]float32, error)
- func NumFaces(mesh Mesh) int
- func NumVertices(mesh Mesh) int
- func ReadFsCurv(filepath string) ([]float32, error)
- func ToObjFormat(mesh Mesh) (string, error)
- func ToPlyFormat(mesh Mesh) (string, error)
- func ToStlFormat(mesh Mesh) (string, error)
- func VertexIsPartOfLabel(label FsLabel, meshNumVertices int32) ([]bool, error)
- func WriteFsCurv(filename string, data []float32) error
- type FsLabel
- type Mesh
- type Mgh
- type MghData
- type MghHeader
Examples ¶
Constants ¶
const MRI_FLOAT int32 = 3
MRI data type representing a 32 bit float. Used by MGH format, see MghHeader struct.
const MRI_INT int32 = 1
MRI data type representing a 32 bit signed integer. Used by MGH format, see MghHeader struct.
const MRI_SHORT int32 = 4
MRI data type representing a 16 bit signed integer. Used by MGH format, see MghHeader struct.
const MRI_UCHAR int32 = 0
MRI data type representing an 8 bit unsigned integer. Used by MGH format, see MghHeader struct.
Variables ¶
var Verbosity int = 0 // WARNING: If you increase Verbosity here and run the unit tests, the examples included with the tests will fail, because they expect a defined output on STDOUT, and increasing verbosity will produce extra output.
Verbosity is the verbosity level of the package. 0 = silent, 1 = info, 2 = debug.
Functions ¶
func Export ¶
Export exports a mesh to a file in the specified mesh file format.
Parameters:
- mesh : the mesh to export
- filepath : the filepath to export the mesh to
- format : the mesh file format to use, one of 'obj' (for Wavefront Object Format), 'ply' (for Stanford PLY format), 'stl' (for StereoLithography format)
Returns
- string : the mesh string representation in the requested format
- error : the error if one occured, or nil otherwise
func MeshStats ¶
Compute some basic mesh statistics.
Parameters:
- mesh : the mesh to compute statistics for
Returns:
- map[string]float32 : a map of statistics, with keys: 'numVertices' (number of vertices, interpret as int), 'numFaces' (number of faces, interpret as int), 'maxX', 'maxY', 'maxZ', 'minX', 'minY', 'minZ', 'meanX', 'meanY', 'meanZ', 'numEdges', 'avgEdgeLength', 'avgFaceArea', 'totalArea'.
Example (FromSurfaceFileVerts) ¶
var surfFile string = "testdata/lh.white" surf, _ := ReadFsSurface(surfFile) stats, _ := MeshStats(surf) fmt.Printf("Surface has %d vertices and %d faces.\n", int(stats["numVertices"]), int(stats["numFaces"]))
Output: Surface has 149244 vertices and 298484 faces.
func NumFaces ¶
NumFaces computes the number of faces (aka polygons, or triangles) of a triangular mesh.
Parameters:
- mesh : the mesh to compute the number of faces for
Returns:
- int : the number of faces
Example ¶
var mycube Mesh = GenerateCube() nv := NumVertices(mycube) nf := NumFaces(mycube) fmt.Printf("Cube mesh has %d vertices and %d faces.\n", nv, nf)
Output: Cube mesh has 8 vertices and 12 faces.
func NumVertices ¶
NumVertices computes the number of vertices of a triangular mesh.
Parameters:
- mesh : the mesh to compute the number of vertices for
Returns:
- int : the number of vertices
Example ¶
var mycube Mesh = GenerateCube() nv := NumVertices(mycube) nf := NumFaces(mycube) fmt.Printf("Cube mesh has %d vertices and %d faces.\n", nv, nf)
Output: Cube mesh has 8 vertices and 12 faces.
func ReadFsCurv ¶
Read a binary file in FreeSurfer curv format.
Curv files are used to store per-vertex descriptors like cortical thickness in native space (i.e., for a single subject, not mapped to a group template).
Parameters:
- filepath: the path to the file, must be a FreeSurfer curv file from recon-all output, like subject/surf/lh.thickness.
Returns:
- pervertex_data: float32 array of per-vertex descriptor values (e.g. cortical thickness)
- error: an error if one occurred
Example ¶
var curvFile string = "testdata/lh.thickness" // Read the curv file pvdata, _ := ReadFsCurv(curvFile) fmt.Printf("Read %d values from curv file '%s'.\n", len(pvdata), curvFile)
Output: Read 149244 values from curv file 'testdata/lh.thickness'.
func ToObjFormat ¶
Convert a mesh to OBJ format.
Parameters:
- mesh : the mesh to convert
Returns:
- string : the mesh string representation in OBJ format
- error : the error if one occured, or nil otherwise
Example ¶
var mycube Mesh = GenerateCube() obj_str, err := ToObjFormat(mycube) if err != nil { fmt.Printf("Error getting OBJ representation: %s\n", err) } fmt.Printf("OBJ format string has %d lines.\n", strings.Count(obj_str, "\n"))
Output: OBJ format string has 21 lines.
func ToPlyFormat ¶
Convert a mesh to PLY format.
Parameters:
- mesh : the mesh to convert
Returns:
- string : the mesh string representation in PLY format
- error : the error if one occured, or nil otherwise
Example ¶
var mycube Mesh = GenerateCube() ply_str, err := ToPlyFormat(mycube) if err != nil { fmt.Printf("Error getting PLY representation: %s\n", err) } fmt.Printf("PLY format string has %d lines.\n", strings.Count(ply_str, "\n"))
Output: PLY format string has 30 lines.
func ToStlFormat ¶
Convert a mesh to STL format.
Parameters:
- mesh : the mesh to convert
Returns:
- string : the mesh string representation in STL format
- error : the error if one occured, or nil otherwise
Example ¶
var mycube Mesh = GenerateCube() stl_str, err := ToStlFormat(mycube) if err != nil { fmt.Printf("Error getting STL representation: %s\n", err) } fmt.Printf("STL format string has %d lines.\n", strings.Count(stl_str, "\n"))
Output: STL format string has 86 lines.
func VertexIsPartOfLabel ¶ added in v0.1.2
Check for all vertices in the mesh whether they are part of the label.
Parameters:
- label: the label to check
- meshNumVertices: the number of vertices in the mesh
Returns:
- is_part_of_label: a bool array of length meshNumVertices, where each element is true if the vertex is part of the label, and false otherwise.
- error: an error if one occurred, e.g., the number of vertices in the mesh is less than the number of elements in the label.
func WriteFsCurv ¶
WriteFsCurv writes a FreeSurfer curv file.
Parameters:
- filename: the name of the file to write. Path to it must exist.
- data: the slice of float32 values. Must not be empty.
Returns:
- error: an error if one occurred, e.g., the slice was empty. Or nil otherwise.
Types ¶
type FsLabel ¶ added in v0.1.2
type FsLabel struct { ElementIndex []int32 // The index of the vertex or voxel in the volume or mesh. The first element is 0. CoordX []float32 // The first coordinate of the vertex or voxel in the volume or mesh. CoordY []float32 // The first coordinate of the vertex or voxel in the volume or mesh. CoordZ []float32 // The first coordinate of the vertex or voxel in the volume or mesh. Value []float32 // The per-element data. }
Struct modelling a FreeSurfer label. A label contains information on a subset of the voxels or vertices only, i.e., the number of entries is typically less than the number of voxels or vertices in the volume or mesh. Sometimes per-vertex or per-voxel data is stored in the labels data field, but sometimes the relevant information is simply whether or not a certain element (voxel, vertex) is part of the label (e.g., for a cortex label), and the per-element data stored is not relevant (and typically set to 0.0).
func ReadFsLabel ¶ added in v0.1.2
Read an file in FreeSurfer label format.
A label file is a text file representing vertices or voxels in a label. A label contains information on a subset of the voxels or vertices only, i.e., the number of entries is typically less than the number of voxels or vertices in the volume or mesh. Sometimes per-vertex or per-voxel data is stored in the labels data field, but sometimes the real information is whether or not a certain element (voxel, vertex) is part of the label (e.g., for a cortex label), and the per-element data stored is not relevant.
Parameters:
- filepath: the path to the file, must be a FreeSurfer label file from recon-all output, like subject/label/lh.cortex.label.
Returns:
- pervertex_data: float32 array of per-vertex descriptor values (e.g. cortical thickness)
- error: an error if one occurred
Example ¶
var labelFile string = "testdata/lh.cortex.label" // Read the curv file label, _ := ReadFsLabel(labelFile) fmt.Printf("Read label containing %d vertices from label file '%s'.\n", len(label.ElementIndex), labelFile)
Output: Read label containing 140891 vertices from label file 'testdata/lh.cortex.label'.
type Mesh ¶
Mesh is a struct that holds a triangular mesh, with vertices and faces. Faces are stored in vertex index representation.
Fields:
- Vertices : the vertices of the mesh, as a slice of float32 values. The vertices are stored as a flat array of 3D coordinates, i.e. [x1, y1, z1, x2, y2, z2, ...]
- Faces : the faces (a.k.a polygons or triangles) of the mesh, as a slice of int32 values. The faces are stored as a flat array of vertex indices, i.e. [v1, v2, v3, v1, v2, v3, ...]
Example ¶
var mycube Mesh = GenerateCube() nv := NumVertices(mycube) nf := NumFaces(mycube) fmt.Printf("Cube mesh has %d vertices and %d faces.\n", nv, nf)
Output: Cube mesh has 8 vertices and 12 faces.
Example (FromData) ¶
mesh := Mesh{} mesh.Vertices = []float32{0.0, 1.0, 2.0, 3.0, 4.0, 5.0} // 2 vertices, 3 dimensions each mesh.Faces = []int32{0, 1, 2, 3, 4, 5} // 2 faces, 3 vertices each nv := NumVertices(mesh) nf := NumFaces(mesh) fmt.Printf("Mesh has %d vertices and %d faces.\n", nv, nf)
Output: Mesh has 2 vertices and 2 faces.
Example (FromSurfaceFile) ¶
var surfFile string = "testdata/lh.white" surf, _ := ReadFsSurface(surfFile) nv := NumVertices(surf) nf := NumFaces(surf) fmt.Printf("Surface has %d vertices and %d faces.\n", nv, nf)
Output: Surface has 149244 vertices and 298484 faces.
func GenerateCube ¶
func GenerateCube() Mesh
GenerateCube creates and returns a Mesh representing a cube.
This is mainly used in the examples and documentation.
Returns:
- Mesh : the cube mesh
Example ¶
var mycube Mesh = GenerateCube() fmt.Printf("Cube mesh has %d vertices and %d faces.\n", NumVertices(mycube), NumFaces(mycube))
Output: Cube mesh has 8 vertices and 12 faces.
func GenerateSphere ¶ added in v0.1.1
GenerateSphere creates and returns a Mesh representing a sphere.
This is mainly used in the examples and documentation.
Parameters:
- radius : the radius of the sphere
- slices : the number of slices (horizontal divisions)
- stacks : the number of stacks (vertical divisions)
Returns:
- Mesh : the sphere mesh
func ReadFsSurface ¶
ReadFsSurface reads a FreeSurfer surface file and returns a Mesh struct.
A surface file is a binary file containing the reconstructed surface of a brain hemisphere.
Parameters:
- filepath: path to the FreeSurfer mesh file, e.g. '<subject>/surf/lh.white'
Returns:
- Mesh: a Mesh struct containing the mesh data
- error: an error if one occurred
Example ¶
var surfaceFile string = "testdata/lh.white" // Read the curv file mesh, _ := ReadFsSurface(surfaceFile) fmt.Printf("Read mesh with %d vertices and %d faces from surface file '%s'.\n", len(mesh.Vertices)/3, len(mesh.Faces)/3, surfaceFile)
Output: Read mesh with 149244 vertices and 298484 faces from surface file 'testdata/lh.white'.
type Mgh ¶
Mgh models a full MGH format file, including the MghHeader and the MghData. See the separate documention for MghHeader and MghData for details on accessing fields.
func ReadFsMgh ¶
ReadFsMgh reads a FreeSurfer MGH file and returns it as an Mgh struct. The Mgh struct contains the MghHeader and MghData.
See the documentation for Mgh, MghHeader and MghData for details on accessing fields.
Parameters:
- filepath: path to the FreeSurfer MGH file, e.g. '<subject>/mri/brain.mgh'. Note that gzipped MGH files (file extension .mgz) are currently not supported.
- isGzipped: Whether to treat the file as gzip-compressed. If "auto", the file extension is used to determine whether the file is gzip-compressed. If not "auto", it has to be "yes"/"mgz" or "no"/"mgh" to force MGZ or MGH format, respectively.
Returns:
- Mgh: an Mgh struct containing the MghHeader and MghData
Example (Tensor) ¶
// Illustrates how to read the 4D MRI image returned by ReadFsMgh into a tensor data structure // from the "gorgonia.org/tensor" package for convenient access to voxel values. // This example requires 'import "gorgonia.org/tensor"'. var mgzFile string = "testdata/brain.mgz" mgh, _ := ReadFsMgh(mgzFile, "yes") var h MghHeader = mgh.Header data := tensor.New(tensor.WithShape(int(h.Dim1Length), int(h.Dim2Length), int(h.Dim3Length), int(h.Dim4Length)), tensor.WithBacking(mgh.Data.DataMriUchar)) val1, _ := data.At(99, 99, 99, 0) // 77 val2, _ := data.At(109, 109, 109, 0) // 71 val3, _ := data.At(0, 0, 0, 0) // 0 // values known from external tests with FreeSurfer software, try on command line: mri_info --voxel 99 99 99 testdata/brain.mgz fmt.Printf("Voxel values=%d, %d, %d", val1, val2, val3)
Output: Voxel values=77, 71, 0
type MghData ¶
type MghData struct { DataMriUchar []uint8 // The data, if MghDataType is MRI_UCHAR. Otherwise this field contains random data. DataMriInt []int32 // The data, if MghDataType is MRI_INT. Otherwise this field contains random data. DataMriFloat []float32 // The data, if MghDataType is MRI_FLOAT. Otherwise this field contains random data. DataMriShort []int16 // The data, if MghDataType is MRI_SHORT. Otherwise this field contains random data. MghDataType int32 // The MRI data type code. See MRI_UCHAR, MRI_INT, MRI_FLOAT, MRI_SHORT. Use this to determine which of the data fields above is valid. }
Struct modelling the data part of an MGH file. Only the data in the field identified by MghDataType is valid.
func ReadFsMghData ¶
ReadFsMghData reads the data part of an MGH or MGZ format file into an MghData struct.
See the documentation for MghData for details on accessing fields.
Parameters:
- filepath: path to readable input file in MGH or MGZ format
- hdr: MghHeader struct containing the header data
- isGzipped: string indicating whether the input file is gzipped or not. If set to 'auto', the function will try to determine this automatically.
Returns:
- MghData: an MghData struct containing the data
- error: an error if one occurred, nil otherwise
type MghHeader ¶
type MghHeader struct { MghVersion int32 // version of the MGH file format. Currently, this is always 1. Dim1Length int32 // number of voxels in x direction Dim2Length int32 // number of voxels in y direction Dim3Length int32 // number of voxels in z direction Dim4Length int32 // number of voxels in 4th dimension (typically time or subject index) MghDataType int32 // MRI data type code. See MRI_UCHAR, MRI_INT, MRI_FLOAT, MRI_SHORT constants in this package. DoF int32 RasGoodFlag int16 // flag (1=yes, everything else=no) indicating whether the file contains valid RAS info. // All fields below are so-called RAS info fields. They should be ignored (assumed to contain random data) unless RasGoodFlag is 1. XSize float32 // size of voxels in x direction (mm) YSize float32 // size of voxels in y direction (mm) ZSize float32 // size of voxels in z direction (mm) Mdc [9]float32 // 9 float values, the 3x3 Mdc matrix that contains image orientation information. The interpretation order is row wise (row1-column1, row1-column2, row1-column3, row2-column1, ...) Pxyz_c [3]float32 // 3 float values, the xyz coordinates of the central voxel. Think of the name 'Pxyz_c' as 'Point (x,y,z) coordinates of the center'. // There are 194 more (currently unused) bytes reserved for the header before the data part starts. Reserved [194]uint8 // Reached end of header after 284 bytes. Data in here should be considered random. }
MghHeader models the header section of an MGH file. MGH stands for Massachusetts General Hospital, and the MGH format is a binary format for storing 3-dimensional or 4-dimensional structural MRI images of the human brain. The MGZ file extension is used for GZIP-compressed files in MGH format.
func ReadFsMghHeader ¶
ReadFsMghHeader reads a FreeSurfer MGH file and returns the header as an MghHeader struct.
See the documentation of the MghHeader struct for details on the header fields.
Parameters:
- filepath: path to the FreeSurfer MGH file, e.g. '<subject>/mri/brain.mgh'. Note that gzipped MGH files (file extension .mgz) are currently not supported.
- isGzipped: Whether to treat the file as gzip-compressed. If "auto", the file extension is used to determine whether the file is gzip-compressed. If not "auto", it has to be "yes"/"mgz" or "no"/"mgh" to force MGZ or MGH format, respectively.
Returns:
- MghHeader: an MghHeader struct containing the header data
- error: an error if one occurred