def calc_native_properties(native_hemi, fs_LR_hemi, prefix, resolution, subject_id=None, method='nearest', cache_directory=None, alignment='MSMAll'): ''' calc_native_properties is a pimms calculator that requires a native hemisphere, an fs_LR hemisphere, and a property prefix and yields the interpolated retinotopic mapping properties. ''' method = to_interpolation_method(method) # first: check for a cache file: if cache_directory is not None: if subject_id is None: pth = cache_directory else: pth = os.path.join(cache_directory, str(subject_id), 'retinotopy') # we load all or none here: ftr = hcp_retinotopy_property_files mtd = '.' if method == 'nearest' else '.linear.' flp = '%s.%s%%s.%s%snative%dk.mgz' % (native_hemi.chirality, prefix, alignment, mtd, resolution) fls = { k: os.path.join(pth, flp % ftr[k]) for k in hcp_retinotopy_property_names } try: return {k: nyio.load(v, 'mgh') for (k, v) in six.iteritems(fls)} except Exception: pass else: fls = None logging.info( 'HCP Dataset: Interpolating retinotopy for HCP subject %s / %s (method: %s)...' % (subject_id, native_hemi.chirality, method)) p = fs_LR_hemi.interpolate(native_hemi, { k: (prefix + k) for k in hcp_retinotopy_property_names if k not in ['polar_angle', 'eccentricity'] }, method=method) # calculate the angle/eccen from the x and y values theta = np.arctan2(p['y'], p['x']) p = pimms.assoc(p, polar_angle=np.mod(90 - 180 / np.pi * theta + 180, 360) - 180, eccentricity=np.hypot(p['x'], p['y'])) # write cache and return if fls is not None: try: for (k, v) in six.iteritems(p): nyio.save(fls[k], v) except Exception as e: tup = (subject_id, native_hemi.chirality, type(e).__name__ + str(e.args)) warnings.warn( 'cache write failed for HCP retinotopy subject %s / %s: %s' % tup, RuntimeWarning) return p
def to_image_spec(img, **kw): ''' to_image_spec(img) yields a dictionary of meta-data for the given nibabel image object img. to_image_spec(hdr) yields the equivalent meta-data for the given nibabel image header. Note that obj may also be a mapping object, in which case it is returned verbatim. ''' if pimms.is_vector(img, 'int') and is_tuple(img) and len(img) < 5: r = image_array_to_spec(np.zeros(img)) elif pimms.is_map(img): r = img elif is_image_header(img): r = image_header_to_spec(img) elif is_image(img): r = image_to_spec(img) elif is_image_array(img): r = image_array_to_spec(img) else: raise ValueError('cannot convert object of type %s to image-spec' % type(img)) if len(kw) > 0: r = {k: v for m in (r, kw) for (k, v) in six.iteritems(m)} # normalize the entries for (k, aliases) in six.iteritems(imspec_aliases): if k in r: continue for al in aliases: if al in r: val = r[al] r = pimms.assoc(pimms.dissoc(r, al), k, val) break return r
def _add_xy(dat): k = next(six.iterkeys(dat)) prefix = k.split('_')[0] + '_' (ang,ecc) = [dat[prefix + k] for k in ('polar_angle', 'eccentricity')] tht = np.pi/180 * (90 - ang) (x,y) = [ecc*np.cos(tht), ecc*np.sin(tht)] return pimms.assoc(dat, prefix + 'x', x, prefix + 'y', y)
def to_image(img, image_type=None, spec=None, **kwargs): ''' to_image(array) yields a Nifti1Image of the given array with default meta-data spec. to_image(array, image_type) yields an image object of the given type; image_type may either be an image class or a class name (see supported types below). to_image((array, spec)) uses the given mapping of meta-data (spec) to construct the image-spec note that spec may simply be an affine transformation matrix or may be an image. to_image((array, affine, spec)) uses the given affine specifically (the given affine overrides any affine included in the spec meta-data). to_image(imspec) constructs an image with the properties specified in the given imspec; the special optional argument fill (default: 0.0) can be set to something else to specify what the default cell value should be. Note that the array may optionally be an image itself, in which case its spec is used as a starting point for the new spec. Any spec-data passed as a tuple overwrites this spec-data, and any spec-data passed as an optional argument overwrites this spec-data in turn. The first optional argument, specifying image_type is as an image type if possible, but if a spec-data mapping or equivalent (e.g., an image header or affine) is passed as the first argument it is used as such; otherwise, the optional third argument is named spec, and any additional keyword arguments passed to to_image are merged into this spec object left-to-right (i.e., keyword arguments overwrite the spec keys). If no affine is given and the image object given is an array then a FreeSurfer-like transform that places the origin at the center of the image. ''' # make sure we return unchanged if no change requested if is_image(img) and image_type is None and spec is None and len(kwargs) == 0: return img elif is_image_spec(img): fill = kwargs.pop('fill', 0.0) return to_image(image_spec_to_image(img, fill=fill), image_type=image_type, spec=spec, **kwargs) # quick cleanup of args: # we have a variety of things that go into spec; in order (where later overwrites earlier): # (1) img spec, (2) image_type map (if not an image type) (3) spec, (4) kw args # see if image_type is actually an image type (might be a spec/image)... if pimms.is_str(image_type) or isinstance(image_type, type): (image_type, s2) = (to_image_type(image_type), {}) else: (image_type, s2) = (None, {} if image_type is None else to_image_spec(image_type)) if image_type is None: image_type = image_types_by_name['nifti1'] s3 = {} if spec is None else to_image_spec(spec) # okay, next, parse the image argument itself: if is_tuple(img): if len(img) == 1: (img,aff,s1) = (img[0], None, {}) elif len(img) == 2: (img,aff,s1) = (img[0], None, img[1]) elif len(img) == 3: (img,aff,s1) = img else: raise ValueError('cannot parse more than 3 elements from image tuple') # check that the affine wasn't given as the meta-data (e.g. (img,aff) instead of (img,mdat)) if aff is None and s1 is not None: try: (aff, s1) = (to_affine(s1, 3), {}) except Exception: pass else: (aff,s1) = (None, {}) s0 = to_image_spec(img) spec = pimms.merge(s0, s1, s2, s3, kwargs) if aff is not None: spec = pimms.assoc(spec, affine=to_affine(aff, 3)) # okay, we create the image now: return image_type.create(img, meta_data=spec)