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
Exemple #2
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()
Exemple #3
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
Exemple #4
0
 def it_fills_with_clipping():
     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()