def fundamental_error(rpc1, rpc2, x, y, w, h, n_learn, n_test):
    """
    Measure the error made when imposing a fundamental matrix fitting on
    Pleiades data.

    Args:
        rpc1, rpc2: two instances of the rpc_model.RPCModel class
        x, y, w, h: four integers definig a rectangular region of interest
            (ROI) in the first view. (x, y) is the top-left corner, and (w, h)
            are the dimensions of the rectangle. In the first view, the keypoints
            used for estimation and evaluation are located in that ROI.
        n_learn: number of points sampled in each of the 3 directions to
            generate image correspondences constraints for fundamental matrix
            estimation.
        n_test: number of points sampled in each of the 3 directions to
            generate correspondences used to test the accuracy of the fundamental
            matrix.

    Returns:
        A float value measuring the accuracy of the fundamental matrix. Smaller
        is better.
    """

    # step 1: estimate the fundamental matrix
    matches = rpc_utils.matches_from_rpc(rpc1, rpc2, x, y, w, h, n_learn)
    F = estimation.fundamental_matrix(matches)

    # step 2: compute the residual error
    matches = rpc_utils.matches_from_rpc(rpc1, rpc2, x, y, w, h, n_test)
    err = evaluation.fundamental_matrix(F, matches)
    return err
Example #2
0
def cost_function_linear(v, rpc1, rpc2, matches):
    """
    Objective function to minimize in order to correct the pointing error.

    Arguments:
        v: vector of size 4, containing the 4 parameters of the euclidean
            transformation we are looking for.
        rpc1, rpc2: two instances of the rpc_model.RPCModel class
        matches: 2D numpy array containing a list of matches. Each line
            contains one pair of points, ordered as x1 y1 x2 y2.
            The coordinate system is the one of the big images.
        alpha: relative weight of the error terms: e + alpha*(h-h0)^2. See
            paper for more explanations.

    Returns:
        The sum of pointing errors and altitude differences, as written in the
        paper formula (1).
    """
    print_params(v)

    # verify that parameters are in the bounding box
    if (np.abs(v[0]) > 200*np.pi or
        np.abs(v[1]) > 10000 or
        np.abs(v[2]) > 10000 or
        np.abs(v[3]) > 20000):
        print 'warning: cost_function is going too far'
        print v

    x, y, w, h = common.bounding_box2D(matches[:, 0:2])
    matches_rpc = rpc_utils.matches_from_rpc(rpc1, rpc2, x, y, w, h, 5)
    F = estimation.fundamental_matrix(matches_rpc)

    # transform the coordinates of points in the second image according to
    # matrix A, built from vector v
    A = euclidean_transform_matrix(v)
    p2 = common.points_apply_homography(A, matches[:, 2:4])

    return evaluation.fundamental_matrix_L1(F, np.hstack([matches[:, 0:2], p2]))
Example #3
0
def compute_rectification_homographies(im1, im2, rpc1, rpc2, x, y, w, h, A=None):
    """
    Computes rectifying homographies for a ROI in a pair of Pleiades images.

    Args:
        im1, im2: paths to the two Pleiades images (usually jp2 or tif)
        rpc1, rpc2: two instances of the rpc_model.RPCModel class
        x, y, w, h: four integers definig the rectangular ROI in the first image.
            (x, y) is the top-left corner, and (w, h) are the dimensions of the
            rectangle.
        A (optional): 3x3 numpy array containing the pointing error correction
            for im2. This matrix is usually estimated with the pointing_accuracy
            module.

    Returns:
        H1, H2: Two 3x3 matrices representing the rectifying homographies to be applied
            to the two images.
        disp_min, disp_max: horizontal disparity range, computed on a set of
            sift matches
    """
    # in brief: use 8-pts normalized algo to estimate F, then use loop-zhang to
    # estimate rectifying homographies.

    print "step 1: find matches, and center them ------------------------------"
    sift_matches = matches_from_projection_matrices_roi(im1, im2, rpc1, rpc2, x+w/4, y+h/4, w*2/4, h*2/4)
    #sift_matches2 = matches_from_sift(im1, im2)
    #sift_matches = sift_matches2
#    import visualisation
#    print visualisation.plot_matches(im1,im2,sift_matches)

    p1 = sift_matches[:, 0:2]
    p2 = sift_matches[:, 2:4]


    # the matching points are translated to be centered in 0, in order to deal
    # with coordinates ranging from -1000 to 1000, and decrease imprecision
    # effects of the loop-zhang rectification. These effects may become very
    # important (~ 10 pixels error) when using coordinates around 20000.
    pp1, T1 = center_2d_points(p1)
    pp2, T2 = center_2d_points(p2)

    print "step 2: estimate F (8-points algorithm) ----------------------------"
    F = estimation.fundamental_matrix(np.hstack([pp1, pp2]))
    F = np.dot(T2.T, np.dot(F, T1)) # convert F for big images coordinate frame

    print "step 3: compute rectifying homographies (loop-zhang algorithm) -----"
    H1, H2 = estimation.loop_zhang(F, w, h)
    #### ATTENTION: LOOP-ZHANG IMPLICITLY ASSUMES THAT F IS IN THE FINAL (CROPPED)
    # IMAGE GEOMETRY. THUS 0,0 IS THE UPPER LEFT CORNER OF THE IMAGE AND W,H ARE
    # USED TO ESTIMATE THE DISTORTION WITHIN THE REGION. BY CENTERING THE COORDINATES
    # OF THE PIXELS WE ARE CONSTRUCTING A RECTIFICATION DOES NOT TAKE INTO ACCOUNT THE
    # CORRECT IMAGE PORTION.
    # compose with previous translations to get H1, H2 in the big images frame
    #H1 = np.dot(H1, T1)
    #H2 = np.dot(H2, T2)

    # for debug
    print "min, max, mean rectification error on rpc matches ------------------"
    tmp = common.points_apply_homography(H1, p1)
    y1 = tmp[:, 1]
    tmp = common.points_apply_homography(H2, p2)
    y2 = tmp[:, 1]
    err = np.abs(y1 - y2)
    print np.min(err), np.max(err), np.mean(err)

#    print "step 4: pull back top-left corner of the ROI in the origin ---------"
    roi = [[x, y], [x+w, y], [x+w, y+h], [x, y+h]]
    pts = common.points_apply_homography(H1, roi)
    x0, y0 = common.bounding_box2D(pts)[0:2]
    T = common.matrix_translation(-x0, -y0)
    H1 = np.dot(T, H1)
    H2 = np.dot(T, H2)

    # add an horizontal translation to H2 to center the disparity range around
    # the origin, if sift matches are available
    print "step 5: horizontal registration ------------------------------------"
    sift_matches2 = matches_from_sift(im1, im2)

    # filter sift matches with the known fundamental matrix
    sift_matches2 = filter_matches_epipolar_constraint(F, sift_matches2,
            cfg['epipolar_thresh'])
    if not len(sift_matches2):
        print """all the sift matches have been discarded by the epipolar
        constraint. This is probably due to the pointing error. Try with a
        bigger value for epipolar_thresh."""
        sys.exit()

    H2, disp_m, disp_M = register_horizontally(sift_matches2, H1, H2, do_scale_horizontally=True)
    disp_m, disp_M = update_minmax_range_extrapolating_registration_affinity(sift_matches2,
        H1, H2, w, h)

    return H1, H2, disp_m, disp_M