Package mvpa :: Package tests :: Module test_niftidataset
[hide private]
[frames] | no frames]

Source Code for Module mvpa.tests.test_niftidataset

  1  # emacs: -*- mode: python; 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 PyMVPA package for the 
  6  #   copyright and license terms. 
  7  # 
  8  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## 
  9  """Unit tests for PyMVPA nifti dataset""" 
 10   
 11  import unittest 
 12  import os.path 
 13  import numpy as N 
 14   
 15  from mvpa import pymvpa_dataroot 
 16  from mvpa.datasets.nifti import * 
 17  from mvpa.misc.exceptions import * 
 18  from mvpa.misc.fsl import FslEV3 
 19  from mvpa.misc.support import Event 
 20   
21 -class NiftiDatasetTests(unittest.TestCase):
22 """Tests of various Nifti-based datasets 23 """ 24
25 - def testNiftiDataset(self):
26 """Basic testing of NiftiDataset 27 """ 28 data = NiftiDataset(samples=os.path.join(pymvpa_dataroot,'example4d'), 29 labels=[1,2]) 30 self.failUnless(data.nfeatures == 294912) 31 self.failUnless(data.nsamples == 2) 32 33 self.failUnless((data.mapper.metric.elementsize \ 34 == data.niftihdr['pixdim'][3:0:-1]).all()) 35 36 #check that mapper honours elementsize 37 nb22 = N.array([i for i in data.mapper.getNeighborIn((1, 1, 1), 2.2)]) 38 nb20 = N.array([i for i in data.mapper.getNeighborIn((1, 1, 1), 2.0)]) 39 self.failUnless(nb22.shape[0] == 7) 40 self.failUnless(nb20.shape[0] == 5) 41 42 # Can't rely on released pynifties, so doing really vague testing 43 # XXX 44 self.failUnless(data.dt in [2.0, 2000.0]) 45 self.failUnless(data.samplingrate in [5e-4, 5e-1]) 46 merged = data + data 47 48 self.failUnless(merged.nfeatures == 294912) 49 self.failUnless(merged.nsamples == 4) 50 51 # check that the header survives 52 #self.failUnless(merged.niftihdr == data.niftihdr) 53 for k in merged.niftihdr.keys(): 54 self.failUnless(N.mean(merged.niftihdr[k] == data.niftihdr[k]) == 1) 55 56 # throw away old dataset and see if new one survives 57 del data 58 self.failUnless(merged.samples[3, 120000] == merged.samples[1, 120000]) 59 60 # check whether we can use a plain ndarray as mask 61 mask = N.zeros((24, 96, 128), dtype='bool') 62 mask[12, 20, 40] = True 63 nddata = NiftiDataset(samples=os.path.join(pymvpa_dataroot,'example4d'), 64 labels=[1,2], 65 mask=mask) 66 self.failUnless(nddata.nfeatures == 1) 67 rmap = nddata.mapReverse([44]) 68 self.failUnless(rmap.shape == (24, 96, 128)) 69 self.failUnless(N.sum(rmap) == 44) 70 self.failUnless(rmap[12, 20, 40] == 44)
71 72
73 - def testNiftiMapper(self):
74 """Basic testing of map2Nifti 75 """ 76 data = NiftiDataset(samples=os.path.join(pymvpa_dataroot,'example4d'), 77 labels=[1,2]) 78 79 # test mapping of ndarray 80 vol = data.map2Nifti(N.ones((294912,), dtype='int16')) 81 self.failUnless(vol.data.shape == (24, 96, 128)) 82 self.failUnless((vol.data == 1).all()) 83 84 # test mapping of the dataset 85 vol = data.map2Nifti(data) 86 self.failUnless(vol.data.shape == (2, 24, 96, 128))
87 88
89 - def testNiftiSelfMapper(self):
90 """Test map2Nifti facility ran without arguments 91 """ 92 example_path = os.path.join(pymvpa_dataroot, 'example4d') 93 example = NiftiImage(example_path) 94 data = NiftiDataset(samples=example_path, 95 labels=[1,2]) 96 97 # Map read data to itself 98 vol = data.map2Nifti() 99 100 self.failUnless(vol.data.shape == example.data.shape) 101 self.failUnless((vol.data == example.data).all()) 102 103 data.samples[:] = 1 104 vol = data.map2Nifti() 105 self.failUnless((vol.data == 1).all())
106 107
108 - def testMultipleCalls(self):
109 """Test if doing exactly the same operation twice yields the same result 110 """ 111 data = NiftiDataset(samples=os.path.join(pymvpa_dataroot,'example4d'), 112 labels=1) 113 data2 = NiftiDataset(samples=os.path.join(pymvpa_dataroot,'example4d'), 114 labels=1) 115 116 # Currently this test fails and I don't know why! 117 # The problem occurs, because in the second call to 118 # NiftiDataset.__init__() there is already a dsattr that has a 'mapper' 119 # key, although dsattr is set to be an empty dict. Therefore the 120 # constructor does not set the proper elementsize, because it thinks 121 # there is already a mapper present. Actually this test is just looking 122 # for a symptom of a buggy dsattr handling. 123 # The tricky part is: I have no clue, what is going on... :( 124 self.failUnless((data.mapper.metric.elementsize \ 125 == data2.mapper.metric.elementsize).all())
126 127
128 - def testERNiftiDataset(self):
129 """Basic testing of ERNiftiDataset 130 """ 131 self.failUnlessRaises(DatasetError, ERNiftiDataset) 132 133 # setup data sources 134 tssrc = os.path.join(pymvpa_dataroot, 'bold') 135 evsrc = os.path.join(pymvpa_dataroot, 'fslev3.txt') 136 # masrc = os.path.join(pymvpa_dataroot, 'mask') 137 evs = FslEV3(evsrc).toEvents() 138 139 # more failure ;-) 140 # no label! 141 self.failUnlessRaises(ValueError, ERNiftiDataset, 142 samples=tssrc, events=evs) 143 144 # set some label for each ev 145 for ev in evs: 146 ev['label'] = 1 147 148 # for real! 149 # using TR from nifti header 150 ds = ERNiftiDataset(samples=tssrc, events=evs) 151 152 # 40x20 volume, 9 volumes per sample + 1 intensity score = 7201 features 153 self.failUnless(ds.nfeatures == 7201) 154 self.failUnless(ds.nsamples == len(evs)) 155 156 # check samples 157 origsamples = getNiftiFromAnySource(tssrc).data 158 for i, ev in enumerate(evs): 159 self.failUnless((ds.samples[i][:-1] \ 160 == origsamples[ev['onset']:ev['onset'] + ev['duration']].ravel() 161 ).all()) 162 163 # do again -- with conversion 164 ds = ERNiftiDataset(samples=tssrc, events=evs, evconv=True, 165 storeoffset=True) 166 self.failUnless(ds.nsamples == len(evs)) 167 # TR=2.5, 40x20 volume, 9 second per sample (4volumes), 1 intensity 168 # score + 1 offset = 3202 features 169 self.failUnless(ds.nfeatures == 3202) 170 171 # map back into voxel space, should ignore addtional features 172 nim = ds.map2Nifti() 173 self.failUnless(nim.data.shape == origsamples.shape) 174 # check shape of a single sample 175 nim = ds.map2Nifti(ds.samples[0]) 176 self.failUnless(nim.data.shape == (4, 1, 20, 40))
177 178
180 """Some mapping testing -- more tests is better 181 """ 182 sample_size = (4, 3, 2) 183 samples = N.arange(120).reshape((5,) + sample_size) 184 dsmask = N.arange(24).reshape(sample_size)%2 185 ds = ERNiftiDataset(samples=NiftiImage(samples), 186 events=[Event(onset=0, duration=2, label=1, 187 chunk=1, features=[1000, 1001]), 188 Event(onset=1, duration=2, label=2, 189 chunk=1, features=[2000, 2001])], 190 mask=dsmask) 191 nfeatures = ds.mapper._mappers[1].getInSize() 192 mask = N.zeros(sample_size) 193 mask[0, 0, 0] = mask[1, 0, 1] = mask[0, 0, 1] = 1 # select only 3 194 # but since 0th is masked out in the dataset, we should end up 195 # selecting only 2 from the dataset 196 #sel_orig_features = [1, 7] 197 198 # select using mask in volume and all features in the other part 199 ds_sel = ds.selectFeatures( 200 ds.mapper.forward([mask, [1]*nfeatures]).nonzero()[0]) 201 202 # now tests 203 self.failUnless((mask.reshape(24).nonzero()[0] == [0, 1, 7]).all()) 204 self.failUnless(ds_sel.samples.shape == (2, 6), 205 msg="We should have selected all samples, and 6 " 206 "features (2 voxels at 2 timepoints + 2 features). " 207 "Got %s" % (ds_sel.samples.shape,)) 208 self.failUnless((ds_sel.samples[:, -2:] == 209 [[1000, 1001], [2000, 2001]]).all(), 210 msg="We should have selected additional features " 211 "correctly. Got %s" % ds_sel.samples[:, -2:]) 212 self.failUnless((ds_sel.samples[:, :-2] == 213 [[ 1, 7, 25, 31], 214 [ 25, 31, 49, 55]]).all(), 215 msg="We should have selected original features " 216 "correctly. Got %s" % ds_sel.samples[:, :-2])
217 218
219 - def testNiftiDatasetFrom3D(self):
220 """Test NiftiDataset based on 3D volume(s) 221 """ 222 tssrc = os.path.join(pymvpa_dataroot, 'bold') 223 masrc = os.path.join(pymvpa_dataroot, 'mask') 224 225 # Test loading of 3D volumes 226 227 # it should puke if we are not enforcing 4D: 228 self.failUnlessRaises(Exception, NiftiDataset, 229 masrc, mask=masrc, labels=1, enforce4D=False) 230 # by default we are enforcing it 231 ds = NiftiDataset(masrc, mask=masrc, labels=1) 232 233 plain_data = NiftiImage(masrc).data 234 # Lets check if mapping back works as well 235 self.failUnless(N.all(plain_data == \ 236 ds.map2Nifti().data.reshape(plain_data.shape))) 237 238 # test loading from a list of filenames 239 240 # for now we should fail if trying to load a mix of 4D and 3D volumes 241 self.failUnlessRaises(ValueError, NiftiDataset, (masrc, tssrc), 242 mask=masrc, labels=1) 243 244 # Lets prepare some custom NiftiImage 245 dsfull = NiftiDataset(tssrc, mask=masrc, labels=1) 246 ds_selected = dsfull['samples', [3]] 247 nifti_selected = ds_selected.map2Nifti() 248 249 # Load dataset from a mix of 3D volumes 250 # (given by filenames and NiftiImages) 251 labels = [123, 2, 123] 252 ds2 = NiftiDataset((masrc, masrc, nifti_selected), 253 mask=masrc, labels=labels) 254 self.failUnless(ds2.nsamples == 3) 255 self.failUnless((ds2.samples[0] == ds2.samples[1]).all()) 256 self.failUnless((ds2.samples[2] == dsfull.samples[3]).all()) 257 self.failUnless((ds2.labels == labels).all())
258
260 """Test if we could request neighbors within spherical ROI whenever 261 center is outside of the mask 262 """ 263 264 # check whether we can use a plain ndarray as mask 265 mask_roi = N.zeros((24, 96, 128), dtype='bool') 266 mask_roi[12, 20, 38:42] = True 267 mask_roi[23, 20, 38:42] = True # far away 268 ds_full = NiftiDataset(samples=os.path.join(pymvpa_dataroot,'example4d'), 269 labels=[1,2]) 270 ds_roi = NiftiDataset(samples=os.path.join(pymvpa_dataroot,'example4d'), 271 labels=[1,2], mask=mask_roi) 272 # Should just work since we are in the mask 273 ids_roi = ds_roi.mapper.getNeighbors(ds_roi.mapper.getOutId((12, 20, 40)), 274 radius=20) 275 self.failUnless(len(ids_roi) == 4) 276 277 # Trying to request feature outside of the mask 278 self.failUnlessRaises(ValueError, ds_roi.mapper.getOutId, (12, 20, 37)) 279 280 # Lets work around using full (non-masked) volume 281 ids_out = [] 282 for id_in in ds_full.mapper.getNeighborIn( (12, 20, 37), radius=20): 283 try: 284 ids_out.append(ds_roi.mapper.getOutId(id_in)) 285 except ValueError: 286 pass 287 self.failUnless(ids_out == ids_roi)
288 289
290 -def suite():
291 return unittest.makeSuite(NiftiDatasetTests)
292 293 294 if __name__ == '__main__': 295 import runner 296