def gen_pairwise_surf_control_points(proj_file, img_fns, display=False):
    """ Use OpenCV for pairwaise image matching

    cf. <opencv samples dir>/find_obj.py
    """
    # get the kps of the first frame
    img1, kp1, ds1 = get_surf_kps(img_fns[0])
    # match the frame t with t+1
    cpoints = []
    for i2 in range(1, len(img_fns)):
        # get the kps of frame t+1
        img2, kp2, ds2 = get_surf_kps(img_fns[i2])
        # get the control points
        cp1, cp2 = get_pairwise_matches(kp1, ds1, kp2, ds2)
        # estimate the homography
        H, mask = cv2.findHomography(cp1, cp2, cv2.RANSAC)
        mask = mask.squeeze() > 0
        # display the matches and homography
        if display:
            hom_warp_image(img1, cp1, img2, cp2, H, mask)
        # filter out the outlier matches
        cp1 = cp1[mask]
        cp2 = cp2[mask]
        # add the control points
        cpoints.extend([hsi.ControlPoint(i2 - 1, x1, y1, i2, x2, y2)
                        for (x1, y1), (x2, y2) in zip(cp1, cp2)])
        # next -> cur
        img1, kp1, ds1 = img2, kp2, ds2
    # write to pto
    pano = hsi.Panorama()
    pano.readData(hsi.ifstream(proj_file))
    pano.setCtrlPoints(cpoints)
    pano.writeData(hsi.ofstream(proj_file))
예제 #2
0
def gen_pairwise_surf_control_points(proj_file, img_fns, display=False):
    """ Use OpenCV for pairwise image matching
    """
    # get the kps of the first frame
    img1, kp1, ds1 = get_surf_kps(img_fns[0])
    # match the frame t with t+1
    cpoints = []
    for i2 in range(1, len(img_fns)):
        # get the kps of frame t+1
        img2, kp2, ds2 = get_surf_kps(img_fns[i2])
        # get the control points
        cp1, cp2 = get_pairwise_matches(kp1, ds1, kp2, ds2)
        # estimate the homography
        H, mask = cv2.findHomography(cp1, cp2, cv2.RANSAC)
        mask = mask.squeeze() > 0
        # display the matches and homography
        if display:
            homo_warp_image(img1, cp1, img2, cp2, H, mask)
        # filter out the outlier matches
        cp1 = cp1[mask]
        cp2 = cp2[mask]
        # add the control points
        cpoints.extend([
            hsi.ControlPoint(i2 - 1, x1, y1, i2, x2, y2)
            for (x1, y1), (x2, y2) in zip(cp1, cp2)
        ])
        # next -> cur
        img1, kp1, ds1 = img2, kp2, ds2
    # write to pto
    pano = hsi.Panorama()
    pano.readData(hsi.ifstream(proj_file))
    pano.setCtrlPoints(cpoints)
    pano.writeData(hsi.ofstream(proj_file))
예제 #3
0
    def writePTO(self, fajlnev=""):
        #print inspect.stack()[0][3]
        if ("" == fajlnev):
            fajlnev = self.pto

        ofs = hsi.ofstream(fajlnev)
        self.p.writeData(ofs)
        del ofs
예제 #4
0
    def writePTO(self, fajlnev=""):
        #print inspect.stack()[0][3]
        if ("" == fajlnev):
            fajlnev = self.pto

        ofs=hsi.ofstream(fajlnev)
        self.p.writeData(ofs)
        del ofs
예제 #5
0
def main():

    # when called from the command line, we import the argparse module.
    # This may not be part of the standard library on your system.

    import argparse

    # and create an argument parser.

    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=gpl + '''
    crop_cp will remove all CPs which are either outside the panorama's ROI
    or inside it's ROI if the inside flag is set
    ''')

    parser.add_argument('-o',
                        '--output',
                        metavar='<output file>',
                        default=None,
                        type=str,
                        help='write output to a different file')

    parser.add_argument('-i',
                        '--inside',
                        action='store_true',
                        default=False,
                        help='remove CPs inside ROI')

    parser.add_argument('input',
                        metavar='<pto file>',
                        type=str,
                        help='pto file to be processed')

    if len(sys.argv) < 2:
        parser.print_help()
        return

    # we parse the arguments into a global variable so we can access
    # them from everywhere without having to pass them around

    global args

    args = parser.parse_args()

    if args.output:
        print('output: ', args.output)
    print('ptofile:', args.input)

    # first we see if we can open the input file

    ifs = hsi.ifstream(args.input)
    if not ifs.good():
        raise CropCpError('cannot open input file %s' % args.input)

    pano = hsi.Panorama()
    success = pano.readData(ifs)
    del ifs
    if success != hsi.DocumentData.SUCCESSFUL:
        raise CropCpError('input file %s contains invalid data' % args.input)

    # if a separate output file was chosen, we open it now to avoid
    # later disappointments

    if args.output:
        ofs = hsi.ofstream(args.output)
        if not ofs.good():
            raise CropCpError('cannot open output file %s' % args.output)

    # we've checked the args, now we call crop_cps()

    crop_cps(pano, args.inside)

    # if no different output file was specified, overwrite the input

    if not args.output:
        ofs = hsi.ofstream(args.input)
        if not ofs.good():
            raise CropCpError('cannot open file %s for output' % args.input)

    success = pano.writeData(ofs)
    del ofs
    if success != hsi.DocumentData.SUCCESSFUL:
        raise CropCpError('error writing pano to %s' % args.input)

    # done.

    return 0
def pto_gen(img_fns, hfov=50, out_pto="project.pto"):
    """ Generate a Hugin .pto project file

    Parameters
    ----------
    img_fns: list,
             the (ordered) full paths to the video frames

    hfov: int, optional, default: 50,
          horizontal field of view in degrees
          (around 50 is ok for most non-fish-eye cameras)

    out_pto: string, optional, default: 'project.pto',
             output path to the generated panotools .pto file

    Notes
    -----
    Suitable as input for further tools such as the cpfind control-point generator.

    Inspired from pto_gen
    (http://hugin.sourceforge.net/docs/html/pto__gen_8cpp-source.html)
    but with some hacks to correct the generated m-line in the header.

    Uses the Hugin python scripting interface (http://wiki.panotools.org/Hugin_Scripting_Interface)
    """
    # projection type: 0 == rectilinear (2 == equirectangular)
    projection = 0
    assert projection >= 0, "Invalid projection number (%d)" % projection
    assert 1 <= hfov <= 360, "Invalid horizontal field of view (%d)" % hfov
    # hugin Panorama object
    pano = hsi.Panorama()
    # add the images in order
    for img_fn in img_fns:
        src_img = hsi.SrcPanoImage(img_fn)
        src_img.setProjection(projection)
        src_img.setHFOV(hfov)
        src_img.setExifCropFactor(1.0)
        pano.addImage(src_img)
    # check we added all of them
    n_inserted = pano.getNrOfImages()
    assert n_inserted == len(img_fns), "Didn't insert all images (%d < %d)" % \
            (n_inserted, len(img_fns))
    # output the .pto file
    pano.writeData(hsi.ofstream(out_pto + '.tmp'))  # same as pano.printPanoramaScript(...)
    # some bug in header: rewrite it manually (TODO through hsi?)
    with open(out_pto + '.tmp', 'r') as tmp_ff:
        with open(out_pto, 'w' ) as ff:
            # re-write the header
            ff.write(tmp_ff.readline())
            ff.write(tmp_ff.readline())
            # force jpeg for the p-line
            p_line = tmp_ff.readline().strip().split()
            assert p_line[0] == 'p', "BUG: should be a p-line"
            ff.write(' '.join(p_line[:7]) + ' n"JPEG q100"\n')
            # remove extra 'f' param in the m-line
            # (screws everything up if left here...)
            m_line = tmp_ff.readline().strip().split()
            assert m_line[0] == 'm', "BUG: should be a m-line"
            ff.write(' '.join(m_line[:3]) + ' ' + ' '.join(m_line[4:]) + '\n')
            # write all other lines
            for l in tmp_ff.readlines():
                ff.write(l)
    os.remove(out_pto + '.tmp')
    print "saved {0}".format(out_pto)
예제 #7
0
        sys.exit ( -14 )

    del ifs

    # if we're here, the load succeeded and we can finally call
    # the plugin
    
    success = hpi_dispatch ( sys.argv[2] , p , *(sys.argv[3:]) )

    # KFJ 2011-06-19 changed writeback to True, so that hpi.py
    # can be used to execute hugin plugins on the command line
    # and the result is written back to the pto file.

    writeback = True

    if writeback :

        ofs = hsi.ofstream ( sys.argv[1] )

        if not ofs.good() :
            print("failed to open %s" % sys.argv[1])
            sys.exit ( -15 )
    
        if p.writeData ( ofs ) != hsi.DocumentData.SUCCESSFUL :
            print("failed to write panorama data to %s" % sys.argv[1])
            sys.exit ( -16 )

        del ofs
    
    sys.exit ( success )
예제 #8
0
파일: hpi.py 프로젝트: marco-m/hugin
        sys.exit(-14)

    del ifs

    # if we're here, the load succeeded and we can finally call
    # the plugin

    success = hpi_dispatch(sys.argv[2], p, *(sys.argv[3:]))

    # KFJ 2011-06-19 changed writeback to True, so that hpi.py
    # can be used to execute hugin plugins on the command line
    # and the result is written back to the pto file.

    writeback = True

    if writeback:

        ofs = hsi.ofstream(sys.argv[1])

        if not ofs.good():
            print("failed to open %s" % sys.argv[1])
            sys.exit(-15)

        if p.writeData(ofs) != hsi.DocumentData.SUCCESSFUL:
            print("failed to write panorama data to %s" % sys.argv[1])
            sys.exit(-16)

        del ofs

    sys.exit(success)
def main() :

    # when called from the command line, we import the argparse module.
    # This may not be part of the standard library on your system.
    
    import argparse

    # and create an argument parser.
    
    parser = argparse.ArgumentParser (
        formatter_class=argparse.RawDescriptionHelpFormatter ,
        description = gpl + '''
    crop_cp will remove all CPs which are either outside the panorama's ROI
    or inside it's ROI if the inside flag is set
    ''' )

    parser.add_argument('-o', '--output',
                        metavar='<output file>',
                        default = None,
                        type=str,
                        help='write output to a different file')

    parser.add_argument('-i', '--inside',
                        action='store_true',
                        default = False,
                        help='remove CPs inside ROI')

    parser.add_argument('input' ,
                        metavar = '<pto file>' ,
                        type = str ,
                        help = 'pto file to be processed' )

    if len ( sys.argv ) < 2 :
        parser.print_help()
        return

    # we parse the arguments into a global variable so we can access
    # them from everywhere without having to pass them around
    
    global args
    
    args = parser.parse_args()

    if args.output :
        print ( 'output: ' , args.output )
    print ( 'ptofile:' , args.input )

    # first we see if we can open the input file

    ifs = hsi.ifstream ( args.input )
    if not ifs.good() :
        raise CropCpError ( 'cannot open input file %s' % args.input )

    pano = hsi.Panorama()
    success = pano.readData ( ifs )
    del ifs
    if success != hsi.DocumentData.SUCCESSFUL :
        raise CropCpError ( 'input file %s contains invalid data' % args.input )

    # if a separate output file was chosen, we open it now to avoid
    # later disappointments
    
    if args.output:
        ofs = hsi.ofstream ( args.output )
        if not ofs.good() :
            raise CropCpError ( 'cannot open output file %s' % args.output )

    # we've checked the args, now we call crop_cps()
    
    crop_cps ( pano , args.inside )

    # if no different output file was specified, overwrite the input
    
    if not args.output :
        ofs = hsi.ofstream ( args.input )
        if not ofs.good() :
            raise CropCpError ( 'cannot open file %s for output' % args.input )

    success = pano.writeData ( ofs )
    del ofs
    if success != hsi.DocumentData.SUCCESSFUL :
        raise CropCpError ( 'error writing pano to %s' % args.input )
    
    # done.
    
    return 0
예제 #10
0
def pto_gen(img_fns, hfov, out_pto="project.pto"):
    """ Generate a Hugin .pto project file

    Parameters
    ----------
    img_fns: list,
             the (ordered) full paths to the video frames

    hfov: int,
          horizontal field of view in degrees
          (around 50 is ok for most non-fish-eye cameras)

    out_pto: string, optional, default: 'project.pto',
             output path to the generated panotools .pto file

    Notes
    -----
    Suitable as input for further tools such as the cpfind control-point
    generator.

    Inspired from pto_gen
    (http://hugin.sourceforge.net/docs/html/pto__gen_8cpp-source.html)
    but with some hacks to correct the generated m-line in the header.

    Uses the Hugin python scripting interface
    (http://wiki.panotools.org/Hugin_Scripting_Interface).
    """
    # projection type: 0 == rectilinear (2 == equirectangular)
    projection = 0
    assert projection >= 0, "Invalid projection number (%d)" % projection
    assert 1 <= hfov <= 360, "Invalid horizontal field of view (%d)" % hfov
    # hugin Panorama object
    pano = hsi.Panorama()
    # add the images in order
    for img_fn in img_fns:
        src_img = hsi.SrcPanoImage(img_fn)
        src_img.setProjection(projection)
        src_img.setHFOV(hfov)
        src_img.setExifCropFactor(1.0)
        pano.addImage(src_img)
    # check we added all of them
    n_inserted = pano.getNrOfImages()
    assert n_inserted == len(img_fns), "Didn't insert all images (%d < %d)" % \
            (n_inserted, len(img_fns))
    # output the .pto file
    pano.writeData(
        hsi.ofstream(out_pto +
                     '.tmp'))  # same as pano.printPanoramaScript(...)
    # some bug in header: rewrite it manually (TODO through hsi?)
    with open(out_pto + '.tmp', 'r') as tmp_ff:
        with open(out_pto, 'w') as ff:
            # re-write the header
            ff.write(tmp_ff.readline())
            ff.write(tmp_ff.readline())
            # force jpeg for the p-line
            p_line = tmp_ff.readline().strip().split()
            assert p_line[0] == 'p', "BUG: should be a p-line"
            ff.write(' '.join(p_line[:7]) + ' n"JPEG q100"\n')
            # remove extra 'f' param in the m-line (screws everything up if left here...)
            m_line = tmp_ff.readline().strip().split()
            assert m_line[0] == 'm', "BUG: should be a m-line"
            ff.write(' '.join(m_line[:3]) + ' ' + ' '.join(m_line[4:]) + '\n')
            # write all other lines
            for l in tmp_ff.readlines():
                ff.write(l)
    os.remove(out_pto + '.tmp')
예제 #11
0
def optimize_geometry(proj_file, optim_vars, optim_ref_fov=False):
    """ Optimise the geometric parameters

    Parameters
    ----------
    proj_file: string,
               the path to the Hugin project file (.pto)

    optim_vars: string,
                the set of variables to optimize for (separated by '_')
                - v: view point
                - p: pitch
                - y: yaw
                - r: roll
                - Tr{X,Y,Z}: translation

    optim_ref_fov: boolean, optional, default: False,
                   whether to optimize the input's reference horizontal field
                   of view (risky)

    Returns
    -------
    optim_proj_file: string,
                     path of the Hugin project file containing the optimized
                     values for the desired variables.

    Notes
    -----
    This is (by far) the most time consuming operation
    (because of hugin's autooptimiser).

    This is also the most likely function where the compensation process tends
    to fail.
    """
    optim_proj_file = proj_file + '.optim.pto'
    # modify the input pto to specify the optimization variables
    pano = hsi.Panorama()
    pano.readData(hsi.ifstream(proj_file))
    n_imgs = pano.getNrOfImages()
    var_tup = tuple(optim_vars.split('_'))
    for v in var_tup:
        assert v in ('v', 'p', 'y', 'r', 'TrX', 'TrY', 'TrZ'), \
                "Unknown var {0} in {1}".format(v, optim_vars)
    optim_opts = [var_tup] * n_imgs  # fov, pitch, roll, yaw
    if optim_ref_fov:
        # optim only field of view for 1st (reference) frame
        optim_opts[0] = ('v')
        # Note: do not optim. pitch, roll and yaw for this one, weird otherwise
    else:
        # 1st reference frame has the same fov as those of the input images
        optim_opts[0] = ()
    pano.setOptimizeVector(optim_opts)
    pano.writeData(hsi.ofstream(proj_file))
    # perform the optimization (TODO through hsi?)
    cmd = "autooptimiser -n -s -o {opto} {pto}"  # leveling can screw things up
    exec_shell(cmd.format(pto=proj_file, opto=optim_proj_file))
    # check for too large output (e.g. too wide panning or traveling)
    pano = hsi.Panorama()
    pano.readData(hsi.ifstream(optim_proj_file))
    opts = pano.getOptions()
    oh = opts.getHeight()
    ow = opts.getWidth()
    if oh * ow > 1e3 * 5e3:
        raise ValueError(
            "Degenerate case: too big output size ({0}, {1})\n".format(ow, oh) + \
            "May be caused by too large panning or translations\n" + \
            "=> Possible fixes: use a different field of view parameter or " + \
            "optimize only for different variables than {0}\n".format(optim_vars))
    return optim_proj_file
예제 #12
0
def optimize_geometry(proj_file, optim_vars, optim_ref_fov=False):
    """ Optimise the geometric parameters

    Parameters
    ----------
    proj_file: string,
               the path to the Hugin project file (.pto)

    optim_vars: string,
                the set of variables to optimize for (separated by '_')
                - v: view point
                - p: pitch
                - y: yaw
                - r: roll
                - Tr{X,Y,Z}: translation

    optim_ref_fov: boolean, optional, default: False,
                   whether to optimize the input's reference horizontal field
                   of view (risky)

    Returns
    -------
    optim_proj_file: string,
                     path of the Hugin project file containing the optimized
                     values for the desired variables.

    Notes
    -----
    This is (by far) the most time consuming operation
    (because of hugin's autooptimiser).

    This is also the most likely function where the compensation process tends
    to fail.
    """
    optim_proj_file = proj_file + '.optim.pto'
    # modify the input pto to specify the optimization variables
    pano = hsi.Panorama()
    pano.readData(hsi.ifstream(proj_file))
    n_imgs = pano.getNrOfImages()
    var_tup = tuple(optim_vars.split('_'))
    for v in var_tup:
        assert v in ('v', 'p', 'y', 'r', 'TrX', 'TrY', 'TrZ'), \
                "Unknown var {0} in {1}".format(v, optim_vars)
    optim_opts = [var_tup] * n_imgs  # fov, pitch, roll, yaw
    if optim_ref_fov:
        # optim only field of view for 1st (reference) frame
        optim_opts[0] = ('v')
        # Note: do not optim. pitch, roll and yaw for this one, weird otherwise
    else:
        # 1st reference frame has the same fov as those of the input images
        optim_opts[0] = ()
    pano.setOptimizeVector(optim_opts)
    pano.writeData(hsi.ofstream(proj_file))
    # perform the optimization (TODO through hsi?)
    cmd = "autooptimiser -n -s -o {opto} {pto}"  # leveling can screw things up
    exec_shell(cmd.format(pto=proj_file, opto=optim_proj_file))
    # check for too large output (e.g. too wide panning or traveling)
    pano = hsi.Panorama()
    pano.readData(hsi.ifstream(optim_proj_file))
    opts = pano.getOptions()
    oh = opts.getHeight()
    ow = opts.getWidth()
    if oh * ow > 1e3 * 5e3:
        raise ValueError(
            "Degenerate case: too big output size ({0}, {1})\n".format(ow, oh) + \
            "May be caused by too large panning or translations\n" + \
            "=> Possible fixes: use a different field of view parameter or " + \
            "optimize only for different variables than {0}\n".format(optim_vars))
    return optim_proj_file