2

I have an Nifti file of ROIs that is a 192 x 192 x 12 array and want to be able to find the center of mass of the whole thing as well as each of the 12 slices. i am using

cm = join(dname, 'cardiac_roi.nii')
roi_img = nib.load(cm)
roi_data = roi_img.get_data()
CM = ndimage.measurements.center_of_mass(roi_data)

and I get the error:

TypeError: 'numpy.float64' object is not iterable

same thing happens when I also try just one slice

CM = ndimage.measurements.center_of_mass(roi_data[:,:,1])

how do I fix this?

Mark Dickinson
  • 29,088
  • 9
  • 83
  • 120
Sidney
  • 71
  • 1
  • 2
  • 6
  • What does `print(type(roi_idata))` show? – Mark Dickinson Aug 18 '14 at 18:49
  • class 'numpy.core.memmap.memmap' I don't know what that means. – Sidney Aug 18 '14 at 18:51
  • 1
    `numpy.memmap` is a subclass of `numpy.ndarray` that allows memory-mapped arrays (that is, objects that *behave* just like a regular NumPy array, but have their data stored on disk instead of in RAM). It looks like you've discovered that `center_of_mass` doesn't work for `memmap` instances. Try converting `roi_data` to a regular `ndarray` first: `CM = ndimage.measurements.center_of_mass(numpy.array(roi_data))` – Mark Dickinson Aug 18 '14 at 19:00
  • This may also be worth a NumPy/SciPy bug report. – Mark Dickinson Aug 18 '14 at 19:15
  • Just to complete the info: Nifti is a standard neuroimaging format. Reading it with python has some quirks: The standard library for doing this, `nibabel`, will return a `memmap` onto the data that was written to disk as bulk, usually in f-contiguous ordering. However, the standard nifti format can also take the form of `.nii.gz`, in which case all data are read into memory when calling `get_data`, because gzip does not seem to be seekable. So depending on something as simple as the filename, this data type will turn into a memmap or not. Calling `.copy()` on it or `np.array(...)` as you ... – eickenberg Aug 18 '14 at 21:24
  • ... describe is therefore a good way to homogenize this, provided that data are meant to go into memory anyway. (This is independent from the apparent scipy.ndimage bug). Also, props to @Sidney for using python in neuroimaging ;) – eickenberg Aug 18 '14 at 21:24

1 Answers1

2

You can fix it by replacing the line:

CM = ndimage.measurements.center_of_mass(roi_data)

with the lines:

import numpy  # Unnecessary if you've already done this.
CM = ndimage.measurements.center_of_mass(numpy.array(roi_data))

Explanation: from your comments, roi_data is a NumPy memory-mapped array. The ndimage.measurements.center_of_mass function expects a regular NumPy array; that is, an instance of ndarray. In theory, since a memory-mapped array has type memmap, and memmap is a subclass of ndarray, your original code should work; in practice it fails (as you've discovered), and the workaround is to explicitly convert the memory-mapped array to a normal NumPy array. The fact that your code doesn't work represents a violation of the Liskov substitution principle, and indicates a bug in either NumPy or SciPy (most likely the former).

Looking at the ndimage source, I tracked the difference in behaviour down to the fact that for a memory-mapped array x, the result of x.sum() is another (zero-dimensional) array, while for a regular NumPy ndarray x, the result of x.sum() is a scalar (an instance of numpy.float64, for example). This NumPy bug report looks relevant.

Mark Dickinson
  • 29,088
  • 9
  • 83
  • 120
  • great that fixed it! thank you so much for the helpful explanation as to what was going on as well! – Sidney Aug 18 '14 at 19:43