Example #1
0
def stack_source(images, x, y, src_shape, ref_index, tx_solutions,
        dqmasks=None, subsampling=5, combine_method='mean', 
        show_plots=False, dqmask_min=0, bad_pix_val=1):
    """
    Stack all the images of a given source.
    
    Parameters
    ----------
    images: list of `~numpy.ndarray`'s
        Images to stack
    x,y: float
        Central pixel of reprojected windows
    src_shape: tuple of integers
        Shape (y,x) of the patch to extract from each image. Typically
        this is 2*aper_radius+1.
    ref_index: int
        Index in ``images`` and ``dqmasks`` of the image the others
        are projected onto for the stack.
    tx_solutions: list of `~astropyp.catalog.ImageSolution`s
        Transformations to convert each image to the projected coordinates
    dqmasks: list of `~numpy.ndarrays`'s, optional
        Dqmasks for images to stack
    subsampling: int
        Number of subdivisions of each pixel. *Default=5*
    combine_method: string
        Method to use for the stack. This can be either 'median' or 'mean'.
        *Default is 'mean'*
    show_plots: bool, optional
        Whether or not to show a plots of the reprojected images and
        dqmasks. *Default=False*
    dqmask_min: int, optional
        Minimum value of a data quality mask that is accepted.
        All pixels higher than ``dqmask_min`` will be masked in the
        reprojected image. *Default=0*
    bad_pix_val: int, optional
        Value to set bad pixels to in the dqmask. This is only 
        necessary if using a dqmask. *Default=1*
    """
    from astropyp.catalog import Catalog
    from scipy.ndimage import zoom
    from astropyp.utils.misc import extract_array
    import astropyp.utils
    
    if combine_method=='median':
        combine = np.ma.median
    elif combine_method=='mean':
        combine = np.ma.mean
    else:
        raise Exception(
            "Combine method must be either 'median' or 'mean'")
    # Get the patch from the original image
    data = extract_array(images[ref_index],
        src_shape, (y,x), subsampling=subsampling)
    y_radius = src_shape[0]>>1
    x_radius = src_shape[1]>>1
    x_new = np.linspace(x-x_radius, x+x_radius, data.shape[1])
    y_new = np.linspace(y-y_radius, y+y_radius, data.shape[0])
    
    # Mask bad pixels and edges
    data = np.ma.array(data)
    data.mask = np.isnan(data)
    
    if dqmasks is not None:
        # Get the data quality mask for the original image and
        # set any edge values to the bad_pix_val, and scale the dqmask
        # with a nearest neighbor (pixelated) interpolation
        dqmask = extract_array(dqmasks[ref_index], src_shape, (y,x), 
                               fill_value=bad_pix_val)
        dqmask[dqmask<0] = bad_pix_val
        dqmask = zoom(dqmask, subsampling, order=0)
        data.mask = data.mask | (dqmask>dqmask_min)
        modified_dqmask = [None, dqmask, None]
    else:
        dqmask = None
        modified_dqmask = [None,None,None]
        dqmasks = [None,None,None]
    
    if show_plots:
        import matplotlib
        import matplotlib.pyplot as plt
        if dqmask is not None:
            plt.imshow(dqmask, interpolation='none')
            plt.show()
        if data is not None:
            plt.imshow(data, interpolation='none')
            plt.show()
    # Reproject the images
    modified_data = [None, data, None]
    for n in [m for m in range(len(images)) if m!=ref_index]:
        modified_data[n],modified_dqmask[n] = reproject_image(
            images[n], x, y, x_new, y_new, tx_solutions[n], dqmasks[n],
            subsampling, show_plots, dqmask_min, bad_pix_val)
    # Only stack non-null images
    modified_data = [m for m in modified_data if m is not None]
    if len(modified_data)==0:
        return None, None
    elif len(modified_data)==1:
        return modified_data[0], modified_dqmask[0]
    
    # Stack the images and combine the data quality masks
    stack = np.ma.array(modified_data)
    stack = combine(stack, axis=0)
    dqmask = modified_data[0].mask
    for n in range(1,len(modified_data)):
        dqmask = np.bitwise_and(dqmask, modified_data[n].mask)
    
    if show_plots:
        import matplotlib
        import matplotlib.pyplot as plt
        from mpl_toolkits.mplot3d.axes3d import Axes3D
        Xmesh, Ymesh = np.meshgrid(x_new, y_new)
        fig = plt.figure(figsize=(6, 6))
        ax=fig.add_subplot(1,1,1, projection='3d')
        ax.plot_wireframe(Xmesh, Ymesh, stack)
        plt.show()
        plt.contour(Xmesh,Ymesh,stack)
        plt.axis('equal')
        plt.show()
        plt.imshow(stack, interpolation='none')
        plt.show()
        plt.imshow(dqmask, interpolation='none')
        plt.show()
    
    return stack, dqmask
Example #2
0
def reproject_image(img, x, y, new_x, new_y, tx_solution=None,
        dqmask=None, subsampling=5, 
        show_plot=False, dqmask_min=0, bad_pix_val=1):
    """
    Reproject one image onto another using image coordinates
    
    Parameters
    ----------
    img: array-like
        Array containing the image to reproject
    x,y: float
        Coordinates at the center of the projection. If ``tx_solutions``
        is None, these must be in the original image coordinates. 
        Otherwise these must be in the reprojected image coordinates.
    new_x, new_y: array-like
        Coordinate positions for each pixel on the x and y axes in the
        image. If ``tx_solutions`` is None, these must be in the 
        original image coordinates. Otherwise these must be in the 
        reprojected image coordinates.
    tx_solution: `~astropyp.catalog.ImageSolution`, optional
        Astrometric solution to transform from the current image coordinates
        to the new image coordinates. If x, y, new_x, new_y are all in the
        original image coordinates, set ``tx_solution`` to None.
        *Default is None*
    dqmask: `~numpy.ndarray`, optional
        Data quality mask to apply to the reprojected image. This can
        either be in the coordinate system of ``img``, in which case
        ``reproject_dqmask=True`` or in the new coordinate system,
        in which case ``reproject_dqmask=False``.
    subsampling: int
        Number of subdivisions of each pixel. *Default=5*
    show_plot: bool, optional
        Whether or not to show a plot of the reprojected image.
        *Default=False*
    dqmask_min: int, optional
        Minimum value of a data quality mask that is accepted.
        All pixels higher than ``dqmask_min`` will be masked in the
        reprojected image. *Default=0*
    bad_pix_val: int, optional
        Value to set bad pixels to in the dqmask. This is only 
        necessary if using a dqmask. *Default=1*
    
    Results
    -------
    modified_data: `~numpy.ndarray`
        Data in the reprojected coordinate system
    modified_dqmask: `~numpy.ndarray`
        dqmask in the reprojected coordinate system. This will be
        ``None`` if no dqmask was passed to the function.
    X0: `~numpy.ndarray`
        Coodinates on the X axis in the original coordinate system
        after it has been subsampled and re-centered
    Y0: `~numpy.ndarray`
        Coodinates on the Y axis in the original coordinate system
        after it has been subsampled and re-centered
    new_pos: tuple
        New position in the original coordinate system after it has
        been subsampled and re-centered
    """
    from scipy import interpolate
    from astropy.nddata.utils import overlap_slices
    import astropyp.utils
    from astropyp.utils.misc import extract_array
    from scipy.ndimage import zoom
    
    src_shape = (len(new_y)/subsampling, len(new_x)/subsampling)
    
    # Convert the centroid position from destination coordinates
    # to current image coordinates and extract the subsampled image
    if tx_solution is not None:
        x0,y0 = tx_solution.transform_coords(x=x, y=y)
    else:
        x0,y0 = (x,y)
    
    data, slices = extract_array(img,
        src_shape, (y0,x0), subsampling=subsampling, return_slices=True)
    y_radius = int(src_shape[0]/2)
    x_radius = int(src_shape[1]/2)
    X0 = np.linspace(x0-x_radius, x0+x_radius, data.shape[1])
    Y0 = np.linspace(y0-y_radius, y0+y_radius, data.shape[0])
    
    #Z = interpolate.RectBivariateSpline(
    #    Y0[slices[1][0]], X0[slices[1][1]], data[slices[1]])
    X0 = X0[slices[1][1]]
    Y0 = Y0[slices[1][0]]
    Z = interpolate.RectBivariateSpline(Y0,X0, data[slices[1]])
    
    # Convert the coordinates from the destination to the
    # current image and extract the interpolated pixels
    if tx_solution is not None:
        X,Y = tx_solution.transform_coords(x=new_x, y=new_y)
    else:
        X,Y = (new_x, new_y)
    X = X[slices[1][1]]
    Y = Y[slices[1][0]]
    
    modified_data = np.zeros(data.shape)
    modified_data[:] = np.nan
    modified_data[slices[1]] = Z(Y,X)
    modified_data = np.ma.array(modified_data)
    modified_data.mask = np.isnan(modified_data)
    if dqmask is not None:
        modified_dqmask = np.zeros(data.shape)
        modified_dqmask[:] = bad_pix_val
        new_dqmask = extract_array(dqmask, src_shape, (y0,x0), 
            masking=True, fill_value=bad_pix_val)
        new_dqmask = zoom(new_dqmask, subsampling, order=0)
        new_dqmask = new_dqmask[slices[1]]
        Xold,Yold = np.meshgrid(X0,Y0)
        Xnew,Ynew = np.meshgrid(X,Y)
        coords = zip(Yold.flatten(), Xold.flatten())
        new_coords = zip(Ynew.flatten(), Xnew.flatten())
        new_dqmask = interpolate.griddata(coords,
            new_dqmask.flatten(),new_coords, method='nearest')
        modified_dqmask[slices[1]] = new_dqmask.reshape(Xold.shape)
        modified_data.mask = modified_data.mask | (modified_dqmask>dqmask_min)
    else:
        modified_dqmask = None
    if show_plot:
        import matplotlib
        import matplotlib.pyplot as plt
        plt.imshow(modified_data, interpolation='none')
        plt.show()
    return modified_data, modified_dqmask