Ejemplo n.º 1
0
def lensDistortionPixelDistances(imagePath=None, mod=None, lensfunDbObj=None, exiftoolObj=None, retH=False):
    """
    Return the difference between the distances from the image center to the distorted and undistorted
    pixel locations.
    
    See :func:`correctLensDistortion` for parameters.
    
    :rtype: ndarray of shape (h,w)
    """
    if not mod:
        mod,_,_ = getLensfunModifier(imagePath, lensfunDbObj, exiftoolObj)
        
    undistCoordsXY = mod.apply_geometry_distortion()

    height, width = undistCoordsXY.shape[0], undistCoordsXY.shape[1]

    y, x = np.mgrid[0:undistCoordsXY.shape[0], 0:undistCoordsXY.shape[1]]
    coordsXY = np.dstack((x,y))
    
    center = np.array([width/2, height/2])
    
    vectorsDist = (coordsXY - center).reshape(-1, 2)
    vectorsUndist = (undistCoordsXY - center).reshape(-1, 2)
    
    hDist = vectorLengths(vectorsDist).reshape(coordsXY.shape[0], coordsXY.shape[1])
    hUndist = vectorLengths(vectorsUndist).reshape(coordsXY.shape[0], coordsXY.shape[1])
    
    distance = hDist - hUndist
    
    if retH:
        return distance, hDist, hUndist
    else:
        return distance
Ejemplo n.º 2
0
 def distance(self):
     """
     Distance for each pixel center between camera and intersection point.
     For debugging purposes only!
     """
     vectors = (self.intersectionInflatedCenter - self.cameraPosGCRS).reshape(-1, 3)
     lens = vectorLengths(vectors).reshape(self.intersectionInflatedCenter.shape[0], self.intersectionInflatedCenter.shape[1])
     return lens
Ejemplo n.º 3
0
def lensDistortionPixelDistances(imagePath=None,
                                 mod=None,
                                 lensfunDbObj=None,
                                 exiftoolObj=None,
                                 retH=False,
                                 minAcceptedScore=MIN_ACCEPTED_SCORE):
    """
    Return the difference between the distances from the image center to the distorted and undistorted
    pixel locations.
    
    See :func:`correctLensDistortion` for parameters.
    
    :rtype: ndarray of shape (h,w)
    """
    if not mod:
        mod, _, _ = getLensfunModifier(imagePath,
                                       lensfunDbObj,
                                       exiftoolObj,
                                       minAcceptedScore=minAcceptedScore)

    undistCoordsXY = mod.apply_geometry_distortion()

    height, width = undistCoordsXY.shape[0], undistCoordsXY.shape[1]

    y, x = np.mgrid[0:undistCoordsXY.shape[0], 0:undistCoordsXY.shape[1]]
    coordsXY = np.dstack((x, y))

    center = np.array([width / 2, height / 2])

    vectorsDist = (coordsXY - center).reshape(-1, 2)
    vectorsUndist = (undistCoordsXY - center).reshape(-1, 2)

    hDist = vectorLengths(vectorsDist).reshape(coordsXY.shape[0],
                                               coordsXY.shape[1])
    hUndist = vectorLengths(vectorsUndist).reshape(coordsXY.shape[0],
                                                   coordsXY.shape[1])

    distance = hDist - hUndist

    if retH:
        return distance, hDist, hUndist
    else:
        return distance
Ejemplo n.º 4
0
def sphereLineIntersection(sphereRadius,
                           lineOrigin,
                           lineDirection,
                           directed=True):
    """
    Return the sphere-line intersection points.
            
    :param sphereRadius: radius of sphere with origin [0,0,0]
    :param lineOrigin: point, e.g. [1,2,3]
    :param lineDirection: unit vector or array of unit vectors
    :param bool directed: 
        True, if the line should be directed. In that case, the first intersection
        along the line is returned.
        If False, then the line is infinite in both ends and the intersection which
        is closest to the line origin is returned.
    :rtype: vector or array of vectors
    """
    directionPosDot = np.dot(lineDirection, lineOrigin)
    rootTerm = np.square(directionPosDot)
    rootTerm -= np.dot(lineOrigin, lineOrigin)
    rootTerm += np.square(sphereRadius)
    with np.errstate(
            invalid='ignore'
    ):  # ignore warnings for negative numbers (= no intersection)
        root = np.sqrt(rootTerm)
    directionPosDotNeg = -directionPosDot

    if directed:
        isInside = vectorLengths([lineOrigin])[0] < sphereRadius
        if isInside:
            d2 = directionPosDotNeg + root
            dMin = d2
        else:
            d1 = directionPosDotNeg - root
            dMin = d1
        dMin = _filterPointsOutsideDirectedLine(dMin)
    else:
        d1 = directionPosDotNeg - root
        d2 = directionPosDotNeg + root
        dMin = _closestDistance(d1, d2)

    return lineOrigin + dMin[..., None] * lineDirection
Ejemplo n.º 5
0
def sphereLineIntersection(sphereRadius, lineOrigin, lineDirection, directed=True):
    """
    Return the sphere-line intersection points.
            
    :param sphereRadius: radius of sphere with origin [0,0,0]
    :param lineOrigin: point, e.g. [1,2,3]
    :param lineDirection: unit vector or array of unit vectors
    :param bool directed: 
        True, if the line should be directed. In that case, the first intersection
        along the line is returned.
        If False, then the line is infinite in both ends and the intersection which
        is closest to the line origin is returned.
    :rtype: vector or array of vectors
    """
    directionPosDot = np.dot(lineDirection,lineOrigin)
    rootTerm = np.square(directionPosDot)
    rootTerm -= np.dot(lineOrigin,lineOrigin)
    rootTerm += np.square(sphereRadius)
    with np.errstate(invalid='ignore'): # ignore warnings for negative numbers (= no intersection)
        root = np.sqrt(rootTerm)
    directionPosDotNeg = -directionPosDot
    
    if directed:
        isInside = vectorLengths([lineOrigin])[0] < sphereRadius
        if isInside:
            d2 = directionPosDotNeg + root
            dMin = d2
        else:
            d1 = directionPosDotNeg - root
            dMin = d1
        dMin = _filterPointsOutsideDirectedLine(dMin)
    else:
        d1 = directionPosDotNeg - root
        d2 = directionPosDotNeg + root
        dMin = _closestDistance(d1, d2)

    return lineOrigin + dMin[...,None]*lineDirection
Ejemplo n.º 6
0
def tan_pix2world(header, px, py, origin, ascartesian=False):
    """
    Fast reimplementation of astropy.wcs.wcs.wcs_pix2world with support for
    only the TAN projection. Speedup is about 2x.
    
    :rtype: tuple (ra,dec) in degrees, or cartesian coordinates in one array (h,w,3) 
            if ascartesian=True
    """
    assert origin in [0,1]
    assert px.shape == py.shape
    shape = px.shape
    px = px.ravel()
    py = py.ravel()
    
    assert header['CTYPE1'] == 'RA---TAN'
    assert header['CTYPE2'] == 'DEC--TAN'
    assert header['LATPOLE'] == 0.0
    lonpole = header['LONPOLE']
    
    ra_ref = header['CRVAL1'] # degrees
    dec_ref = header['CRVAL2']
    px_ref = header['CRPIX1']
    py_ref = header['CRPIX2']
    cd = np.array([[header['CD1_1'], header['CD1_2']],
                   [header['CD2_1'], header['CD2_2']]])
                
    # make pixel coordinates relative to reference point and put them in one array
    pxy = np.empty((len(px),2), float)
    pxy[:,0] = px
    pxy[:,0] -= px_ref
    pxy[:,1] = py
    pxy[:,1] -= py_ref
    if origin == 0:
        pxy += 1
    
    # projection plane coordinates
    xy = matrix_multiply(cd, pxy[...,np.newaxis]).reshape(pxy.shape) # [18% of execution time]
    
    del pxy
    
    # native spherical coordinates
    # spherical projection
    if ne:
        x = xy[:,0]
        y = xy[:,1]
        r = ne('sqrt(x*x+y*y)')
    else:
        r = vectorLengths(xy)
    
    if ne:
        lon = ne('arctan2(x, -y)') # [6% of execution time]
    else:
        lon = np.arctan2(xy[:,0], -xy[:,1])
    del xy
        
    #lat = np.arctan(180/(np.pi*r))
    
    # optimized:
    with np.errstate(divide='ignore'):
        np.reciprocal(r, r)
    np.multiply(180/np.pi, r, r)
    if ne:
        ne('arctan(r)', out=r)
    else:
        np.arctan(r, r)
    lat = r
    
    # celestial spherical coordinates
    # spherical rotation
    euler_z = ra_ref+90
    euler_x = 90-dec_ref
    #euler_z2 = lonpole-90
    euler_z2 = -(lonpole-90) # for some reason, this needs to be negative, contrary to paper
    rotmat = euler_matrix(np.deg2rad(euler_z), np.deg2rad(euler_x), np.deg2rad(euler_z2), 'rzxz')[:3,:3]
    
    lmn = spherical_to_cartesian(None, lat, lon, astuple=False) # [12% of execution time]
    lmnrot = matrix_multiply(rotmat, lmn[...,np.newaxis]).reshape(lmn.shape) # [17% of execution time]
    if ascartesian:
        return lmnrot.reshape(shape + (3,))
    
    dec, ra = cartesian_to_spherical(lmnrot[:,0], lmnrot[:,1], lmnrot[:,2], with_radius=False) # [15% of execution time]
    
    np.rad2deg(dec, dec)    
    np.rad2deg(ra, ra)
    # wrap at 360deg so that values are in [0,360]
    ra -= 360
    np.mod(ra, 360, ra) # [12% of execution time]
    
    ra = ra.reshape(shape)
    dec = dec.reshape(shape)
    
    return ra, dec
Ejemplo n.º 7
0
def tan_pix2world(header, px, py, origin, ascartesian=False):
    """
    Fast reimplementation of astropy.wcs.wcs.wcs_pix2world with support for
    only the TAN projection. Speedup is about 2x.
    
    :rtype: tuple (ra,dec) in degrees, or cartesian coordinates in one array (h,w,3) 
            if ascartesian=True
    """
    assert origin in [0, 1]
    assert px.shape == py.shape
    shape = px.shape
    px = px.ravel()
    py = py.ravel()

    assert header['CTYPE1'] == 'RA---TAN'
    assert header['CTYPE2'] == 'DEC--TAN'
    assert header['LATPOLE'] == 0.0
    lonpole = header['LONPOLE']

    ra_ref = header['CRVAL1']  # degrees
    dec_ref = header['CRVAL2']
    px_ref = header['CRPIX1']
    py_ref = header['CRPIX2']
    cd = np.array([[header['CD1_1'], header['CD1_2']],
                   [header['CD2_1'], header['CD2_2']]])

    # make pixel coordinates relative to reference point and put them in one array
    pxy = np.empty((len(px), 2), float)
    pxy[:, 0] = px
    pxy[:, 0] -= px_ref
    pxy[:, 1] = py
    pxy[:, 1] -= py_ref
    if origin == 0:
        pxy += 1

    # projection plane coordinates
    xy = matrix_multiply(cd, pxy[..., np.newaxis]).reshape(
        pxy.shape)  # [18% of execution time]

    del pxy

    # native spherical coordinates
    # spherical projection
    if ne:
        x = xy[:, 0]
        y = xy[:, 1]
        r = ne('sqrt(x*x+y*y)')
    else:
        r = vectorLengths(xy)

    if ne:
        lon = ne('arctan2(x, -y)')  # [6% of execution time]
    else:
        lon = np.arctan2(xy[:, 0], -xy[:, 1])
    del xy

    #lat = np.arctan(180/(np.pi*r))

    # optimized:
    with np.errstate(divide='ignore'):
        np.reciprocal(r, r)
    np.multiply(180 / np.pi, r, r)
    if ne:
        ne('arctan(r)', out=r)
    else:
        np.arctan(r, r)
    lat = r

    # celestial spherical coordinates
    # spherical rotation
    euler_z = ra_ref + 90
    euler_x = 90 - dec_ref
    #euler_z2 = lonpole-90
    euler_z2 = -(
        lonpole - 90
    )  # for some reason, this needs to be negative, contrary to paper
    rotmat = euler_matrix(np.deg2rad(euler_z), np.deg2rad(euler_x),
                          np.deg2rad(euler_z2), 'rzxz')[:3, :3]

    lmn = spherical_to_cartesian(None, lat, lon,
                                 astuple=False)  # [12% of execution time]
    lmnrot = matrix_multiply(rotmat, lmn[..., np.newaxis]).reshape(
        lmn.shape)  # [17% of execution time]
    if ascartesian:
        return lmnrot.reshape(shape + (3, ))

    dec, ra = cartesian_to_spherical(
        lmnrot[:, 0], lmnrot[:, 1], lmnrot[:, 2],
        with_radius=False)  # [15% of execution time]

    np.rad2deg(dec, dec)
    np.rad2deg(ra, ra)
    # wrap at 360deg so that values are in [0,360]
    ra -= 360
    np.mod(ra, 360, ra)  # [12% of execution time]

    ra = ra.reshape(shape)
    dec = dec.reshape(shape)

    return ra, dec