1# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- 2# vi: set ft=python sts=4 ts=4 sw=4 et: 3### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## 4# 5# See COPYING file distributed along with the NiBabel package for the 6# copyright and license terms. 7# 8### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## 9""" Testing spatialimages 10 11""" 12from ..py3k import BytesIO 13 14import numpy as np 15 16from ..spatialimages import (Header, SpatialImage, HeaderDataError, 17 ImageDataError) 18 19from unittest import TestCase 20 21from nose.tools import (assert_true, assert_false, assert_equal, 22 assert_not_equal, assert_raises) 23 24from numpy.testing import assert_array_equal, assert_array_almost_equal 25 26 27def test_header_init(): 28 # test the basic header 29 hdr = Header() 30 assert_equal(hdr.get_data_dtype(), np.dtype(np.float32)) 31 assert_equal(hdr.get_data_shape(), (0,)) 32 assert_equal(hdr.get_zooms(), (1.0,)) 33 hdr = Header(np.float64) 34 assert_equal(hdr.get_data_dtype(), np.dtype(np.float64)) 35 assert_equal(hdr.get_data_shape(), (0,)) 36 assert_equal(hdr.get_zooms(), (1.0,)) 37 hdr = Header(np.float64, shape=(1,2,3)) 38 assert_equal(hdr.get_data_dtype(), np.dtype(np.float64)) 39 assert_equal(hdr.get_data_shape(), (1,2,3)) 40 assert_equal(hdr.get_zooms(), (1.0, 1.0, 1.0)) 41 hdr = Header(np.float64, shape=(1,2,3), zooms=None) 42 assert_equal(hdr.get_data_dtype(), np.dtype(np.float64)) 43 assert_equal(hdr.get_data_shape(), (1,2,3)) 44 assert_equal(hdr.get_zooms(), (1.0, 1.0, 1.0)) 45 hdr = Header(np.float64, shape=(1,2,3), zooms=(3.0, 2.0, 1.0)) 46 assert_equal(hdr.get_data_dtype(), np.dtype(np.float64)) 47 assert_equal(hdr.get_data_shape(), (1,2,3)) 48 assert_equal(hdr.get_zooms(), (3.0, 2.0, 1.0)) 49 50 51def test_from_header(): 52 # check from header class method. Note equality checks below, 53 # equality methods used here too. 54 empty = Header.from_header() 55 assert_equal(Header(), empty) 56 empty = Header.from_header(None) 57 assert_equal(Header(), empty) 58 hdr = Header(np.float64, shape=(1,2,3), zooms=(3.0, 2.0, 1.0)) 59 copy = Header.from_header(hdr) 60 assert_equal(hdr, copy) 61 assert_false(hdr is copy) 62 class C(object): 63 def get_data_dtype(self): return np.dtype('u2') 64 def get_data_shape(self): return (5,4,3) 65 def get_zooms(self): return (10.0, 9.0, 8.0) 66 converted = Header.from_header(C()) 67 assert_true(isinstance(converted, Header)) 68 assert_equal(converted.get_data_dtype(), np.dtype('u2')) 69 assert_equal(converted.get_data_shape(), (5,4,3)) 70 assert_equal(converted.get_zooms(), (10.0,9.0,8.0)) 71 72 73def test_eq(): 74 hdr = Header() 75 other = Header() 76 assert_equal(hdr, other) 77 other = Header('u2') 78 assert_not_equal(hdr, other) 79 other = Header(shape=(1,2,3)) 80 assert_not_equal(hdr, other) 81 hdr = Header(shape=(1,2)) 82 other = Header(shape=(1,2)) 83 assert_equal(hdr, other) 84 other = Header(shape=(1,2), zooms=(2.0,3.0)) 85 assert_not_equal(hdr, other) 86 87 88def test_copy(): 89 # test that copy makes independent copy 90 hdr = Header(np.float64, shape=(1,2,3), zooms=(3.0, 2.0, 1.0)) 91 hdr_copy = hdr.copy() 92 hdr.set_data_shape((4,5,6)) 93 assert_equal(hdr.get_data_shape(), (4,5,6)) 94 assert_equal(hdr_copy.get_data_shape(), (1,2,3)) 95 hdr.set_zooms((4,5,6)) 96 assert_equal(hdr.get_zooms(), (4,5,6)) 97 assert_equal(hdr_copy.get_zooms(), (3,2,1)) 98 hdr.set_data_dtype(np.uint8) 99 assert_equal(hdr.get_data_dtype(), np.dtype(np.uint8)) 100 assert_equal(hdr_copy.get_data_dtype(), np.dtype(np.float64)) 101 102 103def test_shape_zooms(): 104 hdr = Header() 105 hdr.set_data_shape((1, 2, 3)) 106 assert_equal(hdr.get_data_shape(), (1,2,3)) 107 assert_equal(hdr.get_zooms(), (1.0,1.0,1.0)) 108 hdr.set_zooms((4, 3, 2)) 109 assert_equal(hdr.get_zooms(), (4.0,3.0,2.0)) 110 hdr.set_data_shape((1, 2)) 111 assert_equal(hdr.get_data_shape(), (1,2)) 112 assert_equal(hdr.get_zooms(), (4.0,3.0)) 113 hdr.set_data_shape((1, 2, 3)) 114 assert_equal(hdr.get_data_shape(), (1,2,3)) 115 assert_equal(hdr.get_zooms(), (4.0,3.0,1.0)) 116 # null shape is (0,) 117 hdr.set_data_shape(()) 118 assert_equal(hdr.get_data_shape(), (0,)) 119 assert_equal(hdr.get_zooms(), (1.0,)) 120 # zooms of wrong lengths raise error 121 assert_raises(HeaderDataError, hdr.set_zooms, (4.0, 3.0)) 122 assert_raises(HeaderDataError, 123 hdr.set_zooms, 124 (4.0, 3.0, 2.0, 1.0)) 125 # as do negative zooms 126 assert_raises(HeaderDataError, 127 hdr.set_zooms, 128 (4.0, 3.0, -2.0)) 129 130 131def test_data_dtype(): 132 hdr = Header() 133 assert_equal(hdr.get_data_dtype(), np.dtype(np.float32)) 134 hdr.set_data_dtype(np.float64) 135 assert_equal(hdr.get_data_dtype(), np.dtype(np.float64)) 136 hdr.set_data_dtype('u2') 137 assert_equal(hdr.get_data_dtype(), np.dtype(np.uint16)) 138 139 140def test_affine(): 141 hdr = Header(np.float64, shape=(1,2,3), zooms=(3.0, 2.0, 1.0)) 142 assert_array_almost_equal(hdr.get_default_affine(), 143 [[-3.0,0,0,0], 144 [0,2,0,-1], 145 [0,0,1,-1], 146 [0,0,0,1]]) 147 hdr.default_x_flip = False 148 assert_array_almost_equal(hdr.get_default_affine(), 149 [[3.0,0,0,0], 150 [0,2,0,-1], 151 [0,0,1,-1], 152 [0,0,0,1]]) 153 assert_array_equal(hdr.get_base_affine(), 154 hdr.get_default_affine()) 155 156 157def test_read_data(): 158 hdr = Header(np.int32, shape=(1,2,3), zooms=(3.0, 2.0, 1.0)) 159 fobj = BytesIO() 160 data = np.arange(6).reshape((1,2,3)) 161 hdr.data_to_fileobj(data, fobj) 162 assert_equal(fobj.getvalue(), 163 data.astype(np.int32).tostring(order='F')) 164 fobj.seek(0) 165 data2 = hdr.data_from_fileobj(fobj) 166 assert_array_equal(data, data2) 167 168 169class DataLike(object): 170 # Minimal class implementing 'data' API 171 shape = (3,) 172 def __array__(self): 173 return np.arange(3) 174 175 176class TestSpatialImage(TestCase): 177 # class for testing images 178 image_class = SpatialImage 179 180 def test_isolation(self): 181 # Test image isolated from external changes to header and affine 182 img_klass = self.image_class 183 arr = np.arange(3, dtype=np.int16) 184 aff = np.eye(4) 185 img = img_klass(arr, aff) 186 assert_array_equal(img.get_affine(), aff) 187 aff[0,0] = 99 188 assert_false(np.all(img.get_affine() == aff)) 189 # header, created by image creation 190 ihdr = img.get_header() 191 # Pass it back in 192 img = img_klass(arr, aff, ihdr) 193 # Check modifying header outside does not modify image 194 ihdr.set_zooms((4,)) 195 assert_not_equal(img.get_header(), ihdr) 196 197 def test_float_affine(self): 198 # Check affines get converted to float 199 img_klass = self.image_class 200 arr = np.arange(3, dtype=np.int16) 201 img = img_klass(arr, np.eye(4, dtype=np.float32)) 202 assert_equal(img.get_affine().dtype, np.dtype(np.float64)) 203 img = img_klass(arr, np.eye(4, dtype=np.int16)) 204 assert_equal(img.get_affine().dtype, np.dtype(np.float64)) 205 206 def test_images(self): 207 # Assumes all possible images support int16 208 # See https://github.com/nipy/nibabel/issues/58 209 arr = np.arange(3, dtype=np.int16) 210 img = self.image_class(arr, None) 211 assert_array_equal(img.get_data(), arr) 212 assert_equal(img.get_affine(), None) 213 hdr = self.image_class.header_class() 214 hdr.set_data_shape(arr.shape) 215 hdr.set_data_dtype(arr.dtype) 216 assert_equal(img.get_header(), hdr) 217 218 def test_data_api(self): 219 # Test minimal api data object can initialize 220 img = self.image_class(DataLike(), None) 221 assert_array_equal(img.get_data(), np.arange(3)) 222 assert_equal(img.shape, (3,)) 223 224 def test_data_default(self): 225 # check that the default dtype comes from the data if the header 226 # is None, and that unsupported dtypes raise an error 227 img_klass = self.image_class 228 hdr_klass = self.image_class.header_class 229 data = np.arange(24, dtype=np.int32).reshape((2,3,4)) 230 affine = np.eye(4) 231 img = img_klass(data, affine) 232 assert_equal(data.dtype, img.get_data_dtype()) 233 header = hdr_klass() 234 img = img_klass(data, affine, header) 235 assert_equal(img.get_data_dtype(), np.dtype(np.float32)) 236 237 def test_data_shape(self): 238 # Check shape correctly read 239 img_klass = self.image_class 240 # Assumes all possible images support int16 241 # See https://github.com/nipy/nibabel/issues/58 242 arr = np.arange(4, dtype=np.int16) 243 img = img_klass(arr, np.eye(4)) 244 assert_equal(img.shape, (4,)) 245 img = img_klass(np.zeros((2,3,4)), np.eye(4)) 246 assert_equal(img.shape, (2,3,4)) 247 248 def test_str(self): 249 # Check something comes back from string representation 250 img_klass = self.image_class 251 # Assumes all possible images support int16 252 # See https://github.com/nipy/nibabel/issues/58 253 arr = np.arange(5, dtype=np.int16) 254 img = img_klass(arr, np.eye(4)) 255 assert_true(len(str(img)) > 0) 256 assert_equal(img.shape, (5,)) 257 img = img_klass(np.zeros((2,3,4), dtype=np.int16), np.eye(4)) 258 assert_true(len(str(img)) > 0) 259 260 def test_get_shape(self): 261 # Check there is a get_shape method 262 # (it is deprecated) 263 img_klass = self.image_class 264 # Assumes all possible images support int16 265 # See https://github.com/nipy/nibabel/issues/58 266 img = img_klass(np.arange(1, dtype=np.int16), np.eye(4)) 267 assert_equal(img.get_shape(), (1,)) 268 img = img_klass(np.zeros((2,3,4), np.int16), np.eye(4)) 269 assert_equal(img.get_shape(), (2,3,4)) 270