def add_blob(obj, src_q=None, v=None, scale=0.001, style="star", distance=1.0): angle_rs = { "diamond": [(i, 1) for i in range(0, 450, 90)], "star": [(i, [1, 0.5][((i / 36) & 1)]) for i in range(0, 396, 36)], "triangle": [(i, 1) for i in range(0, 450, 120)], "inv_triangle": [(i, 1) for i in range(60, 450, 120)], } if v is not None: cxyz = v.coords dv = vector_z if (cxyz[0] == 0) and (cxyz[0] == 0): dv = vector_y src_q = quaternion().lookat(v, dv) pass else: cxyz = src_q.rotate_vector(vector((0, 0, distance))).coords pass lxyz = None for (angle, r) in angle_rs[style]: vector_z_sc = vector((0, scale * r, distance)) xyz = (src_q * quaternion().from_euler( roll=angle, degrees=1)).rotate_vector(vector_z_sc).coords if lxyz is not None: obj.add_triangle([cxyz, lxyz, xyz], [(0, 0)] * 3) pass lxyz = xyz pass pass
def propagate(self, ids_propagated_to): """ for every other if that other is not in the set ids_propagated_to then propagate the top optimized orientation to that other and return list of others that were propagated to """ if self.base_orientation is None: return result = [] md = self.map_data.keys() md.sort(cmp=lambda x, y: cmp(str(x), str(y))) for od in md: (other, direction) = od if other in ids_propagated_to: continue bqs = self.map_data[od]['best_qs'] if len(bqs) == 0: continue (iteration, score, opt_q, start_q) = bqs[-1] if (iteration == 0) and (score < 20): print "Ignoring poor match %s => %s" % (self.image_filename, other.image_filename) continue opt_q = gjslib_c.quaternion(r=opt_q[0], i=opt_q[1], j=opt_q[2], k=opt_q[3]) if od[1] == 0: opt_q = ~opt_q other.set_base_orientation(self.base_orientation * opt_q) print self.image_filename, '-->', other.image_filename result.append(other) pass return result
def quaternion_average(qs): vf = gjslib_c.vector(length=3) vu = gjslib_c.vector(length=3) for q in qs: vf += q.rotate_vector(vector_z) vu += q.rotate_vector(vector_x) pass return gjslib_c.quaternion().lookat(vf, vu)
def __init__(self, src_from_tgt_q, score, qic): self.max_distance = score # measure of how good it is - smaller the better self.src_from_tgt_q = src_from_tgt_q self.min_cos_sep = 0 self.max_q_dist = 0 self.mappings = [] # list of (src/tgt) pairs self.best_mappings = [] # list of (src,tgt,n) pairs self.qs = {} # map from src,tgt,src,tgt to orientation, distance self.qic_scores = qic.scores() self.qic_mappings = qic.src_tgt_mappings_of_best_matches( min_score=0, min_count=0) self.optimized_src_from_tgt_q = gjslib_c.quaternion(1) pass
def add_blob(obj, src_q, scale=0.001, style="star"): angle_rs = {"diamond": [(i,1) for i in range(0,450,90)], "star": [(i,[1,0.5][((i/36)&1)]) for i in range(0,396,36)], "triangle": [(i,1) for i in range(0,450,120)], "inv_triangle": [(i,1) for i in range(60,450,120)], } cxyz= src_q.rotate_vector(gjslib_c.vector((0,0,0.8))).coords lxyz = None for (angle,r) in angle_rs[style]: vector_z_sc = gjslib_c.vector((0,scale*r,0.8)) xyz = (src_q*gjslib_c.quaternion().from_euler(roll=angle,degrees=1)).rotate_vector(vector_z_sc).coords if lxyz is not None: obj.add_triangle([cxyz,lxyz,xyz],[(0,0)]*3) pass lxyz = xyz pass pass
def __init__(self, image_filename, frame_width=22.3, focal_length=35.0, lens_type="rectilinear", orientation=None): self.texture = gjslib_c.texture(filename=image_filename) # The lp has to have width/height such that a uv of 0 to 1 maps from left to right, and bottom to top # The uv is derived from the (-1,1) range, i.e. uv can also be conceived as -1=left, -1=bottom, +1=right, +1=top # Hence for images that are wider than high, we want -1=left, +1=right; but the same angle rotated by 90 is off the top # So the uv for that must be = width/height. Hence, for wider than high, width=2.0, height=2.0*width/height # For example, an image that is 300 wide and 200 high will have width=2.0, height=3.0 self.lp = gjslib_c.lens_projection(width=2.0, height=2.0 * self.texture.width / self.texture.height * 0.99, frame_width=frame_width, focal_length=focal_length, lens_type=lens_type) if orientation is None: orientation = gjslib_c.quaternion(r=1) pass self.lp.orient(orientation) pass
def find_mappings_to_try_qic( self, min_q_dist=0.0002, max_q_dist=0.5): # default of 0.5 degrees min sep print "Building from qic list of src_from_tgt_q (min_q_dist %f, max_q_dist %f)" % ( min_q_dist, max_q_dist) mappings_to_try = [] mappings_to_try.append( gjslib_c.quaternion(1)) # Ensure identity is on the list for src_qx in self.qic.src_qs(): for tgt_qx in self.qic.tgt_qs_of_src_q(src_qx): #print src_qx, tgt_qx src_tgt_mappings = self.qic.src_tgt_mappings(src_qx, tgt_qx) for (src_q0, src_q1, tgt_q0, tgt_q1, src_from_tgt_q) in src_tgt_mappings: #print src_q0, tgt_q0, src_q1, tgt_q1, src_from_tgt_q add_to_list = True for src_from_tgt_qx in mappings_to_try: dq = src_from_tgt_q.distance_to(src_from_tgt_qx) if dq < min_q_dist: add_to_list = False break if dq > max_q_dist: add_to_list = False break pass if not add_to_list: continue mappings_to_try.append(src_from_tgt_q) if (len(mappings_to_try) % 500) == 0: print "Have %d mappings, continuing" % len( mappings_to_try) pass pass pass pass return mappings_to_try
def do_it_fine(images, focal_length, lens_type, max_iteration_depth=2, reverse=0, initial_dest_orientation=None, save_wobbles=False): ipqm = c_image_pair_quaternion_match() ipqm.save_pngs = True ipqm.add_image(image_filename=images[0], orientation=gjslib_c.quaternion(r=1), focal_length=focal_length, lens_type=lens_type) ipqm.add_image(image_filename=images[1], orientation=gjslib_c.quaternion(r=1), focal_length=focal_length, lens_type=lens_type) ipqm.orient(images[1], initial_dest_orientation) best_matches = quaternion_image_correlate(ipqm, images, focal_length=30.0, accuracy="80pix35_fine", num_proj=1) results = [] iteration_depth = 0 if True: for bm in best_matches: bm.src_from_tgt_q *= initial_dest_orientation bm.optimized_src_from_tgt_q *= initial_dest_orientation rq0 = bm.src_from_tgt_q rq1 = bm.optimized_src_from_tgt_q print bm.max_distance, "(r=%f,i=%f,j=%f,k=%f)" % ( rq0.r, rq0.i, rq0.j, rq0.k), "(r=%f,i=%f,j=%f,k=%f)" % ( rq1.r, rq1.i, rq1.j, rq1.k), rq1.to_rotation_str(1) results.append((bm, iteration_depth, (iteration_depth + 1) * 100 * bm.max_distance)) pass if len(best_matches) == 0: return [] # Second pass can use more tighter projections - and hence better accuracy is worthwhile initial_dest_orientation = best_matches[0].optimized_src_from_tgt_q ipqm.orient(images[1], initial_dest_orientation) best_matches = quaternion_image_correlate(ipqm, images, focal_length=100.0, num_proj=4, accuracy="20pix35_fine") iteration_depth += 1 if True: for bm in best_matches: bm.src_from_tgt_q *= initial_dest_orientation bm.optimized_src_from_tgt_q *= initial_dest_orientation rq0 = bm.src_from_tgt_q rq1 = bm.optimized_src_from_tgt_q print bm.max_distance, "(r=%f,i=%f,j=%f,k=%f)" % ( rq0.r, rq0.i, rq0.j, rq0.k), "(r=%f,i=%f,j=%f,k=%f)" % ( rq1.r, rq1.i, rq1.j, rq1.k), rq1.to_rotation_str(1) results.append((bm, iteration_depth, (iteration_depth + 1) * 100 * bm.max_distance)) pass results.sort(cmp=lambda x, y: cmp(y[2], x[2])) for (bm, iteration_depth, score) in results: rq0 = bm.src_from_tgt_q rq1 = bm.optimized_src_from_tgt_q print iteration_depth, bm.max_distance, "(r=%f,i=%f,j=%f,k=%f)" % ( rq0.r, rq0.i, rq0.j, rq0.k), "(r=%f,i=%f,j=%f,k=%f)" % ( rq1.r, rq1.i, rq1.j, rq1.k), rq1.to_rotation_str(1) pass if save_wobbles: chosen_q = results[0][0].optimized_src_from_tgt_q ipqm.orient(images[1], chosen_q) src_img_lp_to = gjslib_c.lens_projection(width=2.0, height=2.0, frame_width=36.0, focal_length=15, lens_type="rectilinear") dst_img_lp_to = gjslib_c.lens_projection(width=2.0, height=2.0, frame_width=36.0, focal_length=15, lens_type="rectilinear") src_img_lp_to.orient(gjslib_c.quaternion(1)) dst_img_lp_to.orient(gjslib_c.quaternion(1)) if not ipqm.overlap_projections((images[0], images[1]), (src_img_lp_to, dst_img_lp_to)): raise Exception, "Failed to get final projection" ipqm.project_and_save("found", (images[0], images[1]), (src_img_lp_to, dst_img_lp_to)) base_dst_orient = dst_img_lp_to.orientation for i in range(len(wobbles)): dst_img_lp_to.orient(base_dst_orient * wobbles[i]) ipqm.project_and_save("wobble_%d_" % i, (images[0], images[1]), (src_img_lp_to, dst_img_lp_to)) pass pass return results
def do_it(images, focal_length, lens_type, max_iteration_depth=2, reverse=0, initial_dest_orientation=None): ipqm = c_image_pair_quaternion_match() ipqm.add_image(image_filename=images[0], orientation=gjslib_c.quaternion(r=1), focal_length=focal_length, lens_type=lens_type) ipqm.add_image(image_filename=images[1], orientation=gjslib_c.quaternion(r=1), focal_length=focal_length, lens_type=lens_type) iq = gjslib_c.quaternion(r=1) if reverse: iq = iq.from_euler(roll=180, degrees=1) pass trial_orientations = [(iq, 0)] if initial_dest_orientation is not None: trial_orientations = [(initial_dest_orientation, 0)] pass orientations_attempted = set() results = [] while len(trial_orientations) > 0: (initial_dest_orientation, iteration_depth) = trial_orientations.pop(0) s = (str(initial_dest_orientation), iteration_depth) if s in orientations_attempted: print "Skipping as already attempted" continue orientations_attempted.add(s) ipqm.orient(images[1], initial_dest_orientation) best_matches = quaternion_image_correlate( ipqm, images, focal_length=50.0, accuracy=["80pix35", "20pix35", "8pix35"][iteration_depth]) for bm in best_matches: bm.src_from_tgt_q *= initial_dest_orientation bm.optimized_src_from_tgt_q *= initial_dest_orientation rq0 = bm.src_from_tgt_q rq1 = bm.optimized_src_from_tgt_q print bm.max_distance, "(r=%f,i=%f,j=%f,k=%f)" % ( rq0.r, rq0.i, rq0.j, rq0.k), "(r=%f,i=%f,j=%f,k=%f)" % ( rq1.r, rq1.i, rq1.j, rq1.k), rq1.to_rotation_str(1) if (len(results) == 0) or (bm.max_distance > [10, 20, 30][iteration_depth]): results.append((bm, iteration_depth, (iteration_depth + 1) * 100 * bm.max_distance)) if iteration_depth < max_iteration_depth: trial_orientations.append( (bm.optimized_src_from_tgt_q, iteration_depth + 1)) pass pass pass pass results.sort(cmp=lambda x, y: cmp(y[2], x[2])) for (bm, iteration_depth, score) in results: rq0 = bm.src_from_tgt_q rq1 = bm.optimized_src_from_tgt_q print iteration_depth, bm.max_distance, "(r=%f,i=%f,j=%f,k=%f)" % ( rq0.r, rq0.i, rq0.j, rq0.k), "(r=%f,i=%f,j=%f,k=%f)" % ( rq1.r, rq1.i, rq1.j, rq1.k), rq1.to_rotation_str(1) pass return results
def quaternion_image_correlate(ipqm, images, focal_length=50.0, accuracy="80pix35", max_n=10, num_proj=2): print "Quaternion_Image_Correlate" orientations_to_use = ( gjslib_c.quaternion().from_euler(yaw=-12.0, degrees=1), gjslib_c.quaternion().from_euler(yaw=+12.0, degrees=1), ) if num_proj == 1: orientations_to_use = (gjslib_c.quaternion().from_euler(yaw=0, degrees=1), ) if num_proj > 2: src_img_lp_to = gjslib_c.lens_projection(width=2.0, height=2.0, frame_width=36.0, focal_length=15, lens_type="rectilinear") dst_img_lp_to = gjslib_c.lens_projection(width=2.0, height=2.0, frame_width=36.0, focal_length=15, lens_type="rectilinear") src_img_lp_to.orient(gjslib_c.quaternion(1)) dst_img_lp_to.orient(gjslib_c.quaternion(1)) if not ipqm.overlap_projections((images[0], images[1]), (src_img_lp_to, dst_img_lp_to), verbose=False): raise Exception, "Failed to organize projections" print "Focal length now ", src_img_lp_to.focal_length, "centered on", src_img_lp_to.orientation.rotate_vector( vector_z) print "For num_proj=4, want to double the focal_length and center on quadrants" vs = [] for i in range(4): dxy = ((-1, -1), (1, -1), (1, 1), (-1, 1))[i] vs.append( (src_img_lp_to.orientation_of_xy(dxy).rotate_vector(vector_z), src_img_lp_to.orientation_of_xy(dxy).rotate_vector(vector_x))) pass orientations_to_use = [] for factors in ((9, 3, 1, 3), (3, 9, 3, 1), (1, 3, 9, 3), (3, 1, 3, 9)): vf = gjslib_c.vector(vector=(0, 0, 0)) vu = gjslib_c.vector(vector=(0, 0, 0)) for i in range(4): vf += vs[i][0].copy().scale(factors[i]) vu += vs[i][1].copy().scale(factors[i]) pass orientations_to_use.append(gjslib_c.quaternion().lookat(vf, vu)) pass focal_length = src_img_lp_to.focal_length * 2 pass ci0 = ipqm.camera_images[images[0]] ci1 = ipqm.camera_images[images[1]] ipqm.qic = gjslib_c.quaternion_image_correlator() ipqm.qic.min_cos_angle_src_q = min_cos_seps_same_pt[accuracy] ipqm.qic.min_cos_angle_tgt_q = min_cos_seps_same_pt[accuracy] ipqm.qic.min_cos_sep_score = min_cos_seps_for_score[ accuracy] # tgt point must be within this separation for any match of src->tgt to count ipqm.qic.max_q_dist_score = max_q_dists_for_score[ accuracy] # src/src/tgt/tgt orientation must be within this for a point for src->tgt for initial_orientation in orientations_to_use: src_img_lp_to = gjslib_c.lens_projection(width=2.0, height=2.0, frame_width=36.0, focal_length=focal_length, lens_type="rectilinear") dst_img_lp_to = gjslib_c.lens_projection(width=2.0, height=2.0, frame_width=36.0, focal_length=focal_length, lens_type="rectilinear") src_img_lp_to.orient(initial_orientation) dst_img_lp_to.orient(initial_orientation) projections = (src_img_lp_to, dst_img_lp_to) if not ipqm.overlap_projections((images[0], images[1]), (src_img_lp_to, dst_img_lp_to)): continue print "Using src projection focal length", src_img_lp_to.focal_length, "centered on", ( src_img_lp_to.orientation).rotate_vector(vector_z) ipqm.find_matches((images[0], images[1]), projections=projections) pass ipqm.qic.create_mappings() best_matches = ipqm.find_best_target_matches_qic( max_q_dist=max_q_dists[accuracy], min_q_dist=min_q_dists[accuracy] / 10.0, min_cos_sep=min_cos_seps[accuracy], min_cos_sep_score=min_cos_seps[accuracy], max_q_dist_score=min_q_dists[accuracy], ) print ipqm.times() #b Do clusters def cmp_matches(x, y): return cmp(y.max_distance, x.max_distance) if x.max_distance / len(x.mappings) < y.max_distance / len(y.mappings): return -1 return 1 best_matches.sort(cmp=lambda x, y: cmp(y.max_distance, x.max_distance)) print "Best matches for whole image" n = len(best_matches) if n > max_n: n = max_n best_matches = best_matches[:n] for bm in best_matches: bm.calculate(ipqm.qic) pass return best_matches
import gjslib_c import math import sys from filters import * img_png_n = 0 vector_z = gjslib_c.vector(vector=(0, 0, 1)) vector_x = gjslib_c.vector(vector=(1, 0, 0)) #a Basic lens setup gjslib_c.lens_projection.add_named_polynomial( "canon_20_35_rebel2Ti_20", canon_20_35_rebel2Ti_20_polynomial[0], canon_20_35_rebel2Ti_20_polynomial[1]) #a Cos seps etc wobbles = [] r = gjslib_c.quaternion().from_euler(roll=0.303, degrees=1) p = gjslib_c.quaternion().from_euler(pitch=0.303, degrees=1) y = gjslib_c.quaternion().from_euler(yaw=0.303, degrees=1) for i in range(8): q = gjslib_c.quaternion(1) if i & 1: q = r * q else: q = ~r * q if i & 2: q = p * q else: q = ~p * q if i & 4: q = y * q else: q = ~y * q wobbles.append(q) pass del r, p, y # Useful cosines / min q dists:
ids[i0].add_map_data(other=ids[i1], direction=1, image_mapping=image_map_data[(i0, i1)]) ids[i1].add_map_data(other=ids[i0], direction=0, image_mapping=image_map_data[(i0, i1)]) pass image_names = ids.keys() image_names.sort() ids_sorted = [] for i in image_names: ids_sorted.append(ids[i]) pass key_image = ids[image_names[-1]] key_image.set_base_orientation(gjslib_c.quaternion(r=1)) ids_to_propagate = [key_image] ids_propagated_to = set() while len(ids_to_propagate) > 0: next_id = ids_to_propagate.pop(0) ids_propagated_to.add(next_id) ids_to_propagate.extend(next_id.propagate(ids_propagated_to)) pass vfs = [] vf_c = vector_z vf_c -= vf_c for idn in image_names: vf = ids[idn].base_orientation.rotate_vector(vector_z) vf_c += vf