示例#1
0
def align(im_stack, return_shifted_ims=False, bounds=None):
    """
    Align the image stack (1 pixel accuracy) relative to the first frame in the stack
    Arguments:
        im_stack (3 dimensions)
        return_shifted_ims:
            If True, also return the shifted images truncated to the common
            region of interest
        bounds: If not None limit the search space

    Returns:
        list of YX tuples
        shifted_ims (optional)
    """
    check.array_t(im_stack, ndim=3, dtype=np.float64)
    n_cycles, mea_h, mea_w = im_stack.shape
    assert mea_h == mea_w

    offsets = [YX(0, 0)]
    primary = im_stack[0]
    for im in im_stack[1:]:

        # TODO: This could be optimized by using fft instead of
        #       cv2.filter2D() which would avoid the fft of the
        #       unchanging primary.
        conv = convolve(src=primary, kernel=im)

        # conv is now zero-centered; that is, the peak is
        # an offset relative to the center of the image.

        if bounds is not None:
            edge_fill(conv, (mea_w - 2 * bounds) // 2, val=0)

        peak = YX(np.unravel_index(conv.argmax(), conv.shape))
        center = HW(conv.shape) // 2
        offsets += [center - peak]

    if return_shifted_ims:
        raw_dim = im_stack.shape[-2:]
        roi = intersection_roi_from_aln_offsets(offsets, raw_dim)
        roi_dim = (roi[0].stop - roi[0].start, roi[1].stop - roi[1].start)

        pixel_aligned_cy_ims = np.zeros((n_cycles, mea_h, mea_w))
        for cy_i, offset in zip(range(n_cycles), offsets):
            shifted_im = shift(im_stack[cy_i], offset * -1)
            pixel_aligned_cy_ims[cy_i, 0:roi_dim[0],
                                 0:roi_dim[1]] = shifted_im[roi[0], roi[1]]
        return np.array(offsets), pixel_aligned_cy_ims

    else:
        return np.array(offsets)
示例#2
0
def extract_trace(imstack, loc, dim, center=True):
    """Extract a trace of dim at loc from the stack"""
    imstack = stack(imstack)
    dim = HW(dim)
    loc = YX(loc)
    roi = ROI(loc, dim, center=center)
    return imstack[:, roi[0], roi[1]]
示例#3
0
    def render(self, im, cy_i):
        if self.std_x is None:
            self.std_x = [self.std]
        if self.std_y is None:
            self.std_y = [self.std]

        n_locs = len(self.locs)
        if len(self.std_x) != n_locs:
            self.std_x = np.repeat(self.std_x, (n_locs, ))
        if len(self.std_y) != n_locs:
            self.std_y = np.repeat(self.std_y, (n_locs, ))

        super().render(im, cy_i)
        mea = 17
        for loc, amp, std_x, std_y in zip(self.locs, self.amps, self.std_x,
                                          self.std_y):
            frac_x = np.modf(loc[0])[0]
            frac_y = np.modf(loc[1])[0]
            peak_im = imops.gauss2_rho_form(
                amp=amp,
                std_x=std_x,
                std_y=std_y,
                pos_x=mea // 2 + frac_x,
                pos_y=mea // 2 + frac_y,
                rho=0.0,
                const=0.0,
                mea=mea,
            )

            imops.accum_inplace(im,
                                peak_im,
                                loc=YX(*np.floor(loc)),
                                center=True)
示例#4
0
def _pixel_to_subpixel_one_im(im, peak_dim, locs):
    """
    This is a subtle calculation.

    locs is given as an *integer* position (only has pixel accuracy).
    We then extract out a sub-image using an *integer* half width.
    Peak_dim is typically odd. Suppose it is (11, 11)
    That makes half_peak_mea_i be 11 // 2 = 5

    Suppose that a peak is at (17.5, 17.5).

    Suppose that peak was found a (integer) location (17, 17)
    which is within 1 pixel of its center as expected.

    We extract the sub-image at (17 - 5, 17 - 5) = (12:23, 12:23)

    The Center-of-mass calculation should return (5.5, 5.5) because that is
    relative to the sub-image which was extracted

    We wish to return (17.5, 17.5). So that's the lower left
    (17 - 5) of the peak plus the COM found.
    """
    check.array_t(locs, dtype=int)
    assert peak_dim[0] == peak_dim[1]
    half_peak_mea_i = peak_dim[0] // 2
    lower_left_locs = locs - half_peak_mea_i
    com_per_loc = np.zeros(locs.shape)
    for loc_i, loc in enumerate(lower_left_locs):
        peak_im = imops.crop(im, off=YX(loc), dim=peak_dim, center=False)
        com_per_loc[loc_i] = imops.com(peak_im**2)
    return lower_left_locs + com_per_loc
示例#5
0
 def it_shifts_with_extra_dims():
     src = np.array([
         [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
         [[10, 20, 30], [40, 50, 60], [70, 80, 90]],
     ])
     dst = imops.shift(src, YX(1, -1))
     assert np.all(dst == [
         [[0, 0, 0], [2, 3, 0], [5, 6, 0]],
         [[0, 0, 0], [20, 30, 0], [50, 60, 0]],
     ])
示例#6
0
def fill(tar, loc, dim, val=0, center=False):
    """Fill target with value in ROI"""
    loc = YX(loc)
    dim = HW(dim)
    tar_dim = HW(tar.shape)
    if center:
        loc -= dim // 2
    tar_roi, _ = clip2d(loc.x, tar_dim.w, dim.w, loc.y, tar_dim.h, dim.h)
    if tar_roi is not None:
        tar[tar_roi] = val
示例#7
0
 def render(self, im, cy_i):
     super().render(im, cy_i)
     for loc, amp, z_i in zip(self.locs, self.amps, self.z_iz):
         frac_part, int_part = np.modf(loc)
         shifted_peak_im = imops.sub_pixel_shift(self.z_to_psf[z_i],
                                                 frac_part)
         imops.accum_inplace(im,
                             amp * shifted_peak_im,
                             loc=YX(*int_part),
                             center=True)
示例#8
0
def set_with_mask_in_place(tar, mask, value, loc=XY(0, 0), center=False):
    loc = YX(loc)
    tar_dim = HW(tar.shape)
    msk_dim = HW(mask.shape)
    if center:
        loc -= msk_dim // 2
    tar_roi, msk_roi = clip2d(loc.x, tar_dim.w, msk_dim.w, loc.y, tar_dim.h, msk_dim.h)
    if tar_roi is not None and msk_roi is not None:
        subset = tar[tar_roi]
        subset[mask[msk_roi]] = value
        tar[tar_roi] = subset
示例#9
0
    def it_fits_a_gaussian():
        xs, ys = np.mgrid[0:20, 0:20]
        data = imops._circ_gaussian(20.0, 10, 10, 1.0)(
            xs, ys) + 0.2 * np.random.random(xs.shape)
        center = YX(data.shape) / 2

        g_params = imops.fit_circ_gaussian(data)
        assert -1.0 < (20.0 - g_params[0]) < 1.0
        assert -1.0 < (10.0 - center.y - g_params[1]) < 1.0
        assert -1.0 < (10.0 - center.x - g_params[2]) < 1.0
        assert -0.15 < (1.0 - g_params[3]) < 0.15
示例#10
0
def accum_inplace(tar, src, loc=XY(0, 0), center=False):
    """
    Accumulate the src image into the (tar)get
    at loc with optional source centering
    """
    loc = YX(loc)
    tar_dim = HW(tar.shape)
    src_dim = HW(src.shape)
    if center:
        loc -= src_dim // 2
    tar_roi, src_roi = clip2d(loc.x, tar_dim.w, src_dim.w, loc.y, tar_dim.h, src_dim.h)
    if tar_roi is not None and src_roi is not None:
        tar[tar_roi] += src[src_roi]
示例#11
0
def shift(src, loc=XY(0, 0)):
    """Offset"""
    loc = YX(loc)
    extra_dims = src.shape[0:-2]
    n_extra_dims = len(extra_dims)
    src_dim = HW(src.shape[-2:])
    tar_dim = src_dim
    tar_roi, src_roi = clip2d(loc.x, tar_dim.w, src_dim.w, loc.y, tar_dim.h, src_dim.h)
    tar = np.zeros((*extra_dims, *tar_dim))
    if tar_roi is not None and src_roi is not None:
        if n_extra_dims > 0:
            tar[:, tar_roi[0], tar_roi[1]] += src[:, src_roi[0], src_roi[1]]
        else:
            tar[tar_roi[0], tar_roi[1]] += src[src_roi[0], src_roi[1]]
    return tar
示例#12
0
def align(im_stack):
    """
    Align the stack relative to the first frame.
    I timed this versus a non-DFT solution and it was WAY better.

    Returns:
        list of YX tuples
        max_score
    """
    check.array_t(im_stack, ndim=3)
    offsets = [YX(0, 0)]
    maxs = [0]
    primary = im_stack[0]
    for im in im_stack[1:]:
        conv = convolve(src=primary, kernel=im)

        # conv is now zero-centered; that is, the peak is
        # an offset relative to the center of the image.
        maxs += [np.amax(conv)]
        peak = YX(np.unravel_index(conv.argmax(), conv.shape))
        center = HW(conv.shape) // 2
        offsets += [center - peak]

    return np.array(offsets), np.array(maxs)
示例#13
0
def composite(ims, offsets, start_accum=None, limit_accum=None):
    """Build up a composite image from the stack with offsets"""

    # FIND the largest offset and add a border around the image of that size
    border_size = np.abs(offsets).max()
    border = HW(border_size, border_size)
    comp_dim = HW(ims[0].shape) + border * 2
    comp = np.zeros(comp_dim)
    comp_count = 0
    for i, (im, offset) in enumerate(zip(ims, offsets)):
        if start_accum is not None and i < start_accum:
            continue
        if limit_accum is not None and comp_count >= limit_accum:
            break
        accum_inplace(comp, src=im, loc=border - YX(offset))
        comp_count += 1
    return comp, border_size
示例#14
0
    def render(self, im, fl_i, ch_i, cy_i, aln_offset):
        super().render(im, fl_i, ch_i, cy_i, aln_offset)

        ch_scale = 1.0
        if self._channel_scale_factor is not None:
            ch_scale = self._channel_scale_factor[ch_i]

        for loc, amp, k in zip(self.locs, self._amps, self.row_k):
            loc = loc + aln_offset

            if isinstance(amp, np.ndarray):
                amp = amp[cy_i]

            psf_im, accum_to_loc = self.reg_psf.render_at_loc(
                loc, amp=ch_scale * k * amp, const=0.0
            )
            imops.accum_inplace(im, psf_im, loc=YX(accum_to_loc), center=False)
示例#15
0
def _quality(im):
    """
    Measure the quality of an image by spatial low-pass filter.
    High quality images are one where there is very little low-frequency
    (but above DC) bands.
    """
    a = np.copy(im)
    a -= np.mean(a)
    power = np.abs(np.fft.fftshift(np.fft.fft2(a)))
    power[power == 0] = 1

    cen = YX(power.shape) / 2
    dim_half = 3
    dim = HW(dim_half * 2 + 1, dim_half * 2 + 1)
    roi = ROI(cen, dim, center=True)
    im = power[roi]

    eigen = imops.eigen_moments(im)
    score = power.sum() / np.sqrt(eigen.sum())
    return score
示例#16
0
def edge_fill(tar, loc, dim, val=0, center=False):
    """Fill rect edge target with value in ROI"""
    loc = YX(loc)
    dim = HW(dim)
    tar_dim = HW(tar.shape)
    if center:
        loc -= dim // 2
    tar_roi, _ = clip2d(loc.x, tar_dim.w, dim.w, loc.y, tar_dim.h, dim.h)
    if tar_roi is not None:
        # Bottom
        tar[tar_roi[0].start, tar_roi[1].start : tar_roi[1].stop] = val

        # Top
        tar[tar_roi[0].stop - 1, tar_roi[1].start : tar_roi[1].stop] = val

        # Left
        tar[tar_roi[0].start : tar_roi[0].stop, tar_roi[1].start] = val

        # Right
        tar[tar_roi[0].start : tar_roi[0].stop, tar_roi[1].stop - 1] = val
示例#17
0
def intersection_roi_from_aln_offsets(aln_offsets, raw_dim):
    """
    Compute the ROI that contains pixels from all frames
    given the aln_offsets (returned from align)
    and the dim of the original images.
    """
    aln_offsets = np.array(aln_offsets)
    check.affirm(np.all(aln_offsets[0] == (0, 0)),
                 "intersection roi must start with (0,0)")

    # intersection_roi is the ROI in the coordinate space of
    # the [0] frame that has pixels from every cycle.
    clip_dim = (
        np.min(aln_offsets[:, 0] + raw_dim[0]) - np.max(aln_offsets[:, 0]),
        np.min(aln_offsets[:, 1] + raw_dim[1]) - np.max(aln_offsets[:, 1]),
    )

    b = max(0, -np.min(aln_offsets[:, 0]))
    t = min(raw_dim[0], b + clip_dim[0])
    l = max(0, -np.min(aln_offsets[:, 1]))
    r = min(raw_dim[1], l + clip_dim[1])
    return ROI(loc=YX(b, l), dim=HW(t - b, r - l))
示例#18
0
def low_frequency_power(im, dim_half=3):
    """
    Measure the low_frequency_power (excluding DC) of an image
    by spatial low-pass filter.

    dim_half is the half the width of the region
    """
    a = np.copy(im)
    a -= np.mean(a)
    power = np.abs(np.fft.fftshift(np.fft.fft2(a)))
    power[power == 0] = 1

    cen = YX(power.shape) / 2

    dim = HW(dim_half * 2 + 1, dim_half * 2 + 1)

    # PLUCK out the center (which is the low frequencies)
    roi = ROI(cen, dim, center=True)
    im = power[roi]
    eigen = eigen_moments(im)
    score = power.sum() / np.sqrt(eigen.sum())
    return score
示例#19
0
 def it_shifts_with_equal_ndims():
     src = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
     dst = imops.shift(src, YX(1, -1))
     assert np.all(dst == [[0, 0, 0], [2, 3, 0], [5, 6, 0]])
示例#20
0
 def it_accepts_yx():
     loc = YX(3, 2)
     assert loc.x == 2 and loc.y == 3 and loc == (3, 2)
示例#21
0
def df_filter(
    df,
    fields=None,
    reject_fields=None,
    roi=None,
    channel_i=0,
    dark=None,
    on_through_cy_i=None,
    off_at_cy_i=None,
    monotonic=None,
    min_intensity_cy_0=None,
    max_intensity_cy_0=None,
    max_intensity_any_cycle=None,
    min_intensity_per_cycle=None,
    max_intensity_per_cycle=None,
    radmat_field="signal",
    max_k=None,
    min_score=None,
):
    """
    A general filtering tool that operates on the dataframe returned by
    sigproc_v2.fields__n_peaks__peaks__radmat()
    """
    n_channels = df.channel_i.max() + 1

    # REMOVE unwanted fields
    if fields is None:
        fields = list(range(df.field_i.max() + 1))
    if reject_fields is not None:
        fields = list(filter(lambda x: x not in reject_fields, fields))
    _df = df[df.field_i.isin(fields)].reset_index(drop=True)

    # REMOVE unwanted peaks by ROI
    if roi is None:
        roi = ROI(YX(0, 0), HW(df.raw_y.max(), df.raw_x.max()))
    _df = _df[(roi[0].start <= _df.raw_y)
              & (_df.raw_y < roi[0].stop)
              & (roi[1].start <= _df.raw_x)
              & (_df.raw_x < roi[1].stop)].reset_index(drop=True)

    if max_k is not None:
        _df = _df[_df.k <= max_k]

    if min_score is not None:
        _df = _df[_df.score >= min_score]

    # OPERATE on radmat if needed
    fields_that_operate_on_radmat = [
        dark,
        on_through_cy_i,
        off_at_cy_i,
        monotonic,
        min_intensity_cy_0,
        max_intensity_cy_0,
        max_intensity_any_cycle,
        min_intensity_per_cycle,
        max_intensity_per_cycle,
    ]

    if any([field is not None for field in fields_that_operate_on_radmat]):
        assert 0 <= channel_i < n_channels

        rad_pt = pd.pivot_table(_df,
                                values=radmat_field,
                                index=["peak_i"],
                                columns=["channel_i", "cycle_i"])
        ch_rad_pt = rad_pt.loc[:, channel_i]
        keep_peaks_mask = np.ones((ch_rad_pt.shape[0], ), dtype=bool)

        if on_through_cy_i is not None:
            assert dark is not None
            keep_peaks_mask &= np.all(
                ch_rad_pt.loc[:, 0:on_through_cy_i + 1] > dark, axis=1)

        if off_at_cy_i is not None:
            assert dark is not None
            keep_peaks_mask &= np.all(ch_rad_pt.loc[:, off_at_cy_i:] < dark,
                                      axis=1)

        if monotonic is not None:
            d = np.diff(ch_rad_pt.values, axis=1)
            keep_peaks_mask &= np.all(d < monotonic, axis=1)

        if min_intensity_cy_0 is not None:
            keep_peaks_mask &= ch_rad_pt.loc[:, 0] >= min_intensity_cy_0

        if max_intensity_cy_0 is not None:
            keep_peaks_mask &= ch_rad_pt.loc[:, 0] <= max_intensity_cy_0

        if max_intensity_any_cycle is not None:
            keep_peaks_mask &= np.all(
                ch_rad_pt.loc[:, :] <= max_intensity_any_cycle, axis=1)

        if min_intensity_per_cycle is not None:
            for cy_i, inten in enumerate(min_intensity_per_cycle):
                if inten is not None:
                    keep_peaks_mask &= ch_rad_pt.loc[:, cy_i] >= inten

        if max_intensity_per_cycle is not None:
            for cy_i, inten in enumerate(max_intensity_per_cycle):
                if inten is not None:
                    keep_peaks_mask &= ch_rad_pt.loc[:, cy_i] <= inten

        keep_peak_i = ch_rad_pt[keep_peaks_mask].index.values
        keep_df = pd.DataFrame(
            dict(keep_peak_i=keep_peak_i)).set_index("keep_peak_i")
        _df = keep_df.join(df.set_index("peak_i", drop=False))

    return _df
示例#22
0
def _roi_from_edges(b, t, l, r):
    return ROI(loc=YX(b, l), dim=HW(t - b, r - l))
示例#23
0
文件: psf.py 项目: erisyon/plaster
def _psf_accumulate(im,
                    locs,
                    mea,
                    keep_dist=8,
                    threshold_abs=None,
                    return_reasons=True):
    """
    Given a single im, typically a regional sub-image, accumulate
    PSF evidence from each locs that meets a set of criteria.

    Any one image may not produce enough (or any) candidate spots and it
    is therefore expected that this function is called over a large number
    of fields to get sufficient samples.

    Arguments:
        im: Expected to be a single field, channel, cycle (BG already removed).
        locs: array (n, 2) in coordinates of im. Expected to be well-separated
        mea: The peak_measure (must be odd)
        threshold_abs: The average pixel brightness to accept the peak
        keep_dist: Pixels distance to determine crowding

    Returns:
        psf: ndarray (mea, mea) image
        reason_counts: An array of masks of why peaks were accepted/rejected
            See PSFEstimateMaskFields for the columns
    """
    from scipy.spatial.distance import cdist  # Defer slow import

    n_locs = len(locs)
    dist = cdist(locs, locs, metric="euclidean")
    dist[dist == 0.0] = np.nan

    if not np.all(np.isnan(dist)):
        closest_dist = np.nanmin(dist, axis=1)
    else:
        closest_dist = np.zeros(n_locs)

    # Aligned peaks will accumulate into this psf matrix
    dim = (mea, mea)
    dim2 = (mea + 2, mea + 2)
    psf = np.zeros(dim)

    n_reason_mask_fields = len(PSFEstimateMaskFields)
    reason_masks = np.zeros((n_locs, n_reason_mask_fields))

    for i, (loc, closest_neighbor_dist) in enumerate(zip(locs, closest_dist)):
        reason_masks[i, PSFEstimateMaskFields.considered] = 1

        # EXTRACT a peak with extra pixels around the edges (dim2 not dim)
        peak_im = imops.crop(im, off=YX(loc), dim=HW(dim2), center=True)

        if peak_im.shape != dim2:
            # Skip near edges
            reason_masks[i, PSFEstimateMaskFields.skipped_near_edges] = 1
            continue

        if closest_neighbor_dist < keep_dist:
            reason_masks[i, PSFEstimateMaskFields.skipped_too_crowded] = 1
            continue

        if np.any(np.isnan(peak_im)):
            reason_masks[i, PSFEstimateMaskFields.skipped_has_nan] = 1
            continue

        # Sub-pixel align the peak to the center
        assert not np.any(np.isnan(peak_im))
        centered_peak_im = sub_pixel_center(peak_im.astype(np.float64))

        # Removing ckipping as the noise should cancel out
        # centered_peak_im = np.clip(centered_peak_im, a_min=0.0, a_max=None)
        peak_max = np.max(centered_peak_im)
        if peak_max == 0.0:
            reason_masks[i, PSFEstimateMaskFields.skipped_empty] = 1
            continue

        if threshold_abs is not None and peak_max < threshold_abs:
            # Reject spots that are not active
            reason_masks[i, PSFEstimateMaskFields.skipped_too_dark] = 1
            continue

        r = imops.distribution_aspect_ratio(centered_peak_im)
        if r > 2.0:
            reason_masks[i, PSFEstimateMaskFields.skipped_too_oval] = 1
            continue

        # TRIM off the extra now
        centered_peak_im = centered_peak_im[1:-1, 1:-1]

        psf += centered_peak_im / np.sum(centered_peak_im)
        reason_masks[i, PSFEstimateMaskFields.accepted] = 1

    n_accepted = np.sum(reason_masks[:, PSFEstimateMaskFields.accepted])
    if n_accepted > 0:
        psf /= np.sum(psf)

    if return_reasons:
        return psf, reason_masks

    return psf
示例#24
0
def _step_3_composite_aligned_images(
    field_df, ch_merged_cy_ims, raw_chcy_ims, sigproc_params
):
    """
    Generate aligned images and composites
    """
    n_outchannels, n_inchannels, n_cycles, dim = sigproc_params.channels_cycles_dim

    # Note offsets are the same for each channel, and we only want one set of
    # offsets because we're aligning channel-merged images.
    offsets = [
        XY(row.shift_x, row.shift_y)
        for row in field_df[field_df.channel_i == 0]
        .set_index("cycle_i")
        .sort_index()[["shift_y", "shift_x"]]
        .itertuples()
    ]
    # Needs to be a list of Coords

    median_by_ch_cy = (
        field_df.set_index(["channel_i", "cycle_i"])
        .sort_index()
        .bg_median.values.reshape((n_outchannels, n_cycles))
    )

    chcy_composite_im, border_size = imops.composite(
        ch_merged_cy_ims,
        offsets,
        start_accum=sigproc_params.peak_find_start,
        limit_accum=sigproc_params.peak_find_n_cycles,
    )

    # GENERATE aligned images in the new coordinate system
    aligned_dim = HW(chcy_composite_im.shape)
    aligned_ims = np.zeros((n_outchannels, n_cycles, aligned_dim.h, aligned_dim.w,))
    aligned_raw_chcy_ims = np.zeros_like(aligned_ims)
    border = YX(border_size, border_size)
    for outch in range(n_outchannels):
        inch = sigproc_params.output_channel_to_input_channel(outch)
        for cy, offset in zip(range(n_cycles), offsets):
            imops.accum_inplace(
                aligned_raw_chcy_ims[outch, cy],
                src=raw_chcy_ims[inch, cy],
                loc=border - offset,
            )
            imops.accum_inplace(
                aligned_ims[outch, cy],
                src=(raw_chcy_ims[inch, cy] - median_by_ch_cy[outch, cy]).clip(min=0),
                loc=border - offset,
            )

    # BLACK out the borders by clipping in only pixels that are in every cycle
    l = border_size - field_df.shift_x.min()
    r = aligned_dim.w - border_size - field_df.shift_x.max()
    b = border_size - field_df.shift_y.min()
    t = aligned_dim.h - border_size - field_df.shift_y.max()
    roi = _roi_from_edges(b, t, l, r)
    aligned_roi_rect = Rect(b, t, l, r)

    aligned_composite_chcy_im = np.zeros(aligned_dim)
    aligned_composite_chcy_im[roi] = chcy_composite_im[roi]
    med = np.median(chcy_composite_im[roi])
    aligned_composite_bg_removed_im = (aligned_composite_chcy_im - med).clip(min=0)

    return (
        border_size,
        aligned_roi_rect,
        aligned_composite_bg_removed_im,
        aligned_raw_chcy_ims,
    )
示例#25
0
 def it_shifts_an_roi():
     roi = ROI(loc=YX(5, 10), dim=HW(15, 20))
     new_roi = roi_shift(roi, YX(-2, -3))
     assert new_roi == ROI(YX(5 - 2, 10 - 3), HW(15, 20))
示例#26
0
def _radiometry(chcy_ims, locs, ch_z_reg_psfs, cycle_to_z_index):
    """
    Use the PSFs to compute the Area-Under-Curve of the data in chcy_ims
    for each peak location of locs.

    Arguments:
        chcy_ims: (n_output_channels, n_cycles, width, height)
        locs: (n_peaks, 2). The second dimension is in (y, x) order
        ch_z_reg_psfs: (n_output_channels, n_z_slices, divs, divs, psf_mea, psf_mea)
        cycle_to_z_index: (n_cycles).
            This is the best z-slice of the ch_z_reg_psfs to use for
            each cycle determined by a focal fit.
    """
    check.array_t(chcy_ims, ndim=4)
    check.array_t(locs, ndim=2, shape=(None, 2))
    check.array_t(ch_z_reg_psfs,
                  shape=(chcy_ims.shape[0], None, None, None, None, None))
    check.array_t(cycle_to_z_index, shape=(chcy_ims.shape[1], ))

    n_locs = len(locs)
    n_channels, n_cycles = chcy_ims.shape[0:2]
    psf_divs = ch_z_reg_psfs.shape[2]
    assert psf_divs == ch_z_reg_psfs.shape[3]
    psf_dim = ch_z_reg_psfs.shape[-2:]
    psf_mea = psf_dim[0]
    assert psf_mea == psf_dim[1]

    radmat = np.full((n_locs, n_channels, n_cycles, 2),
                     np.nan)  # 2 is (sig, noi)

    center_weighted_mask = imops.generate_center_weighted_tanh(psf_mea,
                                                               radius=2.0)

    for ch_i in range(n_channels):
        for cy_i in range(n_cycles):
            reg_psfs = ch_z_reg_psfs[ch_i, cycle_to_z_index[cy_i]]

            im = chcy_ims[ch_i, cy_i]

            for loc_i, loc in enumerate(locs):
                peak_im = imops.crop(im,
                                     off=YX(loc),
                                     dim=HW(psf_dim),
                                     center=True)
                if peak_im.shape != psf_dim:
                    # Skip near edges
                    continue

                if np.any(np.isnan(peak_im)):
                    # Skip nan collisions
                    continue

                # There is a small issue here -- when the regional PSFs
                # are computed they divide up the image over the full width
                # but the locs here are actually referring to the aligned
                # space which is typically a little smaller. This might
                # cause problems if alignment is very poor but is probably
                # too small of an effect to worry about in typical operations.
                psf_kernel = reg_psfs[int(psf_divs * loc[0] / im.shape[0]),
                                      int(psf_divs * loc[1] / im.shape[1]), ]

                signal, noise = _peak_radiometry(
                    peak_im,
                    psf_kernel,
                    center_weighted_mask=center_weighted_mask)
                radmat[loc_i, ch_i, cy_i, :] = (signal, noise)

    return radmat