Esempio n. 1
0
 def it_adds_a_sub_image_into_a_target():
     dst = np.ones(WH(4, 4))
     src = np.ones(WH(2, 2))
     imops.accum_inplace(dst, src, XY(1, 1))
     good = np.array([[1, 1, 1, 1], [1, 2, 2, 1], [1, 2, 2, 1],
                      [1, 1, 1, 1]])
     assert (dst == good).all()
Esempio n. 2
0
 def it_clips2d_inclusive():
     """
     ssssssssssss
     sttttttttsss
     sttttttttsss
     ssssssssssss
     """
     tar_roi, src_roi = tools.image.coord.clip2d(-1, 5, 10, -2, 4, 15)
     assert tar_roi == ROI(XY(0, 0), WH(5, 4))
     assert src_roi == ROI(XY(1, 2), WH(5, 4))
Esempio n. 3
0
    def it_fills():
        im = np.ones((3, 3))
        im = imops.edge_fill(im, 1)
        # fmt: off
        assert im.tolist() == [
            [0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0]
        ]
        # fmt: on

        dst = np.ones(WH(4, 4))
        imops.fill(dst, loc=XY(1, 1), dim=WH(10, 10))
        good = np.array([[1, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]])
        assert (dst == good).all()
Esempio n. 4
0
 def it_extracts_a_trace():
     im_times_10 = im2 * 10
     trace = imops.extract_trace(
         [im2, im_times_10], loc=XY(1, 0), dim=WH(2, 2), center=False
     )
     expected = [[[2, 3], [5, 6]], [[20, 30], [50, 60]]]
     assert np.array_equal(trace, expected)
Esempio n. 5
0
 def _subregion(im, pos):
     if subsize is None:
         return im
     else:
         return imops.crop(im,
                           off=pos,
                           dim=WH(subsize, subsize),
                           center=False)
Esempio n. 6
0
def _mask_anomalies_im(im, den_threshold=300):
    """
    Operates on pre-balanced images.
    The den_threshold of 300 was found empirically on Val data

    Sets anomalies to nan
    """
    import skimage.transform  # Defer slow imports
    import cv2

    check.array_t(im, is_square=True)

    # SLICE into square using numpy-foo by reshaping the image
    # into a four-dimensional array can then by np.mean on the inner dimensions.
    sub_mea = 4  # Size of the sub-sample region
    im_mea, _ = im.shape

    squares = im.reshape(im_mea // sub_mea, sub_mea, im_mea // sub_mea,
                         sub_mea)
    # At this point, im is now 4-dimensional like: (256, 2, 256, 2)
    # But we want the small_dims next to each other for simplicity so swap the inner axes
    squares = squares.swapaxes(1, 2)
    # Now squares is (256, 256, 2, 2.)

    # squares is like: 256, 256, 2, 2. So we need the mean of the last two axes
    squares = np.mean(squares, axis=(2, 3))

    bad_mask = (squares > den_threshold).astype(float)

    # EXPAND the bad areas by erosion and dilate.
    # Erosion gets rid of the single-pixel hits and dilation expands the bad areas
    kernel = np.ones((3, 3), np.uint8)
    mask = cv2.erode(bad_mask, kernel, iterations=1)
    mask = cv2.dilate(mask, kernel, iterations=3)

    scale = im.shape[0] // mask.shape[0]

    full_size_mask = skimage.transform.rescale(
        mask,
        scale=scale,
        multichannel=False,
        mode="constant",
        anti_aliasing=False).astype(bool)

    # FIND rect contours of bad areas
    contours, hierarchy = cv2.findContours(full_size_mask.astype("uint8"),
                                           cv2.RETR_LIST,
                                           cv2.CHAIN_APPROX_SIMPLE)
    bad_rects = [cv2.boundingRect(cnt) for cnt in contours]
    im = im.copy()
    for rect in bad_rects:
        imops.fill(im,
                   loc=XY(rect[0], rect[1]),
                   dim=WH(rect[2], rect[3]),
                   val=np.nan)

    return im
Esempio n. 7
0
 def it_builds_multi_channel():
     synth = Synth(
         n_peaks=10,
         n_cycles=3,
         n_channels=2,
         dim=WH(100, 100),
         peak_mean=(60, 120),
         bg_std=1.0,
     )
     assert synth.ims.shape == (2, 3, 100, 100)
     assert (synth.frame_xs[0] == 0 and synth.frame_ys[0] == 0
             )  # The offset of the zero-th frame should be zero
     assert synth.n_peaks == 10
     assert synth.n_cycles == 3
     assert synth.n_channels == 2
Esempio n. 8
0
def _mask_anomalies(cy_ims, bad_rects_by_cycle):
    """
    Given a cycle stack of images and the list of bad rects,
    fill all these rects with background noise so that the aligner
    won't be confused by those anomalies.

    Arguments:
        cy_ims: array (n_cycles, height, width)
        bad_rects_by_cycle: List of bad rects for each cycle

    Returns:
        A copy of cy_ims with the bad rects masked with noise
    """
    assert cy_ims.ndim == 3 and cy_ims.shape[1] == cy_ims.shape[2]

    n_cycles, _, _ = cy_ims.shape

    masked_ims = np.zeros_like(cy_ims)

    for cy in range(n_cycles):
        src_im = cy_ims[cy]
        bad_rects = bad_rects_by_cycle[cy]

        # MAKE a mask_im with 0 inside bad rects, 1 otherwise
        mask_im = np.ones_like(src_im)
        for rect in bad_rects:
            imops.fill(mask_im,
                       loc=XY(rect[0], rect[1]),
                       dim=WH(rect[2], rect[3]),
                       val=0)

        # FIND the characteristics of a normal distribution that fits the
        # data that is not masked out (that is, we don't want the anomalies
        # in this distribution).  If src_im is entirely masked, mean=std=0.
        # TASK: This could be accelerated by subsampling.
        mean = std = 0
        if np.any(mask_im):
            mean, std = norm.fit(src_im[mask_im > 0])

        bg_noise = norm.rvs(loc=mean,
                            scale=std,
                            size=src_im.shape,
                            random_state=None)
        masked_ims[cy] = np.where(mask_im < 1, bg_noise, src_im)

    return masked_ims
Esempio n. 9
0
def spotty_images():
    # CREATE a test spot
    spot = imops.generate_gauss_kernel(2.0)
    spot = spot / np.max(spot)

    dim = WH(50, 50)
    spot_locs = [XY(15, 15), XY(10, 20), XY(20, 21)]

    # CREATE test images with spots
    test_images = []
    for loc in spot_locs:
        im = np.zeros(dim)
        # im = np.random.normal(0, 0.1, dim)
        # im = np.ones(dim) * 0.1
        imops.accum_inplace(im, spot, loc=loc, center=True)
        test_images += [im]

    return spot_locs, np.array(test_images)
Esempio n. 10
0
def crop(src, off=XY(0, 0), dim=WH(-1, -1), center=False):
    if dim.h == -1 and dim.w == -1:
        dim = HW(src.shape)
    return src[ROI(off, dim, center=center)]
Esempio n. 11
0
 def it_centers_an_roi_with_a_tuple():
     orig_dim = (50, 100)  # Note this is in H, W
     roi = roi_center(orig_dim, percent=0.5)
     expected = ROI(loc=XY(25, 12), dim=WH(50, 25))
     assert roi == expected
Esempio n. 12
0
 def it_centers_an_roi_with_a_coord():
     orig_dim = WH(100, 50)
     roi = roi_center(orig_dim, percent=0.5)
     assert roi == ROI(loc=XY(25, 12), dim=WH(50, 25))
Esempio n. 13
0
 def it_can_can_slice_an_roi_with_centering():
     roi = ROI(XY(1, 2), WH(2, 4), center=True)
     assert roi[0] == slice(0, 4) and roi[1] == slice(0, 2)
Esempio n. 14
0
 def it_can_can_slice_and_dice_with_roi():
     dim = WH(10, 10)
     image = np.zeros(dim)
     roi = ROI(XY(1, 1), dim - WH(2, 2))
     cropped_image = image[roi]
     assert np.array_equal(image[1:9, 1:9], cropped_image[:, :])
Esempio n. 15
0
 def it_floors():
     assert WH(1.1, 2.9) == WH(1, 2)
Esempio n. 16
0
 def it_can_scalar_mul():
     assert WH(1, 2) * 2 == WH(2, 4)
Esempio n. 17
0
 def it_can_floor_div_and_true_div():
     assert WH(1, 2) // 2 == WH(0, 1) and WH(1, 2) / 2 == WH(0.5, 1)
Esempio n. 18
0
 def it_can_add_and_sub():
     assert WH(1, 2) + WH(3, 4) == WH(4, 6) and WH(1, 2) - WH(3, 4) == WH(
         -2, -2)
Esempio n. 19
0
 def it_accepts_wh_but_stores_reversed():
     dim = WH(2, 3)
     assert dim.x == 2 and dim.y == 3 and dim == (3, 2)
Esempio n. 20
0
 def it_adds_a_sub_image_into_a_target_with_clipping():
     dst = np.ones(WH(2, 2))
     src = np.ones(WH(4, 4))
     imops.accum_inplace(dst, src, XY(-1, -1))
     good = np.array([[2, 2], [2, 2]])
     assert (dst == good).all()
Esempio n. 21
0
def _step_4_find_peaks(
    aligned_composite_bg_removed_im,
    aligned_roi_rect,
    raw_mask_rects,
    border_size,
    field_df,
    sigproc_params,
):
    """
    Find peaks on the composite image

    TASK: Remove the mask rect checks and replace with the same masking
    logic that is now implemented in the alignment phase. That is, just remove
    the peaks from the source instead of in post-processing.
    """
    from skimage.feature import peak_local_max  # Defer slow import
    from scipy.stats import iqr

    n_outchannels, n_inchannels, n_cycles, dim = sigproc_params.channels_cycles_dim
    assert (
        aligned_composite_bg_removed_im.shape[0]
        == aligned_composite_bg_removed_im.shape[1]
    )
    aligned_dim, _ = aligned_composite_bg_removed_im.shape
    check.array_t(aligned_composite_bg_removed_im, is_square=True)

    hat_rad = sigproc_params.hat_rad
    brim_rad = sigproc_params.hat_rad + 1
    hat_mask, brim_mask = _hat_masks(hat_rad, brim_rad)

    kernel = imops.generate_gauss_kernel(1.0)
    kernel = kernel - kernel.mean()
    _fiducial_im = imops.convolve(aligned_composite_bg_removed_im, kernel)

    # Black out the convolution artifact around the perimeter of the _fiducial_im
    search_roi_rect = Rect(
        aligned_roi_rect.b + brim_rad,
        aligned_roi_rect.t - brim_rad,
        aligned_roi_rect.l + brim_rad,
        aligned_roi_rect.r - brim_rad,
    )
    search_roi = search_roi_rect.roi()
    composite_fiducial_im = np.zeros_like(aligned_composite_bg_removed_im)

    # Use Inter-Quartile Range for some easy filtering
    _iqr = 0
    if sigproc_params.iqr_rng is not None:
        _iqr = iqr(
            _fiducial_im[search_roi],
            rng=(100 - sigproc_params.iqr_rng, sigproc_params.iqr_rng),
        )

    composite_fiducial_im[search_roi] = (_fiducial_im[search_roi] - _iqr).clip(min=0)

    locs = peak_local_max(
        composite_fiducial_im,
        min_distance=hat_rad,
        threshold_abs=sigproc_params.threshold_abs,
    )

    # Emergency exit to prevent memory overflows
    # check.affirm(len(locs) < 7000, f"Too many peaks {len(locs)}")

    shift = field_df.set_index("cycle_i").sort_index()[["shift_y", "shift_x"]].values
    shift_y = shift[:, 0]
    shift_x = shift[:, 1]

    # Discard any peak in any mask_rect
    # ALIGN the mask rects to the composite coordinate system
    aligned_mask_rects = []
    for channel in range(sigproc_params.n_output_channels):
        channel_rects = safe_list_get(raw_mask_rects, channel, [])
        for cycle in range(n_cycles):
            for rect in safe_list_get(channel_rects, cycle, []):
                yx = XY(rect[0], rect[1])
                hw = WH(rect[2], rect[3])
                yx += XY(border_size, border_size) - XY(shift_x[cycle], shift_y[cycle])
                aligned_mask_rects += [(yx[0], yx[1], yx[0] + hw[0], yx[1] + hw[1])]

    aligned_mask_rects = np.array(aligned_mask_rects)
    if aligned_mask_rects.shape[0] > 0:

        # To compare every loc with every mask rect we use the tricky np.fn.outer()
        y_hits = np.greater_equal.outer(locs[:, 0], aligned_mask_rects[:, 0])
        y_hits &= np.less.outer(locs[:, 0], aligned_mask_rects[:, 2])

        x_hits = np.greater_equal.outer(locs[:, 1], aligned_mask_rects[:, 1])
        x_hits &= np.less.outer(locs[:, 1], aligned_mask_rects[:, 3])

        inside_rect = x_hits & y_hits  # inside a rect if x and y are inside the rect
        locs_to_keep = ~np.any(
            inside_rect, axis=1
        )  # Reject if inside of any masked rect
        locs = locs[locs_to_keep]

    circle_im = np.zeros((aligned_dim, aligned_dim))

    center = aligned_dim / 2

    peak_rows = []
    for field_peak_i, loc in enumerate(locs):
        if sigproc_params.radial_filter is not None:
            radius = math.sqrt((loc[0] - center) ** 2 + (loc[1] - center) ** 2)
            radius /= center
            if radius >= sigproc_params.radial_filter:
                continue

        imops.set_with_mask_in_place(circle_im, brim_mask, 1, loc=loc, center=True)

        peak_rows += [
            Munch(
                peak_i=0,
                field_peak_i=field_peak_i,
                aln_y=int(loc[0]),
                aln_x=int(loc[1]),
            )
        ]

    peak_df = pd.DataFrame(peak_rows)

    return peak_df, circle_im, aligned_mask_rects
Esempio n. 22
0
 def it_edge_fills_with_clipping():
     dst = np.ones(WH(4, 4))
     imops.edge_fill(dst, loc=XY(1, 1), dim=WH(10, 10))
     good = np.array([[1, 1, 1, 1], [1, 0, 0, 0], [1, 0, 1, 0],
                      [1, 0, 0, 0]])
     assert (dst == good).all()
Esempio n. 23
0
 def it_crops():
     src = np.array([[1, 1, 1, 1], [1, 2, 2, 1], [1, 2, 2, 1], [1, 1, 1,
                                                                1]])
     inner = imops.crop(src, XY(1, 1), WH(2, 2))
     assert np.array_equal(inner, np.array([[2, 2], [2, 2]]))