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
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]))
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