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 standalone(): import sys # to look at the argument vector import hsi # to use hugin's scripting interface if len(sys.argv) < 2: print('usage: %s <pto file>' % sys.argv[0]) sys.exit(-1) panofile = sys.argv[1] # the only parameter: a pto file ifs = hsi.ifstream(panofile) # create a C++ ifstream from it pano = hsi.Panorama() # and a Panorama object success = pano.readData(ifs) # feed the ifstream to the pano object # check if all went well if success != hsi.DocumentData.SUCCESSFUL: # if it failed, complain print('input file %s contains invalid data' % panofile) success = -1 else: # if it succeeded, call the workhorse entry(pano) success = 0 # and that's it return success
def __init__(self): self.pto_nev = "" self.fajl_path = "" self.fajl_l = [] self.sorok = 0 self.oszlopok = 0 self.epsilon = 1.5 # Erre az értékre érzékeny az eredmény. A teljes panorama automatikus forgatás segíthet talán self.yawBucket = {} self.pitchBucket = {} self.yawValues = [] self.pitchValues = [] self.x_coord = [] self.y_coord = [] self.roll = [] self.yaw = [] self.pitch = [] self.p = hsi.Panorama() self.roll_eh = robjects.vectors.FloatVector self.yaw_eh = robjects.vectors.FloatVector self.pitch_eh = robjects.vectors.FloatVector
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
import sys import hsi # hpi.py has been called standalone rather than having been # mported as a module. In this case we want to look at the # argument vector: if len(sys.argv) < 3: print("use: %s panorama.pto plugin.py [plugin args]" % sys.argv[0]) sys.exit(-12) # okay, there are some arguments, let's go ahead and try # opening the first one as a panorama. p = hsi.Panorama() ifs = hsi.ifstream(sys.argv[1]) if not ifs.good(): print("failed to open %s" % sys.argv[1]) sys.exit(-13) # next, make the panorama object read the file if p.readData(ifs) != hsi.DocumentData.SUCCESSFUL: print("failed to read panorama data from %s" % sys.argv[1]) sys.exit(-14) del ifs # if we're here, the load succeeded and we can finally call # the plugin
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