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))
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))
def writePTO(self, fajlnev=""): #print inspect.stack()[0][3] if ("" == fajlnev): fajlnev = self.pto ofs = hsi.ofstream(fajlnev) self.p.writeData(ofs) del ofs
def writePTO(self, fajlnev=""): #print inspect.stack()[0][3] if ("" == fajlnev): fajlnev = self.pto ofs=hsi.ofstream(fajlnev) self.p.writeData(ofs) del ofs
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)
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 )
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
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')
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