Beispiel #1
0
def test_sky_crop_order():
    # Test that order of cropping and subtraction doesn't affect result if inside cropped image

    img_dim = 80
    img = np.random.random((img_dim, img_dim))
    xmax, ymax = np.random.randint(20, high=img_dim - 20, size=2)
    img[ymax, xmax] = img.max() * 3 + 1  # Add max pixel at pre-determined location

    isz = 2 * np.min([xmax, img.shape[1] - xmax - 1, ymax, img.shape[0] - ymax - 1]) + 1

    dr = 2
    r1 = isz // 2 - dr

    # Correct then crop
    correct = sky_correction(img, r1=r1, dr=dr, center=(xmax, ymax))[0]
    correct_crop = crop_max(correct, isz, filtmed=False)[0]

    # Crop then correct
    cropped, center = crop_max(img, isz, filtmed=False)
    crop_correct = sky_correction(cropped, r1=r1, dr=dr)[0]

    # Make sure find expected center
    assert center == (xmax, ymax)

    # Use 10 * machine precision to make sure passes
    assert np.all(np.abs(correct_crop - crop_correct) < 10 * np.finfo(float).eps)
Beispiel #2
0
def test_crop_max():

    img_size = 80  # Same size as NIRISS images
    img = np.random.random((img_size, img_size))
    xmax, ymax = np.random.randint(0, high=img_size, size=2)
    img[ymax,
        xmax] = img.max() * 3 + 1  # Add max pixel at pre-determined location

    # Pre-calculate expected max size
    isz_max = (2 * np.min(
        [xmax, img.shape[1] - xmax - 1, ymax, img.shape[0] - ymax - 1]) + 1)
    isz_too_big = isz_max + 1

    # Using full message because we also check the suggested size
    size_msg = (
        f"The specified cropped image size, {isz_too_big}, is greater than the distance"
        " to the PSF center in at least one dimension. The max size for this image is"
        f" {isz_max}")
    with pytest.raises(ValueError, match=size_msg):
        # Above max size should raise the error
        tools.crop_max(img, isz_too_big, filtmed=False)

    # Setting filtmed=False because the simple image has only one pixe > 1
    img_cropped, center_pos = tools.crop_max(img, isz_max, filtmed=False)

    assert center_pos == (xmax, ymax)
    assert img_cropped.shape[0] == isz_max
    assert img_cropped.shape[0] == img_cropped.shape[1]
Beispiel #3
0
def test_clean_crop_order():
    # Test that clean_data performs both subtraction and cropping as expected

    img_dim = 80
    n_im = 5
    data = np.random.random((n_im, img_dim, img_dim))
    xmax, ymax = np.random.randint(20, high=img_dim - 20, size=2)
    data[:, ymax, xmax] = data.max() * 3 + 1  # Add max pixel at pre-determined location

    isz = (
        2 * np.min([xmax, data.shape[2] - xmax - 1, ymax, data.shape[1] - ymax - 1]) + 1
    )

    dr = 2
    r1 = isz // 2 - dr

    # Clean cube all at once
    cube = data.copy()
    cube_clean = clean_data(cube, isz=isz, r1=r1, dr=dr, apod=False, f_kernel=None)
    img_cube_clean = cube_clean[0]

    # Correct then crop
    img = data.copy()[0]
    correct = sky_correction(img, r1=r1, dr=dr, center=(xmax, ymax))[0]
    correct[correct < 0] = 0
    img_correct_crop = crop_max(correct, isz, filtmed=False)[0]

    assert np.all(np.abs(img_correct_crop - img_cube_clean) < 10 * np.finfo(float).eps)
Beispiel #4
0
def clean_data(data, isz=None, r1=None, dr=None, edge=0,
               bad_map=None, add_bad=[], apod=True,
               offx=0, offy=0, sky=True, window=None,
               darkfile=None, f_kernel=3, verbose=False):
    """ Clean data.

    Parameters:
    -----------

    `data` {np.array} -- datacube containing the NRM data\n
    `isz` {int} -- Size of the cropped image (default: {None})\n
    `r1` {int} -- Radius of the rings to compute background sky (default: {None})\n
    `dr` {int} -- Outer radius to compute sky (default: {None})\n
    `edge` {int} -- Patch the edges of the image (VLT/SPHERE artifact, default: {200}),\n
    `checkrad` {bool} -- If True, check the resizing and sky substraction parameters (default: {False})\n

    Returns:
    --------
    `cube` {np.array} -- Cleaned datacube.
    """
    n_im = data.shape[0]
    cube_cleaned = []  # np.zeros([n_im, isz, isz])
    l_bad_frame = []
    for i in tqdm(range(n_im), ncols=100, desc='Cleaning', leave=False):
        img0 = data[i]
        img0 = _apply_edge_correction(img0, edge=edge)
        if bad_map is not None:
            img1 = fix_bad_pixels(img0, bad_map, add_bad=add_bad)
        else:
            img1 = img0.copy()
            
        img1 = _remove_dark(img1, darkfile=darkfile, verbose=verbose)
        im_rec_max = crop_max(img1, isz, offx=offx, offy=offy, f=f_kernel)[0]
        if sky:
            img_biased = sky_correction(im_rec_max, r1=r1, dr=dr,
                                        verbose=verbose)[0]
        else:
            img_biased = im_rec_max.copy()
        img_biased[img_biased < 0] = 0  # Remove negative pixels

        if (img_biased.shape[0] != img_biased.shape[1]) or (img_biased.shape[0] != isz):
            l_bad_frame.append(i)
        else:
            if apod:
                img = apply_windowing(img_biased, window=window)
            else:
                img = img_biased.copy()
            cube_cleaned.append(img)
    if verbose:
        print('Bad centering frame number:', l_bad_frame)
    cube_cleaned = np.array(cube_cleaned)
    return cube_cleaned
Beispiel #5
0
def check_data_params(filename, isz, r1, dr, bad_map=None, add_bad=[],
                      edge=0, remove_bad=True, nframe=0, ihdu=0, f_kernel=3,
                      offx=0, offy=0, apod=False, window=None):
    """ Check the input parameters for the cleaning.

    Parameters:
    -----------

    `filename` {str}: filename containing the datacube,\n
    `isz` {int}: Size of the cropped image (default: 256)\n
    `r1` {int}: Radius of the rings to compute background sky (default: 100)\n
    `dr` {int}: Outer radius to compute sky (default: 10)\n
    `bad_map` {array}: Bad pixel map with 0 and 1 where 1 set for a bad pixel (default: None),\n
    `add_bad` {list}: List of 2d coordinates of bad pixels/cosmic rays (default: []),\n
    `edge` {int}: Number of pixel to be removed on the edge of the image (SPHERE),\n
    `remove_bad` {bool}: If True, the bad pixels are removed using a gaussian interpolation,\n
    `nframe` {int}: Frame number to be shown (default: 0),\n
    `ihdu` {int}: Hdu number of the fits file. Normally 1 for NIRISS and 0 for SPHERE (default: 0).
    """
    data = fits.open(filename)[ihdu].data
    img0 = data[nframe]

    if (bad_map is None) and (len(add_bad) != 0):
        bad_map = np.zeros(img0.shape)

    if edge != 0:
        img0[:, 0:edge] = 0
        img0[:, -edge:-1] = 0
        img0[0:edge, :] = 0
        img0[-edge:-1, :] = 0
    if (bad_map is not None) & (remove_bad):
        img1 = fix_bad_pixels(img0, bad_map, add_bad=add_bad)
    else:
        img1 = img0.copy()
    cropped_infos = crop_max(img1, isz, offx=offx, offy=offy, f=f_kernel)
    pos = cropped_infos[1]

    noBadPixel = False
    bad_pix_x, bad_pix_y = [], []
    if (bad_map is not None) & (len(add_bad) != 0):
        for j in range(len(add_bad)):
            bad_map[add_bad[j][1], add_bad[j][0]] = 1
        bad_pix = np.where(bad_map == 1)
        bad_pix_x = bad_pix[0]
        bad_pix_y = bad_pix[1]
    else:
        noBadPixel = True

    r2 = r1 + dr
    theta = np.linspace(0, 2*np.pi, 100)
    x0 = pos[0]
    y0 = pos[1]

    x1 = r1 * np.cos(theta) + x0
    y1 = r1 * np.sin(theta) + y0
    x2 = r2 * np.cos(theta) + x0
    y2 = r2 * np.sin(theta) + y0
    if window is not None:
        r3 = window
        x3 = r3 * np.cos(theta) + x0
        y3 = r3 * np.sin(theta) + y0

    xs1, ys1 = x0 + isz//2, y0 + isz//2
    xs2, ys2 = x0 - isz//2, y0 + isz//2
    xs3, ys3 = x0 - isz//2, y0 - isz//2
    xs4, ys4 = x0 + isz//2, y0 - isz//2

    max_val = img1[y0, x0]
    fig = plt.figure(figsize=(5, 5))
    plt.title("--- CLEANING PARAMETERS ---")
    plt.imshow(img1, norm=PowerNorm(.5), cmap='afmhot', vmin=0, vmax=max_val)
    plt.plot(x1, y1, label='Inner radius for sky subtraction')
    plt.plot(x2, y2, label='Outer radius for sky subtraction')
    if apod:
        if window is not None:
            plt.plot(x3, y3, '--', label='Super-gaussian windowing')
    plt.plot(x0, y0, '+', color='c', ms=10, label='Centering position')
    plt.plot([xs1, xs2, xs3, xs4, xs1], [ys1, ys2, ys3, ys4, ys1], 'w--',
             label='Resized image')
    if not noBadPixel:
        if remove_bad:
            label = 'Fixed hot/bad pixels'
        else:
            label = 'Hot/bad pixels'
        plt.scatter(bad_pix_y, bad_pix_x, color='', marker='s',
                    edgecolors='r', s=20, label=label)

    plt.xlabel('X [pix]')
    plt.ylabel('Y [pix]')
    plt.legend(fontsize=8, loc=1)
    plt.tight_layout()
    return fig
Beispiel #6
0
def clean_data(data,
               isz=None,
               r1=None,
               dr=None,
               edge=0,
               r2=None,
               bad_map=None,
               add_bad=[],
               apod=True,
               offx=0,
               offy=0,
               sky=True,
               window=None,
               f_kernel=3,
               verbose=False):
    """ Clean data.

    Parameters:
    -----------

    `data` {np.array} -- datacube containing the NRM data\n
    `isz` {int} -- Size of the cropped image (default: {None})\n
    `r1` {int} -- Radius of the rings to compute background sky (default: {None})\n
    `dr` {int} -- Outer radius to compute sky (default: {None})\n
    `edge` {int} -- Patch the edges of the image (VLT/SPHERE artifact, default: {200}),\n
    `checkrad` {bool} -- If True, check the resizing and sky substraction parameters (default: {False})\n

    Returns:
    --------
    `cube` {np.array} -- Cleaned datacube.
    """
    # print(data.shape[1])
    # if data.shape[1] % 2 == 1:
    #     data = np.array([im[:-1, :-1] for im in data])

    n_im = data.shape[0]
    cube_cleaned = np.zeros([n_im, isz, isz])
    for i in tqdm(range(n_im), ncols=100, desc='Cleaning', leave=False):
        img0 = data[i]
        if edge != 0:
            img0[:, 0:edge] = 0
            img0[:, -edge:-1] = 0
            img0[0:edge, :] = 0
            img0[-edge:-1, :] = 0
        if bad_map is not None:
            img1 = fix_bad_pixels(img0, bad_map, add_bad=add_bad)
        else:
            img1 = img0.copy()
        im_rec_max = crop_max(img1, isz, offx=offx, offy=offy, f=f_kernel)[0]
        if sky:
            img_biased = sky_correction(im_rec_max,
                                        r1=r1,
                                        dr=dr,
                                        verbose=verbose)[0]
        else:
            img_biased = im_rec_max.copy()
        img_biased[img_biased < 0] = 0  # Remove negative pixels

        if img_biased.shape[0] != img_biased.shape[1]:
            cprint(
                '\nCropped image do not have same X, Y dimensions -> check isz',
                'red')
            return None

        if apod:
            if r2 is None:
                r2 = isz // 3
            img = apply_windowing(img_biased, window=window)

        else:
            img = img_biased.copy()
        cube_cleaned[i] = img
    return cube_cleaned
Beispiel #7
0
def clean_data(
    data,
    isz=None,
    r1=None,
    dr=None,
    edge=0,
    bad_map=None,
    add_bad=None,
    apod=True,
    offx=0,
    offy=0,
    sky=True,
    window=None,
    darkfile=None,
    f_kernel=3,
    verbose=False,
    *,
    mask=None,
):
    """Clean data.

    Parameters:
    -----------

    `data` {np.array} -- datacube containing the NRM data\n
    `isz` {int} -- Size of the cropped image (default: {None})\n
    `r1` {int} -- Radius of the rings to compute background sky (default: {None})\n
    `dr` {int} -- Outer radius to compute sky (default: {None})\n
    `edge` {int} -- Patch the edges of the image (VLT/SPHERE artifact, default: {200}),\n
    `checkrad` {bool} -- If True, check the resizing and sky substraction parameters (default: {False})\n

    Returns:
    --------
    `cube` {np.array} -- Cleaned datacube.
    """
    n_im = data.shape[0]
    cube_cleaned = []  # np.zeros([n_im, isz, isz])
    l_bad_frame = []

    bad_map, add_bad = _get_3d_bad_pixels(bad_map, add_bad, data)

    for i in tqdm(range(n_im), ncols=100, desc="Cleaning", leave=False):
        img0 = data[i]
        img0 = _apply_edge_correction(img0, edge=edge)
        if bad_map is not None:
            img1 = fix_bad_pixels(img0, bad_map[i], add_bad=add_bad[i])
        else:
            img1 = img0.copy()

        img1 = _remove_dark(img1, darkfile=darkfile, verbose=verbose)

        if isz is not None:
            # Get expected center for sky correction
            filtmed = f_kernel is not None
            center = find_max(img1, filtmed=filtmed, f=f_kernel)
        else:
            center = None

        if sky and (r1 is not None or mask is not None):
            img_biased = sky_correction(
                img1, r1=r1, dr=dr, verbose=verbose, center=center, mask=mask
            )[0]
        elif sky:
            warnings.warn(
                "sky is set to True, but r1 and mask are set to None. Skipping sky correction",
                RuntimeWarning,
            )
            img_biased = img1.copy()
        else:
            img_biased = img1.copy()
        img_biased[img_biased < 0] = 0  # Remove negative pixels

        if isz is not None:
            # Get expected center for sky correction
            filtmed = f_kernel is not None
            im_rec_max = crop_max(
                img_biased, isz, offx=offx, offy=offy, filtmed=filtmed, f=f_kernel
            )[0]
        else:
            im_rec_max = img_biased.copy()

        if (
            (im_rec_max.shape[0] != im_rec_max.shape[1])
            or (isz is not None and im_rec_max.shape[0] != isz)
            or (isz is None and im_rec_max.shape[0] != img0.shape[0])
        ):
            l_bad_frame.append(i)
        else:
            if apod and window is not None:
                img = apply_windowing(im_rec_max, window=window)
            elif apod:
                warnings.warn(
                    "apod is set to True, but window is None. Skipping apodisation",
                    RuntimeWarning,
                )
                img = im_rec_max.copy()
            else:
                img = im_rec_max.copy()
            cube_cleaned.append(img)
    if verbose:
        print("Bad centering frame number:", l_bad_frame)
    cube_cleaned = np.array(cube_cleaned)
    return cube_cleaned
Beispiel #8
0
def show_clean_params(
    filename,
    isz,
    r1=None,
    dr=None,
    bad_map=None,
    add_bad=None,
    edge=0,
    remove_bad=True,
    nframe=0,
    ihdu=0,
    f_kernel=3,
    offx=0,
    offy=0,
    apod=False,
    window=None,
    *,
    mask=None,
):
    """Display the input parameters for the cleaning.

    Parameters:
    -----------

    `filename` {str}: filename containing the datacube,\n
    `isz` {int}: Size of the cropped image (default: 256)\n
    `r1` {int}: Radius of the rings to compute background sky (default: 100)\n
    `dr` {int}: Outer radius to compute sky (default: 10)\n
    `bad_map` {array}: Bad pixel map with 0 and 1 where 1 set for a bad pixel (default: None),\n
    `add_bad` {list}: List of 2d coordinates of bad pixels/cosmic rays (default: []),\n
    `edge` {int}: Number of pixel to be removed on the edge of the image (SPHERE),\n
    `remove_bad` {bool}: If True, the bad pixels are removed using a gaussian interpolation,\n
    `nframe` {int}: Frame number to be shown (default: 0),\n
    `ihdu` {int}: Hdu number of the fits file. Normally 1 for NIRISS and 0 for SPHERE (default: 0).
    """
    with fits.open(filename) as fd:
        data = fd[ihdu].data
    img0 = data[nframe]
    dims = img0.shape

    if isz is None:
        print(
            "Warning: isz not found (None by default). isz is set to the original image size (%i)"
            % (dims[0]),
            file=sys.stderr,
        )
        isz = dims[0]

    bad_map, add_bad = _get_3d_bad_pixels(bad_map, add_bad, data)
    bmap0 = bad_map[nframe]
    ab0 = add_bad[nframe]

    if edge != 0:
        img0[:, 0:edge] = 0
        img0[:, -edge:-1] = 0
        img0[0:edge, :] = 0
        img0[-edge:-1, :] = 0
    if (bad_map is not None) & (remove_bad):
        img1 = fix_bad_pixels(img0, bmap0, add_bad=ab0)
    else:
        img1 = img0.copy()
    cropped_infos = crop_max(img1, isz, offx=offx, offy=offy, f=f_kernel)
    pos = cropped_infos[1]

    noBadPixel = False
    bad_pix_x, bad_pix_y = [], []
    if np.any(bmap0):
        if len(ab0) != 0:
            for j in range(len(ab0)):
                bmap0[ab0[j][1], ab0[j][0]] = 1
        bad_pix = np.where(bmap0 == 1)
        bad_pix_x = bad_pix[0]
        bad_pix_y = bad_pix[1]
    else:
        noBadPixel = True

    theta = np.linspace(0, 2 * np.pi, 100)
    x0 = pos[0]
    y0 = pos[1]
    if r1 is not None:
        x1 = r1 * np.cos(theta) + x0
        y1 = r1 * np.sin(theta) + y0
        if dr is not None:
            r2 = r1 + dr
            x2 = r2 * np.cos(theta) + x0
            y2 = r2 * np.sin(theta) + y0
        sky_method = "ring"
    elif mask is not None:
        bg_coords = np.where(mask == 1)
        bg_x = bg_coords[0]
        bg_y = bg_coords[1]
        sky_method = "mask"
    if window is not None:
        r3 = window
        x3 = r3 * np.cos(theta) + x0
        y3 = r3 * np.sin(theta) + y0

    xs1, ys1 = x0 + isz // 2, y0 + isz // 2
    xs2, ys2 = x0 - isz // 2, y0 + isz // 2
    xs3, ys3 = x0 - isz // 2, y0 - isz // 2
    xs4, ys4 = x0 + isz // 2, y0 - isz // 2

    max_val = img1[y0, x0]
    fig = plt.figure(figsize=(5, 5))
    plt.title("--- CLEANING PARAMETERS ---")
    plt.imshow(img1, norm=PowerNorm(0.5, vmin=0, vmax=max_val), cmap="afmhot")
    if sky_method == "ring":
        if dr is not None:
            plt.plot(x1, y1, label="Inner radius for sky subtraction")
            plt.plot(x2, y2, label="Outer radius for sky subtraction")
        else:
            plt.plot(x1, y1, label="Boundary for sky subtraction")
    elif sky_method == "mask":
        plt.scatter(
            bg_y,
            bg_x,
            color="None",
            marker="s",
            edgecolors="C0",
            s=20,
            label="Pixels used for sky subtraction",
        )
    if apod:
        if window is not None:
            plt.plot(x3, y3, "--", label="Super-gaussian windowing")
    plt.plot(x0, y0, "+", color="c", ms=10, label="Centering position")
    plt.plot(
        [xs1, xs2, xs3, xs4, xs1],
        [ys1, ys2, ys3, ys4, ys1],
        "w--",
        label="Resized image",
    )
    plt.xlim((0, dims[0] - 1))
    plt.ylim((0, dims[1] - 1))
    if not noBadPixel:
        if remove_bad:
            label = "Fixed hot/bad pixels"
        else:
            label = "Hot/bad pixels"
        plt.scatter(
            bad_pix_y,
            bad_pix_x,
            color="None",
            marker="s",
            edgecolors="r",
            facecolors="None",
            s=20,
            label=label,
        )

    plt.xlabel("X [pix]")
    plt.ylabel("Y [pix]")
    plt.legend(fontsize=8, loc=1)
    plt.tight_layout()
    return fig