def ght_alternative (img, template, indices): """ Alternative implementation of the general hough transform, which uses iteration over indices rather than broadcasting rules like @see ght(). It is therefore considerably slower, especially for large, multi-dimensional arrays. The only application are cases, where the hough transform should only be computed for a small number of points (=template centers) in the image. In this case the indices of interest can be provided as a list. @param img the original image on which to search for the structure @type img numpy.ndarray @param template a boolean array containing the structure to search for @type template nump.ndarray @param indices a sequence of image indices @type indices sequence @return the general hough transformation @rtype numpy.ndarray """ # cast template to bool and img to scipy array img = scipy.asarray(img) template = scipy.asarray(template).astype(scipy.bool_) # check supplied parameters if img.ndim != template.ndim: raise AttributeError('The supplied image and template must be of the same dimensionality.') if not scipy.all(scipy.greater_equal(img.shape, template.shape)): raise AttributeError('The supplied template is bigger than the image. This setting makes no sense for a hough transform.') # pad the original image img_padded = pad(img, footprint=template, mode='constant') # prepare the hough image if scipy.bool_ == img.dtype: img_hough = scipy.zeros(img.shape, scipy.int32) else: img_hough = scipy.zeros(img.shape, img.dtype) # iterate over the pixels, apply the template center to each of these and save the sum into the hough image for idx_hough in indices: idx_hough = tuple(idx_hough) slices_img_padded = [slice(idx_hough[i], None) for i in range(img_hough.ndim)] img_hough[idx_hough] = sum(img_padded[slices_img_padded][template]) return img_hough
def sls(minuend, subtrahend, metric = "ssd", noise = "global", signed = True, sn_size = None, sn_footprint = None, sn_mode = "reflect", sn_cval = 0.0, pn_size = None, pn_footprint = None, pn_mode = "reflect", pn_cval = 0.0): """ Computes the signed local similarity between two images. Compares a patch around each voxel of the minuend array to a number of patches centered at the points of a search neighbourhood in the subtrahend. Thus, creates a multi-dimensional measure of patch similarity between the minuend and a corresponding search area in the subtrahend. This filter can also be used to compute local self-similarity, obtaining a descriptor similar to the one described in [1]. minuend : array_like Input array from which to subtract the subtrahend. subtrahend : array_like Input array to subtract from the minuend. metric : {'ssd', 'mi', 'nmi', 'ncc'}, optional The `metric` parameter determines the metric used to compute the filter output. Default is 'ssd'. noise : {'global', 'local'}, optional The `noise` parameter determines how the noise is handled. If set to 'global', the variance determining the noise is a scalar, if set to 'local', it is a Gaussian smoothed field of estimated local noise. Default is 'global'. signed : bool, optional Whether the filter output should be signed or not. If set to 'False', only the absolute values will be returned. Default is 'True'. sn_size : scalar or tuple, optional See sn_footprint, below sn_footprint : array, optional The search neighbourhood. Either `sn_size` or `sn_footprint` must be defined. `sn_size` gives the shape that is taken from the input array, at every element position, to define the input to the filter function. `sn_footprint` is a boolean array that specifies (implicitly) a shape, but also which of the elements within this shape will get passed to the filter function. Thus ``sn_size=(n,m)`` is equivalent to ``sn_footprint=np.ones((n,m))``. We adjust `sn_size` to the number of dimensions of the input array, so that, if the input array is shape (10,10,10), and `sn_size` is 2, then the actual size used is (2,2,2). sn_mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The `sn_mode` parameter determines how the array borders are handled, where `sn_cval` is the value when mode is equal to 'constant'. Default is 'reflect' sn_cval : scalar, optional Value to fill past edges of input if `sn_mode` is 'constant'. Default is 0.0 pn_size : scalar or tuple, optional See pn_footprint, below pn_footprint : array, optional The patch over which the distance measure is applied. Either `pn_size` or `pn_footprint` must be defined. `pn_size` gives the shape that is taken from the input array, at every element position, to define the input to the filter function. `pn_footprint` is a boolean array that specifies (implicitly) a shape, but also which of the elements within this shape will get passed to the filter function. Thus ``pn_size=(n,m)`` is equivalent of dimensions of the input array, so that, if the input array is shape (10,10,10), and `pn_size` is 2, then the actual size used is (2,2,2). pn_mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The `pn_mode` parameter determines how the array borders are handled, where `pn_cval` is the value when mode is equal to 'constant'. Default is 'reflect' pn_cval : scalar, optional Value to fill past edges of input if `pn_mode` is 'constant'. Default is 0.0 [1] Mattias P. Heinrich, Mark Jenkinson, Manav Bhushan, Tahreema Matin, Fergus V. Gleeson, Sir Michael Brady, Julia A. Schnabel MIND: Modality independent neighbourhood descriptor for multi-modal deformable registration Medical Image Analysis, Volume 16, Issue 7, October 2012, Pages 1423-1435, ISSN 1361-8415 http://dx.doi.org/10.1016/j.media.2012.05.008 """ minuend = numpy.asarray(minuend) subtrahend = numpy.asarray(subtrahend) if numpy.iscomplexobj(minuend): raise TypeError('complex type not supported') if numpy.iscomplexobj(subtrahend): raise TypeError('complex type not supported') mshape = [ii for ii in minuend.shape if ii > 0] sshape = [ii for ii in subtrahend.shape if ii > 0] if not len(mshape) == len(sshape): raise RuntimeError("minuend and subtrahend must be of same shape") if not numpy.all([sm == ss for sm, ss in zip(mshape, sshape)]): raise RuntimeError("minuend and subtrahend must be of same shape") sn_footprint = __make_footprint(minuend, sn_size, sn_footprint) sn_fshape = [ii for ii in sn_footprint.shape if ii > 0] if len(sn_fshape) != minuend.ndim: raise RuntimeError('search neighbourhood footprint array has incorrect shape.') #!TODO: Is this required? if not sn_footprint.flags.contiguous: sn_footprint = sn_footprint.copy() # created a padded copy of the subtrahend, whereas the padding mode is always 'reflect' subtrahend = pad(subtrahend, footprint=sn_footprint, mode=sn_mode, cval=sn_cval) # compute slicers for position where the search neighbourhood sn_footprint is TRUE slicers = [[slice(x, (x + 1) - d if 0 != (x + 1) - d else None) for x in range(d)] for d in sn_fshape] slicers = [sl for sl, tv in zip(itertools.product(*slicers), sn_footprint.flat) if tv] # compute difference images and sign images for search neighbourhood elements ssds = [ssd(minuend, subtrahend[slicer], normalized=True, signed=signed, size=pn_size, footprint=pn_footprint, mode=pn_mode, cval=pn_cval) for slicer in slicers] distance = [x[0] for x in ssds] distance_sign = [x[1] for x in ssds] # compute local variance, which constitutes an approximation of local noise, out of patch-distances over the neighbourhood structure variance = numpy.average(distance, 0) variance = gaussian_filter(variance, sigma=3) #!TODO: Figure out if a fixed sigma is desirable here... I think that yes if 'global' == noise: variance = variance.sum() / float(numpy.product(variance.shape)) # variance[variance < variance_global / 10.] = variance_global / 10. #!TODO: Should I keep this i.e. regularizing the variance to be at least 10% of the global one? # compute sls sls = [dist_sign * numpy.exp(-1 * (dist / variance)) for dist_sign, dist in zip(distance_sign, distance)] # convert into sls image, swapping dimensions to have varying patches in the last dimension return numpy.rollaxis(numpy.asarray(sls), 0, minuend.ndim + 1)