def center_anchor_by_fn(pto): '''Rely on filename to make an anchor estimate''' pto.parse() m = ImageCoordinateMap.from_tagged_file_names(pto.get_file_names()) # Chose a decent center image fn = m.get_image(int(m.width() / 2), int(m.height() / 2)) print 'Selected %s as anchor' % fn anchor(pto, pto.get_image_by_fn(fn))
def center_anchor_by_fn(pto): '''Rely on filename to make an anchor estimate''' pto.parse() m = ImageCoordinateMap.from_tagged_file_names(pto.get_file_names()) # Chose a decent center image fn = m.get_image(int(m.width() / 2), int(m.height() / 2)) dbg('Selected %s as anchor' % fn) anchor(pto, pto.get_image_by_fn(fn))
def __init__(self, file_names, max_level, min_level = 0, out_dir_base=None): self.map = ImageCoordinateMap.from_tagged_file_names(file_names) #self.map.debug_print() self.max_level = max_level self.min_level = min_level self.out_dir_base = out_dir_base #self.set_out_extension('.png') self.set_out_extension('.jpg') self.zoom_factor = 2 self.t_width = 250 self.t_height = 250 # JPEG quality level, 1-100 or something self.quality = 70
def __init__(self, dir_in, threads=1): print "TileMapSource()" self.tw = 250 self.th = 250 self.threads = threads self.file_names = set() for f in os.listdir(dir_in): self.file_names.add(dir_in + "/" + f) self.src_dir = dir_in self.map = ImageCoordinateMap.from_tagged_file_names(self.file_names) self.x_tiles = self.map.width() self.y_tiles = self.map.height() print "Tile canvas width %d, height %d" % (self.width(), self.height()) MapSource.__init__(self)
def __init__(self, dir_in, threads=1): print 'TileMapSource()' self.tw = 250 self.th = 250 self.threads = threads self.file_names = set() for f in os.listdir(dir_in): self.file_names.add(dir_in + "/" + f) self.src_dir = dir_in self.map = ImageCoordinateMap.from_tagged_file_names(self.file_names) self.x_tiles = self.map.width() self.y_tiles = self.map.height() print 'Tile canvas width %d, height %d' % (self.width(), self.height()) MapSource.__init__(self)
def __init__(self, dir_in): print 'TileMapSource()' tw = None th = None tw = 256 th = 256 self.file_names = set() for f in os.listdir(dir_in): self.file_names.add(dir_in + "/" + f) self.dir_in = dir_in self.map = ImageCoordinateMap.from_tagged_file_names(self.file_names) self.x_tiles = self.map.width() self.y_tiles = self.map.height() self.tw = tw self.th = th print 'Tile canvas width %d, height %d' % (self.width(), self.height()) MapSource.__init__(self)
def linear_reoptimize(pto, pto_ref = None, allow_missing = False, order = 2, border = False): '''Change XY positions to match the trend in a linear XY positioned project (ex from XY stage). pto must have all images in pto_ref ''' if scipy is None: raise Exception('Re-optimizing requires scipi') if order is 0: raise Exception('Can not have order 0') if type(order) != type(0): raise Exception('Order is bad type') ''' Our model should be like this: -Each axis will have some degree of backlash. This backlash will create a difference between adjacent rows / cols -Axes may not be perfectly adjacent The naive approach would give: x = c * dx + xc y = r * dy + yc But really we need this: x = c * dx + r * dx/dy + xc y = c * dy/dx + r * dy + yc Each equation can be solved separately Need 3 points to solve each and should be in the expected direction of that line Perform a linear regression on each row/col? Might lead to very large y = mx + b equations for the column math ''' if pto_ref is None: pto_ref = pto ''' Phase 1: calculate linear system ''' # Start by building an image coordinate map so we know what x and y are pto_ref.parse() ref_fns = pto_ref.get_file_names() real_fns = pto.get_file_names() print 'Files (all: %d, ref: %d):' % (len(real_fns), len(ref_fns)) for fn in real_fns: if fn in ref_fns: ref_str = '*' else: ref_str = ' ' print ' %s%s' % (ref_str, fn) m_ref = ImageCoordinateMap.from_tagged_file_names(ref_fns) m_real = ImageCoordinateMap.from_tagged_file_names(real_fns) #m.debug_print() ''' Ultimately trying to form this equation x = c0 * c + c1 * r + c2 y = c3 * c + c4 * r + c5 Except that constants will also have even and odd varities c2 and c5 will be taken from reasonable points of reference, likely (0, 0) or something like that ''' c0s = [] c1s = [] c3s = [] c4s = [] for cur_order in range(order): # Given a column find x (primary x) c0s.append(regress_c0(m_ref, pto_ref, xrange(cur_order, m_ref.height(), order), allow_missing)) c1s.append(regress_c1(m_ref, pto_ref, xrange(cur_order, m_ref.width(), order), allow_missing)) # Given a row find y (primary y) c3s.append(regress_c3(m_ref, pto_ref, xrange(cur_order, m_ref.height(), order), allow_missing)) c4s.append(regress_c4(m_ref, pto_ref, xrange(cur_order, m_ref.width(), order), allow_missing)) # Now chose a point in the center # it doesn't have to be a good fitting point in the old system, it just has to be centered # Fix at the origin ''' Actually the even and the odd should have the same slope The only difference should be their offset ''' c2 = None c5 = None if 0: print 'Solution found' print ' x = %g c + %g r + TBD' % (c0, c1) print ' y = %g c + %g r + TBD' % (c3, c4) # Verify the solution matrix by checking it against the reference project print print 'Verifying reference solution matrix....' # Entire reference is assumed to be good always, no border (c2s_ref, c5s_ref) = calc_constants(order, m_ref, pto_ref, c0s, c1s, c3s, c4s, m_ref, allow_missing) #c1s = [c1 + 12 for c1 in c1s] # Print the solution matrx for debugging for cur_order in range(order): # XXX: if we really cared we could center these up # its easier to just run the centering algorithm after though if one cares print 'Reference order %d solution:' % cur_order print ' x = %g c + %g r + %g' % (c0s[cur_order], c1s[cur_order], c2s_ref[cur_order]) print ' y = %g c + %g r + %g' % (c3s[cur_order], c4s[cur_order], c5s_ref[cur_order]) calc_ref_xs = [] calc_ref_ys = [] ref_xs = [] ref_ys = [] print 'Errors:' x_last = None y_last = None for col in range(m_ref.width()): for row in range(m_ref.height()): fn = m_ref.get_image(col, row) if fn is None: continue il = pto_ref.get_image_by_fn(fn) col_eo = col % order row_eo = row % order x_calc = c0s[row_eo] * col + c1s[row_eo] * row + c2s_ref[row_eo] y_calc = c3s[col_eo] * col + c4s[col_eo] * row + c5s_ref[col_eo] calc_ref_xs.append(x_calc) calc_ref_ys.append(y_calc) x_orig = il.x() y_orig = il.y() ref_xs.append(x_orig) ref_ys.append(y_orig) print ' c%d r%d: x%g y%g (x%g, y%g)' % (col, row, x_calc - x_orig, y_calc - y_orig, x_orig, y_orig) if col > 0: fn_old = m_ref.get_image(col - 1, row) if fn_old: il_old = pto_ref.get_image_by_fn(fn_old) print ' dx: %g' % (il.x() - il_old.x()) if col > 1: ''' x1' = x1 - x0 x2' = x2 - x1 x2'' = x2' - x1' = (x2 - x1) - (x1 - x0) = x2 - 2 x1 + x0 ''' fn_old2 = m_ref.get_image(col - 2, row) if fn_old2: il_old2 = pto_ref.get_image_by_fn(fn_old2) print ' dx2: %g' % (il.x() - 2 * il_old.x() + il_old2.x()) if row != 0: fn_old = m_ref.get_image(col, row - 1) if fn_old: il_old = pto_ref.get_image_by_fn(fn_old) print ' dy: %g' % (il.y() - il_old.y()) if row > 1: fn_old2 = m_ref.get_image(col, row - 2) if fn_old2: il_old2 = pto_ref.get_image_by_fn(fn_old2) print ' dy2: %g' % (il.y() - 2 * il_old.y() + il_old2.y()) x_ref_rms_error = rms_error_diff(calc_ref_xs, ref_xs) y_ref_rms_error = rms_error_diff(calc_ref_ys, ref_ys) print 'Reference RMS error x%g y%g' % (x_ref_rms_error, y_ref_rms_error) print #exit(1) ''' The reference project might not start at 0,0 Therefore scan through to find some good starting positions so that we can calc each point in the final project ''' print 'Anchoring solution...' ''' Calculate the constant at each reference image Compute reference positions from these values ''' ''' FIXME: we have to calculate these initially and then re-calc for border if required if top_bottom_backlash and border: row_border = 1 else: row_border = 0 if left_right_backlash and border: col_border = 1 else: col_border = 0 ''' row_border = 0 col_border = 0 (c2s, c5s) = calc_constants(order, m_real, pto_ref, c0s, c1s, c3s, c4s, m_ref, allow_missing, col_border, row_border) #c2s = [c2 + 30 for c2 in c2s] # Print the solution matrx for debugging for cur_order in range(order): # XXX: if we really cared we could center these up # its easier to just run the centering algorithm after though if one cares print 'Order %d solution:' % cur_order print ' x = %g c + %g r + %g' % (c0s[cur_order], c1s[cur_order], c2s[cur_order]) print ' y = %g c + %g r + %g' % (c3s[cur_order], c4s[cur_order], c5s[cur_order]) c2_rms = rms_errorl(c2s) c5_rms = rms_errorl(c5s) print 'RMS offset error x%g y%g' % (c2_rms, c5_rms) left_right_backlash = False top_bottom_backlash = False if c2_rms > c5_rms: print 'x offset varies most, expect left-right scanning' left_right_backlash = True else: print 'y offset varies most, expect top-bottom scanning' top_bottom_backlash = True #exit(1) ''' We have the solution matrix now so lets roll ''' optimized = set() for col in range(col_border, m_real.width() - col_border): for row in range(row_border, m_real.height() - row_border): fn = m_real.get_image(col, row) il = pto.get_image_by_fn(fn) if fn is None: if not allow_missing: raise Exception('Missing item') continue col_eo = col % order row_eo = row % order # FIRE! # take the dot product x = c0s[row_eo] * col + c1s[row_eo] * row + c2s[row_eo] y = c3s[col_eo] * col + c4s[col_eo] * row + c5s[col_eo] # And push it out #print '%s: c%d r%d => x%g y%d' % (fn, col, row, x, y) il.set_x(x) il.set_y(y) #print il optimized.add(fn) ''' Finally manually optimize those that were in the border area ''' if border: # Gather all file names # There are essentially four cases to do this faster but be lazy since it will still be O(images) to_manually_optimize = set() for col in range(0, m_real.width()): for row in range(m_real.height()): fn = m_real.get_image(col, row) il = pto.get_image_by_fn(fn) if fn is None: if not allow_missing: raise Exception('Missing item') continue if fn in optimized: continue to_manually_optimize.add(fn) # Prepare the pto to operate on the ones we want optimize_xy_only_for_images(pto, to_manually_optimize) # and run optimizer = PTOptimizer(pto) # Don't clear out the xy data we just calculated optimizer.reoptimize = False optimizer.run()
# Delete the old key del icm.layout[(col + 1, row)] # Nothing to shift in except KeyError: pass if __name__ == "__main__": parser = argparse.ArgumentParser(description='Manipulate .pto files') parser.add_argument('--dry', action='store_true', help='Dont actually do anything') parser.add_argument('dir', help='Image directory to work on') parser.add_argument('actions', nargs='+', help='Actions to perform') args = parser.parse_args() print 'Constructing ICM' working_set = set(glob.glob(os.path.join(args.dir, '*.jpg'))) icm = ImageCoordinateMap.from_tagged_file_names(working_set) print 'ICM ready' for action in args.actions: print 'Action: %s' % action m = re.match('r([0-9]+)-', action) if m: row = int(m.group(1)) print 'Remove row %d' % row # if additional rows exist shift them for cur_row in xrange(row + 1, icm.rows): for cur_col in xrange(icm.cols): fn = icm.get_image(cur_col, cur_row) icm.set_image(cur_col, cur_row - 1, fn) icm.set_image(cur_col, cur_row, None)
from pr0ntools.stitch.image_coordinate_map import ImageCoordinateMap import subprocess import shutil if __name__ == "__main__": parser = argparse.ArgumentParser(description='create tiles from unstitched images') parser.add_argument('--border', default='1', help='border size') parser.add_argument('pto', default='out.pto', nargs='?', help='pto project') args = parser.parse_args() args.border = int(args.border, 0) pto_orig = PTOProject.from_file_name(args.pto) img_fns = [] for il in pto_orig.get_image_lines(): img_fns.append(il.get_name()) icm = ImageCoordinateMap.from_tagged_file_names(img_fns) # Reduced .pto pto_red = pto_orig.copy() # Delete all lines not in the peripheral pto_orig.build_image_fn_map() ils_del = [] for y in xrange(args.border, icm.height() - args.border): for x in xrange(args.border, icm.width() - args.border): im = icm.get_image(x, y) if im is None: continue ils_del.append(pto_orig.img_fn2il[im]) print 'Deleting %d / %d images' % (len(ils_del), icm.width() * icm.height()) pto_red.del_images(ils_del) pto_red.save_as(pto_orig.file_name.replace('.pto', '_sm.pto'), is_new_filename=True)
def linearize(pto, pto_ref=None, allow_missing=False, order=2): if order is 0: raise Exception('Can not have order 0') if type(order) != type(0): raise Exception('Order is bad type') ''' Our model should be like this: -Each axis will have some degree of backlash. This backlash will create a difference between adjacent rows / cols -Axes may not be perfectly adjacent The naive approach would give: x = c * dx + xc y = r * dy + yc But really we need this: x = c * dx + r * dx/dy + xc y = c * dy/dx + r * dy + yc Each equation can be solved separately Need 3 points to solve each and should be in the expected direction of that line Perform a linear regression on each row/col? Might lead to very large y = mx + b equations for the column math ''' if pto_ref is None: pto_ref = pto ''' Phase 1: calculate linear system ''' # Start by building an image coordinate map so we know what x and y are pto_ref.parse() ref_fns = pto_ref.get_file_names() real_fns = pto.get_file_names() print 'Files (all: %d, ref: %d):' % (len(real_fns), len(ref_fns)) if 0: for fn in real_fns: if fn in ref_fns: ref_str = '*' else: ref_str = ' ' print ' %s%s' % (ref_str, fn) m_ref = ImageCoordinateMap.from_tagged_file_names(ref_fns) # Ref likely does not cover the entire map ((ref_x0, ref_x1), (ref_y0, ref_y1)) = m_ref.active_box() print 'Reference map uses x(%d:%d), y(%d:%d)' % (ref_x0, ref_x1, ref_y0, ref_y1) #m_real = ImageCoordinateMap.from_tagged_file_names(real_fns) #print 'Real map uses x(%d:%d), y(%d:%d)' % (ref_x0, ref_x1, ref_y0, ref_y1) #m.debug_print() ''' Ultimately trying to form this equation x = c0 * c + c1 * r + c2 y = c3 * c + c4 * r + c5 Except that constants will also have even and odd varities c2 and c5 will be taken from reasonable points of reference, likely (0, 0) or something like that ''' c0s = [] c1s = [] c3s = [] c4s = [] for cur_order in xrange(order): # Ex: ref_x0 = 3 # cur_order 0: start 4 # cur_order 1: start 3 if ref_x0 % order == cur_order: reg_x0 = ref_x0 else: reg_x0 = ref_x0 + 1 if ref_y0 % order == cur_order: reg_y0 = ref_y0 else: reg_y0 = ref_y0 + 1 reg_x1 = ref_x1 reg_y1 = ref_y1 print 'Order %d: using x(%d:%d), y(%d:%d)' % (cur_order, reg_x0, reg_x1, reg_y0, reg_y1) # Given a column find x (primary x) # dependence of x on col in specified rows c0s.append( regress_row(m_ref, pto_ref, cols=xrange(reg_x0, reg_x1 + 1, order), rows=xrange(reg_y0, reg_y1 + 1, order), selector=lambda x: x.x(), allow_missing=allow_missing)) # dependence of x on row in specified cols c1s.append( regress_col(m_ref, pto_ref, cols=xrange(reg_x0, reg_x1 + 1, order), rows=xrange(reg_y0, reg_y1 + 1, order), selector=lambda x: x.x(), allow_missing=allow_missing)) # Given a row find y (primary y) # dependence of y on col in specified rows c3s.append( regress_row(m_ref, pto_ref, cols=xrange(reg_x0, reg_x1 + 1, order), rows=xrange(reg_y0, reg_y1 + 1, order), selector=lambda x: x.y(), allow_missing=allow_missing)) # cdependence of y on row in specified cols c4s.append( regress_col(m_ref, pto_ref, cols=xrange(reg_x0, reg_x1 + 1, order), rows=xrange(reg_y0, reg_y1 + 1, order), selector=lambda x: x.y(), allow_missing=allow_missing)) # Now chose a point in the center # it doesn't have to be a good fitting point in the old system, it just has to be centered # Fix at the origin ''' Actually the even and the odd should have the same slope The only difference should be their offset ''' if 0: print 'Solution found' print ' x = %g c + %g r + TBD' % (c0s[0], c1s[0]) print ' y = %g c + %g r + TBD' % (c3s[0], c4s[0]) # Verify the solution matrix by checking it against the reference project print print 'Verifying reference solution matrix....' # Entire reference is assumed to be good always, no border (c2s_ref, c5s_ref) = calc_constants(order, m_ref, pto_ref, c0s, c1s, c3s, c4s, m_ref, allow_missing) #c1s = [c1 + 12 for c1 in c1s] # Print the solution matrx for debugging for cur_order in range(order): # XXX: if we really cared we could center these up # its easier to just run the centering algorithm after though if one cares print 'Reference order %d solution:' % cur_order print ' x = %g c + %g r + %g' % (c0s[cur_order], c1s[cur_order], c2s_ref[cur_order]) print ' y = %g c + %g r + %g' % (c3s[cur_order], c4s[cur_order], c5s_ref[cur_order]) return ((c0s, c1s, c2s_ref), (c3s, c4s, c5s_ref))
def linearize(pto, pto_ref = None, allow_missing = False, order = 2): if order is 0: raise Exception('Can not have order 0') if type(order) != type(0): raise Exception('Order is bad type') ''' Our model should be like this: -Each axis will have some degree of backlash. This backlash will create a difference between adjacent rows / cols -Axes may not be perfectly adjacent The naive approach would give: x = c * dx + xc y = r * dy + yc But really we need this: x = c * dx + r * dx/dy + xc y = c * dy/dx + r * dy + yc Each equation can be solved separately Need 3 points to solve each and should be in the expected direction of that line Perform a linear regression on each row/col? Might lead to very large y = mx + b equations for the column math ''' if pto_ref is None: pto_ref = pto ''' Phase 1: calculate linear system ''' # Start by building an image coordinate map so we know what x and y are pto_ref.parse() ref_fns = pto_ref.get_file_names() real_fns = pto.get_file_names() print 'Files (all: %d, ref: %d):' % (len(real_fns), len(ref_fns)) if 0: for fn in real_fns: if fn in ref_fns: ref_str = '*' else: ref_str = ' ' print ' %s%s' % (ref_str, fn) m_ref = ImageCoordinateMap.from_tagged_file_names(ref_fns) # Ref likely does not cover the entire map ((ref_x0, ref_x1), (ref_y0, ref_y1)) = m_ref.active_box() print 'Reference map uses x(%d:%d), y(%d:%d)' % (ref_x0, ref_x1, ref_y0, ref_y1) #m_real = ImageCoordinateMap.from_tagged_file_names(real_fns) #print 'Real map uses x(%d:%d), y(%d:%d)' % (ref_x0, ref_x1, ref_y0, ref_y1) #m.debug_print() ''' Ultimately trying to form this equation x = c0 * c + c1 * r + c2 y = c3 * c + c4 * r + c5 Except that constants will also have even and odd varities c2 and c5 will be taken from reasonable points of reference, likely (0, 0) or something like that ''' c0s = [] c1s = [] c3s = [] c4s = [] for cur_order in xrange(order): # Ex: ref_x0 = 3 # cur_order 0: start 4 # cur_order 1: start 3 if ref_x0 % order == cur_order: reg_x0 = ref_x0 else: reg_x0 = ref_x0 + 1 if ref_y0 % order == cur_order: reg_y0 = ref_y0 else: reg_y0 = ref_y0 + 1 reg_x1 = ref_x1 reg_y1 = ref_y1 print 'Order %d: using x(%d:%d), y(%d:%d)' % (cur_order, reg_x0, reg_x1, reg_y0, reg_y1) # Given a column find x (primary x) # dependence of x on col in specified rows c0s.append(regress_row(m_ref, pto_ref, cols=xrange(reg_x0, reg_x1 + 1, order), rows=xrange(reg_y0, reg_y1 + 1, order), selector=lambda x: x.x(), allow_missing=allow_missing)) # dependence of x on row in specified cols c1s.append(regress_col(m_ref, pto_ref, cols=xrange(reg_x0, reg_x1 + 1, order), rows=xrange(reg_y0, reg_y1 + 1, order), selector=lambda x: x.x(), allow_missing=allow_missing)) # Given a row find y (primary y) # dependence of y on col in specified rows c3s.append(regress_row(m_ref, pto_ref, cols=xrange(reg_x0, reg_x1 + 1, order), rows=xrange(reg_y0, reg_y1 + 1, order), selector=lambda x: x.y(), allow_missing=allow_missing)) # cdependence of y on row in specified cols c4s.append(regress_col(m_ref, pto_ref, cols=xrange(reg_x0, reg_x1 + 1, order), rows=xrange(reg_y0, reg_y1 + 1, order), selector=lambda x: x.y(), allow_missing=allow_missing)) # Now chose a point in the center # it doesn't have to be a good fitting point in the old system, it just has to be centered # Fix at the origin ''' Actually the even and the odd should have the same slope The only difference should be their offset ''' if 0: print 'Solution found' print ' x = %g c + %g r + TBD' % (c0s[0], c1s[0]) print ' y = %g c + %g r + TBD' % (c3s[0], c4s[0]) # Verify the solution matrix by checking it against the reference project print print 'Verifying reference solution matrix....' # Entire reference is assumed to be good always, no border (c2s_ref, c5s_ref) = calc_constants(order, m_ref, pto_ref, c0s, c1s, c3s, c4s, m_ref, allow_missing) #c1s = [c1 + 12 for c1 in c1s] # Print the solution matrx for debugging for cur_order in range(order): # XXX: if we really cared we could center these up # its easier to just run the centering algorithm after though if one cares print 'Reference order %d solution:' % cur_order print ' x = %g c + %g r + %g' % (c0s[cur_order], c1s[cur_order], c2s_ref[cur_order]) print ' y = %g c + %g r + %g' % (c3s[cur_order], c4s[cur_order], c5s_ref[cur_order]) return ((c0s, c1s, c2s_ref), (c3s, c4s, c5s_ref))
def linear_reoptimize(pto, pto_ref=None, allow_missing=False, order=2, border=False): '''Change XY positions to match the trend in a linear XY positioned project (ex from XY stage). pto must have all images in pto_ref ''' if scipy is None: raise Exception('Re-optimizing requires scipi') if order is 0: raise Exception('Can not have order 0') if type(order) != type(0): raise Exception('Order is bad type') ''' Our model should be like this: -Each axis will have some degree of backlash. This backlash will create a difference between adjacent rows / cols -Axes may not be perfectly adjacent The naive approach would give: x = c * dx + xc y = r * dy + yc But really we need this: x = c * dx + r * dx/dy + xc y = c * dy/dx + r * dy + yc Each equation can be solved separately Need 3 points to solve each and should be in the expected direction of that line Perform a linear regression on each row/col? Might lead to very large y = mx + b equations for the column math ''' if pto_ref is None: pto_ref = pto ''' Phase 1: calculate linear system ''' # Start by building an image coordinate map so we know what x and y are pto_ref.parse() ref_fns = pto_ref.get_file_names() real_fns = pto.get_file_names() print 'Files (all: %d, ref: %d):' % (len(real_fns), len(ref_fns)) for fn in real_fns: if fn in ref_fns: ref_str = '*' else: ref_str = ' ' print ' %s%s' % (ref_str, fn) m_ref = ImageCoordinateMap.from_tagged_file_names(ref_fns) m_real = ImageCoordinateMap.from_tagged_file_names(real_fns) #m.debug_print() ''' Ultimately trying to form this equation x = c0 * c + c1 * r + c2 y = c3 * c + c4 * r + c5 Except that constants will also have even and odd varities c2 and c5 will be taken from reasonable points of reference, likely (0, 0) or something like that ''' c0s = [] c1s = [] c3s = [] c4s = [] for cur_order in range(order): # Given a column find x (primary x) c0s.append( regress_c0(m_ref, pto_ref, xrange(cur_order, m_ref.height(), order), allow_missing)) c1s.append( regress_c1(m_ref, pto_ref, xrange(cur_order, m_ref.width(), order), allow_missing)) # Given a row find y (primary y) c3s.append( regress_c3(m_ref, pto_ref, xrange(cur_order, m_ref.height(), order), allow_missing)) c4s.append( regress_c4(m_ref, pto_ref, xrange(cur_order, m_ref.width(), order), allow_missing)) # Now chose a point in the center # it doesn't have to be a good fitting point in the old system, it just has to be centered # Fix at the origin ''' Actually the even and the odd should have the same slope The only difference should be their offset ''' c2 = None c5 = None if 0: print 'Solution found' print ' x = %g c + %g r + TBD' % (c0, c1) print ' y = %g c + %g r + TBD' % (c3, c4) # Verify the solution matrix by checking it against the reference project print print 'Verifying reference solution matrix....' # Entire reference is assumed to be good always, no border (c2s_ref, c5s_ref) = calc_constants(order, m_ref, pto_ref, c0s, c1s, c3s, c4s, m_ref, allow_missing) #c1s = [c1 + 12 for c1 in c1s] # Print the solution matrx for debugging for cur_order in range(order): # XXX: if we really cared we could center these up # its easier to just run the centering algorithm after though if one cares print 'Reference order %d solution:' % cur_order print ' x = %g c + %g r + %g' % (c0s[cur_order], c1s[cur_order], c2s_ref[cur_order]) print ' y = %g c + %g r + %g' % (c3s[cur_order], c4s[cur_order], c5s_ref[cur_order]) calc_ref_xs = [] calc_ref_ys = [] ref_xs = [] ref_ys = [] print 'Errors:' x_last = None y_last = None for col in range(m_ref.width()): for row in range(m_ref.height()): fn = m_ref.get_image(col, row) if fn is None: continue il = pto_ref.get_image_by_fn(fn) col_eo = col % order row_eo = row % order x_calc = c0s[row_eo] * col + c1s[row_eo] * row + c2s_ref[row_eo] y_calc = c3s[col_eo] * col + c4s[col_eo] * row + c5s_ref[col_eo] calc_ref_xs.append(x_calc) calc_ref_ys.append(y_calc) x_orig = il.x() y_orig = il.y() ref_xs.append(x_orig) ref_ys.append(y_orig) print ' c%d r%d: x%g y%g (x%g, y%g)' % ( col, row, x_calc - x_orig, y_calc - y_orig, x_orig, y_orig) if col > 0: fn_old = m_ref.get_image(col - 1, row) if fn_old: il_old = pto_ref.get_image_by_fn(fn_old) print ' dx: %g' % (il.x() - il_old.x()) if col > 1: ''' x1' = x1 - x0 x2' = x2 - x1 x2'' = x2' - x1' = (x2 - x1) - (x1 - x0) = x2 - 2 x1 + x0 ''' fn_old2 = m_ref.get_image(col - 2, row) if fn_old2: il_old2 = pto_ref.get_image_by_fn(fn_old2) print ' dx2: %g' % (il.x() - 2 * il_old.x() + il_old2.x()) if row != 0: fn_old = m_ref.get_image(col, row - 1) if fn_old: il_old = pto_ref.get_image_by_fn(fn_old) print ' dy: %g' % (il.y() - il_old.y()) if row > 1: fn_old2 = m_ref.get_image(col, row - 2) if fn_old2: il_old2 = pto_ref.get_image_by_fn(fn_old2) print ' dy2: %g' % (il.y() - 2 * il_old.y() + il_old2.y()) x_ref_rms_error = rms_error_diff(calc_ref_xs, ref_xs) y_ref_rms_error = rms_error_diff(calc_ref_ys, ref_ys) print 'Reference RMS error x%g y%g' % (x_ref_rms_error, y_ref_rms_error) print #exit(1) ''' The reference project might not start at 0,0 Therefore scan through to find some good starting positions so that we can calc each point in the final project ''' print 'Anchoring solution...' ''' Calculate the constant at each reference image Compute reference positions from these values ''' ''' FIXME: we have to calculate these initially and then re-calc for border if required if top_bottom_backlash and border: row_border = 1 else: row_border = 0 if left_right_backlash and border: col_border = 1 else: col_border = 0 ''' row_border = 0 col_border = 0 (c2s, c5s) = calc_constants(order, m_real, pto_ref, c0s, c1s, c3s, c4s, m_ref, allow_missing, col_border, row_border) #c2s = [c2 + 30 for c2 in c2s] # Print the solution matrx for debugging for cur_order in range(order): # XXX: if we really cared we could center these up # its easier to just run the centering algorithm after though if one cares print 'Order %d solution:' % cur_order print ' x = %g c + %g r + %g' % (c0s[cur_order], c1s[cur_order], c2s[cur_order]) print ' y = %g c + %g r + %g' % (c3s[cur_order], c4s[cur_order], c5s[cur_order]) c2_rms = rms_errorl(c2s) c5_rms = rms_errorl(c5s) print 'RMS offset error x%g y%g' % (c2_rms, c5_rms) left_right_backlash = False top_bottom_backlash = False if c2_rms > c5_rms: print 'x offset varies most, expect left-right scanning' left_right_backlash = True else: print 'y offset varies most, expect top-bottom scanning' top_bottom_backlash = True #exit(1) ''' We have the solution matrix now so lets roll ''' optimized = set() for col in range(col_border, m_real.width() - col_border): for row in range(row_border, m_real.height() - row_border): fn = m_real.get_image(col, row) il = pto.get_image_by_fn(fn) if fn is None: if not allow_missing: raise Exception('Missing item') continue col_eo = col % order row_eo = row % order # FIRE! # take the dot product x = c0s[row_eo] * col + c1s[row_eo] * row + c2s[row_eo] y = c3s[col_eo] * col + c4s[col_eo] * row + c5s[col_eo] # And push it out #print '%s: c%d r%d => x%g y%d' % (fn, col, row, x, y) il.set_x(x) il.set_y(y) #print il optimized.add(fn) ''' Finally manually optimize those that were in the border area ''' if border: # Gather all file names # There are essentially four cases to do this faster but be lazy since it will still be O(images) to_manually_optimize = set() for col in range(0, m_real.width()): for row in range(m_real.height()): fn = m_real.get_image(col, row) il = pto.get_image_by_fn(fn) if fn is None: if not allow_missing: raise Exception('Missing item') continue if fn in optimized: continue to_manually_optimize.add(fn) # Prepare the pto to operate on the ones we want optimize_xy_only_for_images(pto, to_manually_optimize) # and run optimizer = PTOptimizer(pto) # Don't clear out the xy data we just calculated optimizer.reoptimize = False optimizer.run()