def test_multi(self): print 'Multi test' project = PTOProject.parse_from_file_name('in.pto') remapper = Remapper(project) remapper.image_type = Remapper.TIFF_SINGLE remapper.run() self.clean()
def test_single(self): print 'Single test' project = PTOProject.from_file_name('in.pto') remapper = Remapper(project) remapper.image_type = Remapper.TIFF_SINGLE remapper.run() self.clean()
def test_tile_real(self): project = PTOProject.parse_from_file_name('in.pto') print 'Creating tiler' t = Tiler(project, 'out', st_scalar_heuristic=2) self.assertEqual(len(list(t.gen_supertiles())), 4) print 'Unit test running tiler (real)' t.run()
def test_tile_dry(self): ''' Inputs are 1632 x 1224 a 3 x 3 grid allows testing edge boundary conditions as well as internal The reference fully stitched image is 3377 x 2581 ''' project = PTOProject.parse_from_file_name('in.pto') print 'Creating tiler' t = Tiler(project, 'out', st_scalar_heuristic=2) #iw = 1632 #ih = 1224 #t.set_size_heuristic(iw, ih) ''' Should make 4 tiles with 3 X 3 ''' #t.super_tw = 2 * iw #t.super_th = 2 * ih ''' Each supertile should cover two images as setup There will be some overlap in the center and unique area on all four edges ''' self.assertEqual(len(list(t.gen_supertiles())), 4) print 'Unit test running tiler (real)' t.dry = True t.run()
def run(self): from pr0ntools.stitch.pto.project import PTOProject '''Take in a list of pto files and merge them into pto''' pto_temp_file = ManagedTempFile.get(None, ".pto") args = ["pto_merge"] args.append("--output=%s" % pto_temp_file) for pto in self.ptos: args.append(pto.get_a_file_name()) print 'MERGING: %s' % (args,) rc = execute.without_output(args) # go go go if not rc == 0: print print print #print 'Output:' #print output print 'rc: %d' % rc if rc == 35072: # ex: empty projects seem to cause this print 'Out of memory, expect malformed project file' raise Exception('failed pto_merge') if not os.path.exists(str(pto_temp_file)): raise Exception('Output file missing: %s' % (pto_temp_file,)) return PTOProject.from_temp_file(pto_temp_file)
def run(self): from pr0ntools.stitch.pto.project import PTOProject '''Take in a list of pto files and merge them into pto''' pto_temp_file = ManagedTempFile.get(None, ".pto") args = ["pto_merge"] args.append("--output=%s" % pto_temp_file) for pto in self.ptos: args.append(pto.get_a_file_name()) print 'MERGING: %s' % (args, ) rc = execute.without_output(args) # go go go if not rc == 0: print print print #print 'Output:' #print output print 'rc: %d' % rc if rc == 35072: # ex: empty projects seem to cause this print 'Out of memory, expect malformed project file' raise Exception('failed pto_merge') if not os.path.exists(str(pto_temp_file)): raise Exception('Output file missing: %s' % (pto_temp_file, )) return PTOProject.from_temp_file(pto_temp_file)
def test_multi(self): print 'Multi test' project = PTOProject.from_file_name('in.pto') remapper = Remapper(project) remapper.image_type = Remapper.TIFF_SINGLE remapper.run() self.clean()
def test_tile_real(self): project = PTOProject.from_file_name('in.pto') print 'Creating tiler' t = Tiler(project, 'out', st_scalar_heuristic=2) self.assertEqual(len(list(t.gen_supertiles())), 4) print 'Unit test running tiler (real)' t.run()
def test_tile_dry(self): ''' Inputs are 1632 x 1224 a 3 x 3 grid allows testing edge boundary conditions as well as internal The reference fully stitched image is 3377 x 2581 ''' project = PTOProject.from_file_name('in.pto') print 'Creating tiler' t = Tiler(project, 'out', st_scalar_heuristic=2) #iw = 1632 #ih = 1224 #t.set_size_heuristic(iw, ih) ''' Should make 4 tiles with 3 X 3 ''' #t.super_tw = 2 * iw #t.super_th = 2 * ih ''' Each supertile should cover two images as setup There will be some overlap in the center and unique area on all four edges ''' self.assertEqual(len(list(t.gen_supertiles())), 4) print 'Unit test running tiler (real)' t.dry = True t.run()
def test_optimize(self): print 'Loading raw project...' project = PTOProject.from_file_name('in.pto') print 'Creating optimizer...' optimizer = PTOptimizer(project) #self.assertTrue(project.text != None) print 'Running optimizer...' optimizer.run()
def test_center_anchor(self): project = PTOProject.from_file_name('in.pto') center_anchor(project) ''' Image 4 at (1, 1) is the correct answer ''' #vl = project.get_variable_lines()[4] project.save()
def resave_hugin(pto): from pr0ntools.stitch.merger import Merger from pr0ntools.stitch.pto.project import PTOProject # pto_merge -o converted.pto out.pto out.pto blank = PTOProject.from_blank() m = Merger([blank]) m.pto = pto new = m.run(to_pto=True) if new != pto: raise Exception('Expected self merge') print 'Merge into self'
def resave_hugin(pto): from pr0ntools.stitch.merger import Merger from pr0ntools.stitch.pto.project import PTOProject # pto_merge -o converted.pto out.pto out.pto blank = PTOProject.from_blank() m = Merger([blank]) m.pto = pto new = m.run(to_pto=True) if new != pto: raise Exception('Expected self merge') dbg('Merge into self')
def pto_unsub(src_prj, sub_image_files, deltas, sub_to_real): ''' Transforms a sub-project back into original control point coordinate space using original file names Returns a new project file src_prj: base project that needs to be transformed sub_image_files: tuple specifying original project 0/1 positions needed to correctly apply deltas deltas: delta to apply to pair_project coordinates to bring back to target (original) project space 0: x 1: y images are relative to each other only has delta within relative image frame, not entire project canvas sub_to_real: map of project file names to target (original) project file names the output project must use these instead of the original names ''' ret = PTOProject.from_simple() same_order = True # Copy/fix images print 'Order check' for i, src_il in enumerate(src_prj.get_image_lines()): # copy it dst_il = ImageLine(str(src_il), ret) # fix the name so that it can be merged dst_il.set_name(sub_to_real[src_il.get_name()]) # add it ret.add_image_line(dst_il) same_order = same_order and sub_image_files[ i].file_name == src_il.get_name() print ' %d: %s vs %s' % (i, sub_image_files[i].file_name, src_il.get_name()) # Copy/shift control points # Should have been filtered out earlier if len(src_prj.get_control_point_lines()) == 0: raise Exception('No source control point lines') for src_cpl in src_prj.get_control_point_lines(): # copy it dst_cpl = ControlPointLine(str(src_cpl), ret) # shift to original coordinate space if same_order: # normal adjustment dst_cpl.set_variable('x', src_cpl.get_variable('x') + deltas[0]) dst_cpl.set_variable('y', src_cpl.get_variable('y') + deltas[1]) else: # they got flipped dst_cpl.set_variable('X', src_cpl.get_variable('X') + deltas[0]) dst_cpl.set_variable('Y', src_cpl.get_variable('Y') + deltas[1]) # add it ret.add_control_point_line(dst_cpl) return ret
def pto_unsub(src_prj, sub_image_files, deltas, sub_to_real): """ Transforms a sub-project back into original control point coordinate space using original file names Returns a new project file src_prj: base project that needs to be transformed sub_image_files: tuple specifying original project 0/1 positions needed to correctly apply deltas deltas: delta to apply to pair_project coordinates to bring back to target (original) project space 0: x 1: y images are relative to each other only has delta within relative image frame, not entire project canvas sub_to_real: map of project file names to target (original) project file names the output project must use these instead of the original names """ ret = PTOProject.from_simple() same_order = True # Copy/fix images print "Order check" for i, src_il in enumerate(src_prj.get_image_lines()): # copy it dst_il = ImageLine(str(src_il), ret) # fix the name so that it can be merged dst_il.set_name(sub_to_real[src_il.get_name()]) # add it ret.add_image_line(dst_il) same_order = same_order and sub_image_files[i].file_name == src_il.get_name() print " %d: %s vs %s" % (i, sub_image_files[i].file_name, src_il.get_name()) # Copy/shift control points # Should have been filtered out earlier if len(src_prj.get_control_point_lines()) == 0: raise Exception("No source control point lines") for src_cpl in src_prj.get_control_point_lines(): # copy it dst_cpl = ControlPointLine(str(src_cpl), ret) # shift to original coordinate space if same_order: # normal adjustment dst_cpl.set_variable("x", src_cpl.get_variable("x") + deltas[0]) dst_cpl.set_variable("y", src_cpl.get_variable("y") + deltas[1]) else: # they got flipped dst_cpl.set_variable("X", src_cpl.get_variable("X") + deltas[0]) dst_cpl.set_variable("Y", src_cpl.get_variable("Y") + deltas[1]) # add it ret.add_control_point_line(dst_cpl) return ret
def run(self, to_pto = False): from pr0ntools.stitch.pto.project import PTOProject others = self.files pto = self.pto '''Take in a list of pto files and merge them into pto''' if to_pto: pto_temp_file = self.pto.get_a_file_name() else: pto_temp_file = ManagedTempFile.get(None, ".pto") command = "pto_merge" args = list() args.append("--output=%s" % pto_temp_file) # Possible this is still empty if pto.file_name and os.path.exists(pto.file_name): args.append(pto.file_name) for other in others: args.append(other.get_a_file_name()) print_debug(args) (rc, output) = Execute.with_output(command, args) # go go go if not rc == 0: print print print print 'Output:' print output print 'rc: %d' % rc if rc == 35072: # ex: empty projects seem to cause this print 'Out of memory, expect malformed project file' raise Exception('failed pto_merge') if to_pto: self.pto.reopen() return self.pto else: return PTOProject.from_temp_file(pto_temp_file)
def generate_core(self, image_file_names): project_file = ManagedTempFile.get(None, ".pto") command = "autopano-sift-c" args = list() # Try to post process them to make them more accurate #args.append("--refine") # Perform RANSAC to try to get bad control points out #args.append("--ransac") #args.append("on") # Unlimited matches args.append("--maxmatches") args.append("0") # ? #args.append("--maxdim") #args.append("10000") # Project file args.append(project_file.file_name) # Images for image_file_name in image_file_names: args.append(image_file_name) # go go go #(rc, output) = Execute.with_output(command, args) (rc, output) = (exc_ret_istr(command, args), '') if not rc == 0: print print print print 'output:\n%s' % output raise Exception('Bad rc: %d' % rc) # We return PTO object, not string return PTOProject.from_temp_file(project_file)
def generate_core(self, image_file_names): project_file = ManagedTempFile.get(None, ".pto") command = "autopano-sift-c" args = list() # Try to post process them to make them more accurate # args.append("--refine") # Perform RANSAC to try to get bad control points out # args.append("--ransac") # args.append("on") # Unlimited matches args.append("--maxmatches") args.append("0") # ? # args.append("--maxdim") # args.append("10000") # Project file args.append(project_file.file_name) # Images for image_file_name in image_file_names: args.append(image_file_name) # go go go # (rc, output) = Execute.with_output(command, args) (rc, output) = (exc_ret_istr(command, args), "") if not rc == 0: print print print print "output:\n%s" % output raise Exception("Bad rc: %d" % rc) # We return PTO object, not string return PTOProject.from_temp_file(project_file)
def generate_core(self, image_file_names): command = "autopanoaj" args = list() project_file = ManagedTempFile.get(None, ".pto") # default is .oto args.append("/project:hugin") # Use image args instead of dir args.append("/f") args.append('/path:Z:\\tmp') # Images for image_file_name in image_file_names: args.append(image_file_name.replace("/tmp/", "Z:\\tmp\\")) # go go go #(rc, output) = Execute.with_output(command, args) rc, output = exc_ret_istr(command, args, print_out=True) if not rc == 0: raise Exception('Bad rc: %d' % rc) # We return PTO object, not string # Ditch the gen file because its unreliable shutil.move("/tmp/panorama0.pto", project_file.file_name) f = open(project_file.file_name, 'r') project_text = f.read() # Under WINE, do fixup project_text = project_text.replace('Z:\\tmp\\', '/tmp/') if 0: print print print print project_text print print print f.close() f = open(project_file.file_name, 'w') f.write(project_text) return PTOProject.from_temp_file(project_file)
def generate_core(self, image_file_names): command = "autopanoaj" args = list() project_file = ManagedTempFile.get(None, ".pto") # default is .oto args.append("/project:hugin") # Use image args instead of dir args.append("/f") args.append("/path:Z:\\tmp") # Images for image_file_name in image_file_names: args.append(image_file_name.replace("/tmp/", "Z:\\tmp\\")) # go go go # (rc, output) = Execute.with_output(command, args) rc, output = exc_ret_istr(command, args, print_out=True) if not rc == 0: raise Exception("Bad rc: %d" % rc) # We return PTO object, not string # Ditch the gen file because its unreliable shutil.move("/tmp/panorama0.pto", project_file.file_name) f = open(project_file.file_name, "r") project_text = f.read() # Under WINE, do fixup project_text = project_text.replace("Z:\\tmp\\", "/tmp/") if 0: print print print print project_text print print print f.close() f = open(project_file.file_name, "w") f.write(project_text) return PTOProject.from_temp_file(project_file)
def partial_optimize(self, xo0, xo1, yo0, yo1, xf0=0, xf1=0, yf0=0, yf1=0): ''' Return a PTOptimizer optimized sub-self.opt_project o: optimized row/col f: fixed row/col relative to counterpart allows to join in with pre-optimized rows/cols ''' print 'Optimizing base region' print 'Selected base region x(%d:%d), y(%d:%d)' % (xo0, xo1, yo0, yo1) if xf0 > 0: raise Exception('') if xf1 < 0: raise Exception('') if yf0 > 0: raise Exception('') if yf1 < 0: raise Exception('') xf0 += xo0 xf1 += xo1 yf0 += yo0 yf1 += yo1 ''' # Remove all previously selected optimizations project.variable_lines = [] # Mark the selected images for optimization for col in xrange(xo0, xo1 + 1, 1): for row in xrange(yo0, yo1 + 1, 1): fn = self.icm.get_image(col, row) img_i = self.project.img_fn2i(fn) vl = VariableLine('v d%d e%d' % (img_i, img_i), project) project.variable_lines.append(vl) ''' project = PTOProject.from_blank() # Copy special lines # in particular need to keep canvas scale project.set_pano_line_by_text(str(self.opt_project.panorama_line)) project.set_mode_line_by_text(str(self.opt_project.mode_line)) # Copy in image lines # Create a set of all images of interest to make relevant lines easy to find rel_i = set() for col in xrange(xf0, xf1 + 1, 1): for row in xrange(yf0, yf1 + 1, 1): fn = self.icm.get_image(col, row) il = self.project.img_fn2l(fn) rel_i.add(il.get_index()) # Image itself project.image_lines.append(ImageLine(str(il), project)) # save indices to quickly eliminate/replace them cpl_is = [] # Now that all images are added we can add features between them for cpli, cpl in enumerate(self.opt_project.get_control_point_lines()): # c n1 N0 x121.0 y258.0 X133.0 Y1056.0 t0 n = cpl.get_variable('n') N = cpl.get_variable('N') if n in rel_i and N in rel_i: cpl2 = ControlPointLine(str(cpl), project) # Indexes will be different, adjust accordingly cpl2.set_variable('n', project.i2i(self.opt_project, n)) cpl2.set_variable('N', project.i2i(self.opt_project, N)) project.control_point_lines.append(cpl2) cpl_is.append(cpli) anchor = None # All variable? if xo0 == xf0 and xo1 == xf1 and yo0 == yf0 and yo1 == yf1: # Then must anchor solution to a fixed tile anchor = ((xo0 + xo1) / 2, (xf0 + xf1) / 2) # Finally, set images to optimize (XY only) for col in xrange(xo0, xo1 + 1, 1): for row in xrange(yo0, yo1 + 1, 1): # Don't optimize if its the fixed image if (col, row) == anchor: continue fn = self.icm.get_image(col, row) img_i = project.img_fn2i(fn) vl = VariableLine('v d%d e%d' % (img_i, img_i), project) project.variable_lines.append(vl) # In case it crashes do a debug dump pre_run_text = project.get_text() if 0: print project.variable_lines print print print 'PT optimizer project:' print pre_run_text print print raise Exception('Debug break') # "PToptimizer out.pto" args = ["PToptimizer"] args.append(project.get_a_file_name()) #project.save() rc = execute.without_output(args) if rc != 0: fn = '/tmp/pr0nstitch.optimizer_failed.pto' print print print 'Failed rc: %d' % rc print 'Failed project save to %s' % (fn, ) try: open(fn, 'w').write(pre_run_text) except: print 'WARNING: failed to write failure' print print raise Exception('failed position optimization') # API assumes that projects don't change under us project.reopen() ''' Line looks like this # final rms error 24.0394 units ''' rms_error = None for l in project.get_comment_lines(): if l.find('final rms error') >= 00: rms_error = float(l.split()[4]) break print 'Optimize: RMS error of %f' % rms_error # Filter out gross optimization problems if self.rms_error_threshold and rms_error > self.rms_error_threshold: raise Exception("Max RMS error threshold %f but got %f" % (self.rms_error_threshold, rms_error)) if self.debug: print 'Parsed: %s' % str(project.parsed) if self.debug: print print print print 'Optimized project:' print project #sys.exit(1) ret = self.opt_project.copy() print 'Optimized project parsed: %d' % self.opt_project.parsed print 'Merging project...' merge_opt_pto(project, ret) ret.save_as('fixup.pto') return (ret, cpl_is)
arg_key = arg[2:] if arg_key == "help": help() sys.exit(0) else: arg_fatal('Unrecognized arg: %s' % arg) else: if arg.find('.pto') > 0: project_file_names.append(arg) elif os.path.isfile(arg) or os.path.isdir(arg): image_file_names.append(arg) else: arg_fatal('unrecognized arg: %s' % arg) project = PTOProject.from_file_name('panorama0.pto') project.parse() calc_centroid() sys.exit(1) project.regen() print print print print project.get_text() #project.save_as('out_reparsed.pto') print print print
def generate_core(self, img_fns): # cpfind (and likely cpclean) trashes absolute file names # we need to restore them so that tools recognize the file names real_fn_base2full = {} args = list() project = PTOProject.from_default2() fn_obj = ManagedTempFile.get(None, ".pto") project.set_file_name(fn_obj.file_name) # Start with cpfind args.append("--prealigned") args.append("--fullscale") args.append("--minmatches") args.append("1") args.append("--ransacdist") args.append("5") args.append("--kdtreeseconddist") args.append("0.5") # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) # Images for img_fn in img_fns: # xxx: why do we take the realpath? real_fn = os.path.realpath(img_fn) real_fn_base2full[os.path.basename(real_fn)] = img_fn project.add_image(real_fn, def_opt=True) project.save() print print print print project.get_text() print print print #(rc, output) = Execute.with_output('cpfind', args, print_output=self.print_output) print 'cpfind' + ' '.join(args) (rc, output) = exc_ret_istr('cpfind', args, print_out=self.print_output) print 'PanoCP: cpfind done' if not rc == 0: print print print print 'output:' print output print # Happens very rarely # 2018-01-24T04:00:18.720954: Exception: Bad rc: -11 # Log it but consider it a known failure if rc == -11: return None raise Exception('Bad rc: %d' % rc) # Now run cpclean args = list() # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) (rc, output) = exc_ret_istr('cpclean', args, print_out=self.print_output) print 'PanoCP: cpclean done' if not rc == 0: print print print print 'output:' print output print raise Exception('Bad rc: %d' % rc) # Now run geocpset args = list() # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) (rc, output) = exc_ret_istr('geocpset', args, print_out=self.print_output) print 'PanoCP: geocpset done' if not rc == 0: print print print print 'output:' print output print raise Exception('Bad rc: %d' % rc) project.reopen() print 'Fixing image lines...' for il in project.image_lines: src = il.get_name() dst = real_fn_base2full[src.split('/')[-1]] print ' %s => %s' % (src, dst) il.set_name(dst) project.set_file_name(None) fn_obj = None # Will happen if failed to match # be optimistic: cpclean work will be wasted but avoids parsing project twice if len(project.get_control_point_lines()) == 0: print 'WARNING: failed' return None return project
arg_key = arg[2:] if arg_key == "help": help() sys.exit(0) else: arg_fatal("Unrecognized arg: %s" % arg) else: if arg.find(".pto") > 0: project_file_names.append(arg) elif os.path.isfile(arg) or os.path.isdir(arg): image_file_names.append(arg) else: arg_fatal("unrecognized arg: %s" % arg) project = PTOProject.from_file_name("out.pto") project.parse() reset_photometrics = True if reset_photometrics: # Overall exposure # *very* important project.panorama_line.set_variable("E", 1) # What about m's p and s? for image_line in project.image_lines: # Don't adjust exposure image_line.set_variable("Eev", 1) # blue and red white balance correction at normal levels image_line.set_variable("Eb", 1) image_line.set_variable("Er", 1)
def test_optimize_conversion(self): project = PTOProject.from_file_name('in.pto') pt = project.copy()
def generate_control_points(self): ''' Generate control points Generate to all neighbors to start with ''' print 'PHASE 1: adjacent images' cur_x = 0.0 cur_y = 0.0 x_delta = None y_delta = None # Eliminate special case from main loop for pair in self.linear_pairs_gen(): self.spatial_map.add_point(cur_y, cur_x, pair[0]) break n_pairs = len(set(self.linear_pairs_gen())) cur_pair_index = 0 for pair in self.linear_pairs_gen(): cur_pair_index += 1 print 'Working on %s (%d / %d)' % (repr(pair), cur_pair_index, n_pairs) result = self.analyze_image_pair(pair) if result is None: ''' Two situations: Early on: best guess is to go direction of last Also simple to implement, try always for now If we are at an edge (turn point) we are in trouble For large images this should be a minority if all images are equally likely to have issues Edges might have easier feature detection? Or worse since void Better: calculate average length and see how far we are along in the row Make a guess as to whether we should turn or not ''' print 'Attempting error recovery' # Leave values untouched to save from last loop value # If we failed on the first pass give up if x_delta is None or y_delta is None: raise Exception('Die') print 'Using last delta values: y=%f, x=%f' % (y_delta, x_delta) else: # Common / expected case (x_delta, y_delta) = result cur_x += x_delta cur_y += y_delta # Note we must add the estimate even if its not known self.spatial_map.add_point(cur_y, cur_x, pair[1]) print 'Created %d sub projects' % len(self.sub_projects) phase_1_project = PTOProject.from_blank() print 'Sub projects (full image):' for project in self.sub_projects: # prefix so I can grep it for debugging print '\tSUB: ' + project.file_name phase_1_project.merge_into(self.sub_projects) # Save is more of debug thing now...helps analyze crashes phase_1_project.get_a_file_name() phase_1_project.save() print print print print phase_1_project.text print print print print 'Master project file: %s' % phase_1_project.file_name print 'PHASE 1: done' print 'PHASE 2: fortify' fortify_stitch = FortifyStitch.from_wander(phase_1_project, self.image_file_names, self.tried_pairs, self.spatial_map) fortify_stitch.set_output_project_file_name(self.project.file_name) fortify_stitch.run() self.project = fortify_stitch.project print 'PHASE 2: done'
arg_key = arg[2:] if arg_key == "help": help() sys.exit(0) else: arg_fatal('Unrecognized arg: %s' % arg) else: if arg.find('.pto') > 0: project_file_names.append(arg) elif os.path.isfile(arg) or os.path.isdir(arg): image_file_names.append(arg) else: arg_fatal('unrecognized arg: %s' % arg) project = PTOProject.from_file_name('out.pto') project.parse() # Overall exposure # *very* important project.panorama_line.set_variable('E', 1) # What about m's p and s? for image_line in project.image_lines: # Don't adjust exposure image_line.set_variable('Eev', 1) # blue and red white balance correction at normal levels image_line.set_variable('Eb', 1) image_line.set_variable('Er', 1)
def generate_core(self, img_fns): # cpfind (and likely cpclean) trashes absolute file names # we need to restore them so that tools recognize the file names real_fn_base2full = {} args = list() project = PTOProject.from_default2() fn_obj = ManagedTempFile.get(None, ".pto") project.set_file_name(fn_obj.file_name) # Start with cpfind args.append("--multirow") args.append("--fullscale") # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) # Images for img_fn in img_fns: # xxx: why do we take the realpath? real_fn = os.path.realpath(img_fn) real_fn_base2full[os.path.basename(real_fn)] = img_fn project.add_image(real_fn, def_opt=True) project.save() print print print print project.get_text() print print print #(rc, output) = Execute.with_output('cpfind', args, print_output=self.print_output) (rc, output) = exc_ret_istr('cpfind', args, print_out=self.print_output) print 'PanoCP: cpfind done' if not rc == 0: print print print print 'output:' print output print raise Exception('Bad rc: %d' % rc) # Now run cpclean args = list() # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) (rc, output) = exc_ret_istr('cpclean', args, print_out=self.print_output) print 'PanoCP: cpclean done' if not rc == 0: print print print print 'output:' print output print raise Exception('Bad rc: %d' % rc) project.reopen() print 'Fixing image lines...' for il in project.image_lines: src = il.get_name() dst = real_fn_base2full[src] print ' %s => %s' % (src, dst) il.set_name(dst) project.set_file_name(None) fn_obj = None # Will happen if failed to match # be optimistic: cpclean work will be wasted but avoids parsing project twice if len(project.get_control_point_lines()) == 0: print 'WARNING: failed' return None return project
def ajpto2pto_text(pto_str, sub_image_0_file, sub_image_1_file, sub_image_0_x_delta, sub_image_0_y_delta, sub_to_real, load_images = True): '''Take in an old style autopanoaj project and return a .pto object''' # image index to subimage file name link (not symbolic link) index_to_sub_file_name = dict() imgfile_index = 0 part_pair_index = 0 ret = PTOProject.from_simple() #out = '' '''Convert .oto text (like from autopanoaj) to a .pto''' # Actually I think really is a .pto, just in a less common format for line in pto_str.split('\n'): if len(line) == 0: continue # This type of line is gen by autopano-sift-c elif line[0] == 'c': # c n0 N1 x1142.261719 y245.074757 X699.189408 Y426.042661 t0 ''' Okay def alphabetical issues # Not strictly related to this code, but close enough if not index_to_sub_file_name[0] == sub_image_0_file: print '0 index indicated file: %s, pair gen order expected %s' % (index_to_sub_file_name[0], sub_image_0_file) raise Exception('mismatch') if not index_to_sub_file_name[1] == sub_image_1_file: print '1 index indicated file: %s, pair gen order expected %s' % (index_to_sub_file_name[1], sub_image_1_file) raise Exception('mismatch') ''' # Parse parts = line.split() if not parts[1] == 'n0': print parts[1] raise Exception('mismatch') if not parts[2] == 'N1': print parts[2] raise Exception('mismatch') x = float(parts[3][1:]) y = float(parts[4][1:]) X = float(parts[5][1:]) Y = float(parts[6][1:]) #sub_image_1_x_end = image_1.width() #sub_image_1_y_end = image_1.height() # Adjust the image towards the upper left hand corner if index_to_sub_file_name[0] == sub_image_0_file.file_name: # normal adjustment x += sub_image_0_x_delta y += sub_image_0_y_delta elif index_to_sub_file_name[1] == sub_image_0_file.file_name: # they got flipped X += sub_image_0_x_delta Y += sub_image_0_y_delta else: print index_to_sub_file_name print 'index_to_sub_file_name[0]: %s' % repr(index_to_sub_file_name[0]) print 'index_to_sub_file_name[1]: %s' % repr(index_to_sub_file_name[1]) print 'sub_image_0_file: %s' % repr(sub_image_0_file) print 'sub_image_1_file: %s' % repr(sub_image_1_file) raise Exception("confused") # Write new_line = "c n0 N1 x%f y%f X%f Y%f t0" % (x, y, X, Y) #out += new_line + '\n' ret.add_control_point_line_by_text(new_line) # This type of line is generated by pto_merge elif line[0] == 'o': ''' #-imgfile 1632 408 "/tmp/pr0ntools_6691335AD228382E.jpg" o f0 y+0.000000 r+0.000000 p+0.000000 u20 d0.000000 e0.000000 v70.000000 a0.000000 b0.000000 c0.000000 to i w2816 h704 f0 a0 b-0.01 c0 d0 e0 p0 r0 v180 y0 u10 n"/tmp/pr0ntools_6691335AD228382E.jpg" ''' new_line = '' new_line += 'i' # Deferred to end if 0: # panotools fails in very exciting ways if you don't set this new_line += ' w%d' % images[0].width() new_line += ' w%d' % images[0].height() # default FOV new_line += ' v51' orig_fn = index_to_sub_file_name[part_pair_index] new_fn = sub_to_real[orig_fn] print 'Replacing %s => %s' % (orig_fn, new_fn) new_line += ' n"%s"' % new_fn part_pair_index += 1 print 'new line: %s' % new_line ret.add_image_line_by_text(new_line) # These lines are generated by autopanoaj # The comment line is literally part of the file format, some sort of bizarre encoding # #-imgfile 2816 704 "/tmp/pr0ntools_2D24DE9F6CC513E0/pr0ntools_6575AA69EA66B3C3.jpg" # o f0 y+0.000000 r+0.000000 p+0.000000 u20 d0.000000 e0.000000 v70.000000 a0.000000 b0.000000 c0.000000 elif line.find('#-imgfile') == 0: # Replace pseudo file names with real ones new_line = line index_to_sub_file_name[imgfile_index] = line.split('"')[1] imgfile_index += 1 elif line.find('#') == 0: pass else: #new_line = line print 'WARNING: discarding unknown line %s' % line #out += new_line + '\n' #else: #out += line + '\n' #ret = PTOProject.from_text(out) if load_images: print 'Fixing up image lines' fixup_image_dim(ret) return ret
_outdate = IOTimestamp(sys, 'stdout') _errdate = IOTimestamp(sys, 'stderr') if exist: _outlog.out_fd.write('\n') _outlog.out_fd.write('\n') _outlog.out_fd.write('\n') _outlog.out_fd.write('*' * 80 + '\n') _outlog.out_fd.write('*' * 80 + '\n') _outlog.out_fd.write('*' * 80 + '\n') print 'pr0npto starting' print 'In: %s' % pto_in print 'Out: %s' % pto_out bench = Benchmark() pto = PTOProject.from_file_name(pto_in) # Make sure we don't accidently override the original pto.remove_file_name() if args.center is True: center(pto) if args.anchor: print 'Re-finding anchor' center_anchor(pto) if args.basename: print 'Converting to basename' make_basename(pto) if args.hugin:
def run(self): if self.dry: print 'Dry run abort' return bench = Benchmark() if not self.output_project_file_name: raise Exception("need project file") #if not self.output_project_file_name: #self.project_temp_file = ManagedTempFile.get() #self.output_project_file_name = self.project_temp_file.file_name print 'Beginning stitch' print 'output project file name: %s' % self.output_project_file_name #sys.exit(1) self.init_failures() # Generate control points and merge them into a master project self.control_point_gen = get_cp_engine() # How many rows and cols to go to each side # If you hand took the pictures, this might suit you self.project = PTOProject.from_blank() if self.output_project_file_name: self.project.set_file_name(self.output_project_file_name) if os.path.exists(self.output_project_file_name): # Otherwise, we merge into it print 'WARNING: removing old project file: %s' % self.output_project_file_name os.remove(self.output_project_file_name) else: self.project.get_a_file_name(None, "_master.pto") self.project.image_file_names = self.image_file_names try: ''' Generate control points ''' self.generate_control_points() print 'Soften try: %s' % (self.soften_try, ) print 'Soften ok: %s' % (self.soften_ok, ) print 'Post stitch fixup...' optimize_xy_only(self.project) fixup_i_lines(self.project) fixup_p_lines(self.project) print print '***PTO project baseline final (%s / %s) data length %d***' % ( self.project.file_name, self.output_project_file_name, len(self.project.get_text())) print self.failure_json_w() print # Make dead sure its saved up to date self.project.save() # having issues with this.. if self.output_project_file_name and not self.project.file_name == self.output_project_file_name: raise Exception('project file name changed %s %s', self.project.file_name, self.output_project_file_name) # TODO: missing calc opt size/width/height/fov and crop except Exception as e: sys.stdout.flush() sys.stderr.flush() print print 'WARNING: stitch FAILED' traceback.print_exc() try: fn = self.project.file_name + ".failed" print 'Attempting to save intermediate result to %s' % fn self.project.save_as(fn) except: print 'WARNING: failed intermediate save' raise e finally: bench.stop() print 'Stitch done in %s' % bench
def generate_core(self, img_fns): # cpfind (and likely cpclean) trashes absolute file names # we need to restore them so that tools recognize the file names real_fn_base2full = {} args = list() project = PTOProject.from_default2() fn_obj = ManagedTempFile.get(None, ".pto") project.set_file_name(fn_obj.file_name) # Start with cpfind args.append("--multirow") args.append("--fullscale") # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) # Images for img_fn in img_fns: # xxx: why do we take the realpath? real_fn = os.path.realpath(img_fn) real_fn_base2full[os.path.basename(real_fn)] = img_fn project.add_image(real_fn, def_opt=True) project.save() print print print print project.get_text() print print print # (rc, output) = Execute.with_output('cpfind', args, print_output=self.print_output) (rc, output) = exc_ret_istr("cpfind", args, print_out=self.print_output) print "PanoCP: cpfind done" if not rc == 0: print print print print "output:" print output print raise Exception("Bad rc: %d" % rc) # Now run cpclean args = list() # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) (rc, output) = exc_ret_istr("cpclean", args, print_out=self.print_output) print "PanoCP: cpclean done" if not rc == 0: print print print print "output:" print output print raise Exception("Bad rc: %d" % rc) project.reopen() print "Fixing image lines..." for il in project.image_lines: src = il.get_name() dst = real_fn_base2full[src] print " %s => %s" % (src, dst) il.set_name(dst) project.set_file_name(None) fn_obj = None # Will happen if failed to match # be optimistic: cpclean work will be wasted but avoids parsing project twice if len(project.get_control_point_lines()) == 0: print "WARNING: failed" return None return project
def test_center(self): project = PTOProject.from_file_name('in.pto') center(project) (ybar, xbar) = calc_center(project) print 'Final xbar %f, ybar %f' % (ybar, xbar) project.save()
def generate_core(self, image_file_names): command = "autopanoaj" args = list() final_project_file = ManagedTempFile.get(None, ".pto") temp_dir = ManagedTempDir.get() # default is .oto args.append("/project:hugin") # Use image args instead of dir # Images image_links = dict() for image_file_name in image_file_names: # args.append(image_file_name.replace("/tmp/", "Z:\\tmp\\")) image_file_name = os.path.realpath(image_file_name) link_file_name = os.path.join(temp_dir.file_name, os.path.basename(image_file_name)) print 'Linking %s -> %s' % (link_file_name, image_file_name) os.symlink(image_file_name, link_file_name) #sys.exit(1) # go go go (rc, output) = Execute.with_output(command, args, temp_dir.file_name) print 'Finished control point pair execution' if not rc == 0: print print print print 'output:\n%s' % output if output.find('This application has requested the Runtime to terminate it in an unusual way'): print 'WARNING: skipping crash' return None raise Exception('Bad rc: %d' % rc) ''' Doesn't like the match: PICTURE PAIRS VALIDATION Pair ( 0, 1) Ransac (In : 21, Out : 4, Residu : 4.43799) REMOVED Timing : 583.7 us ''' if output.find('REMOVED') >= 0: print 'WARNING: RANSAC invalidated control points' return None output_file_name = os.path.join(temp_dir.file_name, "panorama0.pto") # This happens occassionally, not sure why if not os.path.exists(output_file_name): print 'WARNING: missing output pto file!' return None # We return PTO object, not string # Ditch the gen file because its unreliable shutil.move(output_file_name, final_project_file.file_name) f = open(final_project_file.file_name, 'r') project_text = f.read() # Under WINE, do fixup # #-imgfile 2816 704 "Z:\tmp\pr0ntools_471477ADA1679A2E\pr0ntools_3CD1C0B1BB218E40.jpg" project_text = project_text.replace('Z:\\', '/').replace('\\', '/') for image_file_name in image_file_names: link_file_name = os.path.join(temp_dir.file_name, os.path.basename(image_file_name)) print 'Replacing %s -> %s' % (link_file_name, image_file_name) project_text = project_text.replace(link_file_name, image_file_name) if False: print print 'Raw control point project (after symbolic link and WINE file name substitution)' print print print project_text print print print #sys.exit(1) f.close() f = open(final_project_file.file_name, 'w') f.write(project_text) project = PTOProject.from_temp_file(final_project_file) return project
def test_optimize_conversion(self): project = PTOProject.parse_from_file_name('in.pto') pt = project.to_ptoptimizer()
def run(self): if self.dry: print 'Dry run abort' return if not self.output_project_file_name and not self.output_image_file_name: raise Exception("need either project or image file") #if not self.output_project_file_name: #self.project_temp_file = ManagedTempFile.get() #self.output_project_file_name = self.project_temp_file.file_name print 'Beginning stitch' print 'output project file name: %s' % self.output_project_file_name print 'output image file name: %s' % self.output_image_file_name #sys.exit(1) self.init_failures() # Generate control points and merge them into a master project self.control_point_gen = ControlPointGenerator() # How many rows and cols to go to each side # If you hand took the pictures, this might suit you self.project = PTOProject.from_blank() if self.output_project_file_name: self.project.set_file_name(self.output_project_file_name) if os.path.exists(self.output_project_file_name): # Otherwise, we merge into it print 'WARNING: removing old project file: %s' % self.output_project_file_name os.remove(self.output_project_file_name) else: self.project.get_a_file_name(None, "_master.pto") self.project.image_file_names = self.image_file_names try: ''' Generate control points ''' self.generate_control_points() if False: self.photometric_optimizer = PhotometricOptimizer(self.project) self.photometric_optimizer.run() # Remove statistically unpleasant points if False: self.cleaner = PTOClean(self.project) self.cleaner.run() print 'Post stitch fixup...' optimize_xy_only(self.project) fixup_i_lines(self.project) fixup_p_lines(self.project) if 0: center_anchor(self.project) print print '***PTO project baseline final (%s / %s) data length %d***' % (self.project.file_name, self.output_project_file_name, len(self.project.get_text())) print if self.failures: print 'Writing failure JSON' cc = self.failures.critical_count() print '%d pairs failed to make %d images critical' % (self.failures.pair_count(), cc) if cc: print '******WARNING WARNING WARING******' print '%d images are not connected' % cc print '******WARNING WARNING WARING******' open('stitch_failures.json', 'w').write(str(self.failures)) print # Make dead sure its saved up to date self.project.save() # having issues with this.. if self.output_project_file_name and not self.project.file_name == self.output_project_file_name: raise Exception('project file name changed %s %s', self.project.file_name, self.output_project_file_name) self.optimize = False if self.optimize: self.optimizer = optimizer.PTOptimizer(self.project) self.optimizer.run() center(self.project) # TODO: missing calc opt size/width/height/fov and crop # Did we request an actual stitch? if self.output_image_file_name: print 'Stitching...' self.remapper = Remapper(self.project) self.remapper.remap(self.output_image_file_name) else: print 'NOT stitching (common stitch)' except Exception as e: print print 'WARNING: stitch FAILED' try: fn = self.project.file_name + ".failed" print 'Attempting to save intermediate result to %s' % fn self.project.save_as(fn) except: print 'WARNING: failed intermediate save' raise e
def generate_core(self, img_fns): # cpfind (and likely cpclean) trashes absolute file names # we need to restore them so that tools recognize the file names real_fn_base2full = {} args = list() project = PTOProject.from_default2() fn_obj = ManagedTempFile.get(None, ".pto") project.set_file_name(fn_obj.file_name) # Start with cpfind args.append("--multirow") args.append("--fullscale") # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) # Images for img_fn in img_fns: # xxx: why do we take the realpath? real_fn = os.path.realpath(img_fn) real_fn_base2full[os.path.basename(real_fn)] = img_fn project.add_image(real_fn, def_opt=True) project.save() print print print print project.get_text() print print print #(rc, output) = Execute.with_output('cpfind', args, print_output=self.print_output) print 'cpfind' + ' '.join(args) (rc, output) = exc_ret_istr('cpfind', args, print_out=self.print_output) print 'PanoCP: cpfind done' if not rc == 0: print print print print 'output:' print output print # Happens very rarely # 2018-01-24T04:00:18.720954: Exception: Bad rc: -11 # Log it but consider it a known failure if rc == -11: return None raise Exception('Bad rc: %d' % rc) # Now run cpclean args = list() # output file args.append("-o") args.append(project.file_name) # input file args.append(project.file_name) (rc, output) = exc_ret_istr('cpclean', args, print_out=self.print_output) print 'PanoCP: cpclean done' if not rc == 0: print print print print 'output:' print output print raise Exception('Bad rc: %d' % rc) project.reopen() print 'Fixing image lines...' for il in project.image_lines: src = il.get_name() dst = real_fn_base2full[src] print ' %s => %s' % (src, dst) il.set_name(dst) project.set_file_name(None) fn_obj = None # Will happen if failed to match # be optimistic: cpclean work will be wasted but avoids parsing project twice if len(project.get_control_point_lines()) == 0: print 'WARNING: failed' return None return project
args = parser.parse_args() if args.threads < 1: raise Exception('Bad threads') print 'Using %d threads' % args.threads log_dir = args.log out_dir = 'out' _dt = logwt(log_dir, 'main.log', shift_d=True) fn = args.pto[0] auto_size = not (args.stp or args.stm or args.stw or args.sth) print 'Assuming input %s is pto project to be stitched' % args.pto project = PTOProject.from_file_name(args.pto) print 'Creating tiler' stp = None if args.stp: stp = mksize(args.stp) elif args.stm: stp = mem2pix(mksize(args.stm)) print 'Memory %s => %s pix' % (args.stm, size2str(stp)) elif auto_size: stm = config.super_tile_memory() if stm: stp = mem2pix(mksize(stm)) # having issues creating very large if stp > 2**32/4: # 66 GB max useful as currently written print 'WARNING: reducing to maximum tile size'
args = parser.parse_args() if args.threads < 1: raise Exception('Bad threads') print 'Using %d threads' % args.threads log_dir = args.log out_dir = 'out' _dt = logwt(log_dir, 'main.log', shift_d=True) fn = args.pto[0] auto_size = not (args.stp or args.stm or args.stw or args.sth) print 'Assuming input %s is pto project to be stitched' % args.pto project = PTOProject.from_file_name(args.pto) print 'Creating tiler' stp = None if args.stp: stp = mksize(args.stp) elif args.stm: stp = mem2pix(mksize(args.stm)) print 'Memory %s => %s pix' % (args.stm, size2str(stp)) elif auto_size: stm = config.super_tile_memory() if stm: stp = mem2pix(mksize(stm)) # having issues creating very large if stp > 2**32 / 4: # 66 GB max useful as currently written print 'WARNING: reducing to maximum tile size'
def test_load(self): project = PTOProject.from_file_name('in.pto') #self.assertTrue(project.text != None) self.assertEqual(len(project.image_lines), 4)
''' import argparse from pr0ntools.stitch.pto.project import PTOProject 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
def run(self): if self.dry: print 'Dry run abort' return bench = Benchmark() if not self.output_project_file_name: raise Exception("need project file") #if not self.output_project_file_name: #self.project_temp_file = ManagedTempFile.get() #self.output_project_file_name = self.project_temp_file.file_name print 'Beginning stitch' print 'output project file name: %s' % self.output_project_file_name #sys.exit(1) self.init_failures() # Generate control points and merge them into a master project self.control_point_gen = get_cp_engine() # How many rows and cols to go to each side # If you hand took the pictures, this might suit you self.project = PTOProject.from_blank() if self.output_project_file_name: self.project.set_file_name(self.output_project_file_name) if os.path.exists(self.output_project_file_name): # Otherwise, we merge into it print 'WARNING: removing old project file: %s' % self.output_project_file_name os.remove(self.output_project_file_name) else: self.project.get_a_file_name(None, "_master.pto") self.project.image_file_names = self.image_file_names try: ''' Generate control points ''' self.generate_control_points() print 'Soften try: %s' % (self.soften_try,) print 'Soften ok: %s' % (self.soften_ok,) print 'Post stitch fixup...' optimize_xy_only(self.project) fixup_i_lines(self.project) fixup_p_lines(self.project) print print '***PTO project baseline final (%s / %s) data length %d***' % (self.project.file_name, self.output_project_file_name, len(self.project.get_text())) print self.failure_json_w() print # Make dead sure its saved up to date self.project.save() # having issues with this.. if self.output_project_file_name and not self.project.file_name == self.output_project_file_name: raise Exception('project file name changed %s %s', self.project.file_name, self.output_project_file_name) # TODO: missing calc opt size/width/height/fov and crop except Exception as e: sys.stdout.flush() sys.stderr.flush() print print 'WARNING: stitch FAILED' traceback.print_exc() try: fn = self.project.file_name + ".failed" print 'Attempting to save intermediate result to %s' % fn self.project.save_as(fn) except: print 'WARNING: failed intermediate save' raise e finally: bench.stop() print 'Stitch done in %s' % bench
def usage(): print 'optimizer <file in> [file out]' print 'If file out is not given it will be file in' if __name__ == "__main__": from pr0ntools.stitch.pto.project import PTOProject if len(sys.argv) < 2: usage() sys.exit(1) file_name_in = sys.argv[1] if len(sys.argv) > 2: file_name_out = sys.argv[2] else: file_name_out = file_name_in print 'Loading raw project...' project = PTOProject.from_file_name(file_name_in) print 'Creating optimizer...' optimizer = PTOptimizer(project) #self.assertTrue(project.text != None) print 'Running optimizer...' print 'Parsed main pre-run: %s' % str(project.parsed) optimizer.run() print 'Parsed main: %d' % project.parsed print 'Saving...' project.save_as(file_name_out) print 'Parsed main done: %s' % str(project.parsed)
help='reference project to work on') parser.add_argument('images', metavar='images', type=str, nargs='+', help='image files to put int output') parser.add_argument('--out', action='store', type=str, dest="pto_out", default="out.pto", help='output file name (default: out.pto)') parser.add_argument('--allow-missing', action="store_true", dest="allow_missing", default=True, help='Allow missing images') parser.add_argument('--border', action="store_true", dest="border", default=False, help='Manually optimize border') args = parser.parse_args() pto_ref_fn = args.pto_ref[0] pto_out_fn = args.pto_out print 'Reference in: %s' % pto_ref_fn print 'Out: %s' % pto_out_fn # Have to start somewhere... pto_out = PTOProject.from_default() # Add the images in for image in args.images: pto_out.add_image(image) pto_ref = PTOProject.from_file_name(pto_ref_fn) pto_ref.remove_file_name() linear_reoptimize(pto_out, pto_ref, allow_missing=args.allow_missing, order=2, border=args.border) print 'Centering...' center(pto_out) print 'Converting to Hugin form...' resave_hugin(pto_out)