GithubHelp home page GithubHelp logo

jonclayden / rnifti Goto Github PK

View Code? Open in Web Editor NEW
44.0 4.0 14.0 2.33 MB

Fast R and C++ access to NIfTI images

R 3.70% C++ 8.07% C 87.53% Shell 0.01% Makefile 0.66% M4 0.04%
nifti-format r medical-imaging

rnifti's Introduction

CRAN version CI codecov Dependencies

RNifti: Fast R and C++ Access to NIfTI Images

The NIfTI-1 format is a popular file format for storing medical imaging data, widely used in medical research and related fields. Conceptually, a NIfTI-1 file incorporates multidimensional numeric data, like an R array, but with additional metadata describing the real-space resolution of the image, the physical orientation of the image, and how the image should be interpreted. The NIfTI-2 format was a later revision mostly to use wider data types for very large images.

There are several packages available for reading and writing NIfTI-1 files in R, and these are summarised in the Medical Imaging task view. However, RNifti is distinguished by its

The latest development version of the package can always be installed from GitHub using the remotes package.

## install.packages("remotes")
remotes::install_github("jonclayden/RNifti")

Please note that the RNifti package is to be used for research purposes only, and is not a clinical tool. It comes with no warranty.

Usage

The primary role of RNifti is to read and write NIfTI-1 and (since package version 1.2.0) NIfTI-2 files, either gzip-compressed or uncompressed, and provide access to image data and metadata. An image may be read into R using the readNifti function.

library(RNifti)
image <- readNifti(system.file("extdata", "example.nii.gz", package="RNifti"))

This image is an R array with some additional attributes containing information such as its dimensions and the size of its pixels (or voxels, in this case, since it is a 3D image). There are auxiliary functions for extracting this information: the standard dim(), plus pixdim() and pixunits().

dim(image)
## [1] 96 96 60
pixdim(image)
## [1] 2.5 2.5 2.5
pixunits(image)
## [1] "mm" "s"

So this image is of size 96 x 96 x 60 voxels, with each voxel representing 2.5 x 2.5 x 2.5 mm in real space. (The temporal unit, seconds here, only applies to the fourth dimension, if it is present.) Replacement versions of the latter functions are also available, for modifying the metadata.

The package contains a basic image viewer, which can be used interactively or noninteractively to examine 2D or 3D images.

view(image)

plot of chunk unnamed-chunk-5

By default, the viewer shows labels indicating image orientation, crosshairs pinpointing the currently selected location, the numerical indices of the current location, and the value of the image at that location. Options allow each of these to be turned off, for the content of the bottom-right panel to be customised entirely, for the colour scale to be changed, and for additional images to be layered on top of the base image. See ?view for details.

A fuller list of the raw metadata stored in the file can be obtained using the niftiHeader function.

niftiHeader(image)
## NIfTI-1 header
##     sizeof_hdr: 348
##       dim_info: 0
##            dim: 3  96  96  60  1  1  1  1
##      intent_p1: 0
##      intent_p2: 0
##      intent_p3: 0
##    intent_code: 0 (Unknown)
##       datatype: 8 (INT32)
##         bitpix: 32
##    slice_start: 0
##         pixdim: -1.0  2.5  2.5  2.5  0.0  0.0  0.0  0.0
##     vox_offset: 352
##      scl_slope: 0
##      scl_inter: 0
##      slice_end: 0
##     slice_code: 0 (Unknown)
##     xyzt_units: 10
##        cal_max: 2503
##        cal_min: 0
## slice_duration: 0
##        toffset: 0
##        descrip: TractoR NIfTI writer v3.0.0
##       aux_file: 
##     qform_code: 2 (Aligned Anat)
##     sform_code: 2 (Aligned Anat)
##      quatern_b: 0
##      quatern_c: 1
##      quatern_d: 0
##      qoffset_x: 122.0339
##      qoffset_y: -95.18523
##      qoffset_z: -55.03814
##         srow_x: -2.5000  0.0000  0.0000  122.0339
##         srow_y: 0.00000  2.50000  0.00000  -95.18523
##         srow_z: 0.00000  0.00000  2.50000  -55.03814
##    intent_name: 
##          magic: n+1

Advanced users who know the NIfTI format well may want to alter elements of this metadata directly, and this can be performed using the $ operator shorthand, as in

image$intent_code <- 1
image$intent_code
## [1] 1

If you need to modify multiple metadata elements at once, or replace metadata wholesale with new information from another image, the asNifti function provides a more efficient interface. See ?asNifti for details.

An image can be written back to NIfTI-1 format using the writeNifti function. gzip compression will be used if the specified file name ends with ".gz".

writeNifti(image, "file.nii.gz")

Image orientation

The NIfTI-1 and NIfTI-2 formats have a mechanism for indicating the physical orientation and location of the image volume in real space. The reference orientation has the left–right direction aligned with the x-axis, the posterior–anterior (back–front) direction aligned with the y-axis, and the inferior–superior (bottom–top) direction aligned with the z-axis; but "xform" information stored with an image can describe a transformation from that coordinate system to the one used by that particular image, in the form of an affine matrix. To obtain the full xform matrix for an image, call the xform function:

xform(image)
##      [,1] [,2] [,3]      [,4]
## [1,] -2.5  0.0  0.0 122.03390
## [2,]  0.0  2.5  0.0 -95.18523
## [3,]  0.0  0.0  2.5 -55.03814
## [4,]  0.0  0.0  0.0   1.00000
## attr(,"imagedim")
## [1] 96 96 60
## attr(,"code")
## [1] 2

Just the rotation with respect to the canonical axes can be obtained with the rotation function:

rotation(image)
##      [,1] [,2] [,3]
## [1,]   -1    0    0
## [2,]    0    1    0
## [3,]    0    0    1

In this case, the image is flipped along the x-axis relative to the canonical axes, so the positive x-direction points towards the left rather than the right. This is compactly represented by the output of the orientation function, which indicates the approximate real-world directions of the positive axes in each dimension.

orientation(image)
## [1] "LAS"

So, here, "LAS" means that the positive x-axis points left, the positive y-axis anterior and the positive z-axis superior. This is the so-called "radiological" orientation convention, and can be requested when viewing images for those who are used to it:

view(image, radiological=TRUE)

plot of chunk unnamed-chunk-12

Notice the left (L) and right (R) labels, relative to the view shown above. Setting the radiologicalView option to TRUE will make this the default for all future views.

There is a replacement version of the orientation function, which will reorient the image to align with the requested directions. This is a relatively complex operation, affecting the xform and the storage order of the data.

image[50,39,23]
## [1] 300
orientation(image) <- "RAS"
xform(image)
##      [,1] [,2] [,3]       [,4]
## [1,]  2.5  0.0  0.0 -115.46610
## [2,]  0.0  2.5  0.0  -95.18523
## [3,]  0.0  0.0  2.5  -55.03814
## [4,]  0.0  0.0  0.0    1.00000
## attr(,"imagedim")
## [1] 96 96 60
## attr(,"code")
## [1] 2
image[50,39,23]
## [1] 310
image[47,39,23]
## [1] 300

Notice that the sign of the top-left element of the xform has now flipped, and the value of the image at location (50,39,23) has changed because the data has been reordered. The equivalent x-location is now 47, which is the 50th element counting in the other direction (96 - 50 + 1 = 47).

This latter operation can be useful to ensure that indexing into several images with different native storage conventions will end up always having approximately the same meaning (and it is performed internally by the viewer, if required). It is non-destructive, because no interpolation of the data is performed. This means that the axes will not exactly align with the requested directions if the original image was oblique to the canonical axes, but conversely it ensures that no degradation in the image will result. (The RNiftyReg package can be used to apply an arbitrary rotation to an image and interpolate the data onto the new grid, if required.)

Support for composite types

The NIfTI standard supports composite types such as complex-valued and RGB images, and support for these was added in version 1.0.0 of this package. Complex data is exposed to R using the standard complex vector type:

image <- readNifti(system.file("extdata", "example.nii.gz", package="RNifti"))
complexImage <- asNifti(image + 0i)
print(complexImage)
## Image array of mode "complex" (8.4 Mb)
## - 96 x 96 x 60 voxels
## - 2.5 x 2.5 x 2.5 mm per voxel
complexImage[50,39,23]
## [1] 300+0i

R's native representation for RGB values is CSS-style hex strings of character mode, which are reasonably space-efficient (8 or 10 bytes per value) but a little clunky to work with. For efficiency of interchange between R and the NIfTI-internal datatypes, RNifti uses a byte-packed representation of integer mode instead, which takes up 4 bytes per value. Of course, the viewer understands this format.

rgbImage <- readNifti(system.file("extdata", "example_rgb.nii.gz", package="RNifti"))
print(rgbImage)
## Image array of mode "integer" (2.1 Mb)
## - 96 x 96 x 60 voxels
## - 2.5 x 2.5 x 2.5 mm per voxel
class(rgbImage)
## [1] "niftiImage" "rgbArray"   "array"
view(rgbImage)

plot of chunk unnamed-chunk-15

Notice that values are shown in the viewer using R's conventional hex string format, but the data is of class rgbArray. The function of the same name can be used to create these arrays from strings or channel values, for the purposes of building RGB images from data, while the as.character method and channels function perform the opposite conversions.

as.character(rgbImage, flatten=FALSE)[50,39,23]
## [1] "#1F5B8A"
channels(rgbImage, "red")[50,39,23,1]
## red 
##  31

RGB images with an alpha (opacity) channel are also supported.

Performance

The RNifti package uses the robust and widely used NIfTI reference implementation, which is written in C, to read and write NIfTI files. It also uses the standard NIfTI-2 data structure as its canonical representation of an image in memory. Together, these make the package extremely fast, as the following benchmark against packages AnalyzeFMRI, ANTsRCore, neuroim, oro.nifti and tractor.base shows.

installed.packages()[c("AnalyzeFMRI","ANTsRCore","neuroim","oro.nifti","RNifti",
                       "tractor.base"), "Version"]
##  AnalyzeFMRI    ANTsRCore      neuroim    oro.nifti       RNifti tractor.base 
##     "1.1-24"      "0.7.5"      "0.0.6"     "0.11.0"      "1.4.0"    "3.3.3.1"

library(microbenchmark)
microbenchmark(AnalyzeFMRI::f.read.volume("example.nii"),
               ANTsRCore::antsImageRead("example.nii"),
               neuroim::loadVolume("example.nii"),
               oro.nifti::readNIfTI("example.nii"),
               RNifti::readNifti("example.nii"),
               RNifti::readNifti("example.nii", internal=TRUE),
               tractor.base::readImageFile("example.nii"), unit="ms")
## Unit: milliseconds
##                                               expr       min         lq
##          AnalyzeFMRI::f.read.volume("example.nii") 29.734889 30.8786055
##            ANTsRCore::antsImageRead("example.nii")  3.336989  4.0922635
##                 neuroim::loadVolume("example.nii") 37.631847 39.6159530
##                oro.nifti::readNIfTI("example.nii") 39.190034 42.4400090
##                   RNifti::readNifti("example.nii")  1.928004  2.2818390
##  RNifti::readNifti("example.nii", internal = TRUE)  0.392529  0.7233765
##         tractor.base::readImageFile("example.nii") 13.726200 16.8920740
##        mean    median        uq         max neval
##  43.1935622 32.127420 37.147587  873.351879   100
##  22.1543773  4.538117  5.270167 1727.918618   100
##  63.6164186 41.908256 51.502174 1583.497529   100
##  67.8210527 49.280901 57.436492  578.222950   100
##   5.3772204  2.415228  2.741401  179.865678   100
##   0.8355802  0.836148  0.951779    1.470726   100
##  25.9411984 19.371901 26.144958  274.506899   100

With a median runtime of less than 2.5 ms, RNifti is typically around ten times as fast as the alternatives to read this image into R. The exception is ANTsRCore, which uses a similar low-level pointer-based arrangement as RNifti, and is therefore comparable in speed. However, ANTsRCore has substantial dependencies, which may affect its suitability in some applications.

Moreover, when reading the file into an "internal" image, which does not copy the pixel values into R data structures until they are required, the median runtime drops by a further 65%, to just 840 µs. This saves time and memory, while still allowing data access through standard R indexing operations.

Implementation details

The package does not fully duplicate the NIfTI structure's contents in R-visible objects. Instead, it passes key metadata back to R, such as the image dimensions and pixel dimensions, and it also passes back the pixel values where they are needed. Finally, it creates an external pointer to the native data structure, which is stored in an attribute. This pointer is dereferenced whenever the object is passed back to the C++ code, thereby avoiding unnecessary duplication and ensuring that all metadata remains intact. The full NIfTI-1 header can be obtained using the niftiHeader R function, if it is needed.

This arrangement is efficient and generally works well, but certain R operations strip attributes—in which case the external pointer will be removed. The internal structure will be built again when necessary, but using default metadata. In these cases, if it is important to keep the original metadata, the asNifti function should be called explicitly, with a template object. This reconstructs the NIfTI data structure, using the template as a starting point.

API

It is possible to use the package's NIfTI-handling code in other R packages' compiled code, thereby obviating the need to duplicate the reference implementation. Moreover, RNifti provides two key C++ wrapper classes:

  • NiftiImage, which simplifies memory management and supports the package's internal image pointers and associated reference counting, and
  • NiftiImageData, which encapsulates the pixel data within an image, and handles datatype multiplexing and data scaling, as well as providing indexing, iterators and other niceties.

Full doxygen documentation for these classes is available at https://doxygen.flakery.org/RNifti/, and is also provided with package releases.

A third-party package can use the NiftiImage class by including

LinkingTo: Rcpp, RNifti

in its DESCRIPTION file, and then including the RNifti.h header file. For example,

#include "RNifti.h"

void myfunction ()
{
    RNifti::NiftiImage image("example.nii.gz");
    // Do something with the image
}

If you're using the sourceCpp function from Rcpp, you may also need to add the attribute line

// [[Rcpp::depends(RNifti)]]

to the top of your C++ source file.

In addition to the one taking a file path, there are also constructors taking a SEXP (i.e., an R object), another NiftiImage, or a nifti_image structure from the reference implementation. NiftiImage objects can be implicitly cast to pointers to nifti_image structs, meaning that they can be directly used in calls to the reference implementation's own API. The latter is accessed through the separate RNiftiAPI.h header file.

#include "RNifti.h"
#include "RNiftiAPI.h"

void myfunction (SEXP image_)
{
    RNifti::NiftiImage image(image_);
    const size_t volsize = nifti_get_volsize(image);
}

(RNifti will also have to be added to the Imports list in the package's DESCRIPTION file, as well as LinkingTo.) The RNiftiAPI.h header should only be included once per package, since it contains function implementations. Multiple includes will lead to duplicate symbol warnings from your linker. Therefore, if multiple source files require access to the NIfTI-1 reference implementation, it is recommended that the API header be included alone in a separate ".c" or ".cpp" file, while others only include the main RNifti.h.

RNifti is not specifically designed to be thread-safe, and R itself is expressly single-threaded. However, some effort has been made to try to minimise problems associated with parallelisation, such as putting R API calls within a critical region if OpenMP is being used. If you are using the API in a package that does use OpenMP or another form of threads, it is wise to preregister the functions exported by RNifti before use, by calling niftilib_register_all(). In single-threaded contexts this is optional, and will be performed when required.

Packages must choose which version of the NIfTI library to work with, since their definitions of the core nifti_image structure are incompatible. By default the NIfTI-1 version is used, but the NIfTI-2 version may be chosen instead by defining RNIFTI_NIFTILIB_VERSION to 2 before including RNifti.h. The header file itself contains more detailed documentation. The clients directory has stub examples of packages using each version of the library.

Use in pure C++ projects

Thanks to contributions from Matt Hall, it is possible (as of package version 0.7.0) to use the NiftiImage C++ class in standalone C++ projects. The standalone directory provides a minimal example, as well as further documentation, and its contents can be copied to a new directory (including symlinked files) as a new project template.

rnifti's People

Contributors

jonclayden avatar soolijoo avatar tawilkinson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

rnifti's Issues

image.data().size() is not equal to size from image.getData<T>.begin() to image.getData<T>.end() ?

I am using some C++ codes like this to come to the conclusion:

RNifti::NiftiImage image(path, DT_FLOAT64); 
std::cout << "image.data().size() = " << image.data().size() << std::endl; 
std::vector<float> idata; 
idata = std::vector<float>(image.getData<float>().begin(), image.getData<float>().end()); 
std::cout << "idata.size() = " <<idata.size() << std::endl; 

but the std::cout is:

image.data().size() = 22282240
idata.size() = 44565504

and dim info from the header is:
dim[8] = 3 85 512 512 1 1 1 1

NA/NaN propogation

I brought this up at muschellij2/extrantsr#14, but I think wanted to make a proper issue for tracking. Issue is converting a nifti object to a niftiImage object, we see NaN turns to NA, but not the case when converting an array to niftiImage. This is surprising and unexpected as nifti objects are essentially S4 arrays with additional header slots:

library(RNifti)
library(oro.nifti)
#> oro.nifti 0.11.0
#> 
#> Attaching package: 'oro.nifti'
#> The following object is masked from 'package:RNifti':
#> 
#>     origin
suppressPackageStartupMessages(library(neurobase))
mask_file = MNITemplate::getMNIPath("Brain_Mask")

binary_mask = readnii(mask_file)
na_mask = binary_mask
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
class(na_mask)
#> [1] "nifti"
#> attr(,"package")
#> [1] "oro.nifti"
na_mask[1,1,1:3]
#> [1]  NA NaN   0

asNifti(na_mask)[1,1, 1:3]
#> [1] NA NA  0
asNifti(na_mask@.Data)[1,1, 1:3]
#> [1]  NA NaN   0
tfile = tempfile(fileext = ".nii.gz")
writeNifti(na_mask, tfile); readNifti(tfile)[1,1,1:3]
#> [1] NA NA  0
writeNifti(na_mask@.Data, tfile); readNifti(tfile)[1,1,1:3]
#> [1]  NA NaN   0

Created on 2020-09-04 by the reprex package (v0.3.0)

Session info
devtools::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 4.0.2 (2020-06-22)
#>  os       macOS Mojave 10.14.6        
#>  system   x86_64, darwin17.0          
#>  ui       X11                         
#>  language (EN)                        
#>  collate  en_US.UTF-8                 
#>  ctype    en_US.UTF-8                 
#>  tz       America/New_York            
#>  date     2020-09-04                  
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version     date       lib
#>  abind         1.4-5       2016-07-21 [1]
#>  assertthat    0.2.1       2019-03-21 [1]
#>  backports     1.1.9       2020-08-24 [1]
#>  bitops        1.0-6       2013-08-17 [1]
#>  callr         3.4.3       2020-03-28 [1]
#>  cli           2.0.2       2020-02-28 [1]
#>  crayon        1.3.4       2017-09-16 [1]
#>  desc          1.2.0       2020-06-01 [1]
#>  devtools      2.3.1.9000  2020-08-25 [1]
#>  digest        0.6.25      2020-02-23 [1]
#>  ellipsis      0.3.1       2020-05-15 [1]
#>  evaluate      0.14        2019-05-28 [1]
#>  fansi         0.4.1       2020-01-08 [1]
#>  fs            1.5.0       2020-07-31 [1]
#>  glue          1.4.1       2020-05-13 [1]
#>  highr         0.8         2019-03-20 [1]
#>  htmltools     0.5.0       2020-06-16 [1]
#>  knitr         1.29        2020-06-23 [1]
#>  lifecycle     0.2.0       2020-03-06 [1]
#>  magrittr      1.5         2014-11-22 [1]
#>  matrixStats   0.56.0      2020-03-13 [1]
#>  memoise       1.1.0       2017-04-21 [1]
#>  MNITemplate   1.0.0       2020-06-01 [1]
#>  neurobase   * 1.31.0      2020-09-04 [1]
#>  oro.nifti   * 0.11.0      2020-09-04 [1]
#>  pkgbuild      1.1.0       2020-07-13 [1]
#>  pkgload       1.1.0       2020-05-29 [1]
#>  prettyunits   1.1.1       2020-01-24 [1]
#>  processx      3.4.3       2020-07-05 [1]
#>  ps            1.3.4       2020-08-11 [1]
#>  purrr         0.3.4       2020-04-17 [1]
#>  R.methodsS3   1.8.0       2020-02-14 [1]
#>  R.oo          1.23.0      2019-11-03 [1]
#>  R.utils       2.9.2       2019-12-08 [1]
#>  R6            2.4.1       2019-11-12 [1]
#>  Rcpp          1.0.5       2020-07-06 [1]
#>  remotes       2.2.0       2020-07-21 [1]
#>  rlang         0.4.7.9000  2020-08-25 [1]
#>  rmarkdown     2.3         2020-06-18 [1]
#>  RNifti      * 1.2.0       2020-08-25 [1]
#>  rprojroot     1.3-2       2018-01-03 [1]
#>  sessioninfo   1.1.1       2018-11-05 [1]
#>  stringi       1.4.6       2020-02-17 [1]
#>  stringr       1.4.0       2019-02-10 [1]
#>  testthat      2.99.0.9000 2020-08-25 [1]
#>  usethis       1.6.1.9001  2020-08-25 [1]
#>  withr         2.2.0       2020-04-20 [1]
#>  xfun          0.16        2020-07-24 [1]
#>  yaml          2.2.1       2020-02-01 [1]
#>  source                                  
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  Github (muschellij2/desc@b0c374f)       
#>  Github (r-lib/devtools@df619ce)         
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.2)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.2)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  Github (muschellij2/MNITemplate@46e8f81)
#>  local                                   
#>  local                                   
#>  CRAN (R 4.0.2)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.2)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.2)                          
#>  Github (r-lib/rlang@de0c176)            
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.2)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.0)                          
#>  Github (r-lib/testthat@6a24275)         
#>  Github (r-lib/usethis@860c1ea)          
#>  CRAN (R 4.0.0)                          
#>  CRAN (R 4.0.2)                          
#>  CRAN (R 4.0.0)                          
#> 
#> [1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library

Nifti file to c++ vector

I need to get nifti file data to a vector I used this code

RNifti::NiftiImage image("../../example.nii.gz");
vector<float> data = image.getData();

But I get errors

../../3d_out.cpp:175:32: error: no matching member function for call to 'getData'
    vector<float> data = image.getData();
                         ~~~~~~^~~~~~~
./RNifti/NiftiImage_impl.h:1722:44: note: candidate template ignored: couldn't infer template argument 'TargetType'
inline std::vector<TargetType> NiftiImage::getData (const bool useSlope) const
                                           ^
1 error generated.

Is this the right way to do it?

3D coordinates to nifty image

Hi, I'm a PhD candidate in forest ecology and I'm working on identification and quantification of forest fuels (branches and logs on the ground) using a 3D scanner.
I'm pre-processing the data (spatial points with X,Y,Z coordinates) with R but I would like to test some analyses using BoneJ (bonej.org) for the 3D modelling.
Is there a way to convert 3D coordinates (database?) or a RasterStack made of binary images to a nifty image?

Thanks in advance for any help!

Niccolò

Failing install

On mac OSX:

Loading required package: colorout
* installing *source* packageRNifti...
** packageRNiftisuccessfully unpacked and MD5 sums checked
** using staged installation
** libs
ccache clang++ -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -DNDEBUG -DHAVE_ZLIB -DUSING_R -I../inst/include -Izlib -I"/Library/Frameworks/R.framework/Versions/3.6/Resources/library/Rcpp/include" -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -I/usr/local/include  -fPIC  -Wall -g -O2  -c main.cpp -o main.o
main.cpp:511:28: error: default initialization of an object of const type 'const Rcomplex' without a user-provided default constructor
            const Rcomplex naValue { NA_REAL, NA_REAL };
                           ^
                                   = {}
main.cpp:511:35: error: expected ';' at end of declaration
            const Rcomplex naValue { NA_REAL, NA_REAL };
                                  ^
                                  ;
main.cpp:565:28: error: default initialization of an object of const type 'const Rcomplex' without a user-provided default constructor
            const Rcomplex naValue { NA_REAL, NA_REAL };
                           ^
                                   = {}
main.cpp:565:35: error: expected ';' at end of declaration
            const Rcomplex naValue { NA_REAL, NA_REAL };
                                  ^
                                  ;
4 errors generated.
make: *** [main.o] Error 1
ERROR: compilation failed for packageRNifti* removing/Library/Frameworks/R.framework/Versions/3.6/Resources/library/RNifti* restoring previous/Library/Frameworks/R.framework/Versions/3.6/Resources/library/RNiftiWarning in install.packages :
  installation of packageRNiftihad non-zero exit status
Session info
sessioninfo::session_info()
#> ─ Session info ──────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 3.6.0 (2019-04-26)
#>  os       macOS Mojave 10.14.6        
#>  system   x86_64, darwin15.6.0        
#>  ui       X11                         
#>  language (EN)                        
#>  collate  en_US.UTF-8                 
#>  ctype    en_US.UTF-8                 
#>  tz       America/New_York            
#>  date     2019-11-21                  
#> 
#> ─ Packages ──────────────────────────────────────────────────────────────
#>  package     * version date       lib source                            
#>  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.6.0)                    
#>  cli           1.1.0   2019-03-19 [1] CRAN (R 3.6.0)                    
#>  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.6.0)                    
#>  digest        0.6.22  2019-10-21 [1] CRAN (R 3.6.0)                    
#>  evaluate      0.14    2019-05-28 [1] CRAN (R 3.6.0)                    
#>  highr         0.8     2019-03-20 [1] CRAN (R 3.6.0)                    
#>  htmltools     0.4.0   2019-10-04 [1] CRAN (R 3.6.0)                    
#>  knitr         1.24.3  2019-08-28 [1] Github (muschellij2/knitr@abcea3d)
#>  magrittr      1.5     2014-11-22 [1] CRAN (R 3.6.0)                    
#>  Rcpp          1.0.3   2019-11-08 [1] CRAN (R 3.6.0)                    
#>  rlang         0.4.1   2019-10-24 [1] CRAN (R 3.6.0)                    
#>  rmarkdown     1.16    2019-10-01 [1] CRAN (R 3.6.0)                    
#>  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.6.0)                    
#>  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.6.0)                    
#>  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.6.0)                    
#>  withr         2.1.2   2018-03-15 [1] CRAN (R 3.6.0)                    
#>  xfun          0.11    2019-11-12 [1] CRAN (R 3.6.0)                    
#>  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.6.0)                    
#> 
#> [1] /Library/Frameworks/R.framework/Versions/3.6/Resources/library

ERROR: compilation failed for package ‘RNifti’

Hi!
I am trying to install RNifti on a Linux system running R version 3.6.1.
I am getting an error message "Makevars:6: *** missing separator. Stop. ERROR: compilation failed for package ‘RNifti’" .
Please see below.
This happens with devtools, conda, and remotes.
It happens with RScript and when I try it from within R.
Any advice would be appreciated.
Thanks! Caspar

* installing *source* package ‘RNifti’ ...
** using staged installation
checking for gcc... x86_64-conda_cos6-linux-gnu-cc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether x86_64-conda_cos6-linux-gnu-cc accepts -g... yes
checking for x86_64-conda_cos6-linux-gnu-cc option to enable C11 features... none needed
checking for library containing inflate... no
configure: creating ./config.status
config.status: creating src/Makevars
** libs
Makevars:6: *** missing separator.  Stop.
ERROR: compilation failed for package ‘RNifti’
* removing ‘/home/neuro_tools/R/RNifti’
Warning message:
In i.p(...) :
  installation of package ‘/tmp/RtmpqT0FkL/file761418002c9b/RNifti_1.4.0.tar.gz’ had non-zero exit status

SEXP to nifti_image conversion from C

Because the .nifti_image_ptr external pointer wraps a NiftiImage, there is currently no way to retrieve a nifti_image pointer from a SEXP of class niftiImage in plain C code. This is an issue for C-based client packages, as it means they can't take advantage of the conversions of asNifti().

A bare pointer to the nifti_image could be attached as a second attribute, but care would have to be taken to make sure it doesn't clash with reference counting.

Possible to get dimensions of a nifti file without fully reading it?

Hello! Is it possible to obtain the dimensions of a nifti file without fully loading it into memory? Due to memory limits, I am trying to load and process a 4D bold volume time-series in chunks of time ([,,,1:20], [,,,21:40], etc.). However, this is difficult without knowing the total number of time points.

I am guessing it might be possible, since readNifti('my_file.nii.gz', volumes=0) yields an error saying
** volume index -1 (#0) is out of range [0,number_of_volumes]

Improved reorientation of bare xform matrices

Reorienting an entire image currently produces a different origin, compared to reorienting the bare xform matrix. This is documented, and arises because no image dimension information is available from the bare xform, but it's undesirable.

i <- readNifti(system.file("extdata", "example.nii.gz", package="RNifti"))
x <- xform(i)
origin(i)
# [1] 49.81356 39.07409 23.01525
origin(x)
# [1] 49.81356 39.07409 23.01525

orientation(i) <- "RAS"
orientation(x) <- "RAS"
origin(i)
# [1] 47.18644 39.07409 23.01525
origin(x)
# [1] -47.81356  39.07409  23.01525

This could be tackled by attaching an imagedim attribute to the result of xform() and friends, and using it when reorienting, but that wouldn't help when a user-specified xform matrix is given. A warning could be issued if the attribute is missing when attempting to reorient.

Unable to build RNifti

Hi,

I'm using a custom script that uses RNifti. Here is a very small script.

#include <iostream>
#include "RNifti.h"
#include "RNiftiAPI.h"
using namespace std;

int main() {
    RNifti::NiftiImage image("image.nii");
    return 0;
}

The CMakeLists.txt for the executable is

add_executable(read_nifti read_nifti.cpp)
target_link_libraries(read_nifti PUBLIC rnifti)

And the CMakeLists.txt for the library is

cmake_minimum_required(VERSION 3.16)
project(rnifti)
set(SOURCES 
    niftilib/nifti1_io.c 
    niftilib/nifti2_io.c 
)
set(ZLIBSOURCES
    zlib/adler32.c
    zlib/compress.c
    zlib/crc32.c
    zlib/crc32.h
    zlib/deflate.c
    zlib/deflate.h
    zlib/gzclose.c
    zlib/gzguts.h
    zlib/gzlib.c
    zlib/gzread.c
    zlib/gzwrite.c
    zlib/infback.c
    zlib/inffast.c
    zlib/inffast.h
    zlib/inffixed.h
    zlib/inflate.c
    zlib/inflate.h
    zlib/inftrees.c
    zlib/inftrees.h
    zlib/trees.c
    zlib/trees.h
    zlib/uncompr.c
    zlib/zutil.c
    zlib/zutil.h
)

set(ZNZLIBSOURCES
    znzlib/znzlib.c
)

add_library(rnifti STATIC ${SOURCES} ${ZLIBSOURCES} ${ZNZLIBSOURCES})
set_target_properties(rnifti PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(rnifti PUBLIC ./include)

.
├── CMakeLists.txt
├── include
│   ├── niftilib
│   │   ├── nifti1.h
│   │   ├── nifti1_io.h
│   │   ├── nifti2.h
│   │   ├── nifti2_image.h
│   │   └── nifti2_io.h
│   ├── RNifti
│   │   ├── NiftiImage.h
│   │   ├── NiftiImage_impl.h
│   │   ├── NiftiImage_matrix.h
│   │   └── NiftiImage_print.h
│   ├── RNiftiAPI.h
│   ├── RNiftiAPI.h.in
│   ├── RNifti.h
│   ├── zlib
│   │   ├── zconf.h
│   │   └── zlib.h
│   └── znzlib
│       └── znzlib.h
├── niftilib
│   ├── nifti1_io.c
│   └── nifti2_io.c
├── zlib
│   ├── adler32.c
│   ├── compress.c
│   ├── crc32.c
│   ├── crc32.h
│   ├── deflate.c
│   ├── deflate.h
│   ├── gzclose.c
│   ├── gzguts.h
│   ├── gzlib.c
│   ├── gzread.c
│   ├── gzwrite.c
│   ├── infback.c
│   ├── inffast.c
│   ├── inffast.h
│   ├── inffixed.h
│   ├── inflate.c
│   ├── inflate.h
│   ├── inftrees.c
│   ├── inftrees.h
│   ├── trees.c
│   ├── trees.h
│   ├── uncompr.c
│   ├── zutil.c
│   └── zutil.h
└── znzlib
    └── znzlib.c

The error that I'm getting while doing make is

[ 89%] Building CUDA object samples/CMakeFiles/read_nifti.dir/read_nifti.cu.o
In file included from /home/rjena/code/tiny-cuda-nn/samples/read_nifti.cu:3:
/home/rjena/code/tiny-cuda-nn/niftilib/./include/RNiftiAPI.h:4:10: fatal error: R_ext/Rdynload.h: No such file or directory
    4 | #include <R_ext/Rdynload.h>
      |          ^~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [samples/CMakeFiles/read_nifti.dir/build.make:76: samples/CMakeFiles/read_nifti.dir/read_nifti.cu.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:232: samples/CMakeFiles/read_nifti.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

ERROR (nifti_image_write_hdr_img2)

I want to use a convolutional Neural Network that is written with Guotai Wang for BRATS 2017 but I face with this error and I cannot solve it!!

ERROR (nifti_image_write_hdr_img2): cannot open output file 'result15/HGG/brats_tcia_pat205_0001.nii.gz'

Undefined Symbols Error

  1. I have cloned the repository and executed the make file inside it.
  2. I included #include "RNifti.h" in my code and used RNifti::NiftiImage image("t1_c.nii.gz");
  3. I executed the code using g++ 3d_out.cpp -o 3d_out.out -L/opt/homebrew/lib -lafcpu -I/opt/homebrew/include -I./RNifti/standalone/
  4. I get errors
    ld: Undefined symbols:
    _nifti2_image_free, referenced from:
    RNifti::NiftiImage::release() in 3d_out-0eaa8b.o
    _nifti2_image_read, referenced from:
    RNifti::NiftiImage::NiftiImage(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, bool) in 3d_out-0eaa8b.o
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

Rescaling done in retrieveNifti scl_slope

Description of the problem

It seems as though if you put a nifti object into retrieveNifti it will have different behavior with respect to scale/slope if you put in a filename.

Reading in the data

As we see it's a binary mask:

library(RNifti)
library(neurobase)
#> Loading required package: oro.nifti
#> oro.nifti 0.9.11.1
#> 
#> Attaching package: 'oro.nifti'
#> The following object is masked from 'package:RNifti':
#> 
#>     origin
img = readnii("roi.nii.gz")
unique(c(img))
#> [1] 0 1
rimg = readNifti("roi.nii.gz")
unique(c(rimg))
#> [1] 0 1
sum(img)
#> [1] 29437
sum(rimg)
#> [1] 29437
sum(as.array(retrieveNifti(rimg)))
#> [1] 29437

When we use retrieveNifti and then run as.array to calculate the sum, we get very different answers:

retrieveNifti("roi.nii.gz")
#> Internal image: "NIfTI image"
#> - 512 x 512 x 33 voxels
#> - 0.4883 x 0.4883 x 5 mm per voxel

sum(as.array(retrieveNifti("roi.nii.gz")))
#> [1] 29437
sum(as.array(retrieveNifti(img)))
#> [1] -8858340611

We see this is due to scl_slope and scl_inter:

dumpNifti(img)
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  512  512  33  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 0
#>       datatype: 8
#>         bitpix: 32
#>    slice_start: 0
#>         pixdim: -1.000000  0.488281  0.488281  5.000000  1.000000  1.000000  1.000000  1.000000
#>     vox_offset: 352
#>      scl_slope: 1
#>      scl_inter: -1024
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 1
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: Time=154424.000
#>       aux_file: AXIAL_5MM
#>     qform_code: 1
#>     sform_code: 1
#>      quatern_b: 0.7071068
#>      quatern_c: 0.7071068
#>      quatern_d: 0
#>      qoffset_x: -218.7221
#>      qoffset_y: -161.1053
#>      qoffset_z: 8.700012
#>         srow_x: 0.000000  0.488281  0.000000  -218.722122
#>         srow_y: 0.488281  0.000000  0.000000  -161.105270
#>         srow_z: 0.000000  0.000000  5.000000  8.700012
#>    intent_name: 
#>          magic: n+1

After retrieving the info, it's scaled and sloped:

aimg = retrieveNifti(img)
unique(c(as.array(aimg)))
#> [1] -1024 -1023
hist(as.array(aimg))

Histogram of the output array:

But this information is also in the .nii.gz:

hd = dumpNifti("roi.nii.gz")
hd$scl_slope
#> [1] 1
hd$scl_inter
#> [1] -1024

img_hd = dumpNifti(img)
img_hd$scl_slope
#> [1] 1
img_hd$scl_inter
#> [1] -1024

I guess the fact that the data stored in the .nii.gz may actually have values which are not scaled already makes sense, it may be because the data are already transformed but the header is preserved: https://github.com/muschellij2/oro.nifti/blob/5b685cb75c8994f7336530d66d968813e86089fc/R/readS4.R#L453

Created on 2019-04-09 by the reprex package (v0.2.1)

RNifti Memory Usage

I am using RNifti to read in 4-D .nii files. I am trying to troubleshoot memory usage during read in.

Using R 3.5.2, Ubuntu 16.04.6, and RNifti_0.10.0 I read in a single precision (dim: 182x218x182x142) .nii file using readNifti with internal = FALSE

The workspace reports an object size of 8.203093528 gb. However the R process itself uses about 12.1gb of memory.

When reading in the file with internal = FALSE, the R process looks to use about 4.673504gb of memory.

When defining a regular double precision R array of the same dimensions the R process looks to use 8.70244gb of memory.

Running gc() after read in does not seem to free much memory. It also seems that the extra memory used by the R process tends to increase if I increase the number of volumes in the file.

Let me know if you have any suggestions or insights into this issue.

ERROR TRYING TO INSTALL RNifti PACKAGE

Hi!
I am trying to install RNifti on a macOS Monterey (12.6.2) system running R Studio 2022.02.1+461, © 2009-2022 RStudio, PBC
I am getting an error message: "Warning in install.packages :
installation of package ‘RNifti’ had non-zero exit status"

Thank you in Advance

  • installing source package ‘RNifti’ ...
    ** package ‘RNifti’ successfully unpacked and MD5 sums checked
    ** using staged installation
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    checking for gcc... gcc
    checking whether the C compiler works... no
    configure: error: in /private/var/folders/ry/tj6wg0bs4md70p0w2xqs2w8h0000gn/T/Rtmp8fPVeP/R.INSTALL3cbc4806c986/RNifti': configure: error: C compiler cannot create executables See config.log' for more details
    ERROR: configuration failed for package ‘RNifti’
  • removing ‘/Library/Frameworks/R.framework/Versions/4.1/Resources/library/RNifti’
    Warning in install.packages :
    installation of package ‘RNifti’ had non-zero exit status

The downloaded source packages are in
‘/private/var/folders/ry/tj6wg0bs4md70p0w2xqs2w8h0000gn/T/Rtmp9werz4/downloaded_packages’

Exported niftiImage class?

Do you plan on defining exporting the niftiImage class? I was wondering because I've been trying to make generic functions and incorporate the RNifti package for these object types.

Currently, I can perform

is.niftiImage = function(x) {
    inherits(x, "niftiImage")
}
myfunc(x) {
if (is.niftiImage(x)) {
#DEFINED FOR niftiImage 
} else {
}

but it would be useful to have

setMethod("myfunc", "niftiImage", function() { #DEFINED FOR niftiImage 
})

but it does not seem that the niftiImage class is exported from RNifti. This may be because I did not using LinkingTo, but don't know if that's the case.

I don't know if I can implement this effectively or what you want. If you plan on doing this, I'd appreciate it (disregard below). Otherwise, I can take a shot with a PR (then see below)
It seems like I could send a PR with:

setClass( "niftiImage", representation( pointer = "externalptr" ) )

but this seems to be an attribute versus element of the object.

How may I change pixel dimension to fit size?

I have the following code but the chest CT seems compressed. Any hints for this error?

library(oro.nifti)
library(ggBrain)
library(RNifti)

chestImage = readNIfTI("/Users/zhangzhongheng/Documents/2022/ChestCT_Zhejiang/CTclean/17171437.nii.gz")
chestImage
NIfTI-1 format
  Type            : nifti
  Data Type       : 4 (INT16)
  Bits per Pixel  : 16
  Slice Code      : 0 (Unknown)
  Intent Code     : 0 (None)
  Qform Code      : 1 (Scanner_Anat)
  Sform Code      : 1 (Scanner_Anat)
  Dimension       : 512 x 512 x 140
  Pixel Dimension : 0.74 x 0.74 x 2
  Voxel Units     : mm
  Time Units      : Unknown
#now add aethetic changes with conventional ggplot code.
ggBrain(brains=chestImage,mar=1:3,mar_ind=c(250,250,80),
        row_ind=    c(1,2,1),
        col_ind=    c(2,1,1),
        type='structural',tri_planar=TRUE, lines_color='black',
        fix_ratio = F) +
  scale_fill_continuous(low="black", high="white") + 
  theme_black_bg()

The ratio of width and heigth are incorrect.

./configure does not generate Makefile

./configure --help show below message, but /confgure did not generate Makefile. My OS is Ubuntu 20.04. Why does not generate Makefile?

By default, make install' will install all the files in /usr/local/bin', /usr/local/lib' etc. You can specify an installation prefix other than /usr/local' using --prefix', for instance --prefix=$HOME'.

Need path.expand for writeNifti.

If you use a ~ in your path name, the path is not absolute and writeNifti fails:

fname = system.file("extdata", "example.nii.gz", package = "RNifti")
image <- readNifti(fname)
writeNifti(image, file = "~/Desktop/test.nii.gz")
** ERROR (nifti_image_write_hdr_img2): cannot open output file '~/Desktop/test.nii.gz'

If you use path.expand, it works fine:

writeNifti(image, file = path.expand("~/Desktop/test.nii.gz"))

setting sform

Hi,

I noticed something that looks like a regression in version 0.7.0. The sform<- function doesn't seem to work as it does it version 0.6.0.

Martin

C++ build errors

Upon trying to build the c++ standalone on linux, I came across the following error:

RNifti-1.5.1/standalone$ make all
cc -I. -DNDEBUG -DHAVE_ZLIB  -c -o niftilib/nifti1_io.o niftilib/nifti1_io.c
niftilib/nifti1_io.c:1:1: error: expected identifier or ‘(’ before ‘.’ token
    1 | ../../src/niftilib/nifti1_io.c
      | ^
make: *** [<builtin>: niftilib/nifti1_io.o] Error 1

if I change the file niftilib/nifti1_io.c's faulty line (also, its only line) into #include "../../src/niftilib/nifti1_io.c, and I do the same for the niftilib/nifti1_io.h file (#include "../../inst/include/niftilib/nifti1_io.h") and the file niftilib/nifti1.h (#include "../../inst/include/niftilib/nifti1.h") then I get the following error:

RNifti-1.5.1/standalone$ make all
In file included from ./niftilib/nifti1_io.h:1,
                 from niftilib/../../src/niftilib/nifti1_io.c:3,
                 from niftilib/nifti1_io.c:1:
./niftilib/../../inst/include/niftilib/nifti1_io.h:24:10: fatal error: RNifti/NiftiImage_print.h: No such file or directory
   24 | #include "RNifti/NiftiImage_print.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [<builtin>: niftilib/nifti1_io.o] Error 1

At this point I'm not sure how to proceed, though I'm still looking into it. Is there anything am I missing? Was I wrong to change the include lines in the standalone directory?

Edit:
I added an include in the makefile to solve not finding the RNifti header.

CFLAGS += -I. -I../inst/include
CXXFLAGS += -I. -I../inst/include

I noticed other #include statement missing in the standalone directory source files:

  • znzlib/*
  • zlib/*
  • niftilib/*
  • RNifti.h

Finally, it seems to compile

RNifti-1.5.1/standalone$ make all
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o niftilib/nifti1_io.o niftilib/nifti1_io.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o znzlib/znzlib.o znzlib/znzlib.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/adler32.o zlib/adler32.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/compress.o zlib/compress.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/crc32.o zlib/crc32.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/deflate.o zlib/deflate.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/gzclose.o zlib/gzclose.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/gzlib.o zlib/gzlib.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/gzread.o zlib/gzread.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/gzwrite.o zlib/gzwrite.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/infback.o zlib/infback.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/inffast.o zlib/inffast.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/inflate.o zlib/inflate.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/inftrees.o zlib/inftrees.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/trees.o zlib/trees.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/uncompr.o zlib/uncompr.c
cc -I. -I../inst/include -DNDEBUG -DHAVE_ZLIB  -c -o zlib/zutil.o zlib/zutil.c
g++ -DNDEBUG -DHAVE_ZLIB -I. -I../inst/include  -o nii_info nii_info.cpp niftilib/nifti1_io.o znzlib/znzlib.o zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/deflate.o zlib/gzclose.o zlib/gzlib.o zlib/gzread.o zlib/gzwrite.o zlib/infback.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o zlib/uncompr.o zlib/zutil.o
g++ -DNDEBUG -DHAVE_ZLIB -DRNIFTI_NIFTILIB_VERSION=2 -DNO_REMAP_NIFTI2_FUNCTIONS -I. -I../inst/include  -o nii2_info nii_info.cpp niftilib/nifti2_io.o znzlib/znzlib.o zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/deflate.o zlib/gzclose.o zlib/gzlib.o zlib/gzread.o zlib/gzwrite.o zlib/infback.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o zlib/uncompr.o zlib/zutil.o

Changing bitpix does nothing without datatype

Examples rendered by https://github.com/tidyverse/reprex @jennybryan

library(RNifti)
path <- system.file("extdata", "example.nii.gz", package="RNifti")
nim = readNifti(path)
nim
#> Image array of mode "integer" (2.1 Mb)
#> - 96 x 96 x 60 voxels
#> - 2.5 x 2.5 x 2.5 mm per voxel

Read example data

hdr = dumpNifti(nim)
hdr
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  96  96  60  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 0
#>       datatype: 8
#>         bitpix: 32
#>    slice_start: 0
#>         pixdim: -1.0  2.5  2.5  2.5  0.0  0.0  0.0  0.0
#>     vox_offset: 352
#>      scl_slope: 0
#>      scl_inter: 0
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 2503
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: TractoR NIfTI writer v3.0.0
#>       aux_file: 
#>     qform_code: 2
#>     sform_code: 2
#>      quatern_b: 0
#>      quatern_c: 1
#>      quatern_d: 0
#>      qoffset_x: 122.0339
#>      qoffset_y: -95.18523
#>      qoffset_z: -55.03814
#>         srow_x: -2.5000  0.0000  0.0000  122.0339
#>         srow_y: 0.00000  2.50000  0.00000  -95.18523
#>         srow_z: 0.00000  0.00000  2.50000  -55.03814
#>    intent_name: 
#>          magic: n+1

We see in the header:

#>       datatype: 8
#>         bitpix: 32

change bitpix only

hdr$bitpix = 8
updateNifti(nim, template = hdr)
#> Image array of mode "integer" (2.1 Mb)
#> - 96 x 96 x 60 voxels
#> - 2.5 x 2.5 x 2.5 mm per voxel
dumpNifti(hdr)
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  96  96  60  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 0
#>       datatype: 8
#>         bitpix: 32
#>    slice_start: 0
#>         pixdim: -1.0  2.5  2.5  2.5  0.0  0.0  0.0  0.0
#>     vox_offset: 352
#>      scl_slope: 0
#>      scl_inter: 0
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 2503
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: TractoR NIfTI writer v3.0.0
#>       aux_file: 
#>     qform_code: 2
#>     sform_code: 2
#>      quatern_b: 0
#>      quatern_c: 1
#>      quatern_d: 0
#>      qoffset_x: 122.0339
#>      qoffset_y: -95.18523
#>      qoffset_z: -55.03814
#>         srow_x: -2.5000  0.0000  0.0000  122.0339
#>         srow_y: 0.00000  2.50000  0.00000  -95.18523
#>         srow_z: 0.00000  0.00000  2.50000  -55.03814
#>    intent_name: 
#>          magic: n+1

No warning was issued about inconsistency in the bitpix/datatype designation and we see that nothing is changed in the image.

change datatype as well - works fine

hdr$datatype = 2
updateNifti(nim, template = hdr)
#> Image array of mode "integer" (2.1 Mb)
#> - 96 x 96 x 60 voxels
#> - 2.5 x 2.5 x 2.5 mm per voxel
dumpNifti(hdr)
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  96  96  60  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 0
#>       datatype: 2
#>         bitpix: 8
#>    slice_start: 0
#>         pixdim: -1.0  2.5  2.5  2.5  0.0  0.0  0.0  0.0
#>     vox_offset: 352
#>      scl_slope: 0
#>      scl_inter: 0
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 2503
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: TractoR NIfTI writer v3.0.0
#>       aux_file: 
#>     qform_code: 2
#>     sform_code: 2
#>      quatern_b: 0
#>      quatern_c: 1
#>      quatern_d: 0
#>      qoffset_x: 122.0339
#>      qoffset_y: -95.18523
#>      qoffset_z: -55.03814
#>         srow_x: -2.5000  0.0000  0.0000  122.0339
#>         srow_y: 0.00000  2.50000  0.00000  -95.18523
#>         srow_z: 0.00000  0.00000  2.50000  -55.03814
#>    intent_name: 
#>          magic: n+1

Changing datatype is the driver it seems

library(RNifti)
path <- system.file("extdata", "example.nii.gz", package="RNifti")
nim = readNifti(path)
hdr = dumpNifti(nim)
hdr$datatype = 2
updateNifti(nim, template = hdr)
#> Image array of mode "integer" (2.1 Mb)
#> - 96 x 96 x 60 voxels
#> - 2.5 x 2.5 x 2.5 mm per voxel
dumpNifti(hdr)
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  96  96  60  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 0
#>       datatype: 2
#>         bitpix: 8
#>    slice_start: 0
#>         pixdim: -1.0  2.5  2.5  2.5  0.0  0.0  0.0  0.0
#>     vox_offset: 352
#>      scl_slope: 0
#>      scl_inter: 0
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 2503
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: TractoR NIfTI writer v3.0.0
#>       aux_file: 
#>     qform_code: 2
#>     sform_code: 2
#>      quatern_b: 0
#>      quatern_c: 1
#>      quatern_d: 0
#>      qoffset_x: 122.0339
#>      qoffset_y: -95.18523
#>      qoffset_z: -55.03814
#>         srow_x: -2.5000  0.0000  0.0000  122.0339
#>         srow_y: 0.00000  2.50000  0.00000  -95.18523
#>         srow_z: 0.00000  0.00000  2.50000  -55.03814
#>    intent_name: 
#>          magic: n+1

writeNifti produces unreasonably large files and takes way to long

Sorry for the provocative title, so far I enjoyed your package very much, appreciate the work. However, I am currently working on 4D (fMRI) images and I couldn't help but notice that the writeNifti function is terribly slow. So far with 3D images I haven't noticed anything but with 4D it is way out of hand. Please compare:

RNifti::writeNifti(array(runif(5000), dim = c(100, 100, 100, 200)), "test.nii.gz")
oro.nifti::writeNIfTI(array(runif(5000), dim = c(100, 100, 100, 200)), "test2", compression = 5)

At first, I thought the code crashed, but no, it just takes a couple of minutes and produces a multi-gigabite sized file. I would have tried to look into it myself but I don't understand C :(

Thanks for you help.

Orientation of Image

I was wondering what the default is for the orientation information in RNifti?
The file is located at:
https://figshare.com/articles/Orientation_issue_questino/5566708

Using FSL - it shows its RPI, but RNifti says it's LAS. Is this due to neurological/radiological orientation or something else?

setwd("~/Desktop/")
library(RNifti)
library(fslr)
#> Loading required package: oro.nifti
#> oro.nifti 0.9.1
#> 
#> Attaching package: 'oro.nifti'
#> The following objects are masked from 'package:RNifti':
#> 
#>     origin, pixdim, pixdim<-
#> Loading required package: neurobase
img = readNifti("test.nii.gz")
img
#> Image array of mode "integer" (30 Mb)
#> - 256 x 256 x 120 voxels
#> - 0.8281 x 0.8281 x 1.17 mm per voxel
fslgetorient("test.nii.gz", verbose = FALSE)
#> Warning in get.fsl(): Setting fsl.path to /usr/local/fsl
#> Warning in get.fsloutput(): Can't find FSLOUTPUTTYPE, setting to NIFTI_GZ
#> [1] "RADIOLOGICAL"

orientation(img)
#> [1] "LAS"
orientation(img, useQuaternionFirst = FALSE)
#> [1] "LAS"

forms = getForms("test.nii.gz", verbose = FALSE)
forms$ssor
#> [1] "RL" "PA" "IS"
forms$sqor
#> [1] "RL" "PA" "IS"

xform(img)
#>             [,1]        [,2]        [,3]      [,4]
#> [1,] -0.82395548 -0.06480335 -0.07326235 118.07638
#> [2,] -0.05903414  0.82128185 -0.12479428 -64.77468
#> [3,] -0.05833857  0.08418799  1.16101635 -14.63630
#> [4,]  0.00000000  0.00000000  0.00000000   1.00000
forms$qform
#>           [,1]      [,2]      [,3]      [,4]
#> [1,] -0.823955 -0.064803 -0.073262 118.07638
#> [2,] -0.059034  0.821282 -0.124794 -64.77468
#> [3,] -0.058339  0.084188  1.161016 -14.63630
#> [4,]  0.000000  0.000000  0.000000   1.00000
xform(img, useQuaternionFirst = FALSE)
#>             [,1]        [,2]       [,3]      [,4]
#> [1,] -0.82395548 -0.06480330 -0.0732611 118.07638
#> [2,] -0.05903418  0.82128185 -0.1247942 -64.77468
#> [3,] -0.05833768  0.08418803  1.1610165 -14.63630
#> [4,]  0.00000000  0.00000000  0.0000000   1.00000
forms$sform
#>           [,1]      [,2]      [,3]      [,4]
#> [1,] -0.823955 -0.064803 -0.073261 118.07638
#> [2,] -0.059034  0.821282 -0.124794 -64.77468
#> [3,] -0.058338  0.084188  1.161016 -14.63630
#> [4,]  0.000000  0.000000  0.000000   1.00000

interactive in shiny

Wonderful package! Is there a way to:

1: Edit labels/colors of overlay images?
2. Plot this to a shiny dashboard while retaining the interactive bit. I'm now using this in my app to select and plot two images, then using the renderPlot() function to plot it, but that seems to remove the interactive option and fix it in place (while printing "right click to leave interactive mode" in the image without it actually being interaction.

    dataset <- dataset[dataset$participant %in% input$data_select,]
    
    subject <- dataset$participant
    
    img <- readNifti(paste0("./data/nifti/",subject,".nii.gz"))
    img2 <- readNifti(paste0("./data/nifti/",subject,"_seg.nii.gz"))
        
    RNifti::view(img,img2,labels=T,interactive = T)

updateNifti only working for certain attributes

Hi! May I first just say that this package is brilliant, and that i love its speed, and I'm so happy that it exists.

I ran into an issue today with trying to rescale nii images, in that some attributes seem to be possible to update, while others were not.

Load some data

library(RNifti)
#> Warning: package 'RNifti' was built under R version 3.4.3

devtools::install_github('muschellij2/kirby21.t1')
#> Using GitHub PAT from envvar GITHUB_PAT
#> Skipping install of 'kirby21.t1' from a github remote, the SHA1 (01795b50) has not changed since last install.
#>   Use `force = TRUE` to force installation

kirby21.t1::download_t1_data()
#> [1] TRUE

kirby21.t1::get_t1_filenames()
...

Original file attributes

dat <- RNifti::readNifti(kirby21.t1::get_t1_filenames()[1])
dumpNifti(dat)
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  170  256  256  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 0  # HERE
#>       datatype: 64
#>         bitpix: 64
#>    slice_start: 0
#>         pixdim: -1.0  1.2  1.0  1.0  0.0  0.0  0.0  0.0
#>     vox_offset: 352
#>      scl_slope: 0  # HERE
#>      scl_inter: 0
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 2408322  # HERE
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: Magnetic Resonance
#>       aux_file:  
#>     qform_code: 1
#>     sform_code: 0
#>      quatern_b: 1
#>      quatern_c: 0
#>      quatern_d: 0
#>      qoffset_x: -202.8
#>      qoffset_y: 0
#>      qoffset_z: 0
#>         srow_x: 0  0  0  0
#>         srow_y: 0  0  0  0
#>         srow_z: 0  0  0  0
#>    intent_name:  
#>          magic: n+1

Updating intent_code works fine

dat2 <- RNifti::updateNifti(dat, list(intent_code=1))
dumpNifti(dat2)
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  170  256  256  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 1  # HERE
#>       datatype: 64
#>         bitpix: 64
#>    slice_start: 0
#>         pixdim: 0.0  1.2  1.0  1.0  0.0  0.0  0.0  0.0
#>     vox_offset: 348
#>      scl_slope: 0
#>      scl_inter: 0
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 2408322
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: 
#>       aux_file: 
#>     qform_code: 0
#>     sform_code: 0
#>      quatern_b: 0
#>      quatern_c: 0
#>      quatern_d: 0
#>      qoffset_x: 0
#>      qoffset_y: 0
#>      qoffset_z: 0
#>         srow_x: 0  0  0  0
#>         srow_y: 0  0  0  0
#>         srow_z: 0  0  0  0
#>    intent_name: 
#>          magic: n+1

Updating scl_slope or cal_max does not work

dat3 <- RNifti::updateNifti(dat, list(scl_slope=5))
dumpNifti(dat3)
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  170  256  256  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 0
#>       datatype: 64
#>         bitpix: 64
#>    slice_start: 0
#>         pixdim: 0.0  1.2  1.0  1.0  0.0  0.0  0.0  0.0
#>     vox_offset: 348
#>      scl_slope: 0  # HERE
#>      scl_inter: 0
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 2408322
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: 
#>       aux_file: 
#>     qform_code: 0
#>     sform_code: 0
#>      quatern_b: 0
#>      quatern_c: 0
#>      quatern_d: 0
#>      qoffset_x: 0
#>      qoffset_y: 0
#>      qoffset_z: 0
#>         srow_x: 0  0  0  0
#>         srow_y: 0  0  0  0
#>         srow_z: 0  0  0  0
#>    intent_name: 
#>          magic: n+1


dat4 <- RNifti::updateNifti(dat, list(cal_max=1000))
dumpNifti(dat4)
#> NIfTI-1 header
#>     sizeof_hdr: 348
#>       dim_info: 0
#>            dim: 3  170  256  256  1  1  1  1
#>      intent_p1: 0
#>      intent_p2: 0
#>      intent_p3: 0
#>    intent_code: 0
#>       datatype: 64
#>         bitpix: 64
#>    slice_start: 0
#>         pixdim: 0.0  1.2  1.0  1.0  0.0  0.0  0.0  0.0
#>     vox_offset: 348
#>      scl_slope: 0
#>      scl_inter: 0
#>      slice_end: 0
#>     slice_code: 0
#>     xyzt_units: 10
#>        cal_max: 2408322  # HERE
#>        cal_min: 0
#> slice_duration: 0
#>        toffset: 0
#>        descrip: 
#>       aux_file: 
#>     qform_code: 0
#>     sform_code: 0
#>      quatern_b: 0
#>      quatern_c: 0
#>      quatern_d: 0
#>      qoffset_x: 0
#>      qoffset_y: 0
#>      qoffset_z: 0
#>         srow_x: 0  0  0  0
#>         srow_y: 0  0  0  0
#>         srow_z: 0  0  0  0
#>    intent_name: 
#>          magic: n+1

Any idea why this might be the case? I'm looking to implement a system to change the units of a PET image in nii format, and there are different units which involve a scalar multiplicative change. But neither way that I would do this appears to work.

Thanks again for this tool: it's a really awesome package!

All the best,
Granville

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.