def do_merge(self, others): 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 self.file_name and os.path.exists(self.file_name): args.append(self.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 raise Exception('failed pto_merge') return PTOProject.from_temp_file(pto_temp_file)
def soften_composite(src_fn, dst_fn=None): tmp_file = ManagedTempFile.from_same_extension(src_fn) soften_gauss(src_fn, tmp_file.file_name) if dst_fn is None: dst_fn = src_fn args = ["convert"] args.append(src_fn) args.append(tmp_file.file_name) args.append("-compose") args.append("Blend") args.append("-define") args.append("compose:args=60,40%") args.append("-composite") # If we got a dest file, use it args.append(dst_fn) print 'going to execute: %s' % (args,) subp = subprocess.Popen(args, stdout=None, stderr=None, shell=False) subp.communicate() print 'Execute done, rc: %s' % (subp.returncode,) if not subp.returncode == 0: raise Exception('failed to form strong blur') # having some problems that looks like file isn't getting written to disk # monitoring for such errors # remove if I can root cause the source of these glitches for i in xrange(30): if os.path.exists(dst_fn): break if i == 0: print 'WARNING: soften missing strong blur dest file name %s, waiting a bit...' % (dst_fn,) time.sleep(0.1) else: raise Exception('Missing soften strong blur output file name %s' % dst_fn)
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 from_file_name(file_name, is_temporary = False): ret = PTOProject() ret.file_name = file_name if is_temporary: ret.temp_file = ManagedTempFile.from_existing(file_name) ret.parse() return ret
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 parse_from_file_name(file_name, is_temporary = False): ret = PTOProject() ret.file_name = file_name if is_temporary: ret.temp_file = ManagedTempFile.from_existing(file_name) ret.parse() return ret
def do_get_a_file_name(self, prefix = None, postfix = None): '''If doesn't have a real file, create a temp file''' if self.file_name: return self.file_name if postfix is None: postfix = ".pto" self.temp_file = ManagedTempFile.get(prefix, postfix) self.file_name = self.temp_file.file_name return self.file_name
def get_a_file_name(self, prefix = None, postfix = None): '''Return a file name that has current .pto contents''' '''If doesn't have a real file, create a temp file''' if self.file_name: return self.file_name if postfix is None: postfix = ".pto" self.temp_file = ManagedTempFile.get(prefix, postfix) self.file_name = self.temp_file.file_name # hmmm... self.save() return self.file_name
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): 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): 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 run(self, source_file_name, dest_file_name = None): ''' http://www.imagemagick.org/Usage/convolve/#soft_blur convert face.png -morphology Convolve Gaussian:0x3 face_strong_blur.png convert face.png face_strong_blur.png \ -compose Blend -define compose:args=60,40% -composite \ face_soft_blur.png If dest_file_name is not given, done in place ''' strong_blur_mtemp_file = ManagedTempFile.from_same_extension(source_file_name) args = list() args.append(source_file_name) args.append("-morphology") args.append("Convolve") args.append("Gaussian:0x3") args.append(strong_blur_mtemp_file.file_name) (rc, output) = Execute.with_output("convert", args) if not rc == 0: raise Exception('failed to form strong blur') args = list() args.append(source_file_name) args.append(strong_blur_mtemp_file.file_name) args.append("-compose") args.append("Blend") args.append("-define") args.append("compose:args=60,40%") args.append("-composite") # If we got a dest file, use it if dest_file_name: args.append(dest_file_name) # Otherwise, overwrite else: args.append(source_file_name) (rc, output) = Execute.with_output("convert", args) if not rc == 0: raise Exception('failed to form strong blur')
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): 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 soften_composite(src_fn, dst_fn=None): tmp_file = ManagedTempFile.from_same_extension(src_fn) soften_gauss(src_fn, tmp_file.file_name) if dst_fn is None: dst_fn = src_fn args = ["convert"] args.append(src_fn) args.append(tmp_file.file_name) args.append("-compose") args.append("Blend") args.append("-define") args.append("compose:args=60,40%") args.append("-composite") # If we got a dest file, use it args.append(dst_fn) print 'going to execute: %s' % (args, ) subp = subprocess.Popen(args, stdout=None, stderr=None, shell=False) subp.communicate() print 'Execute done, rc: %s' % (subp.returncode, ) if not subp.returncode == 0: raise Exception('failed to form strong blur') # having some problems that looks like file isn't getting written to disk # monitoring for such errors # remove if I can root cause the source of these glitches for i in xrange(30): if os.path.exists(dst_fn): break if i == 0: print 'WARNING: soften missing strong blur dest file name %s, waiting a bit...' % ( dst_fn, ) time.sleep(0.1) else: raise Exception('Missing soften strong blur output file name %s' % dst_fn)
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 try_supertile(self, st_bounds): '''x0/1 and y0/1 are global absolute coordinates''' # First generate all of the valid tiles across this area to see if we can get any useful work done? # every supertile should have at least one solution or the bounds aren't good x0, x1, y0, y1 = st_bounds bench = Benchmark() try: if self.st_dir: # nah...tiff takes up too much space dst = os.path.join(self.st_dir, 'st_%06dx_%06dy.jpg' % (x0, y0)) if os.path.exists(dst): # normally this is a .tif so slight loss in quality img = PImage.from_file(dst) print 'supertile short circuit on already existing: %s' % ( dst, ) return img # st_081357x_000587y.jpg temp_file = ManagedTempFile.get(None, '.tif', prefix_mangle='st_%06dx_%06dy_' % (x0, y0)) stitcher = PartialStitcher(self.pto, st_bounds, temp_file.file_name, self.i, self.running, pprefix=self.pprefix) stitcher.enblend_lock = self.enblend_lock stitcher.nona_args = self.nona_args stitcher.enblend_args = self.enblend_args if self.dry: print 'dry: skipping partial stitch' stitcher = None else: stitcher.run() print print 'phase 3: loading supertile image' if self.dry: print 'dry: skipping loading PTO' img_fn = None else: if self.st_dir: self.st_fns.put(dst) #shutil.copyfile(temp_file.file_name, dst) args = [ 'convert', '-quality', '90', temp_file.file_name, dst ] print 'going to execute: %s' % (args, ) subp = subprocess.Popen(args, stdout=None, stderr=None, shell=False) subp.communicate() if subp.returncode != 0: raise Exception('Failed to copy stitched file') # having some problems that looks like file isn't getting written to disk # monitoring for such errors # remove if I can root cause the source of these glitches for i in xrange(30): if os.path.exists(dst): break if i == 0: print 'WARNING: soften missing strong blur dest file name %s, waiting a bit...' % ( dst, ) time.sleep(0.1) else: raise Exception( 'Missing soften strong blur output file name %s' % dst) # FIXME: was passing loaded image object # Directory should delete on exit # otherwise parent can delete it #img = PImage.from_file(temp_file.file_name) img_fn = temp_file.file_name # prevent deletion temp_file.file_name = '' #print 'supertile width: %d, height: %d' % (img.width(), img.height()) print 'Supertile done w/ fn %s' % (img_fn, ) return img_fn except: print 'supertile failed at %s' % (bench, ) raise
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 hugin_form(self): ''' This is used when merging through fortify stitch Something is causing pto_merge to hang, but NOT ptomerge Only occurs if I wrap my commands in a script... The script doesn't do any fancy I/O redirection clear rm -rf /tmp/pr0ntools_* pr0nstitch *.jpg out.pto pto_merge produces nicer output than ptomerge While ptomerge produces the fields I need, it leaves some other junk I think pto_merge also calculates width/heigh attributes part of Hugin [mcmaster@gespenst first]$ pto_merge Warning: pto_merge requires at least 2 project files pto_merge: merges several project files pto_merge version 2010.4.0.854952d82c8f part of perl-Panotools-Script [mcmaster@gespenst first]$ ptomerge --help cannot read-open --help at /usr/share/perl5/Panotools/Script.pm line 91. man ptomerge ... ptomerge infile1.pto infile2.pto infile3.pto [...] outfile.pto ... ''' # However, this tool also generates an archaic .pto format that pto can parse, but I don't want to # pretend to merge into an empty project to force Hugin to clean it up # pto_merge --output=temp.pto /dev/null temp.pto if False: args = list() args.append("%s" % self.get_a_file_name()) args.append("%s" % self.get_a_file_name()) args.append("%s" % self.get_a_file_name()) (rc, output) = Execute.with_output("ptomerge", args) else: args = list() args.append("--output=%s" % self.get_a_file_name()) args.append("%s" % self.get_a_file_name()) if False: args.append("/dev/null") else: empty_file = ManagedTempFile.get(None, ".pto") open(empty_file.file_name, 'w').write('') args.append(empty_file.file_name) (rc, output) = Execute.with_output("pto_merge", args) if not rc == 0: print print print if rc == 35072: # ex: empty projects seem to cause this print 'Out of memory, expect malformed project file' print 'output:%s' % output raise Exception('Bad rc: %d' % rc) self.reopen()
def hugin_form(self): ''' Something is causing pto_merge to hang, but NOT ptomerge Only occurs if I wrap my commands in a script... The script doesn't do any fancy I/O redirection clear rm -rf /tmp/pr0ntools_* pr0nstitch *.jpg out.pto pto_merge produces nicer output than ptomerge While ptomerge produces the fields I need, it leaves some other junk I think pto_merge also calculates width/heigh attributes part of Hugin [mcmaster@gespenst first]$ pto_merge Warning: pto_merge requires at least 2 project files pto_merge: merges several project files pto_merge version 2010.4.0.854952d82c8f part of perl-Panotools-Script [mcmaster@gespenst first]$ ptomerge --help cannot read-open --help at /usr/share/perl5/Panotools/Script.pm line 91. man ptomerge ... ptomerge infile1.pto infile2.pto infile3.pto [...] outfile.pto ... ''' # However, this tool also generates an archaic .pto format that pto can parse, but I don't want to # pretend to merge into an empty project to force Hugin to clean it up # pto_merge --output=temp.pto /dev/null temp.pto if False: args = list() args.append("%s" % self.get_a_file_name()) args.append("%s" % self.get_a_file_name()) args.append("%s" % self.get_a_file_name()) (rc, output) = Execute.with_output("ptomerge", args) else: args = list() args.append("--output=%s" % self.get_a_file_name()) args.append("%s" % self.get_a_file_name()) if False: args.append("/dev/null") else: empty_file = ManagedTempFile.get(None, ".pto") open(empty_file.file_name, 'w').write('') args.append(empty_file.file_name) (rc, output) = Execute.with_output("pto_merge", args) if not rc == 0: print print print print 'output:%s' % output raise Exception('Bad rc: %d' % rc) self.reopen()
def control_points_by_subimage(self, pair, pair_images): ''' Just work on the overlap section, maybe even less ''' overlap = 1.0 / 3.0 images = [PImage.from_file(image_file_name) for image_file_name in pair_images] ''' image_0 used as reference 4 basic situations: left, right, up right 8 extended: 4 basic + corners Pairs should be sorted, which simplifies the logic ''' sub_image_0_x_delta = 0 sub_image_0_y_delta = 0 sub_image_1_x_end = images[1].width() sub_image_1_y_end = images[1].height() # image 0 left of image 1? if pair.first.col < pair.second.col: # Keep image 0 right, image 1 left sub_image_0_x_delta = int(images[0].width() * (1.0 - overlap)) sub_image_1_x_end = int(images[1].width() * overlap) # image 0 above image 1? if pair.first.row < pair.second.row: # Keep image 0 top, image 1 bottom sub_image_0_y_delta = int(images[0].height() * (1.0 - overlap)) sub_image_1_y_end = int(images[1].height() * overlap) ''' print 'image 0 x delta: %d, y delta: %d' % (sub_image_0_x_delta, sub_image_0_y_delta) Note y starts at top in PIL ''' sub_image_0 = images[0].subimage(sub_image_0_x_delta, None, sub_image_0_y_delta, None) sub_image_1 = images[1].subimage(None, sub_image_1_x_end, None, sub_image_1_y_end) sub_image_0_file = ManagedTempFile.get(None, '.jpg') sub_image_1_file = ManagedTempFile.get(None, '.jpg') print 'sub image 0: width=%d, height=%d, name=%s' % (sub_image_0.width(), sub_image_0.height(), sub_image_0_file.file_name) print 'sub image 1: width=%d, height=%d, name=%s' % (sub_image_1.width(), sub_image_1.height(), sub_image_0_file.file_name) #sys.exit(1) sub_image_0.image.save(sub_image_0_file.file_name) sub_image_1.image.save(sub_image_1_file.file_name) sub_pair_images = (sub_image_0_file.file_name, sub_image_1_file.file_name) # image index to subimage file name link (not symbolic link) index_to_sub_file_name = dict() imgfile_index = 0 # subimage file name symbolic link to subimage file name # this should be taken care of inside of control point actually #sub_link_to_sub = dict() # subimage to the image it came from sub_to_real = dict() sub_to_real[sub_image_0_file.file_name] = pair_images[0] sub_to_real[sub_image_1_file.file_name] = pair_images[1] ''' # Hugin project file # generated by Autopano # Panorama settings: p w8000 h1200 f2 v250 n"PSD_mask" # input images: #-imgfile 2816 704 "/tmp/pr0ntools_C21F246F52E9D691/AA9627DC60B39FC8.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 #-imgfile 2816 704 "/tmp/pr0ntools_C21F246F52E9D691/EDE10C14171B2078.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 # Control points: c n0 N1 x1024 y176 X555 Y119 # Control Point No 0: 1.00000 c n0 N1 x1047 y160 X578 Y105 ... autopano-sift-c style file # Hugin project file generated by APSCpp p f2 w3000 h1500 v360 n"JPEG q90" m g1 i0 i w2816 h704 f0 a0 b-0.01 c0 d0 e0 p0 r0 v180 y0 u10 n"/tmp/pr0ntools_6691335AD228382E.jpg" i w2816 h938 f0 a0 b-0.01 c0 d0 e0 p0 r0 v180 y0 u10 n"/tmp/pr0ntools_64D97FF4621BC36E.jpg" v p1 r1 y1 # automatically generated control points c n0 N1 x1142.261719 y245.074757 X699.189408 Y426.042661 t0 c n0 N1 x887.417450 y164.602097 X1952.346197 Y921.975829 t0 ... c n0 N1 x823.803714 y130.802771 X674.596763 Y335.994699 t0 c n0 N1 x1097.192159 y121.170416 X937.394996 Y329.998934 t0 # :-) ''' fast_pair_project = self.control_point_gen.generate_core(sub_pair_images) if fast_pair_project is None: print 'WARNING: failed to gen control points @ %s' % repr(pair) return None out = '' part_pair_index = 0 for line in fast_pair_project.__repr__().split('\n'): if len(line) == 0: new_line = '' # 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' # This type of line is generated by pto_merge elif line[0] == 'i': # i w2816 h704 f0 a0 b-0.01 c0 d0 e0 p0 r0 v180 y0 u10 n"/tmp/pr0ntools_6691335AD228382E.jpg" new_line = '' for part in line.split(): t = part[0] if t == 'i': new_line += 'i' elif t == 'w': new_line += ' w%d' % images[0].width() elif t == 'h': new_line += ' w%d' % images[0].height() elif t == 'n': new_line += ' n%s' % pair_images[part_pair_index] part_pair_index += 1 else: new_line += ' %s' % part print 'new line: %s' % 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 else: new_line = line out += new_line + '\n' else: out += line + '\n' for k in sub_to_real: v = sub_to_real[k] print 'Replacing %s => %s' % (k, v) out = out.replace(k, v) final_pair_project = PTOProject.from_text(out) return final_pair_project
def control_points_by_subimage(self, pair, image_fn_pair): '''Stitch two images together by cropping to restrict overlap''' # subimage_factor: (y, x) overlap percent tuple or none for default # pair: pair of row/col or coordinate positions (used to determine relative positions) # (0, 0) at upper left # image_fn_pair: pair of image file names print 'Preparing subimage stitch on %s:%s' % (image_fn_pair[0], image_fn_pair[1]) ''' Just work on the overlap section, maybe even less ''' images = [PImage.from_file(image_file_name) for image_file_name in image_fn_pair] ''' image_0 used as reference 4 basic situations: left, right, up right 8 extended: 4 basic + corners Pairs should be sorted, which simplifies the logic ''' sub_image_0_x_delta = 0 sub_image_0_y_delta = 0 sub_image_1_x_end = images[1].width() sub_image_1_y_end = images[1].height() # Add some backlash margin # "more overlap" means will try a slightly larger area #margin = 0.05 x_overlap = self.x_overlap y_overlap = self.y_overlap # image 0 left of image 1? if pair.first.col < pair.second.col: # Keep image 0 right, image 1 left sub_image_0_x_delta = int(images[0].width() * x_overlap) sub_image_1_x_end = int(round(images[1].width() * (1.0 - x_overlap))) # image 0 above image 1? if pair.first.row < pair.second.row: # Keep image 0 top, image 1 bottom sub_image_0_y_delta = int(images[0].height() * y_overlap) sub_image_1_y_end = int(round(images[1].height() * (1.0 - y_overlap))) ''' print 'image 0 x delta: %d, y delta: %d' % (sub_image_0_x_delta, sub_image_0_y_delta) Note y starts at top in PIL ''' sub_image_0 = images[0].subimage(sub_image_0_x_delta, None, sub_image_0_y_delta, None) sub_image_1 = images[1].subimage(None, sub_image_1_x_end, None, sub_image_1_y_end) sub_image_0_file = ManagedTempFile.get(None, '.jpg') sub_image_1_file = ManagedTempFile.get(None, '.jpg') print 'sub image 0: width=%d, height=%d, name=%s' % (sub_image_0.width(), sub_image_0.height(), sub_image_0_file.file_name) print 'sub image 1: width=%d, height=%d, name=%s' % (sub_image_1.width(), sub_image_1.height(), sub_image_1_file.file_name) #sys.exit(1) sub_image_0.image.save(sub_image_0_file.file_name) sub_image_1.image.save(sub_image_1_file.file_name) sub_image_fn_pair = (sub_image_0_file.file_name, sub_image_1_file.file_name) # subimage file name symbolic link to subimage file name # this should be taken care of inside of control point actually #sub_link_to_sub = dict() # subimage to the image it came from sub_to_real = dict() sub_to_real[sub_image_0_file.file_name] = image_fn_pair[0] sub_to_real[sub_image_1_file.file_name] = image_fn_pair[1] # Returns a pto project object pair_project = self.control_point_gen.generate_core(sub_image_fn_pair) if pair_project is None: print 'WARNING: failed to gen control points @ %s' % repr(pair) return None # all we need to do is adjust xy positions # afaik above is way overcomplicated final_pair_project = pto_unsub(pair_project, (sub_image_0_file, sub_image_1_file), (sub_image_0_x_delta, sub_image_0_y_delta), sub_to_real) # Filenames become absolute #sys.exit(1) return final_pair_project
def control_points_by_subimage(self, pair, image_fn_pair, subimage_factor=None): '''Stitch two images together by cropping to restrict overlap''' # subimage_factor: (y, x) overlap percent tuple or none for default # pair: pair of row/col or coordinate positions (used to determine relative positions) # (0, 0) at upper left # image_fn_pair: pair of image file names print 'Preparing subimage stitch on %s:%s' % (image_fn_pair[0], image_fn_pair[1]) ''' Just work on the overlap section, maybe even less ''' images = [ PImage.from_file(image_file_name) for image_file_name in image_fn_pair ] ''' image_0 used as reference 4 basic situations: left, right, up right 8 extended: 4 basic + corners Pairs should be sorted, which simplifies the logic ''' sub_image_0_x_delta = 0 sub_image_0_y_delta = 0 sub_image_1_x_end = images[1].width() sub_image_1_y_end = images[1].height() if subimage_factor: y_overlap = subimage_factor[0] x_overlap = subimage_factor[1] else: x_overlap = self.x_overlap y_overlap = self.y_overlap # image 0 left of image 1? if pair.first.col < pair.second.col: # Keep image 0 right, image 1 left sub_image_0_x_delta = int(images[0].width() * (1.0 - x_overlap)) sub_image_1_x_end = int(images[1].width() * x_overlap) # image 0 above image 1? if pair.first.row < pair.second.row: # Keep image 0 top, image 1 bottom sub_image_0_y_delta = int(images[0].height() * (1.0 - y_overlap)) sub_image_1_y_end = int(images[1].height() * y_overlap) ''' print 'image 0 x delta: %d, y delta: %d' % (sub_image_0_x_delta, sub_image_0_y_delta) Note y starts at top in PIL ''' sub_image_0 = images[0].subimage(sub_image_0_x_delta, None, sub_image_0_y_delta, None) sub_image_1 = images[1].subimage(None, sub_image_1_x_end, None, sub_image_1_y_end) sub_image_0_file = ManagedTempFile.get(None, '.jpg') sub_image_1_file = ManagedTempFile.get(None, '.jpg') print 'sub image 0: width=%d, height=%d, name=%s' % (sub_image_0.width( ), sub_image_0.height(), sub_image_0_file.file_name) print 'sub image 1: width=%d, height=%d, name=%s' % (sub_image_1.width( ), sub_image_1.height(), sub_image_0_file.file_name) #sys.exit(1) sub_image_0.image.save(sub_image_0_file.file_name) sub_image_1.image.save(sub_image_1_file.file_name) sub_image_fn_pair = (sub_image_0_file.file_name, sub_image_1_file.file_name) # subimage file name symbolic link to subimage file name # this should be taken care of inside of control point actually #sub_link_to_sub = dict() # subimage to the image it came from sub_to_real = dict() sub_to_real[sub_image_0_file.file_name] = image_fn_pair[0] sub_to_real[sub_image_1_file.file_name] = image_fn_pair[1] # Returns a pto project object pair_project = self.control_point_gen.generate_core(sub_image_fn_pair) if pair_project is None: print 'WARNING: failed to gen control points @ %s' % repr(pair) return None # all we need to do is adjust xy positions # afaik above is way overcomplicated final_pair_project = pto_unsub( pair_project, (sub_image_0_file, sub_image_1_file), (sub_image_0_x_delta, sub_image_0_y_delta), sub_to_real) # Filenames become absolute #sys.exit(1) return final_pair_project
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
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
def control_points_by_subimage(self, pair, image_fn_pair, subimage_factor = None): '''Stitch two images together by cropping to restrict overlap''' # subimage_factor: (y, x) overlap percent tuple or none for default # pair: pair of row/col or coordinate positions (used to determine relative positions) # (0, 0) at upper left # image_fn_pair: pair of image file names print 'Preparing subimage stitch on %s:%s' % (image_fn_pair[0], image_fn_pair[1]) ''' Just work on the overlap section, maybe even less ''' images = [PImage.from_file(image_file_name) for image_file_name in image_fn_pair] ''' image_0 used as reference 4 basic situations: left, right, up right 8 extended: 4 basic + corners Pairs should be sorted, which simplifies the logic ''' sub_image_0_x_delta = 0 sub_image_0_y_delta = 0 sub_image_1_x_end = images[1].width() sub_image_1_y_end = images[1].height() if subimage_factor: y_overlap = subimage_factor[0] x_overlap = subimage_factor[1] else: x_overlap = self.x_overlap y_overlap = self.y_overlap # image 0 left of image 1? if pair.first.col < pair.second.col: # Keep image 0 right, image 1 left sub_image_0_x_delta = int(images[0].width() * (1.0 - x_overlap)) sub_image_1_x_end = int(images[1].width() * x_overlap) # image 0 above image 1? if pair.first.row < pair.second.row: # Keep image 0 top, image 1 bottom sub_image_0_y_delta = int(images[0].height() * (1.0 - y_overlap)) sub_image_1_y_end = int(images[1].height() * y_overlap) ''' print 'image 0 x delta: %d, y delta: %d' % (sub_image_0_x_delta, sub_image_0_y_delta) Note y starts at top in PIL ''' sub_image_0 = images[0].subimage(sub_image_0_x_delta, None, sub_image_0_y_delta, None) sub_image_1 = images[1].subimage(None, sub_image_1_x_end, None, sub_image_1_y_end) sub_image_0_file = ManagedTempFile.get(None, '.jpg') sub_image_1_file = ManagedTempFile.get(None, '.jpg') print 'sub image 0: width=%d, height=%d, name=%s' % (sub_image_0.width(), sub_image_0.height(), sub_image_0_file.file_name) print 'sub image 1: width=%d, height=%d, name=%s' % (sub_image_1.width(), sub_image_1.height(), sub_image_0_file.file_name) #sys.exit(1) sub_image_0.image.save(sub_image_0_file.file_name) sub_image_1.image.save(sub_image_1_file.file_name) sub_image_fn_pair = (sub_image_0_file.file_name, sub_image_1_file.file_name) # subimage file name symbolic link to subimage file name # this should be taken care of inside of control point actually #sub_link_to_sub = dict() # subimage to the image it came from sub_to_real = dict() sub_to_real[sub_image_0_file.file_name] = image_fn_pair[0] sub_to_real[sub_image_1_file.file_name] = image_fn_pair[1] # Returns a pto project object fast_pair_project = self.control_point_gen.generate_core(sub_image_fn_pair) if fast_pair_project is None: print 'WARNING: failed to gen control points @ %s' % repr(pair) return None oto_text = str(fast_pair_project) if 0: print oto_text # are we actually doing anything useful here? # The original intention was to make dead sure we had the right file order # but I'm pretty sure its consistent and we don't need to parse the comments final_pair_project = ajpto2pto_text(oto_text, sub_image_0_file, sub_image_1_file, sub_image_0_x_delta, sub_image_0_y_delta, sub_to_real) # Filenames become absolute #sys.exit(1) return final_pair_project
def try_supertile(self, st_bounds): '''x0/1 and y0/1 are global absolute coordinates''' # First generate all of the valid tiles across this area to see if we can get any useful work done? # every supertile should have at least one solution or the bounds aren't good x0, x1, y0, y1 = st_bounds bench = Benchmark() try: if self.st_dir: # nah...tiff takes up too much space dst = os.path.join(self.st_dir, 'st_%06dx_%06dy.jpg' % (x0, y0)) if os.path.exists(dst): # normally this is a .tif so slight loss in quality print 'supertile short circuit on already existing: %s' % (dst,) return dst # st_081357x_000587y.jpg temp_file = ManagedTempFile.get(None, '.tif', prefix_mangle='st_%06dx_%06dy_' % (x0, y0)) stitcher = PartialStitcher(self.pto, st_bounds, temp_file.file_name, self.i, self.running, pprefix=self.pprefix) stitcher.enblend_lock = self.enblend_lock stitcher.nona_args = self.nona_args stitcher.enblend_args = self.enblend_args if self.dry: print 'dry: skipping partial stitch' stitcher = None else: stitcher.run() print print 'phase 3: loading supertile image' if self.dry: print 'dry: skipping loading PTO' img_fn = None else: if self.st_dir: self.st_fns.put(dst) #shutil.copyfile(temp_file.file_name, dst) args = ['convert', '-quality', '90', temp_file.file_name, dst] print 'going to execute: %s' % (args,) subp = subprocess.Popen(args, stdout=None, stderr=None, shell=False) subp.communicate() if subp.returncode != 0: raise Exception('Failed to copy stitched file') # having some problems that looks like file isn't getting written to disk # monitoring for such errors # remove if I can root cause the source of these glitches for i in xrange(30): if os.path.exists(dst): break if i == 0: print 'WARNING: soften missing strong blur dest file name %s, waiting a bit...' % (dst,) time.sleep(0.1) else: raise Exception('Missing soften strong blur output file name %s' % dst) # FIXME: was passing loaded image object # Directory should delete on exit # otherwise parent can delete it #img = PImage.from_file(temp_file.file_name) img_fn = temp_file.file_name # prevent deletion temp_file.file_name = '' #print 'supertile width: %d, height: %d' % (img.width(), img.height()) print 'Supertile done w/ fn %s' % (img_fn,) return img_fn except: print 'supertile failed at %s' % (bench,) raise
def try_supertile(self, x0, x1, y0, y1): '''x0/1 and y0/1 are global absolute coordinates''' # First generate all of the valid tiles across this area to see if we can get any useful work done? # every supertile should have at least one solution or the bounds aren't good bench = Benchmark() try: temp_file = ManagedTempFile.get(None, '.tif') bounds = [x0, x1, y0, y1] #out_name_base = "%s/r%03d_c%03d" % (self.out_dir, row, col) #print 'Working on %s' % out_name_base stitcher = PartialStitcher(self.pto, bounds, temp_file.file_name) if self.dry: print 'Dry: skipping partial stitch' stitcher = None else: stitcher.run() print print 'Phase 3: loading supertile image' if self.dry: print 'Dry: skipping loading PTO' img = None else: img = PImage.from_file(temp_file.file_name) print 'Supertile width: %d, height: %d' % (img.width(), img.height()) new = 0 ''' A tile is valid if its in a safe location There are two ways for the location to be safe: -No neighboring tiles as found on canvas edges -Sufficiently inside the blend area that artifacts should be minimal ''' gen_tiles = 0 print # TODO: get the old info back if I miss it after yield refactor print 'Phase 4: chopping up supertile' self.msg('step(x: %d, y: %d)' % (self.tw, self.th), 3) #self.msg('x in xrange(%d, %d, %d)' % (xt0, xt1, self.tw), 3) #self.msg('y in xrange(%d, %d, %d)' % (yt0, yt1, self.th), 3) for (y, x) in self.gen_supertile_tiles(x0, x1, y0, y1): # If we made it this far the tile can be constructed with acceptable enblend artifacts row = self.y2row(y) col = self.x2col(x) # Did we already do this tile? if self.is_done(row, col): # No use repeating it although it would be good to diff some of these print 'Rejecting tile x%d, y%d / r%d, c%d: already done' % (x, y, row, col) continue # note that x and y are in whole pano coords # we need to adjust to our frame # row and col on the other hand are used for global naming self.make_tile(img, x - x0, y - y0, row, col) gen_tiles += 1 bench.stop() print 'Generated %d new tiles for a total of %d / %d in %s' % (gen_tiles, len(self.closed_list), self.net_expected_tiles, str(bench)) if gen_tiles == 0: raise Exception("Didn't generate any tiles") # temp_file should be automatically deleted upon exit except: print 'Supertile failed at %s' % bench raise
def do_generate_control_points_by_pair(self, pair, image_fn_pair): '''high level function uses by sub-stitches. Given a pair of images make a best effort to return a .pto object''' ''' pair: ImageCoordinatePair() object image_fn_pair: tuple of strings Algorithm: First try to stitch normally (either whole image or partial depending on the mode) If that doesn't succeed and softening is enabled try up to three times to soften to produce a match If that still doesn't produce a decent solution return None and let higher levels deal with ''' soften_iterations = 3 print print #print 'Generating project for image pair (%s / %s, %s / %s)' % (image_fn_pair[0], str(pair[0]), image_fn_pair[1], str(pair[1])) print 'Generating project for image pair (%s, %s)' % (image_fn_pair[0], image_fn_pair[1]) if True: # Try raw initially print 'Attempting sharp match...' ret_project = self.try_control_points_with_position( pair, image_fn_pair) if ret_project: return ret_project print 'WARNING: bad project, attempting soften...' soften_image_file_0_managed = ManagedTempFile.from_same_extension( image_fn_pair[0]) soften_image_file_1_managed = ManagedTempFile.from_same_extension( image_fn_pair[1]) print 'Soften fn0: %s' % soften_image_file_0_managed.file_name print 'Soften fn1: %s' % soften_image_file_1_managed.file_name for i in xrange(soften_iterations): self.soften_try[i] += 1 # And then start screwing with it # Wonder if we can combine features from multiple soften passes? # Or at least take the maximum # Do features get much less accurate as the soften gets up there? print 'Attempting soften %d / %d' % (i + 1, soften_iterations) if i == 0: soften_composite(image_fn_pair[0], soften_image_file_0_managed.file_name) soften_composite(image_fn_pair[1], soften_image_file_1_managed.file_name) else: soften_composite(soften_image_file_0_managed.file_name) soften_composite(soften_image_file_1_managed.file_name) pair_soften_image_file_names = ( soften_image_file_0_managed.file_name, soften_image_file_1_managed.file_name) ret_project = self.try_control_points_with_position( pair, pair_soften_image_file_names) # Did we win? if ret_project: # Fixup the project to reflect the correct file names text = str(ret_project) if 0: print print 'Before sub' print print str(ret_project) print print print print '%s => %s' % (soften_image_file_0_managed.file_name, image_fn_pair[0]) text = text.replace(soften_image_file_0_managed.file_name, image_fn_pair[0]) print '%s => %s' % (soften_image_file_1_managed.file_name, image_fn_pair[1]) text = text.replace(soften_image_file_1_managed.file_name, image_fn_pair[1]) ret_project.set_text(text) if 0: print print 'After sub' print print str(ret_project) print print print #sys.exit(1) self.soften_ok[i] += 1 print 'Soften try: %s' % (self.soften_try, ) print 'Soften ok: %s' % (self.soften_ok, ) return ret_project print 'WARNING: gave up on generating control points!' return None
def generate_control_points(self, pair, pair_images): soften_iterations = 3 if True: # Try raw initially ret_project = self.try_control_points(pair, pair_images) if ret_project: return ret_project print 'WARNING: bad project, attempting soften...' soften_image_file_0_managed = ManagedTempFile.from_same_extension(pair_images[0]) soften_image_file_1_managed = ManagedTempFile.from_same_extension(pair_images[1]) softener = Softener() first_run = True for i in range(0, soften_iterations): # And then start screwing with it # Wonder if we can combine features from multiple soften passes? # Or at least take the maximum # Do features get much less accurate as the soften gets up there? print 'Attempting soften %d / %d' % (i + 1, soften_iterations) if first_run: softener.run(pair_images[0], soften_image_file_0_managed.file_name) softener.run(pair_images[1], soften_image_file_1_managed.file_name) else: softener.run(soften_image_file_0_managed.file_name) softener.run(soften_image_file_1_managed.file_name) pair_soften_image_file_names = (soften_image_file_0_managed.file_name, soften_image_file_1_managed.file_name) ret_project = self.try_control_points(pair, pair_soften_image_file_names) # Did we win? if ret_project: # Fixup the project to reflect the correct file names text = ret_project.__repr__() print print 'Before sub' print print ret_project.__repr__() print print print print '%s => %s' % (soften_image_file_0_managed.file_name, pair_images[0]) text = text.replace(soften_image_file_0_managed.file_name, pair_images[0]) print '%s => %s' % (soften_image_file_1_managed.file_name, pair_images[1]) text = text.replace(soften_image_file_1_managed.file_name, pair_images[1]) ret_project.set_text(text) print print 'After sub' print print ret_project.__repr__() print print print #sys.exit(1) return ret_project first_run = False print 'WARNING: gave up on generating control points!' return None
def do_generate_control_points_by_pair(self, pair, image_fn_pair): '''high level function uses by sub-stitches. Given a pair of images make a best effort to return a .pto object''' ''' pair: ImageCoordinatePair() object image_fn_pair: tuple of strings Algorithm: First try to stitch normally (either whole image or partial depending on the mode) If that doesn't succeed and softening is enabled try up to three times to soften to produce a match If that still doesn't produce a decent solution return None and let higher levels deal with ''' soften_iterations = 3 print print #print 'Generating project for image pair (%s / %s, %s / %s)' % (image_fn_pair[0], str(pair[0]), image_fn_pair[1], str(pair[1])) print 'Generating project for image pair (%s, %s)' % (image_fn_pair[0], image_fn_pair[1]) if True: # Try raw initially print 'Attempting sharp match...' ret_project = self.try_control_points_with_position(pair, image_fn_pair) if ret_project: return ret_project print 'WARNING: bad project, attempting soften...' soften_image_file_0_managed = ManagedTempFile.from_same_extension(image_fn_pair[0]) soften_image_file_1_managed = ManagedTempFile.from_same_extension(image_fn_pair[1]) print 'Soften fn0: %s' % soften_image_file_0_managed.file_name print 'Soften fn1: %s' % soften_image_file_1_managed.file_name for i in xrange(soften_iterations): self.soften_try[i] += 1 # And then start screwing with it # Wonder if we can combine features from multiple soften passes? # Or at least take the maximum # Do features get much less accurate as the soften gets up there? print 'Attempting soften %d / %d' % (i + 1, soften_iterations) if i == 0: soften_composite(image_fn_pair[0], soften_image_file_0_managed.file_name) soften_composite(image_fn_pair[1], soften_image_file_1_managed.file_name) else: soften_composite(soften_image_file_0_managed.file_name) soften_composite(soften_image_file_1_managed.file_name) pair_soften_image_file_names = (soften_image_file_0_managed.file_name, soften_image_file_1_managed.file_name) ret_project = self.try_control_points_with_position(pair, pair_soften_image_file_names) # Did we win? if ret_project: # Fixup the project to reflect the correct file names text = str(ret_project) if 0: print print 'Before sub' print print str(ret_project) print print print print '%s => %s' % (soften_image_file_0_managed.file_name, image_fn_pair[0]) text = text.replace(soften_image_file_0_managed.file_name, image_fn_pair[0]) print '%s => %s' % (soften_image_file_1_managed.file_name, image_fn_pair[1]) text = text.replace(soften_image_file_1_managed.file_name, image_fn_pair[1]) ret_project.set_text(text) if 0: print print 'After sub' print print str(ret_project) print print print #sys.exit(1) self.soften_ok[i] += 1 print 'Soften try: %s' % (self.soften_try,) print 'Soften ok: %s' % (self.soften_ok,) return ret_project print 'WARNING: gave up on generating control points!' return None
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