def kpts_matrices(kpts): # We are given the keypoint in invA format # invV = perdoch.invA # V = perdoch.A # Z = perdoch.E # invert into V #invV = kpts_to_invV(kpts) invV = ktool.get_invV_mats3x3(kpts) V = ktool.invert_invV_mats(invV) Z = ktool.get_Z_mats(V) return invV, V, Z
def sample_uniform(kpts, nSamples=128): """ SeeAlso: python -m pyhesaff.tests.test_ellipse --test-in_depth_ellipse --show """ nKp = len(kpts) # Get keypoint matrix forms invV_mats3x3 = ktool.get_invV_mats3x3(kpts) V_mats3x3 = ktool.invert_invV_mats(invV_mats3x3) #------------------------------- # Get uniform points on a circle circle_pts = homogenous_circle_pts(nSamples + 1)[0:-1] assert circle_pts.shape == (nSamples, 3) #------------------------------- # Get uneven points sample (get_uneven_point_sample) polygon1_list = matrix_multiply(invV_mats3x3, circle_pts.T).transpose(0, 2, 1) assert polygon1_list.shape == (nKp, nSamples, 3) # ------------------------------- # The transformed points are not sampled uniformly... Bummer # We will sample points evenly across the sampled polygon # then we will project them onto the ellipse dists = np.array([circular_distance(arr) for arr in polygon1_list]) assert dists.shape == (nKp, nSamples) # perimeter of the polygon perimeter = dists.sum(1) assert perimeter.shape == (nKp, ) # Take a perfect multiple of steps along the perimeter multiplier = 1 step_size = perimeter / (nSamples * multiplier) assert step_size.shape == (nKp, ) # Walk along edge num_steps_list = [] offset_list = [] total_dist = np.zeros(step_size.shape) # step_size.copy() dist_walked = np.zeros(step_size.shape) assert dist_walked.shape == (nKp, ) assert total_dist.shape == (nKp, ) distsT = dists.T assert distsT.shape == (nSamples, nKp) # This loops over the pt samples and performs the operation for every keypoint for count in range(nSamples): segment_len = distsT[count] # Find where your starting location is offset_list.append(total_dist - dist_walked) # How far can you possibly go? total_dist += segment_len # How many steps can you take? num_steps = (total_dist - dist_walked) // step_size num_steps_list.append(num_steps) # Log how much further youve gotten dist_walked += (num_steps * step_size) # Check for floating point errors # take an extra step if you need to num_steps_list[-1] += np.round((perimeter - dist_walked) / step_size) assert np.all(np.array(num_steps_list).sum(0) == nSamples) """ #offset_iter1 = zip(num_steps_list, distsT, offset_list) #offset_list = [((step_size - offset) / dist, ((num * step_size) - offset) / dist, num) #for num, dist, offset in zip(num_steps_list, distsT, offset_list)] #offset_iter2 = offset_list #cut_locs = [[ #np.linspace(off1, off2, n, endpoint=True) for (off1, off2, n) in zip(offset1, offset2, num)] #for (offset1, offset2, num) in offset_iter2 #] # store the percent location at each line segment where # the cut will be made """ # HERE IS NEXT cut_list = [] # This loops over the pt samples and performs the operation for every keypoint for num, dist, offset in zip(num_steps_list, distsT, offset_list): #if num == 0 #cut_list.append([]) #continue # This was a bitch to keep track of offset1 = (step_size - offset) / dist offset2 = ((num * step_size) - offset) / dist cut_locs = [ np.linspace(off1, off2, n, endpoint=True) for (off1, off2, n) in zip(offset1, offset2, num) ] # post check for divide by 0 cut_locs = [ np.array([0 if np.isinf(c) else c for c in cut]) for cut in cut_locs ] cut_list.append(cut_locs) cut_list = np.array(cut_list).T assert cut_list.shape == (nKp, nSamples) # ================= # METHOD 1 # ================= # Linearly interpolate between points on the polygons at the places we cut def interpolate(pt1, pt2, percent): # interpolate between point1 and point2 return ((1 - percent) * pt1) + ((percent) * pt2) def polygon_points(polygon_pts, dist_list): return np.array([ interpolate(polygon_pts[count], polygon_pts[(count + 1) % nSamples], loc) for count, locs in enumerate(dist_list) for loc in iter(locs) ]) new_locations = np.array([ polygon_points(polygon_pts, cuts) for polygon_pts, cuts in zip(polygon1_list, cut_list) ]) # ================= # ================= # METHOD 2 """ #from itertools import cycle as icycle #from itertools import islice #def icycle_shift1(iterable): #return islice(icycle(poly_pts), 1, len(poly_pts) + 1) #cutptsIter_list = [zip(iter(poly_pts), icycle_shift1(poly_pts), cuts) #for poly_pts, cuts in zip(polygon1_list, cut_list)] #new_locations = [[[((1 - cut) * pt1) + ((cut) * pt2) for cut in cuts] #for (pt1, pt2, cuts) in cutPtsIter] #for cutPtsIter in cutptsIter_list] """ # ================= # assert new_locations.shape == (nKp, nSamples, 3) # Warp new_locations to the unit circle #new_unit = V.dot(new_locations.T).T new_unit = np.array( [v.dot(newloc.T).T for v, newloc in zip(V_mats3x3, new_locations)]) # normalize new_unit new_mag = np.sqrt((new_unit**2).sum(-1)) new_unorm_unit = new_unit / np.dstack([new_mag] * 3) new_norm_unit = new_unorm_unit / np.dstack([new_unorm_unit[:, :, 2]] * 3) # Get angle (might not be necessary) #x_axis = np.array([1, 0, 0]) #arccos_list = x_axis.dot(new_norm_unit.T) #uniform_theta_list = np.arccos(arccos_list) # Maybe this? # Find the angle from the center of the circle theta_list2 = np.arctan2(new_norm_unit[:, :, 1], new_norm_unit[:, :, 0]) # assert uniform_theta_list.shape = (nKp, nSample) # Use this angle to unevenly sample the perimeter of the circle uneven_cicrle_pts = np.dstack( [np.cos(theta_list2), np.sin(theta_list2), np.ones(theta_list2.shape)]) # The uneven circle points were sampled in such a way that when they are # transformeed they will be approximately uniform along the boundary of the # ellipse. uniform_ell_hpts = [ v.dot(pts.T).T for (v, pts) in zip(invV_mats3x3, uneven_cicrle_pts) ] # Remove the homogenous coordinate and we're done ell_border_pts_list = [pts[:, 0:2] for pts in uniform_ell_hpts] return ell_border_pts_list
def get_affine_inliers(kpts1, kpts2, fm, fs, xy_thresh_sqrd, scale_thresh_sqrd, ori_thresh): """ Estimates inliers deterministically using elliptical shapes Compute all transforms from kpts1 to kpts2 (enumerate all hypothesis) We transform from chip1 -> chip2 The determinants are squared keypoint scales FROM PERDOCH 2009:: H = inv(Aj).dot(Rj.T).dot(Ri).dot(Ai) H = inv(Aj).dot(Ai) The input invVs = perdoch.invA's CommandLine: python -m vtool.spatial_verification --test-get_affine_inliers Example: >>> # ENABLE_DOCTEST >>> from vtool.spatial_verification import * # NOQA >>> import vtool.tests.dummy as dummy >>> import vtool.keypoint as ktool >>> kpts1, kpts2 = dummy.get_dummy_kpts_pair((100, 100)) >>> fm = dummy.make_dummy_fm(len(kpts1)).astype(np.int32) >>> fs = np.ones(len(fm), dtype=np.float64) >>> xy_thresh_sqrd = ktool.KPTS_DTYPE(.009) ** 2 >>> scale_thresh_sqrd = ktool.KPTS_DTYPE(2) >>> ori_thresh = ktool.KPTS_DTYPE(TAU / 4) >>> output = get_affine_inliers(kpts1, kpts2, fm, fs, xy_thresh_sqrd, >>> scale_thresh_sqrd, ori_thresh) >>> result = ut.hashstr(output) >>> print(result) 89kz8nh6p+66t!+u Ignore:: from vtool.spatial_verification import * # NOQA import vtool.tests.dummy as dummy import vtool.keypoint as ktool kpts1, kpts2 = dummy.get_dummy_kpts_pair((100, 100)) a = kpts1[fm.T[0]] b = kpts1.take(fm.T[0]) align = fm.dtype.itemsize * fm.shape[1] align2 = [fm.dtype.itemsize, fm.dtype.itemsize] viewtype1 = np.dtype(np.void, align) viewtype2 = np.dtype(np.int32, align2) c = np.ascontiguousarray(fm).view(viewtype1) fm_view = np.ascontiguousarray(fm).view(viewtype1) qfx = fm.view(np.dtype(np.int32 np.int32.itemsize)) dfx = fm.view(np.dtype(np.int32, np.int32.itemsize)) d = np.ascontiguousarray(c).view(viewtype2) fm.view(np.dtype(np.void, align)) np.ascontiguousarray(fm).view(np.dtype((np.void, Z.dtype.itemsize * Z.shape[1]))) """ #http://ipython-books.github.io/featured-01/ kpts1_m = kpts1.take(fm.T[0], axis=0) kpts2_m = kpts2.take(fm.T[1], axis=0) # Get keypoints to project in matrix form #invVR2s_m = ktool.get_invV_mats(kpts2_m, with_trans=True, with_ori=True) #invVR1s_m = ktool.get_invV_mats(kpts1_m, with_trans=True, with_ori=True) invVR2s_m = ktool.get_invVR_mats3x3(kpts2_m) invVR1s_m = ktool.get_invVR_mats3x3(kpts1_m) RV1s_m = ktool.invert_invV_mats(invVR1s_m) # 539 us # BUILD ALL HYPOTHESIS TRANSFORMS: The transform from kp1 to kp2 is: Aff_mats = matrix_multiply(invVR2s_m, RV1s_m) # Get components to test projects against xy2_m = ktool.get_xys(kpts2_m) det2_m = ktool.get_sqrd_scales(kpts2_m) ori2_m = ktool.get_oris(kpts2_m) # SLOWER EQUIVALENT # RV1s_m = ktool.get_V_mats(kpts1_m, with_trans=True, with_ori=True) # 5.2 ms # xy2_m = ktool.get_invVR_mats_xys(invVR2s_m) # ori2_m = ktool.get_invVR_mats_oris(invVR2s_m) # assert np.all(ktool.get_oris(kpts2_m) == ktool.get_invVR_mats_oris(invVR2s_m)) # assert np.all(ktool.get_xys(kpts2_m) == ktool.get_invVR_mats_xys(invVR2s_m)) # The previous versions of this function were all roughly comparable. # The for loop one was the slowest. I'm deciding to go with the one # where there is no internal function definition. It was moderately faster, # and it gives us access to profile that function inliers_and_errors_list = [ _test_hypothesis_inliers(Aff, invVR1s_m, xy2_m, det2_m, ori2_m, xy_thresh_sqrd, scale_thresh_sqrd, ori_thresh) for Aff in Aff_mats ] aff_inliers_list = [tup[0] for tup in inliers_and_errors_list] aff_errors_list = [tup[1] for tup in inliers_and_errors_list] return aff_inliers_list, aff_errors_list, Aff_mats
def get_affine_inliers(kpts1, kpts2, fm, fs, xy_thresh_sqrd, scale_thresh_sqrd, ori_thresh): """ Estimates inliers deterministically using elliptical shapes Compute all transforms from kpts1 to kpts2 (enumerate all hypothesis) We transform from chip1 -> chip2 The determinants are squared keypoint scales FROM PERDOCH 2009:: H = inv(Aj).dot(Rj.T).dot(Ri).dot(Ai) H = inv(Aj).dot(Ai) The input invVs = perdoch.invA's CommandLine: python -m vtool.spatial_verification --test-get_affine_inliers Example: >>> # ENABLE_DOCTEST >>> from vtool.spatial_verification import * # NOQA >>> import vtool.tests.dummy as dummy >>> import vtool.keypoint as ktool >>> kpts1, kpts2 = dummy.get_dummy_kpts_pair((100, 100)) >>> fm = dummy.make_dummy_fm(len(kpts1)).astype(np.int32) >>> fs = np.ones(len(fm), dtype=np.float64) >>> xy_thresh_sqrd = ktool.KPTS_DTYPE(.009) ** 2 >>> scale_thresh_sqrd = ktool.KPTS_DTYPE(2) >>> ori_thresh = ktool.KPTS_DTYPE(TAU / 4) >>> output = get_affine_inliers(kpts1, kpts2, fm, fs, xy_thresh_sqrd, >>> scale_thresh_sqrd, ori_thresh) >>> result = ut.hashstr(output) >>> print(result) 89kz8nh6p+66t!+u Ignore:: from vtool.spatial_verification import * # NOQA import vtool.tests.dummy as dummy import vtool.keypoint as ktool kpts1, kpts2 = dummy.get_dummy_kpts_pair((100, 100)) a = kpts1[fm.T[0]] b = kpts1.take(fm.T[0]) align = fm.dtype.itemsize * fm.shape[1] align2 = [fm.dtype.itemsize, fm.dtype.itemsize] viewtype1 = np.dtype(np.void, align) viewtype2 = np.dtype(np.int32, align2) c = np.ascontiguousarray(fm).view(viewtype1) fm_view = np.ascontiguousarray(fm).view(viewtype1) qfx = fm.view(np.dtype(np.int32 np.int32.itemsize)) dfx = fm.view(np.dtype(np.int32, np.int32.itemsize)) d = np.ascontiguousarray(c).view(viewtype2) fm.view(np.dtype(np.void, align)) np.ascontiguousarray(fm).view(np.dtype((np.void, Z.dtype.itemsize * Z.shape[1]))) """ #http://ipython-books.github.io/featured-01/ kpts1_m = kpts1.take(fm.T[0], axis=0) kpts2_m = kpts2.take(fm.T[1], axis=0) # Get keypoints to project in matrix form #invVR2s_m = ktool.get_invV_mats(kpts2_m, with_trans=True, with_ori=True) #invVR1s_m = ktool.get_invV_mats(kpts1_m, with_trans=True, with_ori=True) invVR2s_m = ktool.get_invVR_mats3x3(kpts2_m) invVR1s_m = ktool.get_invVR_mats3x3(kpts1_m) RV1s_m = ktool.invert_invV_mats(invVR1s_m) # 539 us # BUILD ALL HYPOTHESIS TRANSFORMS: The transform from kp1 to kp2 is: Aff_mats = matrix_multiply(invVR2s_m, RV1s_m) # Get components to test projects against xy2_m = ktool.get_xys(kpts2_m) det2_m = ktool.get_sqrd_scales(kpts2_m) ori2_m = ktool.get_oris(kpts2_m) # SLOWER EQUIVALENT # RV1s_m = ktool.get_V_mats(kpts1_m, with_trans=True, with_ori=True) # 5.2 ms # xy2_m = ktool.get_invVR_mats_xys(invVR2s_m) # ori2_m = ktool.get_invVR_mats_oris(invVR2s_m) # assert np.all(ktool.get_oris(kpts2_m) == ktool.get_invVR_mats_oris(invVR2s_m)) # assert np.all(ktool.get_xys(kpts2_m) == ktool.get_invVR_mats_xys(invVR2s_m)) # The previous versions of this function were all roughly comparable. # The for loop one was the slowest. I'm deciding to go with the one # where there is no internal function definition. It was moderately faster, # and it gives us access to profile that function inliers_and_errors_list = [_test_hypothesis_inliers(Aff, invVR1s_m, xy2_m, det2_m, ori2_m, xy_thresh_sqrd, scale_thresh_sqrd, ori_thresh) for Aff in Aff_mats] aff_inliers_list = [tup[0] for tup in inliers_and_errors_list] aff_errors_list = [tup[1] for tup in inliers_and_errors_list] return aff_inliers_list, aff_errors_list, Aff_mats
def sample_uniform(kpts, nSamples=128): """ SeeAlso: python -m pyhesaff.tests.test_ellipse --test-in_depth_ellipse --show """ nKp = len(kpts) # Get keypoint matrix forms invV_mats3x3 = ktool.get_invV_mats3x3(kpts) V_mats3x3 = ktool.invert_invV_mats(invV_mats3x3) #------------------------------- # Get uniform points on a circle circle_pts = homogenous_circle_pts(nSamples + 1)[0:-1] assert circle_pts.shape == (nSamples, 3) #------------------------------- # Get uneven points sample (get_uneven_point_sample) polygon1_list = matrix_multiply(invV_mats3x3, circle_pts.T).transpose(0, 2, 1) assert polygon1_list.shape == (nKp, nSamples, 3) # ------------------------------- # The transformed points are not sampled uniformly... Bummer # We will sample points evenly across the sampled polygon # then we will project them onto the ellipse dists = np.array([circular_distance(arr) for arr in polygon1_list]) assert dists.shape == (nKp, nSamples) # perimeter of the polygon perimeter = dists.sum(1) assert perimeter.shape == (nKp,) # Take a perfect multiple of steps along the perimeter multiplier = 1 step_size = perimeter / (nSamples * multiplier) assert step_size.shape == (nKp,) # Walk along edge num_steps_list = [] offset_list = [] total_dist = np.zeros(step_size.shape) # step_size.copy() dist_walked = np.zeros(step_size.shape) assert dist_walked.shape == (nKp,) assert total_dist.shape == (nKp,) distsT = dists.T assert distsT.shape == (nSamples, nKp) # This loops over the pt samples and performs the operation for every keypoint for count in range(nSamples): segment_len = distsT[count] # Find where your starting location is offset_list.append(total_dist - dist_walked) # How far can you possibly go? total_dist += segment_len # How many steps can you take? num_steps = (total_dist - dist_walked) // step_size num_steps_list.append(num_steps) # Log how much further youve gotten dist_walked += (num_steps * step_size) # Check for floating point errors # take an extra step if you need to num_steps_list[-1] += np.round((perimeter - dist_walked) / step_size) assert np.all(np.array(num_steps_list).sum(0) == nSamples) """ #offset_iter1 = zip(num_steps_list, distsT, offset_list) #offset_list = [((step_size - offset) / dist, ((num * step_size) - offset) / dist, num) #for num, dist, offset in zip(num_steps_list, distsT, offset_list)] #offset_iter2 = offset_list #cut_locs = [[ #np.linspace(off1, off2, n, endpoint=True) for (off1, off2, n) in zip(offset1, offset2, num)] #for (offset1, offset2, num) in offset_iter2 #] # store the percent location at each line segment where # the cut will be made """ # HERE IS NEXT cut_list = [] # This loops over the pt samples and performs the operation for every keypoint for num, dist, offset in zip(num_steps_list, distsT, offset_list): #if num == 0 #cut_list.append([]) #continue # This was a bitch to keep track of offset1 = (step_size - offset) / dist offset2 = ((num * step_size) - offset) / dist cut_locs = [np.linspace(off1, off2, n, endpoint=True) for (off1, off2, n) in zip(offset1, offset2, num)] # post check for divide by 0 cut_locs = [np.array([0 if np.isinf(c) else c for c in cut]) for cut in cut_locs] cut_list.append(cut_locs) cut_list = np.array(cut_list).T assert cut_list.shape == (nKp, nSamples) # ================= # METHOD 1 # ================= # Linearly interpolate between points on the polygons at the places we cut def interpolate(pt1, pt2, percent): # interpolate between point1 and point2 return ((1 - percent) * pt1) + ((percent) * pt2) def polygon_points(polygon_pts, dist_list): return np.array([interpolate(polygon_pts[count], polygon_pts[(count + 1) % nSamples], loc) for count, locs in enumerate(dist_list) for loc in iter(locs)]) new_locations = np.array([polygon_points(polygon_pts, cuts) for polygon_pts, cuts in zip(polygon1_list, cut_list)]) # ================= # ================= # METHOD 2 """ #from itertools import cycle as icycle #from itertools import islice #def icycle_shift1(iterable): #return islice(icycle(poly_pts), 1, len(poly_pts) + 1) #cutptsIter_list = [zip(iter(poly_pts), icycle_shift1(poly_pts), cuts) #for poly_pts, cuts in zip(polygon1_list, cut_list)] #new_locations = [[[((1 - cut) * pt1) + ((cut) * pt2) for cut in cuts] #for (pt1, pt2, cuts) in cutPtsIter] #for cutPtsIter in cutptsIter_list] """ # ================= # assert new_locations.shape == (nKp, nSamples, 3) # Warp new_locations to the unit circle #new_unit = V.dot(new_locations.T).T new_unit = np.array([v.dot(newloc.T).T for v, newloc in zip(V_mats3x3, new_locations)]) # normalize new_unit new_mag = np.sqrt((new_unit ** 2).sum(-1)) new_unorm_unit = new_unit / np.dstack([new_mag] * 3) new_norm_unit = new_unorm_unit / np.dstack([new_unorm_unit[:, :, 2]] * 3) # Get angle (might not be necessary) #x_axis = np.array([1, 0, 0]) #arccos_list = x_axis.dot(new_norm_unit.T) #uniform_theta_list = np.arccos(arccos_list) # Maybe this? # Find the angle from the center of the circle theta_list2 = np.arctan2(new_norm_unit[:, :, 1], new_norm_unit[:, :, 0]) # assert uniform_theta_list.shape = (nKp, nSample) # Use this angle to unevenly sample the perimeter of the circle uneven_cicrle_pts = np.dstack([np.cos(theta_list2), np.sin(theta_list2), np.ones(theta_list2.shape)]) # The uneven circle points were sampled in such a way that when they are # transformeed they will be approximately uniform along the boundary of the # ellipse. uniform_ell_hpts = [v.dot(pts.T).T for (v, pts) in zip(invV_mats3x3, uneven_cicrle_pts)] # Remove the homogenous coordinate and we're done ell_border_pts_list = [pts[:, 0:2] for pts in uniform_ell_hpts] return ell_border_pts_list