Exemple #1
0
    def run(self):
        from xystitch.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)
Exemple #2
0
def run_print(pto_fn, stdev=3):
    print('In: %s' % pto_fn)

    pto = PTOProject.from_file_name(pto_fn)
    icm = pto2icm(pto)
    for ((n_fn, N_fn), (nx, ny), (Nx, Ny)) in gen_cps(pto, icm=icm):
        print("%s:(%s, %s) %s:(%s, %s)" % (n_fn, nx, ny, N_fn, Nx, Ny))
        print("  %s, %s" % (nx - Nx, ny - Ny))
Exemple #3
0
def run(pto_fn, pto_fn_out=None, stdev=3.0):
    print('In: %s' % pto_fn)
    bench = Benchmark()

    # TODO: l/r compensation

    pto = PTOProject.from_file_name(pto_fn)
    icm = pto2icm(pto)
    deltas = []
    pairs = []
    cpls = []
    for cpl, ((n_fn, N_fn), (nx, ny), (Nx, Ny)) in gen_cps(pto, icm=icm):
        delta = ((nx - Nx)**2 + (ny - Ny)**2)**0.5
        deltas.append(delta)
        pairs.append((n_fn, N_fn))
        cpls.append(cpl)
        if tmpdbg and (n_fn == 'c005_r003.jpg' and N_fn == 'c005_r004.jpg'):
            print('debug', (n_fn, N_fn), (nx, ny), (Nx, Ny))
            print('debug', delta)

    deltas_u = statistics.mean(deltas)
    deltas_sd = statistics.stdev(deltas)
    print("Delta mean: %0.1f" % deltas_u)
    print("Delta stdev: %0.1f" % deltas_sd)
    _deltas_min = deltas_u - deltas_sd * stdev
    deltas_max = deltas_u + deltas_sd * stdev

    outlier_cps = 0
    outlier_pairs = set()
    pair_cur = None
    pairi = 0
    for cpl, (n_fn, N_fn), delta in zip(cpls, pairs, deltas):
        if pair_cur != (n_fn, N_fn):
            pairi = 0
            pair_cur = (n_fn, N_fn)
        else:
            pairi += 1

        # really only care about max
        if delta > deltas_max:
            # canonical file names
            fna, fnb = sorted((n_fn, N_fn))
            print("%s %s %u: outlier delta %0.1f" % (fna, fnb, pairi, delta))
            outlier_pairs.add((fna, fnb))
            outlier_cps += 1
            pto.remove_control_point_line(cpl)
    print("")
    print("Flagged cps: %u" % outlier_cps)
    print("Flagged pairs: %u" % len(outlier_pairs))
    for fna, fnb in sorted(list(outlier_pairs)):
        print("  %s %s" % (fna, fnb))

    if pto_fn_out:
        pto.save_as(pto_fn_out)

    bench.stop()
    print('Completed in %s' % bench)
Exemple #4
0
def resave_hugin(pto):
    from xystitch.merger import Merger
    from xystitch.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')
Exemple #5
0
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
Exemple #6
0
    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)
Exemple #7
0
    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)
Exemple #8
0
def run(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'
                stp = 2**32 / 4

    t = Tiler(project,
              out_dir,
              stw=mksize(args.stw),
              sth=mksize(args.sth),
              stp=stp,
              clip_width=args.clip_width,
              clip_height=args.clip_height,
              log_dir=log_dir,
              is_full=args.full)
    t.threads = args.threads
    t.verbose = args.verbose
    t.st_dir = args.st_dir
    t.out_extension = args.out_ext
    t.ignore_errors = args.ignore_errors
    t.ignore_crop = args.ignore_crop
    t.st_limit = float(args.st_limit)

    # TODO: make this more proper?
    if args.nona_args:
        t.nona_args = args.nona_args.replace('"', '').split(' ')
    if args.enblend_args:
        t.enblend_args = args.enblend_args.replace('"', '').split(' ')

    if args.super_t_xstep:
        t.super_t_xstep = args.super_t_xstep
    if args.super_t_ystep:
        t.super_t_ystep = args.super_t_ystep
    if args.clip_width:
        t.clip_width = args.clip_width
    if args.clip_height:
        t.clip_height = args.clip_height
    # if they specified clip but not supertile step recalculate the step so they don't have to do it
    if args.clip_width or args.clip_height and not (args.super_t_xstep
                                                    or args.super_t_ystep):
        t.recalc_step()

    t.enblend_lock = args.enblend_lock

    if args.single_dir and not os.path.exists(args.single_dir):
        os.mkdir(args.single_dir)

    print('Running tiler')
    try:
        t.run()
    except KeyboardInterrupt:
        if t.stale_worker:
            print 'WARNING: forcing exit on stuck worker'
            time.sleep(0.5)
            os._exit(1)
        raise
    print('Tiler done!')

    print('Creating single image')
    single_fn = args.single_fn
    if single_fn is None:
        single_fn = 'out.jpg'
    if args.single_dir:
        single_fn = os.path.join(args.single_dir, single_fn)
    # sometimes I restitch with different supertile size
    # this results in excessive merge, although really I should just delete the old files
    if 1:
        print 'Single: using glob strategy on merge'
        s_fns = glob.glob(os.path.join(args.st_dir, 'st_*x_*y.jpg'))
    else:
        print 'Single: using output strategy'
        s_fns = t.st_fns

    single_fn_alt = None
    if args.single_fn is None:
        single_fn_alt = single_fn.replace('.jpg', '.tif')

    try:
        singlify(s_fns, single_fn, single_fn_alt)
    except HugeImage:
        print 'WARNING: single: exceeds max image size, skipped'
Exemple #9
0
        _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()

    config_pto_defaults(pto)

    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)
Exemple #10
0
def main():
    parser = argparse.ArgumentParser(
        description='create tiles from unstitched images')
    # +/- 2 => 5 x 5 => 25 images
    # +/- 3 => 7 x 7 => 49 images
    parser.add_argument('--xydelta', default=3, type=int, help='border size')
    parser.add_argument('pto',
                        default='out.pto',
                        nargs='?',
                        help='pto project')
    args = parser.parse_args()

    pto_orig = PTOProject.from_file_name(args.pto)

    print("Finding worst image optimization")
    n, rms = worst_image(pto_orig)
    print(("got", n, rms))
    il = pto_orig.image_lines[n]
    fn = il.get_name()
    refrow, refcol = get_row_col(fn)
    print((fn, refcol, refrow))

    img_fns = []
    for il in pto_orig.get_image_lines():
        img_fns.append(il.get_name())
    icm = ImageCoordinateMap.from_tagged_file_names(img_fns)

    # Delete all ils not in our ROI
    pto_orig.build_image_fn_map()
    ils_keep = set()
    for col, row in iter_center_cr_max(icm, refcol, refrow, args.xydelta):
        im = icm.get_image(col, row)
        if im is None:
            continue
        ils_keep.add(pto_orig.img_fn2il[im])
    ils_del = set(pto_orig.image_lines) - ils_keep
    print(("%s - %s image lines, keeping %s" %
           (len(pto_orig.image_lines), len(ils_del), len(ils_keep))))

    # Reduced .pto
    pto_red = pto_orig.copy()

    print(('Deleting %d / %d images' %
           (len(ils_del), icm.width() * icm.height())))
    pto_red.del_images(ils_del)
    print((len(pto_orig.image_lines), len(pto_red.image_lines)))

    print("Centering...")
    center(pto_red)
    print("Set XY var optimization mode...")
    optimize_xy_only(pto_red)

    # p w25989 h25989 f0 v165 n"TIFF_m c:LZW" E0.0 R0 S"514,25955,8128,32815"
    pto_red.get_panorama_line().uncrop()

    print("Saving preliminary project...")
    pto_red_fn = pto_orig.file_name.replace('.pto', '_sm.pto')
    pto_red.save_as(pto_red_fn, is_new_filename=True)
    print("Fitting FOV")
    subprocess.check_call("pano_modify --fov=AUTO --canvas=AUTO -o %s %s" %
                          (pto_red_fn, pto_red_fn),
                          shell=True)

    print(('Opening temp file %s' % pto_red.file_name))
    subp = subprocess.Popen(['hugin', pto_red.file_name], shell=False)
    subp.communicate()
    print(('Hugin exited with code %d' % subp.returncode))

    red_orig_ncpls = len(pto_red.control_point_lines)
    pto_red.reopen()
    red_new_ncpls = len(pto_red.control_point_lines)

    # Filter control point lines
    # Delete all control points associated with subproject
    # Then import all new control points
    print("Deleting stale control points")

    # Convert image lines to indices
    iln_keep = set()
    orig_ncpls = len(pto_orig.control_point_lines)
    for iln, il in enumerate(pto_orig.image_lines):
        if il in ils_keep:
            iln_keep.add(iln)

    # Filter out any control point lines that were within our ROI
    cpls_new = []
    for cpl in pto_orig.control_point_lines:
        n = cpl.get_variable("n")
        N = cpl.get_variable("N")
        if not (n in iln_keep and N in iln_keep):
            cpls_new.append(cpl)
    # Shift into main object, discarding munged cpls
    print(("cpl filtering %u => %u" %
           (len(pto_orig.control_point_lines), len(cpls_new))))
    pto_orig.control_point_lines = cpls_new

    red_fn2il = pto_red.build_image_fn_map()
    red_il2fn = dict([(v, k) for k, v in list(red_fn2il.items())])
    red_il2i = pto_red.build_il2i()
    red_i2il = dict([(v, k) for k, v in list(red_il2i.items())])

    full_fn2il = pto_orig.build_image_fn_map()
    full_il2i = pto_orig.build_il2i()

    def iln_red2orig(nred):
        fn = red_il2fn[red_i2il[nred]]
        return full_il2i[full_fn2il[fn]]

    # Now add new cpls in
    # Be very careful translating image indices
    print("Adding new control points")
    for cpl in pto_red.control_point_lines:
        n = cpl.get_variable("n")
        n2 = iln_red2orig(n)
        cpl.set_variable('n', n2)
        N = cpl.get_variable("N")
        N2 = iln_red2orig(N)
        cpl.set_variable('N', N2)
        # print("cpl n=%u N=%u => n=%u N=%u" % (n, N, n2, N2))
        cpl.project = pto_orig
        pto_orig.control_point_lines.append(cpl)

    print(("image lines", len(pto_orig.image_lines), len(pto_red.image_lines)))

    print('Saving final project')
    # small backup in case something went wrong
    shutil.copy(pto_orig.file_name, 'cphugin_old.pto')
    pto_orig.save_as(pto_orig.file_name)

    new_ncpls = len(pto_orig.control_point_lines)
    print(("roi %u => %u cpls" % (red_orig_ncpls, red_new_ncpls)))
    print(("pto %u => %u cpls" % (orig_ncpls, new_ncpls)))

    print('Done!')
Exemple #11
0
from xystitch.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
Exemple #12
0
                        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)
Exemple #13
0
    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
Exemple #14
0
def run(args):
    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)

    if args.threads < 1:
        raise Exception('Bad threads')
    print(('Using %d threads' % args.threads))

    print(('Loading %s' % args.pto))
    project = PTOProject.from_file_name(args.pto)
    print('Creating tiler')

    t = Tiler(project,
              out_dir,
              stw=mksize(args.stw),
              sth=mksize(args.sth),
              stp=None,
              clip_width=args.clip_width,
              clip_height=args.clip_height,
              log_dir=log_dir,
              is_full=args.full)
    t.threads = args.threads
    t.verbose = args.verbose
    t.st_dir = args.st_dir
    t.force = args.force
    t.merge = args.merge
    t.out_extension = args.out_ext
    t.ignore_errors = args.ignore_errors
    t.ignore_crop = args.ignore_crop
    t.st_limit = float(args.st_limit)

    # TODO: make this more proper?
    if args.nona_args:
        t.nona_args = args.nona_args.replace('"', '').split(' ')
    if args.enblend_args:
        t.enblend_args = args.enblend_args.replace('"', '').split(' ')

    if args.super_t_xstep:
        t.super_t_xstep = args.super_t_xstep
    if args.super_t_ystep:
        t.super_t_ystep = args.super_t_ystep

    t.enblend_lock = args.enblend_lock

    if args.single_dir and not os.path.exists(args.single_dir):
        os.mkdir(args.single_dir)

    t.calc_expected_tiles()
    t.calc_vars()

    print('Forcing tiler on all images')
    for fn in glob.glob(args.st_dir + "/*.jpg"):
        print("")
        print(("%s" % fn))
        im = Image.open(fn)
        width, height = im.size
        x0, y0 = coord(fn)
        #t.make_tile(im, x, y, row, col)
        st_bounds = [x0, x0 + width, y0, y0 + height]
        t.process_image(fn, im, st_bounds)
Exemple #15
0
def run(args):
    log_dir = args.log
    out_dir = 'out'
    _outlog, _errlog, outdate, _errdate = logwt(log_dir,
                                                'main.log',
                                                shift_d=True)
    worker_stdout = outdate.fd
    bench = Benchmark()

    try:
        print('Assuming input %s is pto project to be stitched' % args.pto)
        project = PTOProject.from_file_name(args.pto)
        print('Creating tiler')
        threads, stp = make_threads_stp(args)

        t = Tiler(pto=project,
                  out_dir=out_dir,
                  stw=mksize(args.stw),
                  sth=mksize(args.sth),
                  stp=stp,
                  clip_width=args.clip_width,
                  clip_height=args.clip_height,
                  log_dir=log_dir,
                  is_full=args.full,
                  dry=args.dry,
                  worker_stdout=worker_stdout)
        t.set_threads(threads)
        t.set_verbose(args.verbose)
        t.set_st_dir(args.st_dir)
        t.set_out_extension(args.out_ext)
        t.set_ignore_errors(args.ignore_errors)
        t.set_ignore_crop(args.ignore_crop)
        t.set_st_limit(float(args.st_limit))

        # TODO: make this more proper?
        if args.nona_args:
            t.nona_args = args.nona_args.replace('"', '').split(' ')
        if args.enblend_args:
            t.enblend_args = args.enblend_args.replace('"', '').split(' ')

        if args.super_t_xstep:
            t.set_super_t_xstep(args.super_t_xstep)
        if args.super_t_ystep:
            t.set_super_t_ystep(args.super_t_ystep)
        if args.clip_width:
            t.set_clip_width(args.clip_width)
        if args.clip_height:
            t.set_clip_height(args.clip_height)
        # if they specified clip but not supertile step recalculate the step so they don't have to do it
        if args.clip_width or args.clip_height and not (args.super_t_xstep
                                                        or args.super_t_ystep):
            t.recalc_step()

        t.set_enblend_lock(args.enblend_lock)

        if args.single_dir and not os.path.exists(args.single_dir):
            os.mkdir(args.single_dir)

        config.set_enblend_safer_mode(args.safer_mode)
        config.set_enblend_safest_mode(args.safest_mode)

        print('Running tiler')
        try:
            t.run()
        except KeyboardInterrupt:
            if t.stale_worker:
                print('WARNING: forcing exit on stuck worker')
                time.sleep(0.5)
                os._exit(1)
            raise
        print('Tiler done!')

        print('Creating single image')
        single_fn = args.single_fn
        if single_fn is None:
            single_fn = 'out.jpg'
        if args.single_dir:
            single_fn = os.path.join(args.single_dir, single_fn)
        # sometimes I restitch with different supertile size
        # this results in excessive merge, although really I should just delete the old files
        if 1:
            print('Single: using glob strategy on merge')
            s_fns = glob.glob(os.path.join(args.st_dir, 'st_*x_*y.jpg'))
        else:
            print('Single: using output strategy')
            s_fns = t.st_fns

        single_fn_alt = None
        if args.single_fn is None:
            single_fn_alt = single_fn.replace('.jpg', '.tif')

        try:
            singlify(s_fns, single_fn, single_fn_alt)
        except HugeImage:
            print('WARNING: single: exceeds max image size, skipped')
    finally:
        bench.stop()
        print('Completed in %s' % bench)
Exemple #16
0
    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
Exemple #17
0
    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'