Exemplo n.º 1
0
    def it_align_bounds():
        im0 = np.zeros((21, 21))
        im0[3, 3] = 1
        im0[10, 5] = 4

        im1 = np.zeros((21, 21))
        im1[5, 6] = 1

        ims = np.stack((im0, im1))
        aln_no_bounds = imops.align(ims, bounds=None)
        assert aln_no_bounds.astype(int).flatten().tolist() == [0, 0, -5, 1]

        aln_no_bounds = imops.align(ims, bounds=3)
        assert aln_no_bounds.astype(int).flatten().tolist() == [0, 0, 2, 3]
Exemplo n.º 2
0
def _align(cy_ims):
    """
    Align a stack of cy_ims by generating simplified fiducial for each cycle
    (assumes camera does not move between channels)

    Returns:
        aln_offsets: list of YX tuples
        max_score: list of max_score
    """

    kern = _kernel()

    fiducial_ims = []
    for im in cy_ims:
        med = float(np.nanmedian(im))
        im = np.nan_to_num(im, nan=med)
        fiducial_ims += [imops.convolve(im, kern)]
    fiducial_ims = np.array(fiducial_ims) - np.median(fiducial_ims)
    noise_floor = -np.min(fiducial_ims)
    fiducial_ims = np.where(fiducial_ims < noise_floor, 0, 1).astype(np.uint8)

    kern = imops.generate_circle_mask(3).astype(np.uint8)

    fiducial_cy_ims = np.array([
        cv2.dilate(im, kern, iterations=1) for im in fiducial_ims
    ]).astype(float)

    aln_offsets, aln_scores = imops.align(fiducial_cy_ims)
    return aln_offsets, aln_scores
Exemplo n.º 3
0
def _step_2_align(raw_chcy_ims, sigproc_params):
    """
    Each cycle the stage moves, but it is not perfectly accurate when it returns
    to the same field.

    The stage does _not_ move between channels, therefore
    the channels for each field over each cycle can be merged to improve alignment.

    Returns:
        A DataFrame of all the results, most importantly the shift_y, shift_x
            needed to each cycle to align the images.
        ch_merged_cy_ims
    """

    n_outchannels, n_inchannels, n_cycles, dim = sigproc_params.channels_cycles_dim

    raw_mask_rects, anomaly_removed_ims = _step_2a_mask_anomalies(
        raw_chcy_ims, sigproc_params)

    medians_by_ch_cy = _step_2b_find_bg_median(raw_chcy_ims, sigproc_params)

    ch_merged_cy_ims = _step_2c_composite_channels(anomaly_removed_ims,
                                                   medians_by_ch_cy,
                                                   sigproc_params)

    # GENERATE fiducial_ims
    kernel = imops.generate_gauss_kernel(1.0)
    kernel = kernel - kernel.mean()  # Eliminate DC bias
    fiducial_ims = np.array(
        [imops.convolve(im.clip(min=0), kernel) for im in ch_merged_cy_ims])

    alignment_offsets = imops.align(fiducial_ims)

    ch_out_to_in = sigproc_params.output_channel_to_input_channel

    field_df = pd.DataFrame([
        dict(
            cycle_i=cy,
            shift_y=off[0],
            shift_x=off[1],
            channel_i=outch,
            bg_median=medians_by_ch_cy[ch_out_to_in(outch), cy],
            n_mask_rects=len(raw_mask_rects[ch_out_to_in(outch)][cy]),
            mask_area=sum([
                rect[2] * rect[3]
                for rect in raw_mask_rects[ch_out_to_in(outch)][cy]
            ]),
        ) for outch in range(n_outchannels)
        for cy, off in zip(range(n_cycles), alignment_offsets)
    ])

    return field_df, ch_merged_cy_ims, raw_mask_rects
Exemplo n.º 4
0
def _sub_pixel_align_cy_ims(cy_ims, bounds=None):
    """
    Align image stack with sub-pixel precision.

    As an optimization, this will subdivide into a number of smaller
    random subregions and then average the offset.

    However, this optimization can fail when the image is very sparse.
    And that failure mode is trapped and then the stack is
    re-run without the subregion optimization.

    I tried to go down to 64 pixels sub-regions but could only get to 0.1 of a pixel
    which might be enough but decided to stay at 128 where I can get 0.05
    I found that i needed 8 samples for stability and each is taking about 1 sec
    on 100 cycles.
    """

    # ALIGN within one pixel
    with prof("pixel_align"):
        pixel_offsets, pixel_aligned_cy_ims = imops.align(
            cy_ims, return_shifted_ims=True, bounds=bounds)

    # IMPROVE with sub-pixel precision
    with prof("subpixel_align"):
        try:
            sub_pixel_offset = _subsize_sub_pixel_align_cy_ims(
                pixel_aligned_cy_ims, subsize=128, n_samples=8)
        except AlignmentError:
            # The subsize parameter is merely an optimization but in very sparse images
            # the aligner can fail to find enough peaks in an subregion to align so in
            # that case we try again but with the subsize optimization disabled.
            try:
                sub_pixel_offset = _subsize_sub_pixel_align_cy_ims(
                    pixel_aligned_cy_ims, subsize=None, n_samples=1)
            except AlignmentError:
                # This is a true failure. There was no alignment even using the entire
                # image so we jam in an impossible shift of the entire image.
                im_mea = pixel_aligned_cy_ims.shape[-1]
                far_away = np.full(pixel_offsets.shape, im_mea, dtype=float)
                far_away[0, :] = 0.0
                sub_pixel_offset = far_away

    return pixel_offsets + sub_pixel_offset
Exemplo n.º 5
0
 def it_aligns_two_images():
     spot_locs, test_images = spotty_images()
     found_offsets, _ = imops.align(test_images)
     actual_offset = spot_locs[1] - spot_locs[0]
     assert np.all(found_offsets[1] == actual_offset)
Exemplo n.º 6
0
 def it_returns_offsets():
     found_offsets = imops.align(test_images)
     actual_offset = spot_locs[1] - spot_locs[0]
     assert np.all(found_offsets[1] == actual_offset)