Open avalcarcel9 opened 4 years ago
dtype = TRUE
in writenii
- can you point to the line in the code?
So you want it so that dtype = FALSE
when using readnii
, correct?
Looks like line 60 in this function set: https://github.com/muschellij2/extrantsr/blob/6d9f61058c558dc0934cce358d2a24b42f379ae1/R/oro2ants.R
Honestly, I'm still having some strange behavior due to the default of readnii and writenii being dtype = TRUE. Should we really have the default possibly changing images on users? There is no consistency across packages of how to deal with NA values in reading and writing images. Seems like RNifti, neurobase, and ANTsR all treat them subtly different.
So https://github.com/muschellij2/extrantsr/blob/6d9f61058c558dc0934cce358d2a24b42f379ae1/R/oro2ants.R#L61, dtype = dtype
, but you think that shouldn't be TRUE
by default?
I'm thinking the default of the original function in neurobase shouldn't default to dtype = TRUE but if you keep it the default in neurobase then here in line 61 it does need to be an option at least so the user can decide.
I think I pinned it down: It's this value https://github.com/muschellij2/oro.nifti/blob/master/R/writeS4.R#L215
vs. this value
https://github.com/muschellij2/neurobase/blob/master/R/rescale_img.R#L134
This is a bit of slop, but try this code on your older versions and I bet they give some funky results.
rm(list=ls())
library(RNifti)
library(oro.nifti)
#> oro.nifti 0.11.0
#>
#> Attaching package: 'oro.nifti'
#> The following object is masked from 'package:RNifti':
#>
#> origin
library(neurobase)
library(ANTsRCore)
#>
#> Attaching package: 'ANTsRCore'
#> The following objects are masked from 'package:oro.nifti':
#>
#> origin, origin<-
#> The following object is masked from 'package:RNifti':
#>
#> origin
#> The following objects are masked from 'package:stats':
#>
#> sd, var
#> The following objects are masked from 'package:base':
#>
#> all, any, apply, max, min, prod, range, sum
library(fslr)
mask_file = MNITemplate::getMNIPath("Brain_Mask")
mask_file = MNITemplate::getMNIPath("Brain_Mask")
mask = readNifti(mask_file)
mask[1,1,1] = NA
mask[1,1,2] = NaN
tfile_nif = tempfile(fileext = ".nii.gz")
writeNifti(mask, tfile_nif)
fslhd(tfile_nif)
#> Warning in get.fsl(): Setting fsl.path to /usr/local/fsl
#> Warning in get.fsloutput(): Can't find FSLOUTPUTTYPE, setting to NIFTI_GZ
#> FSLDIR='/usr/local/fsl'; PATH=${FSLDIR}/bin:${PATH};export PATH FSLDIR; sh "${FSLDIR}/etc/fslconf/fsl.sh"; FSLOUTPUTTYPE=NIFTI_GZ; export FSLOUTPUTTYPE; ${FSLDIR}/bin/fslhd "/private/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T/RtmpuJeiqI/file851531aa0982.nii.gz"
#> [1] "filename /private/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T/RtmpuJeiqI/file851531aa0982.nii.gz"
#> [2] ""
#> [3] "sizeof_hdr 348"
#> [4] "data_type FLOAT64"
#> [5] "dim0 3"
#> [6] "dim1 182"
#> [7] "dim2 218"
#> [8] "dim3 182"
#> [9] "dim4 1"
#> [10] "dim5 1"
#> [11] "dim6 1"
#> [12] "dim7 1"
#> [13] "vox_units mm"
#> [14] "time_units s"
#> [15] "datatype 64"
#> [16] "nbyper 8"
#> [17] "bitpix 64"
#> [18] "pixdim0 0.000000"
#> [19] "pixdim1 1.000000"
#> [20] "pixdim2 1.000000"
#> [21] "pixdim3 1.000000"
#> [22] "pixdim4 0.000000"
#> [23] "pixdim5 0.000000"
#> [24] "pixdim6 0.000000"
#> [25] "pixdim7 0.000000"
#> [26] "vox_offset 352"
#> [27] "cal_max 1.0000"
#> [28] "cal_min 0.0000"
#> [29] "scl_slope 0.000000"
#> [30] "scl_inter 0.000000"
#> [31] "phase_dim 0"
#> [32] "freq_dim 0"
#> [33] "slice_dim 0"
#> [34] "slice_name Unknown"
#> [35] "slice_code 0"
#> [36] "slice_start 0"
#> [37] "slice_end 0"
#> [38] "slice_duration 0.000000"
#> [39] "time_offset 0.000000"
#> [40] "intent Unknown"
#> [41] "intent_code 0"
#> [42] "intent_name "
#> [43] "intent_p1 0.000000"
#> [44] "intent_p2 0.000000"
#> [45] "intent_p3 0.000000"
#> [46] "qform_name MNI_152"
#> [47] "qform_code 4"
#> [48] "qto_xyz:1 -1.000000 0.000000 -0.000000 90.000000"
#> [49] "qto_xyz:2 0.000000 1.000000 -0.000000 -126.000000"
#> [50] "qto_xyz:3 0.000000 0.000000 1.000000 -72.000000"
#> [51] "qto_xyz:4 0.000000 0.000000 0.000000 1.000000"
#> [52] "qform_xorient Right-to-Left"
#> [53] "qform_yorient Posterior-to-Anterior"
#> [54] "qform_zorient Inferior-to-Superior"
#> [55] "sform_name MNI_152"
#> [56] "sform_code 4"
#> [57] "sto_xyz:1 -1.000000 0.000000 0.000000 90.000000"
#> [58] "sto_xyz:2 0.000000 1.000000 0.000000 -126.000000"
#> [59] "sto_xyz:3 0.000000 0.000000 1.000000 -72.000000"
#> [60] "sto_xyz:4 0.000000 0.000000 0.000000 1.000000"
#> [61] "sform_xorient Right-to-Left"
#> [62] "sform_yorient Posterior-to-Anterior"
#> [63] "sform_zorient Inferior-to-Superior"
#> [64] "file_type NIFTI-1+"
#> [65] "file_code 1"
#> [66] "descrip FSL4.0eta"
#> [67] "aux_file "
tmask = readNifti(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
tmask = readnii(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
arr = array(mask, dim = dim(mask))
arr[1,1,1:3]
#> [1] NA NaN 0
asNifti(arr)[1,1,1:3]
#> [1] NA NaN 0
writeNifti(arr, tfile_nif)
tmask = readNifti(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
tmask = readNIfTI(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
tmask
#> NIfTI-1 format
#> Type : nifti
#> Data Type : 64 (FLOAT64)
#> Bits per Pixel : 64
#> Slice Code : 0 (Unknown)
#> Intent Code : 0 (None)
#> Qform Code : 0 (Unknown)
#> Sform Code : 0 (Unknown)
#> Dimension : 182 x 218 x 182
#> Pixel Dimension : 1 x 1 x 1
#> Voxel Units : Unknown
#> Time Units : Unknown
tmask = readnii(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
run_checks = function(file) {
mask = readNifti(file)
print(mask[1,1,1:3])
mask[1,1,1] = NA
print(mask[1,1,1:3])
mask[1,1,2] = NaN
print(mask[1,1,1:3])
mask
}
mask = run_checks(mask_file)
#> [1] 0 0 0
#> [1] NA 0 0
#> [1] NA NaN 0
tfile = tempfile(fileext = ".nii.gz")
writeNifti(mask, file = tfile)
run_checks(tfile)
#> [1] NA NaN 0
#> [1] NA NaN 0
#> [1] NA NaN 0
#> Image array of mode "double" (55.1 Mb)
#> - 182 x 218 x 182 voxels
#> - 1 x 1 x 1 mm per voxel
mask = readnii(tfile)
print(mask[1,1,1:3])
#> [1] NA NaN 0
tfile = tempfile(fileext = ".nii.gz")
writenii(mask, tfile)
mask = readnii(tfile)
print(mask[1,1,1:3])
#> [1] NA NaN 0
binary_mask = MNITemplate::readMNI()
binary_mask[binary_mask > 0] = 1
any(is.na(binary_mask))
#> [1] FALSE
na_mask = binary_mask
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
any(is.na(na_mask))
#> [1] TRUE
na_filepath = tempfile(fileext = "na_mask")
oro.nifti::writeNIfTI(na_mask, na_filepath)
#> [1] "/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T//RtmpuJeiqI/file85158fa327ena_mask.nii.gz"
tfile = paste0(na_filepath, ".nii.gz")
na_mask1 = oro.nifti::readNIfTI(tfile, reorient = FALSE)
print(na_mask1[1,1,1:3])
#> [1] NA NaN 0
any(is.na(na_mask1))
#> [1] TRUE
THIS WORKS FINE
mask = readNifti(tfile)
print(mask[1,1,1:3])
#> [1] NA NaN 0
## use readnii
readnii(tfile)[1,1,1:3]
#> [1] NA NaN 0
readnii(writenii(na_mask, tempfile()))[1,1, 1:3]
#> [1] NA NaN 0
na_mask1 = oro.nifti::readNIfTI(tfile, reorient = FALSE)
print(na_mask1[1,1,1:3])
#> [1] NA NaN 0
any(is.na(na_mask1))
#> [1] TRUE
mask = readNifti(tfile)
print(mask[1,1,1:3])
#> [1] NA NaN 0
file.remove(tfile)
#> [1] TRUE
file.remove(na_filepath)
#> Warning in file.remove(na_filepath): cannot remove file '/var/folders/1s/
#> wrtqcpxn685_zk570bnx9_rr0000gr/T//RtmpuJeiqI/file85158fa327ena_mask', reason 'No
#> such file or directory'
#> [1] FALSE
writenii(na_mask, tfile)
#> Warning in datatyper(nim, warn = warn): Need to change bitpix and datatype to
#> FLOAT64 due to NAs
mask = readNifti(tfile)
print(mask[1,1,1:3])
#> [1] NA NaN 0
na_mask = binary_mask
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
arr = as.array(na_mask)
arr[1,1,1:3]
#> [1] NA NaN 0
This is an RNifti
issue: NaN
turned to NA
asNifti(arr)[1,1,1:3]
#> [1] NA NA 0
writeNifti(mask, tfile_nif)
tmask = readNifti(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
nif = asNifti(arr)
tfile2 = tempfile(fileext = ".nii.gz")
writeNifti(nif, tfile2)
readNifti(tfile2)[1,1,1:3]
#> [1] NA NA 0
mask = readNifti(tfile)
print(mask[1,1,1:3])
#> [1] NA NaN 0
na_mask1 = readnii(paste0(na_filepath, ".nii.gz"))
na_mask1[1,1,1]
#> [1] NA
na_mask1[1,1,2]
#> [1] NaN
Created on 2020-09-03 by the reprex package (v0.3.0)
Here is with the CRAN (older) versions.
rm(list=ls())
library(RNifti)
library(oro.nifti)
#> oro.nifti 0.10.3
#>
#> Attaching package: 'oro.nifti'
#> The following object is masked from 'package:RNifti':
#>
#> origin
library(neurobase)
library(ANTsRCore)
#>
#> Attaching package: 'ANTsRCore'
#> The following objects are masked from 'package:oro.nifti':
#>
#> origin, origin<-
#> The following object is masked from 'package:RNifti':
#>
#> origin
#> The following objects are masked from 'package:stats':
#>
#> sd, var
#> The following objects are masked from 'package:base':
#>
#> all, any, apply, max, min, prod, range, sum
library(fslr)
mask_file = MNITemplate::getMNIPath("Brain_Mask")
mask_file = MNITemplate::getMNIPath("Brain_Mask")
mask = readNifti(mask_file)
mask[1,1,1] = NA
mask[1,1,2] = NaN
tfile_nif = tempfile(fileext = ".nii.gz")
writeNifti(mask, tfile_nif)
fslhd(tfile_nif)
#> Warning in get.fsl(): Setting fsl.path to /usr/local/fsl
#> Warning in get.fsloutput(): Can't find FSLOUTPUTTYPE, setting to NIFTI_GZ
#> FSLDIR='/usr/local/fsl'; PATH=${FSLDIR}/bin:${PATH};export PATH FSLDIR; sh "${FSLDIR}/etc/fslconf/fsl.sh"; FSLOUTPUTTYPE=NIFTI_GZ; export FSLOUTPUTTYPE; ${FSLDIR}/bin/fslhd "/private/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T/Rtmp9oK9Ay/file86ff4905e8ec.nii.gz"
#> [1] "filename /private/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T/Rtmp9oK9Ay/file86ff4905e8ec.nii.gz"
#> [2] ""
#> [3] "sizeof_hdr 348"
#> [4] "data_type FLOAT64"
#> [5] "dim0 3"
#> [6] "dim1 182"
#> [7] "dim2 218"
#> [8] "dim3 182"
#> [9] "dim4 1"
#> [10] "dim5 1"
#> [11] "dim6 1"
#> [12] "dim7 1"
#> [13] "vox_units mm"
#> [14] "time_units s"
#> [15] "datatype 64"
#> [16] "nbyper 8"
#> [17] "bitpix 64"
#> [18] "pixdim0 0.000000"
#> [19] "pixdim1 1.000000"
#> [20] "pixdim2 1.000000"
#> [21] "pixdim3 1.000000"
#> [22] "pixdim4 0.000000"
#> [23] "pixdim5 0.000000"
#> [24] "pixdim6 0.000000"
#> [25] "pixdim7 0.000000"
#> [26] "vox_offset 352"
#> [27] "cal_max 1.0000"
#> [28] "cal_min 0.0000"
#> [29] "scl_slope 0.000000"
#> [30] "scl_inter 0.000000"
#> [31] "phase_dim 0"
#> [32] "freq_dim 0"
#> [33] "slice_dim 0"
#> [34] "slice_name Unknown"
#> [35] "slice_code 0"
#> [36] "slice_start 0"
#> [37] "slice_end 0"
#> [38] "slice_duration 0.000000"
#> [39] "time_offset 0.000000"
#> [40] "intent Unknown"
#> [41] "intent_code 0"
#> [42] "intent_name "
#> [43] "intent_p1 0.000000"
#> [44] "intent_p2 0.000000"
#> [45] "intent_p3 0.000000"
#> [46] "qform_name MNI_152"
#> [47] "qform_code 4"
#> [48] "qto_xyz:1 -1.000000 0.000000 -0.000000 90.000000"
#> [49] "qto_xyz:2 0.000000 1.000000 -0.000000 -126.000000"
#> [50] "qto_xyz:3 0.000000 0.000000 1.000000 -72.000000"
#> [51] "qto_xyz:4 0.000000 0.000000 0.000000 1.000000"
#> [52] "qform_xorient Right-to-Left"
#> [53] "qform_yorient Posterior-to-Anterior"
#> [54] "qform_zorient Inferior-to-Superior"
#> [55] "sform_name MNI_152"
#> [56] "sform_code 4"
#> [57] "sto_xyz:1 -1.000000 0.000000 0.000000 90.000000"
#> [58] "sto_xyz:2 0.000000 1.000000 0.000000 -126.000000"
#> [59] "sto_xyz:3 0.000000 0.000000 1.000000 -72.000000"
#> [60] "sto_xyz:4 0.000000 0.000000 0.000000 1.000000"
#> [61] "sform_xorient Right-to-Left"
#> [62] "sform_yorient Posterior-to-Anterior"
#> [63] "sform_zorient Inferior-to-Superior"
#> [64] "file_type NIFTI-1+"
#> [65] "file_code 1"
#> [66] "descrip FSL4.0eta"
#> [67] "aux_file "
tmask = readNifti(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
tmask = readnii(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
arr = array(mask, dim = dim(mask))
arr[1,1,1:3]
#> [1] NA NaN 0
asNifti(arr)[1,1,1:3]
#> [1] NA NaN 0
writeNifti(arr, tfile_nif)
tmask = readNifti(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
tmask = readNIfTI(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
tmask
#> NIfTI-1 format
#> Type : nifti
#> Data Type : 64 (FLOAT64)
#> Bits per Pixel : 64
#> Slice Code : 0 (Unknown)
#> Intent Code : 0 (None)
#> Qform Code : 0 (Unknown)
#> Sform Code : 0 (Unknown)
#> Dimension : 182 x 218 x 182
#> Pixel Dimension : 1 x 1 x 1
#> Voxel Units : Unknown
#> Time Units : Unknown
tmask = readnii(tfile_nif)
tmask[1,1,1:3]
#> [1] NA NaN 0
run_checks = function(file) {
mask = readNifti(file)
print(mask[1,1,1:3])
mask[1,1,1] = NA
print(mask[1,1,1:3])
mask[1,1,2] = NaN
print(mask[1,1,1:3])
mask
}
mask = run_checks(mask_file)
#> [1] 0 0 0
#> [1] NA 0 0
#> [1] NA NaN 0
tfile = tempfile(fileext = ".nii.gz")
writeNifti(mask, file = tfile)
run_checks(tfile)
#> [1] NA NaN 0
#> [1] NA NaN 0
#> [1] NA NaN 0
#> Image array of mode "double" (55.1 Mb)
#> - 182 x 218 x 182 voxels
#> - 1 x 1 x 1 mm per voxel
mask = readnii(tfile)
print(mask[1,1,1:3])
#> [1] NA NaN 0
tfile = tempfile(fileext = ".nii.gz")
writenii(mask, tfile)
mask = readnii(tfile)
print(mask[1,1,1:3])
#> [1] NA NaN 0
binary_mask = MNITemplate::readMNI()
binary_mask[binary_mask > 0] = 1
any(is.na(binary_mask))
#> [1] FALSE
na_mask = binary_mask
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
any(is.na(na_mask))
#> [1] TRUE
na_filepath = tempfile(fileext = "na_mask")
oro.nifti::writeNIfTI(na_mask, na_filepath)
tfile = paste0(na_filepath, ".nii.gz")
na_mask1 = oro.nifti::readNIfTI(tfile, reorient = FALSE)
print(na_mask1[1,1,1:3])
#> [1] NA NaN 0
any(is.na(na_mask1))
#> [1] TRUE
HERE IS A BAD LINE:
mask = readNifti(tfile)
print(mask[1,1,1:3])
#> [1] 2.738137e-42 0.000000e+00 0.000000e+00
## use readnii
readnii(tfile)[1,1,1:3]
#> [1] NA NaN 0
readnii(writenii(na_mask, tempfile()))[1,1, 1:3]
#> Error in strsplit(fname, "/"): non-character argument
na_mask1 = oro.nifti::readNIfTI(tfile, reorient = FALSE)
print(na_mask1[1,1,1:3])
#> [1] NA NaN 0
any(is.na(na_mask1))
#> [1] TRUE
mask = readNifti(tfile)
print(mask[1,1,1:3])
#> [1] 2.738137e-42 0.000000e+00 0.000000e+00
file.remove(tfile)
#> [1] TRUE
file.remove(na_filepath)
#> [1] FALSE
writenii(na_mask, tfile)
mask = readNifti(tfile)
print(mask[1,1,1:3])
#> [1] 2.738137e-42 0.000000e+00 0.000000e+00
na_mask = binary_mask
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
arr = as.array(na_mask)
arr[1,1,1:3]
#> [1] NA NaN 0
This is an RNifti
issue: NaN
turned to NA
asNifti(arr)[1,1,1:3]
#> [1] NA NA 0
writeNifti(mask, tfile_nif)
tmask = readNifti(tfile_nif)
tmask[1,1,1:3]
#> [1] 2.738137e-42 0.000000e+00 0.000000e+00
nif = asNifti(arr)
tfile2 = tempfile(fileext = ".nii.gz")
writeNifti(nif, tfile2)
readNifti(tfile2)[1,1,1:3]
#> [1] NA NA 0
mask = readNifti(tfile)
print(mask[1,1,1:3])
#> [1] 2.738137e-42 0.000000e+00 0.000000e+00
na_mask1 = readnii(paste0(na_filepath, ".nii.gz"))
na_mask1[1,1,1]
#> [1] NA
na_mask1[1,1,2]
#> [1] NaN
Created on 2020-09-03 by the reprex package (v0.3.0)
I think here is a more concise reprex and now seeing what's going on with ANTsRCore
. Here it is with the newer GitHub versions of oro.nifti
and neurobase
:
rm(list=ls())
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))
suppressPackageStartupMessages(library(ANTsRCore))
printer = function(file) {
print("readNIfTI")
print(readNIfTI(tfile, reorient = FALSE)[1,1,1:3])
print("readNifti")
print(readNifti(tfile)[1,1,1:3])
print("readnii")
print(readnii(tfile)[1,1,1:3])
print("antsImageRead")
print(c(antsImageRead(tfile)[1,1,1:3]))
}
mask_file = MNITemplate::getMNIPath("Brain_Mask")
nifti
object reading with oro.nifti
binary_mask = readNIfTI(mask_file, reorient = FALSE)
na_mask = binary_mask
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
any(is.na(na_mask))
#> [1] TRUE
na_mask[1,1,1:3]
#> [1] NA NaN 0
na_filepath = tempfile(fileext = "na_mask")
tfile = paste0(na_filepath, ".nii.gz")
oro.nifti::writeNIfTI(na_mask, na_filepath)
#> [1] "/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T//Rtmp6fyOcx/file8b353f1febcbna_mask.nii.gz"
printer(tfile)
#> [1] "readNIfTI"
#> [1] NA NaN 0
#> [1] "readNifti"
#> [1] NA NaN 0
#> [1] "readnii"
#> [1] NA NaN 0
#> [1] "antsImageRead"
#> [1] 0 0 0
writenii(na_mask, tfile)
#> Warning in datatyper(nim, warn = warn): Need to change bitpix and datatype to
#> FLOAT64 due to NAs
printer(tfile)
#> [1] "readNIfTI"
#> [1] NA NaN 0
#> [1] "readNifti"
#> [1] NA NaN 0
#> [1] "readnii"
#> [1] NA NaN 0
#> [1] "antsImageRead"
#> [1] 0 0 0
writeNifti(na_mask, tfile)
printer(tfile)
#> [1] "readNIfTI"
#> [1] NaN NaN 0
#> [1] "readNifti"
#> [1] NaN NaN 0
#> [1] "readnii"
#> [1] NaN NaN 0
#> [1] "antsImageRead"
#> [1] 0 0 0
nifti
object - but with readnii
binary_mask = readnii(mask_file)
na_mask = binary_mask
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
any(is.na(na_mask))
#> [1] TRUE
na_mask[1,1,1:3]
#> [1] NA NaN 0
writenii(na_mask, tfile)
#> Warning in datatyper(nim, warn = warn): Need to change bitpix and datatype to
#> FLOAT64 due to NAs
printer(tfile)
#> [1] "readNIfTI"
#> [1] NA NaN 0
#> [1] "readNifti"
#> [1] NA NaN 0
#> [1] "readnii"
#> [1] NA NaN 0
#> [1] "antsImageRead"
#> [1] 0 0 0
writeNIfTI(na_mask, tfile)
#> [1] "/var/folders/1s/wrtqcpxn685_zk570bnx9_rr0000gr/T//Rtmp6fyOcx/file8b353f1febcbna_mask.nii.gz.nii.gz"
printer(tfile)
#> [1] "readNIfTI"
#> [1] NA NaN 0
#> [1] "readNifti"
#> [1] NA NaN 0
#> [1] "readnii"
#> [1] NA NaN 0
#> [1] "antsImageRead"
#> [1] 0 0 0
writeNifti(na_mask, tfile)
printer(tfile)
#> [1] "readNIfTI"
#> [1] NA NA 0
#> [1] "readNifti"
#> [1] NA NA 0
#> [1] "readnii"
#> Warning in datatyper(nim, warn = warn): Need to change bitpix and datatype to
#> FLOAT64 due to NAs
#> [1] NA NA 0
#> [1] "antsImageRead"
#> [1] -2147483648 -2147483648 0
We see that the NaN
becomes NA
, even for readNifti
binary_mask = readNifti(mask_file)
na_mask = binary_mask
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
any(is.na(na_mask))
#> [1] TRUE
na_mask[1,1,1:3]
#> [1] NA NaN 0
writeNifti(na_mask, tfile)
printer(tfile)
#> [1] "readNIfTI"
#> [1] NA NaN 0
#> [1] "readNifti"
#> [1] NA NaN 0
#> [1] "readnii"
#> [1] NA NaN 0
#> [1] "antsImageRead"
#> [1] 0 0 0
Other writers don’t work for that object
binary_mask = antsImageRead(mask_file)
na_mask = binary_mask
na_mask[1,1,1] = NA
#> Error in na_mask[1, 1, 1] = NA: object of type 'S4' is not subsettable
na_mask[1,1,2] = NaN
any(is.na(na_mask))
#> Warning in base::any(x, ..., na.rm = na.rm): coercing argument of type 'double'
#> to logical
#> [1] TRUE
na_mask[1,1,1:3]
#> , , 1
#>
#> [,1]
#> [1,] 0
#>
#> , , 2
#>
#> [,1]
#> [1,] NaN
#>
#> , , 3
#>
#> [,1]
#> [1,] 0
antsImageWrite(na_mask, tfile)
printer(tfile)
#> [1] "readNIfTI"
#> [1] 0 NaN 0
#> [1] "readNifti"
#> [1] 0 NaN 0
#> [1] "readnii"
#> Warning in datatyper(nim, warn = warn): Need to change bitpix and datatype to
#> FLOAT64 due to NAs
#> [1] 0 NaN 0
#> [1] "antsImageRead"
#> [1] 0 0 0
Need to make
na_mask = as.array(binary_mask)
na_mask[1,1,1] = NA
na_mask[1,1,2] = NaN
na_mask = as.antsImage(na_mask, reference = binary_mask)
any(is.na(na_mask))
#> Warning in base::any(x, ..., na.rm = na.rm): coercing argument of type 'double'
#> to logical
#> [1] TRUE
na_mask[1,1,1:3]
#> , , 1
#>
#> [,1]
#> [1,] NaN
#>
#> , , 2
#>
#> [,1]
#> [1,] NaN
#>
#> , , 3
#>
#> [,1]
#> [1,] 0
antsImageWrite(na_mask, tfile)
printer(tfile)
#> [1] "readNIfTI"
#> [1] NaN NaN 0
#> [1] "readNifti"
#> [1] NaN NaN 0
#> [1] "readnii"
#> Warning in datatyper(nim, warn = warn): Need to change bitpix and datatype to
#> FLOAT64 due to NAs
#> [1] NaN NaN 0
#> [1] "antsImageRead"
#> [1] 0 0 0
Other writers don’t work for that object Created on 2020-09-03 by the reprex package (v0.3.0)
@stnava @jonclayden @bjw34032 - this may be interesting to talk about with respect to NA
or NaN
Happy to discuss, although I'm slightly lost about the crux of the issue here. When I boil down one of the examples above it appears to work as expected with current RNifti
:
library(RNifti)
mask <- readNifti(MNITemplate::getMNIPath("Brain_Mask"))
mask[1,1,1] <- NA
mask[1,1,2] <- NaN
arr <- array(mask, dim = dim(mask))
arr[1,1,1:3]
# [1] NA NaN 0
asNifti(arr)[1,1,1:3]
# [1] NA NaN 0
nif <- asNifti(arr)
tfile2 <- tempfile(fileext = ".nii.gz")
writeNifti(nif, tfile2)
readNifti(tfile2)[1,1,1:3]
# [1] NA NaN 0
A couple of points that may or may not be relevant:
RNifti
fences out this behaviour because obviously it prevents this kind of NA propagation from working properly.NA_INTEGER
(aka INT_MIN
) specially, and may therefore convert integer NAs to a large negative floating-point value when changing the datatype of an image.I guess I'm just more surprised about this case:
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)
OK, thanks – I'll pick this up on the RNifti
issue thread.
the ants2oro function needs to have a dtype option passed to neurobase::writenii. Since changes to neurobase::writenii to fix previous NA bug fix the behavior of dtype for any other package functions that call neurobase::writenii need to allow for this option to be passed in the event of NA values.