Beispiel #1
0
def make_Zernike_grads(mask, roi = None, max_order = 100, return_grids = False, return_basis = False, yx_bounds = None, test = False):
    if return_grids :
        basis, basis_grid, y, x = make_Zernike_basis(mask, roi, max_order, return_grids, yx_bounds, test)
    else :
        basis = make_Zernike_basis(mask, roi, max_order, return_grids, yx_bounds, test)

    # calculate the x and y gradients
    from numpy.polynomial import polynomial as P
    
    # just a list of [(grad_ss, grad_fs), ...] where the grads are in a polynomial basis
    grads = [ (P.polyder(b, axis=0), P.polyder(b, axis=1)) for b in basis ]

    if return_grids :
        # just a list of [(grad_ss, grad_fs), ...] where the grads are evaluated on a y, x grid
        grad_grids = [(P.polygrid2d(y, x, g[0]), P.polygrid2d(y, x, g[1])) for g in grads]

        if return_basis :
            return grads, grad_grids, basis, basis_grid
        else :
            return grads, grad_grids
    else :
        if return_basis :
            return grads, basis
        else :
            return grads
Beispiel #2
0
    def test_polygrid2d(self):
        x1, x2, x3 = self.x
        y1, y2, y3 = self.y

        #test values
        tgt = np.einsum('i,j->ij', y1, y2)
        res = poly.polygrid2d(x1, x2, self.c2d)
        assert_almost_equal(res, tgt)

        #test shape
        z = np.ones((2,3))
        res = poly.polygrid2d(z, z, self.c2d)
        assert_(res.shape == (2, 3)*2)
Beispiel #3
0
    def test_polygrid2d(self):
        x1, x2, x3 = self.x
        y1, y2, y3 = self.y

        # test values
        tgt = np.einsum('i,j->ij', y1, y2)
        res = poly.polygrid2d(x1, x2, self.c2d)
        assert_almost_equal(res, tgt)

        # test shape
        z = np.ones((2, 3))
        res = poly.polygrid2d(z, z, self.c2d)
        assert_(res.shape == (2, 3) * 2)
Beispiel #4
0
def polygrid2d(x, y, c):
    """
    Evaluate a 2-D polynomial on the Cartesian product of x and y.

    This function returns the values:

    .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * a^i * b^j

    where the points `(a, b)` consist of all pairs formed by taking
    `a` from `x` and `b` from `y`. The resulting points form a grid with
    `x` in the first dimension and `y` in the second.

    The parameters `x` and `y` are converted to arrays only if they are
    tuples or a lists, otherwise they are treated as a scalars. In either
    case, either `x` and `y` or their elements must support multiplication
    and addition both with themselves and with the elements of `c`.

    If `c` has fewer than two dimensions, ones are implicitly appended to
    its shape to make it 2-D. The shape of the result will be c.shape[2:] +
    x.shape + y.shape.

    Parameters
    ----------
    x, y : array_like, compatible objects
        The two dimensional series is evaluated at the points in the
        Cartesian product of `x` and `y`.  If `x` or `y` is a list or
        tuple, it is first converted to an ndarray, otherwise it is left
        unchanged and, if it isn't an ndarray, it is treated as a scalar.
    c : array_like
        Array of coefficients ordered so that the coefficients for terms of
        degree i,j are contained in `c[i,j]`. If `c` has dimension
        greater than two the remaining indices enumerate multiple sets of
        coefficients.

    Returns
    -------
    values : ndarray, compatible object
        The values of the two dimensional polynomial at points in the Cartesian
        product of `x` and `y`.

    See Also
    --------
    polyval2d, polyfit2d
    numpy.polynomial.polynomial.polygrid2d
    """
    from numpy.polynomial.polynomial import polygrid2d

    c = np.asarray(c)
    if c.ndim != 2 or c.shape[0] != c.shape[1]:
        raise ValueError("c must be a squard 2-dim array.")
    return polygrid2d(x, y, c)
Beispiel #5
0
def polygrid2d(x, y, c):
    """
    Evaluate a 2-D polynomial on the Cartesian product of x and y.

    This function returns the values:

    .. math:: p(a,b) = \sum_{i,j} c_{i,j} * a^i * b^j

    where the points `(a, b)` consist of all pairs formed by taking
    `a` from `x` and `b` from `y`. The resulting points form a grid with
    `x` in the first dimension and `y` in the second.

    The parameters `x` and `y` are converted to arrays only if they are
    tuples or a lists, otherwise they are treated as a scalars. In either
    case, either `x` and `y` or their elements must support multiplication
    and addition both with themselves and with the elements of `c`.

    If `c` has fewer than two dimensions, ones are implicitly appended to
    its shape to make it 2-D. The shape of the result will be c.shape[2:] +
    x.shape + y.shape.

    Parameters
    ----------
    x, y : array_like, compatible objects
        The two dimensional series is evaluated at the points in the
        Cartesian product of `x` and `y`.  If `x` or `y` is a list or
        tuple, it is first converted to an ndarray, otherwise it is left
        unchanged and, if it isn't an ndarray, it is treated as a scalar.
    c : array_like
        Array of coefficients ordered so that the coefficients for terms of
        degree i,j are contained in ``c[i,j]``. If `c` has dimension
        greater than two the remaining indices enumerate multiple sets of
        coefficients.

    Returns
    -------
    values : ndarray, compatible object
        The values of the two dimensional polynomial at points in the Cartesian
        product of `x` and `y`.

    See Also
    --------
    polyval2d, polyfit2d
    numpy.polynomial.polynomial.polygrid2d
    """
    from numpy.polynomial.polynomial import polygrid2d

    c = np.asarray(c)
    if c.ndim != 2 or c.shape[0] != c.shape[1]:
        raise ValueError("c must be a squard 2-dim array.")
    return polygrid2d(x, y, c)
Beispiel #6
0
def apply_skew_poly(input_data,
                    delta_kcoa_poly,
                    row_array,
                    col_array,
                    fft_sgn,
                    dimension,
                    forward=False):
    """
    Performs the skew operation on the complex array, according to the provided
    delta kcoa polynomial.

    Parameters
    ----------
    input_data : numpy.ndarray
        The input data.
    delta_kcoa_poly : numpy.ndarray
        The delta kcoa polynomial to use.
    row_array : numpy.ndarray
        The row array, should agree with input_data first dimension definition.
    col_array : numpy.ndarray
        The column array, should agree with input_data second dimension definition.
    fft_sgn : int
        The fft sign to use.
    dimension : int
        The dimension to apply along.
    forward : bool
        If True, this shifts forward (i.e. skews), otherwise applies in inverse
        (i.e. deskew) direction.

    Returns
    -------
    numpy.ndarray
    """

    if numpy.all(delta_kcoa_poly == 0):
        return input_data

    delta_kcoa_poly_int = polynomial.polyint(delta_kcoa_poly, axis=dimension)
    if forward:
        fft_sgn *= -1
    return input_data * numpy.exp(
        1j * fft_sgn * 2 * numpy.pi *
        polynomial.polygrid2d(row_array, col_array, delta_kcoa_poly_int))
Beispiel #7
0
def _deskew_array(input_data, delta_kcoa_poly, row_array, col_array, fft_sgn, dimension):
    """
    Performs deskew (centering of the spectrum on zero frequency) on a complex array.

    Parameters
    ----------
    input_data : numpy.ndarray
    delta_kcoa_poly : numpy.ndarray
    row_array : numpy.ndarray
    col_array : numpy.ndarray
    fft_sgn : int

    Returns
    -------
    numpy.ndarray
    """

    delta_kcoa_poly_int = polynomial.polyint(delta_kcoa_poly, axis=dimension)
    return input_data*numpy.exp(1j*fft_sgn*2*numpy.pi*polynomial.polygrid2d(
        row_array, col_array, delta_kcoa_poly_int))
Beispiel #8
0
    def __init__(self, cal_img: np.ndarray):
        self.width = int(np.size(cal_img, 1) / 2)
        self.height = np.size(cal_img, 0)

        # Normalise and convert to 8-bit
        im = np.zeros_like(cal_img, dtype="uint8")
        cv2.normalize(cal_img, im, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)

        # find all spots in left and right images
        posl = self._find_spots(im[:, 0:self.width])
        nl = len(posl)
        posr = self._find_spots(im[:, self.width:])
        nr = len(posr)

        # Reduce parameter-space for determining the affine transform by
        # finding 6-way co-ordinated spots that lie at the centre of Penrose
        # stars. Find star radius, central spot positions, and centroid offsets
        # for left and right images.
        (dmidl, pos6l, diff6l) = self._find_penrose(posl)
        (dmidr, pos6r, diff6r) = self._find_penrose(posr)

        # find matched 6-way co-ordinated spot pairs
        pmatch6l = []
        pmatch6r = []

        for i in range(
                len(pos6l)):  # loop over all 6-way co-ordinated left spots
            dist6 = np.hypot(
                pos6r[:, 1] - pos6l[i, 1],
                self.width - 1 - pos6r[:, 0] - pos6l[i, 0],
            )
            # the distance of all right spots from this left spot
            distoffs = np.hypot(diff6l[i, 1] - diff6r[:, 1],
                                diff6l[i, 0] + diff6r[:, 0])
            # the distance between the right and left 6-spot centroids
            for j in range(len(
                    pos6r)):  # loop over all 6-way co-ordinated spots on right
                if (dist6[j] < 4 * dmidl) & (distoffs[j] < dmidl / 4):
                    # select spots as pairs if they are close enough and if the
                    # centroids are close enough
                    pmatch6l = np.append(pmatch6l, pos6l[i, :])
                    # add to list of left and right matched spots
                    pmatch6r = np.append(pmatch6r, pos6r[j, :])
        nmatch6 = int(len(pmatch6l) / 2)
        pmatch6l = np.reshape(pmatch6l, (nmatch6, 2))
        pmatch6r = np.reshape(pmatch6r, (nmatch6, 2))

        # find affine transform based on 6-way matches
        [retval, p_affine] = cv2.solve(np.c_[pmatch6r,
                                             np.ones(nmatch6)],
                                       pmatch6l,
                                       flags=cv2.DECOMP_SVD)

        # transform all right spot positions to find matches on left
        posrt = np.matmul(np.c_[posr, np.ones(nr)], p_affine)

        pmatchl = []
        pmatchr = []
        for i in range(nl):
            dist = np.hypot(*(posl[i] - posrt).T)
            mind = min(dist)
            if mind < 5:
                pmatchl = np.append(pmatchl, posl[i, :])
                pmatchr = np.append(pmatchr, posr[np.argmin(dist), :])

        nmatch = int(len(pmatchl) / 2)
        pmatchl = np.reshape(pmatchl, (nmatch, 2))
        pmatchr = np.reshape(pmatchr, (nmatch, 2))

        # Determine polynomial transform for all matched pairs
        # Sum terms: 1, x, y, x^2, y^2, x*y, x^2*y, x*y^2, x^3, y^3
        # Use polygrid2d: ~5x quicker, may avoid fp error accumulation,
        # gives same result to within < 1ppm.
        from numpy.polynomial.polynomial import polygrid2d

        p1 = np.ones(nmatch)
        px = pmatchl[:, 0]
        py = pmatchl[:, 1]
        rmatp = np.c_[p1, py, py * py, py * py * py, px, px * py, px * py * py,
                      px * px, px * px * py, px * px * px, ]
        [retval, pcoeffs_raw] = cv2.solve(rmatp, pmatchr, flags=cv2.DECOMP_SVD)
        # Put raw coeffs into matrix such that element [i,j] holds Cij in
        # poly = sum (Cij * x^i * y^j).
        pcoeffs = np.zeros((4, 4, 2))
        pcoeffs[(0, 0, 0, 0, 1, 1, 1, 2, 2, 3),
                (0, 1, 2, 3, 0, 1, 2, 0, 1, 0), :] = pcoeffs_raw
        xs = np.arange(self.width)
        ys = np.arange(self.height)
        deformation = polygrid2d(xs, ys, pcoeffs).T.astype(np.float32)

        # Convential memory deformation map
        self.defXcpu = deformation[..., 0].copy()
        self.defYcpu = deformation[..., 1].copy()

        # GPU memory deformation map
        self.defX = cv2.UMat(self.defXcpu)
        self.defY = cv2.UMat(self.defYcpu)
Beispiel #9
0
 def product(a, b):
     c = P.polygrid2d(y[roi[0]:roi[1]+1], x[roi[2]:roi[3]+1], a)
     d = P.polygrid2d(y[roi[0]:roi[1]+1], x[roi[2]:roi[3]+1], b)
     v = np.sum(sub_mask * c * d)
     return v
Beispiel #10
0
def make_Zernike_basis(mask, roi = None, max_order = 100, return_grids = False, yx_bounds = None, test = False):
    """
    Make Zernike basis functions, such that:
        np.sum( Z_i * Z_j * mask) = delta_ij

    Returns
    -------
    basis_poly : list of arrays
        The basis functions in a polynomial basis.

    basis_grid : list of arrays
        The basis functions evaluated on the cartesian grid
    """
    shape = mask.shape
    
    # list the Zernike indices in the Noll indexing order:
    # ----------------------------------------------------
    Noll_indices = make_Noll_index_sequence(max_order)
    
    # set the x-y values and scale to the roi
    # ---------------------------------------
    if roi is None :
        roi = [0, shape[0]-1, 0, shape[1]-1]
    
    sub_mask  = mask[roi[0]:roi[1]+1, roi[2]:roi[3]+1] 
    sub_shape = sub_mask.shape
    
    if yx_bounds is None :
        if (roi[1] - roi[0]) > (roi[3] - roi[2]) :
            m = float(roi[1] - roi[0]) / float(roi[3] - roi[2])
            yx_bounds = [-m, m, -1., 1.]
        else :
            m = float(roi[3] - roi[2]) / float(roi[1] - roi[0])
            yx_bounds = [-1., 1., -m, m]
    
    dom = yx_bounds
    y = ((dom[1]-dom[0])*np.arange(shape[0]) + dom[0]*roi[1]-dom[1]*roi[0])/(roi[1]-roi[0])
    x = ((dom[3]-dom[2])*np.arange(shape[1]) + dom[2]*roi[3]-dom[3]*roi[2])/(roi[3]-roi[2])

    # define the area element
    # -----------------------
    dA = (x[1] - x[0]) * (y[1] - y[0])
    
    # generate the Zernike polynomials in a cartesian basis:
    # ------------------------------------------------------
    Z_polynomials = []
    for j in range(1, max_order+1):
        n, m, name           = Noll_indices[j]
        mat, A               = make_Zernike_polynomial_cartesian(n, m, order = max_order)
        Z_polynomials.append(mat * A * dA)
    
    # define the product method
    # -------------------------
    from numpy.polynomial import polynomial as P
    def product(a, b):
        c = P.polygrid2d(y[roi[0]:roi[1]+1], x[roi[2]:roi[3]+1], a)
        d = P.polygrid2d(y[roi[0]:roi[1]+1], x[roi[2]:roi[3]+1], b)
        v = np.sum(sub_mask * c * d)
        return v
    
    basis = Gram_Schmit_orthonormalisation(Z_polynomials, product)
    
    # test the basis function
    if test :
        print '\n\nbasis_i, basis_j, product(basis_i, basis_j)'
        for i in range(len(basis)) :
            for j in range(len(basis)) :
                print i, j, product(basis[i], basis[j])

    if return_grids :
        basis_grid = [P.polygrid2d(y, x, b) for b in basis]
        
        if test :
            print '\n\nbasis_i, basis_j, np.sum(mask * basis_i * basis_j)'
            for i in range(len(basis_grid)) :
                for j in range(len(basis_grid)) :
                    print i, j, np.sum(mask * basis_grid[i] * basis_grid[j])
        return basis, basis_grid, y, x
    else :
        return basis