Ejemplo n.º 1
0
def build_heat_map(shape, coords):
    """Build a heat map for an image based on point placement within it.
    
    The heat map is scaled at the level of ``shape``, generally assuming 
    that ``coords`` have been scaled from a larger size. In other words, 
    the heat map will show the density at the level of its pixels and 
    can be further rescaled/resized to show density at different resolutions.
    
    Args:
        shape: Shape of image that contains ``coords``.
        coords: Array of coordinates of points. The array 
            should have shape (n, m), where n = number of coordinate sets, 
            and m = number of coordinate dimensions.
    
    Returns:
        :obj:`np.ndaarry`: An image of shape ``shape`` with values
        corresponding to the number of point occurrences at each pixel.
    """
    if coords is not None and len(coords) > 0:
        # get counts of points at the same coordinate as a measure of density
        coords_unique, coords_count = np.unique(coords,
                                                return_counts=True,
                                                axis=0)
        coordsi = libmag.coords_for_indexing(coords_unique)
        dtype = libmag.dtype_within_range(0, np.amax(coords_count), True,
                                          False)
        heat_map = np.zeros(shape, dtype=dtype)
        heat_map[tuple(coordsi)] = coords_count
    else:
        # generate an array with small int type if no coords are available
        heat_map = np.zeros(shape, dtype=np.uint8)
    return heat_map
Ejemplo n.º 2
0
def _markers_from_blobs(roi, blobs):
    # use blobs as seeds by converting blobs into marker image
    markers = np.zeros(roi.shape, dtype=np.uint8)
    coords = libmag.coords_for_indexing(blobs[:, :3].astype(int))
    markers[tuple(coords)] = 1
    markers = morphology.dilation(markers, morphology.ball(1))
    markers = measure.label(markers)
    return markers
Ejemplo n.º 3
0
def get_label_ids_from_position(coord,
                                labels_img,
                                scaling=None,
                                rounding=False,
                                return_coord_scaled=False):
    """Get the atlas label IDs for the given coordinates.
    
    Args:
        coord: Coordinates of experiment image in (z, y, x) order. Can be an 
            [n, 3] array of coordinates.
        labels_img: The registered image whose intensity values correspond to 
            label IDs.
        scaling: Scaling factor for the labels image size compared with the 
            experiment image; defaults to None.
        rounding: True to round coordinates after scaling, which should be 
            used rounding to reverse coordinates that were previously scaled 
            inversely to avoid size degredation with repeated scaling. 
            Typically rounding is False (default) so that coordinates fall 
            evenly to their lowest integer, without exceeding max bounds.
        return_coord_scaled: True to return the array of scaled coordinates; 
            defaults to False.
    
    Returns:
        An array of label IDs corresponding to ``coord``, or a scalar of 
        one ID if only one coordinate is given. If ``return_coord_scaled`` is 
        True, also returns a Numpy array of the same shape as ``coord`` 
        scaled based on ``scaling``.
    """
    libmag.printv("getting label IDs from coordinates using scaling", scaling)
    coord_scaled = coord
    if scaling is not None:
        # scale coordinates to atlas image size
        coord_scaled = np.multiply(coord, scaling)
    if rounding:
        # round when extra precision is necessary, such as during reverse
        # scaling, which requires clipping so coordinates don't exceed labels
        # image shape
        coord_scaled = np.around(coord_scaled).astype(np.int)
        coord_scaled = np.clip(coord_scaled, None,
                               np.subtract(labels_img.shape, 1))
    else:
        # typically don't round to stay within bounds
        coord_scaled = coord_scaled.astype(np.int)

    # index blob coordinates into labels image by int array indexing to
    # get the corresponding label IDs
    coordsi = libmag.coords_for_indexing(coord_scaled)
    label_ids = labels_img[tuple(coordsi)][0]
    if return_coord_scaled:
        return label_ids, coord_scaled
    return label_ids
Ejemplo n.º 4
0
def get_label_ids_from_position(coord_scaled, labels_img):
    """Get the atlas label IDs for the given coordinates.

    Args:
        coord_scaled (:class:`numpy.ndarray`): 2D array of coordinates in
            ``[[z,y,x], ...]`` format, or a single row as a 1D array.
        labels_img (:class:`numpy.ndarray`): Labeled image from which to
            extract labels at coordinates in ``coord_scaled``.

    Returns:
        :class:`numpy.ndarray`: An array of label IDs corresponding to
        ``coord``, or a scalar of one ID if only one coordinate is given.
    
    """
    # index blob coordinates into labels image by int array indexing to
    # get the corresponding label IDs
    coordsi = libmag.coords_for_indexing(coord_scaled)
    label_ids = labels_img[tuple(coordsi)][0]
    return label_ids
Ejemplo n.º 5
0
def colocalize_blobs(roi, blobs, thresh=None):
    """Co-localize blobs from different channels based on surrounding
    intensities.
    
    Thresholds for detection are first identified in each channel by taking
    the blobs in the given channel, finding the surrounding intensities,
    and taking a low (5th) percentile. Then for each channel, the
    surrounding intensities of blobs in that channel are compared with
    the thresholds in the other channels. Blobs exceeding any given
    threshold are considered to co-localize in that channel.
    
    Args:
        roi (:obj:`np.ndarray`): Region of interest as a 3D+channel array.
        blobs (:obj:`np.ndarray`): Blobs as a 2D array in the format
            ``[[z, y, x, radius, confirmation, truth, channel...], ...]``.
        thresh (int, float, str): Threshold percentile of intensities from
            pixels surrounding each blob in the given channel. Use "min"
            to instead take the mininimum average intensity of all blobs
            in the channel. Defaults to None to use "min".

    Returns:
        :obj:`np.ndarray`: 2D Numpy array of same length as ``blobs`` with
        a column for each channel where 1 indicates that the corresponding
        blob has signal is present in the given channels at the blob's
        location, and 0 indicates insufficient signal.

    """
    if blobs is None or roi is None or len(roi.shape) < 4:
        return None
    if thresh is None:
        thresh = "min"
    print("Colocalizing blobs based on image intensity across channels")
    threshs = []
    selem = morphology.ball(2)
    
    # find only blobs in ROI since blobs list may include blobs from immediate
    # surrounds, but ROI is not available for them
    blobs_roi, blobs_roi_mask = detector.get_blobs_in_roi(
        blobs, (0, 0, 0), roi.shape[:3], reverse=False)
    blobs_chl = detector.get_blobs_channel(blobs_roi)
    blobs_range_chls = []
    
    # get labeled masks of blobs for each channel and threshold intensities
    mask_roi = np.ones(roi.shape[:3], dtype=int)
    mask_roi_chls = []
    for chl in range(roi.shape[3]):
        # label a mask with blob indices surrounding each blob
        blobs_chl_mask = np.isin(blobs_chl, chl)
        blobs_range = np.where(blobs_chl_mask)[0]
        blobs_range_chls.append(blobs_range)
        mask = np.copy(mask_roi) * -1
        mask[tuple(libmag.coords_for_indexing(
            blobs_roi[blobs_chl_mask, :3].astype(int)))] = blobs_range
        mask = morphology.dilation(mask, selem=selem)
        mask_roi_chls.append(mask)
        
        if thresh == "min":
            # set minimum average surrounding intensity of all blobs as thresh
            threshs.append(
                None if len(blobs_range) == 0 else np.amin([
                    np.mean(roi[mask == b, chl]) for b in blobs_range]))
        else:
            # set a percentile of intensities surrounding all blobs in channel
            # as threshold for that channel, or the whole ROI if no blobs
            mask_blobs = mask >= 0
            roi_mask = roi if np.sum(mask_blobs) < 1 else roi[mask_blobs, chl]
            threshs.append(np.percentile(roi_mask, thresh))

    channels = np.unique(detector.get_blobs_channel(blobs_roi)).astype(int)
    colocs_roi = np.zeros((blobs_roi.shape[0], roi.shape[3]), dtype=np.uint8)
    for chl in channels:
        # get labeled mask of blobs in the given channel
        mask = mask_roi_chls[chl]
        blobs_range = blobs_range_chls[chl]
        for chl_other in channels:
            if threshs[chl_other] is None: continue
            for blobi in blobs_range:
                # find surrounding intensity of blob in another channel
                mask_blob = mask == blobi
                blob_avg = np.mean(roi[mask_blob, chl_other])
                if config.verbose:
                    print(blobi, detector.get_blob_channel(blobs_roi[blobi]),
                          blobs_roi[blobi, :3], blob_avg, threshs[chl_other])
                if blob_avg >= threshs[chl_other]:
                    # intensities in another channel around blob's position
                    # is above that channel's threshold
                    colocs_roi[blobi, chl_other] = 1
    
    # create array for all blobs including those outside ROI
    colocs = np.zeros((blobs.shape[0], roi.shape[3]), dtype=np.uint8)
    colocs[blobs_roi_mask] = colocs_roi
    if config.verbose:
        for i, (blob, coloc) in enumerate(zip(blobs_roi, colocs)):
            print(i, detector.get_blob_channel(blob), blob[:3], coloc)
    return colocs