def main(sysargs): args = EasyArgs(sysargs) cfg = EasyConfig(args.config, group="chessboard_extract") if "help" in args: usage() return 0 # test args if len(args) <= 2: usage() return 1 # video settings, etc window_name = "Chessboard Extractor" side = Theta.resolve(args.split) rotate = BuffSplitCap.r0 crop = (0, 0, 0, 0) font = cv2.FONT_HERSHEY_SIMPLEX # image stuff image_path = os.path.join(args[2], args.prefix or 'frame_') if not os.path.exists(args[2]): os.makedirs(args[2]) cv2.namedWindow(window_name) cap = BuffSplitCap(args[1], side=side, rotate=rotate, crop=crop, buff_max=cfg.buffer_size) # loop video file while cap.isOpened(): frame = cap.frame() # display status textframe = frame.copy() displayText(textframe, cap.status(), top=True) cv2.imshow(window_name, textframe) # controls key = cv2.waitKey(0) if key == Key.right: cap.next() elif key == Key.left: cap.back() elif key == Key.enter: print "Snapped at: ", cap.at() cv2.imwrite("{}{:02d}.jpg".format(image_path, cap.at()), frame) elif key == Key.esc: print "Quitting." break # clean up cap.release() cv2.destroyAllWindows() print "\nDone." return 0
def main(sysargs): args = EasyArgs(sysargs) cfg = EasyConfig(args.config, group="calib") # argument sanity checks if 'help' in args: usage() return 0 elif 'version' in args: version() return 0 elif len(args) < 10: print "Requires a minimum 10 chessboard images." usage() return 0 elif 'output' not in args: print "Requires an output path." usage() return 0 # default args s_size = args.square_size or cfg.default_squares if args.chess_size: p_size = ast.literal_eval("({})".format(args.chess_size)) else: p_size = cfg.default_chess # create preview folder if specified if args.preview and not os.path.exists(args.preview): os.makedirs(args.preview) try: # calibration cam_mat, dist, err = stdCalib(args[1:], p_size, s_size, args.preview) # XML Output intWriter(args.output, cam_mat, dist, err) except: print "Aborting." return 1 # Rectify if args.preview: undistort(args.preview, args[1:], cam_mat, dist) print '--------------------------------------' print 'Intrinsic Calibration has completed successfully!' return 0
def main(sysargs): args = EasyArgs(sysargs) cfg = EasyConfig(args.config, group="mapper") if "help" in args: usage() return 0 if ["calib", "trainer", "output"] not in args: print "Must specify: -calib, -trainer, -output files" usage() return 1 if len(args) == 1: print "Not enough input CSV files" usage() return 1 if len(args) > 2 and args.map_trainer_mode: print "Too many CSV for trainer-mapping mode" usage() return 1 if "force_side" in args: side = Theta.resolve(args.force_side) if side == Theta.NonDual: print "Invalid force_side argument:", args.force_side usage() return 1 # set side overrides force_button = (side == Theta.Buttonside) force_back = not force_button else: force_button = force_back = False # working vars csvs = {} frame_num = 0 # open source CSV datasets for i in range(1, len(args)): print args[i] csvs[i] = Memset(args[i]) # reel all the files up to their first flash for i in csvs: csvs[i].restrict() if len(csvs[i].row()) < 10: print "CSV file:", args[i], "contains no marker data!\nAborting." return 1 # override csv name if args.map_trainer_mode: csvs[1]._name = cfg.trainer_target # open calib files try: buttonside = Mapper(args.calib, args.trainer, cfg, Theta.Buttonside) backside = Mapper(args.calib, args.trainer, cfg, Theta.Backside) except Exception as e: print e.message return 1 count = {'bts': 0, 'bks': 0, 'rej': 0} # open destination XML with open(args.output, "w") as xmlfile: w = XMLWriter(xmlfile) w.declaration() xmlfile.write( "<!DOCTYPE dataset SYSTEM \"http://storage.gwillz.com.au/eagleeye_v2.dtd\">" ) doc = w.start("dataset") # iterates until all vicon csvs reach eof while True: w.start("frameInformation") w.element("frame", number=str(frame_num)) #iterates through each vicon csv at the current row for i in csvs: c = csvs[i] # determine marker quality try: max_reflectors = int(c.row()[8]) visible_reflectors = int(c.row()[9]) except: print "Error in reading quality at row {}".format(i) return 1 try: # read VICON data x = float(c.row()[2]) y = float(c.row()[3]) z = float(c.row()[4]) # TODO: is this necessary? We never use the object's rotation rx = float(c.row()[5]) ry = float(c.row()[6]) rz = float(c.row()[7]) except: print "Error occurred when converting VICON data at row {}".format( i) return 1 # run projection/mapping on VICON data if backside.isVisible((x, y, z)): points = backside.reprojpts((x, y, z)) side = 'backside' count['bks'] += 1 elif buttonside.isVisible((x, y, z)): points = buttonside.reprojpts((x, y, z)) points[ 0] += 960 # add 960 to x for rightside points (Ricoh video is both frames side by side) side = 'buttonside' count['bts'] += 1 # TODO don't write non visible dots? else: points = [0., 0.] count['rej'] += 1 # TODO: Change DTD and double check with Manjung w.start("object", id=str(i), name=c.name(), lens=Theta.name(side)) w.element("boxinfo", height="99", width="99", x=str(points[0] - 50), y=str(points[1] - 50)) w.element("centroid", x=str(points[0]), y=str(points[1]), rx=str(rx), ry=str(ry), rz=str(rz)) w.element("visibility", visible=str(visible_reflectors), visibleMax=str(max_reflectors)) w.end() w.end() # test end of files eofs = 0 for i in csvs: if csvs[i].eof(): eofs += 1 if len(csvs) == eofs: print "end of all datasets" break # load next vicon frame frame_num += 1 for i in csvs: csvs[i].next() w.close(doc) print "\nbuttonside", count['bts'] print "backside", count['bks'] print "rejected", count['rej'] return 0
def main(sysargs): args = EasyArgs(sysargs) cfg = EasyConfig(args.config, group="calib") # argument sanity checks if 'help' in args: usage() return 0 elif 'version' in args: version() return 0 elif 'output' not in args: print "Requires an output path." usage() return 0 if not ('buttonside' in args or 'backside' in args): print "Requires one of -buttonside or -backside." usage() return 0 # default args s_size = args.square_size or cfg.default_squares if args.chess_size: p_size = ast.literal_eval("({})".format(args.chess_size)) else: p_size = cfg.default_chess # camera intrinsics buttonside_cam, buttonside_dist, buttonside_err = np.asarray([]), np.asarray([]), {} backside_cam, backside_dist, backside_err = np.asarray([]), np.asarray([]), {} try: # find chessboard images from prefixes if args.buttonside: buttonside_images = glob.glob(args.buttonside + "*") buttonside_cam, buttonside_dist, buttonside_err = stdCalib(buttonside_images, p_size, s_size, args.preview, cfg.calib_flags) if args.backside: backside_images = glob.glob(args.backside + "*") backside_cam, backside_dist, backside_err = stdCalib(backside_images, p_size, s_size, args.preview, cfg.calib_flags) # create preview folder if specified if args.preview and not os.path.exists(args.preview): os.makedirs(args.preview) # XML Output intWriter(args.output, (buttonside_cam, buttonside_dist, buttonside_err), (backside_cam, backside_dist, backside_err)) # Rectify if args.preview: if args.buttonside: undistort(args.preview, buttonside_images, buttonside_cam, buttonside_dist) if args.backside: undistort(args.preview, backside_images, backside_cam, backside_dist) except Exception as e: print e.message print "Aborting." return 1 # well otherwise everything worked out, right? print '--------------------------------------' print 'Intrinsic Calibration has completed successfully!' return 0
def main(sysargs): args = EasyArgs(sysargs) global scale, img_h if 'help' in args: usage() return 0 # arg sanity checks if len(args) < 3: usage() return 1 # default args height = args.height or 3000 # milimetres width = args.width or 8000 # milimetres max_height = args.max_height or 400 # pixels cfg = EasyConfig(args.config, group="mapper") # working vars scale = float(max_height) / height img_h = int(height * scale) img_w = int(width * scale) # open window window_name = "Tracer" cv2.namedWindow(window_name) # settings font = cv2.FONT_HERSHEY_SIMPLEX text_size = 0.5 colour = (255, 255, 255) # a frame to paste the trace on baseframe = np.zeros((img_h, img_w, 3), np.uint8) # load appropriate mappers if not args.singlemode: mappers = [ Mapper(args[1], args[2], cfg, Theta.Buttonside), Mapper(args[1], args[2], cfg, Theta.Backside) ] else: mappers = [Mapper(args[1], args[2], cfg, Theta.NonDual)] for m in mappers: colour = (55 + random.random() * 200, 55 + random.random() * 200, 55 + random.random() * 200) # calculate world camera pos Rt = np.matrix(m.R).T tv = -Rt.dot(np.matrix(m.tv)) dir = unit(cv2.Rodrigues(-Rt)[0]) #dir = unit(-Rt.dot(np.array([[0.], [0.], [1.]]))) unvis = 0 pts = m.obj_pts for i in pts: # draw circle around it if not-visible x, y, z = i p = (int(x * scale), img_h - int(y * scale)) cv2.circle(baseframe, p, 1, colour, 2) # circle the point if not visible if not m.isVisible((x, y, z)): unvis += 1 cv2.circle(baseframe, p, 6, colour, 1) x, y, z = tv pt1 = (int(x * scale), img_h - int(y * scale)) cv2.circle(baseframe, pt1, 1, colour, 2) cv2.circle(baseframe, pt1, 10, colour, 1) # draw direction of lens #draw_arrow(baseframe, tv, dir[0], colour) # and it's FOV #draw_arrow(baseframe, tv, dir.dot(m.half_fov), colour, length=375) #draw_arrow(baseframe, tv, dir.dot(-m.half_fov), colour, length=375) # and some text data stuff displayText(baseframe, "{}: {}, {}, {}".format(Theta.name(m.mode), *tv), colour=colour) displayText(baseframe, " visible: {}/{}".format(len(pts) - unvis, len(pts)), endl=True, colour=colour) # clean up cv2.imshow(window_name, baseframe) cv2.waitKey(0) if args.export: cv2.imwrite(args.export, baseframe) cv2.destroyAllWindows() print "\ndone" return 0
def main(sysargs): args = EasyArgs(sysargs) cfg = EasyConfig(args.cfg, group="compare") window_name = "EagleEye Comparator" if "help" in args: usage() return 0 # grab marks from args if len(args) > 5: mark_in = args[4] mark_out = args[5] # test integer-ness try: int(mark_in) and int(mark_out) except: usage() return 1 # or grab them from a marker tool elif len(args) > 3: ret, mark_in, mark_out = marker_tool(args[1], 50, window_name) if not ret: print "Not processing - exiting." return 1 else: usage() return 1 # open video files vid = BuffSplitCap(args[1], buff_max=cfg.buffer_size) xml1 = Xmlset(args[2]) xml2 = Xmlset(args[3]) # trim the video vid.restrict(mark_in, mark_out) # trim the CSV cropped_total = mark_out - mark_in xml1.setRatio(cropped_total) xml2.setRatio(cropped_total ) # should be 1.0 (total frames should be the same as video) print 'xml1 ratio:', xml1.ratio() print 'xml2 ratio:', xml2.ratio() # open export (if specified) if 'export' in args: in_fps = vid.get(cv2.CAP_PROP_FPS) in_size = (int(vid.get(cv2.CAP_PROP_FRAME_WIDTH)), int(vid.get(cv2.CAP_PROP_FRAME_HEIGHT))) out_vid = cv2.VideoWriter(args.export, cv2.VideoWriter_fourcc(*cfg.fourcc), in_fps, in_size) else: cv2.namedWindow(window_name) while vid.isOpened(): sys.stdout.write(vid.status() + "\r") sys.stdout.flush() frame = vid.frame() # draw objects from each dataset for name in xml1.data(): draw(frame, xml1.data()[name], cfg.xml1_colour) for name in xml2.data(): draw(frame, xml2.data()[name], cfg.xml2_colour) # print status to screen displayText(frame, vid.status(), top=True) displayText(frame, "{}: {}".format(os.path.basename(args[2]), xml1.status()), colour=cfg.xml1_colour) displayText(frame, "{}: {}".format(os.path.basename(args[3]), xml2.status()), colour=cfg.xml2_colour) # export or navigate if 'export' in args: sys.stdout.write("{}/{}\r".format(vid.at(), cropped_total)) sys.stdout.flush() out_vid.write(frame) if vid.next(): xml1.next() xml2.next() else: print "\nend of video" break else: cv2.imshow(window_name, frame) key = cv2.waitKey(0) # controls if key == Key.esc: print "\nexiting." break elif key == Key.right: if vid.next(): xml1.next() xml2.next() elif key == Key.left: if vid.back(): xml1.back() xml2.back() # clean up vid.release() if 'export' in args: out_vid.release() else: cv2.destroyAllWindows() return 0
def main(sysargs): # settings args = EasyArgs(sysargs) cfg = EasyConfig(args.config, group="trainer") max_clicks = args.clicks or cfg.default_clicks window_name = "EagleEye Trainer" if "help" in args: usage() return 0 # grab marks from args if len(args) > 5: mark_in = args[4] mark_out = args[5] # test integer-ness try: int(mark_in) and int(mark_out) except: usage() return 1 elif len(args) > 3: ret, mark_in, mark_out = marker_tool(args[1], cfg.buffer_size, window_name) if not ret: print "Not processing - exiting." return 1 else: usage() return 1 ## clicking time! cropped_total = mark_out - mark_in print "video cropped at:", mark_in, "to", mark_out, "- ({} frames)".format( cropped_total) # clicking function def on_mouse(event, x, y, flags, params): # left click to mark if event == cv2.EVENT_LBUTTONDOWN: params['pos'] = (x, y) params['status'] = Status.record # right click to skip elif event == cv2.EVENT_RBUTTONDOWN: params['status'] = Status.skip # working variables params = {'status': Status.wait, 'pos': None} write_xml = False textstatus = "" dataQuality = 0 # 0 = good, >0 = bad/potentially bad # default right side (buttonside) if cfg.dual_mode: lens = Theta.Right trainer_points = {Theta.Right: {}, Theta.Left: {}} else: # both sides otherwise lens = Theta.Both trainer_points = {Theta.Both: {}} print "Minimum reflectors: {} | Ignore Negative xyz: {}".format( cfg.min_reflectors, cfg.check_negatives) # load video (again) in_vid = BuffSplitCap(args[1], crop=(0, 0, 0, 0), rotate=BuffSplitCap.r0, buff_max=cfg.buffer_size) in_vid.restrict(mark_in, mark_out) # load csv (with appropriate ratio) in_csv = Memset(args[2]) in_csv.restrict() in_csv.setRatio(cropped_total) # test for marker data if len(in_csv.row()) < 10: print "This CSV contains no marker data!\nAborting." return 1 # status print "" print "Writing to:", args[3] print "Number of clicks at:", max_clicks print "" cv2.namedWindow(window_name) cv2.setMouseCallback(window_name, on_mouse, params) # grab clicks (Process 2) while in_vid.isOpened(): frame = in_vid.frame(side=lens) sys.stdout.write(in_vid.status() + " | Clicks {} / {}\r".format( len(trainer_points[lens]), max_clicks)) sys.stdout.flush() # prepare CSV data, click data tx = float(in_csv.row()[2]) ty = float(in_csv.row()[3]) tz = float(in_csv.row()[4]) rx = float(in_csv.row()[5]) ry = float(in_csv.row()[6]) rz = float(in_csv.row()[7]) # data quality status visible = int(in_csv.row()[9]) max_visible = int(in_csv.row()[8]) # status text to write textrow = "VICON - x: {:.4f} y: {:.4f} z: {:.4f} | rx: {:.4f} ry: {:.4f} rz: {:.4f}".format( tx, ty, tz, rx, ry, rz) textquality = "Visible: {} , Max Visible: {}".format( visible, max_visible) textstatus = "{} | {}/{} clicks".format(in_vid.status(), len(trainer_points[lens]), max_clicks) if lens == Theta.Left: textstatus += " - back side" elif lens == Theta.Right: textstatus += " - button side" #else none, no lens split # if data is qualified bad, reduce timeout by one if dataQuality > 0: dataQuality -= 1 if dataQuality == 0: dataStatus = " - Good data!!" dataStatus_colour = (0, 255, 0) # green else: dataStatus = " - Potentially bad data (wait {})".format( dataQuality) dataStatus_colour = (0, 255, 255) # yellow # Data tests # values must be above 0 and minimum reflectors if (cfg.check_negatives and (tx <= 0 or ty <= 0 or tz <= 0)) \ or visible < cfg.min_reflectors: dataStatus = " - Bad data!!" dataStatus_colour = (0, 0, 255) # red if cfg.ignore_baddata: dataStatus += " Ignored." dataQuality = 1 + cfg.quality_delay # draw the trainer dot (if applicable) if in_vid.at() in trainer_points[lens]: cv2.circle(frame, trainer_points[lens][in_vid.at()][0], 1, cfg.dot_colour, 2) cv2.circle(frame, trainer_points[lens][in_vid.at()][0], 15, cfg.dot_colour, 1) # draw text and show displayText(frame, textrow, top=True) displayText(frame, textquality) displayText(frame, textstatus) displayText(frame, dataStatus, endl=True, colour=dataStatus_colour) cv2.imshow(window_name, frame) # pause for input while params['status'] == Status.wait: key = cv2.waitKey(10) if key == Key.esc: params['status'] = Status.stop elif key == Key.enter: write_xml = True params['status'] = Status.stop elif key == Key.right: params['status'] = Status.skip elif key == Key.left: params['status'] = Status.back elif key == Key.backspace: params['status'] = Status.remove elif Key.char(key, '1') and cfg.dual_mode: params['status'] = Status.still lens = Theta.Left elif Key.char(key, '2') and cfg.dual_mode: params['status'] = Status.still lens = Theta.Right # catch exit status if params['status'] == Status.stop: print "\nprocess aborted!" break # write data if params['status'] == Status.record \ and len(trainer_points[lens]) != max_clicks: # TODO: does this disable recording clicks on the last frame if dataQuality == 0: trainer_points[lens][in_vid.at()] = (params['pos'], in_csv.row()[2:5], in_csv.row()[8:10]) params['status'] = Status.skip # or remove it elif params['status'] == Status.remove \ and in_vid.at() in trainer_points[lens]: del trainer_points[lens][in_vid.at()] print "\nremoved dot" # load next csv frame if params['status'] == Status.skip: if in_vid.next(): in_csv.next() else: write_xml = True print "\nend of video: {}/{}".format(in_vid.at() - 1, mark_out - 1) break # or load previous csv frame elif params['status'] == Status.back: if in_vid.back(): in_csv.back() # reset status params['status'] = Status.wait # clean up cv2.destroyAllWindows() ## write xml if write_xml: out_xml = XMLWriter(args[3]) out_xml.declaration() doc = out_xml.start("TrainingSet") # source information out_xml.start("video", mark_in=str(mark_in), mark_out=str(mark_out)) out_xml.data(os.path.basename(args[1])) out_xml.end() out_xml.element("csv", os.path.basename(args[2])) # training point data for lens in trainer_points: if lens == Theta.Right: out_xml.start("buttonside", points=str(len(trainer_points[lens]))) elif lens == Theta.Left: out_xml.start("backside", points=str(len(trainer_points[lens]))) else: # non dualmode out_xml.start("frames", points=str(len(trainer_points[lens]))) for i in trainer_points[lens]: pos, row, markers = trainer_points[lens][i] x, y = pos out_xml.start("frame", num=str(i)) out_xml.element("plane", x=str(x), y=str(y)) out_xml.element("vicon", x=str(row[0]), y=str(row[1]), z=str(row[2])) out_xml.element("visibility", visibleMax=str(markers[0]), visible=str(markers[1])) out_xml.end() out_xml.end() # frames # clean up out_xml.close(doc) print "Data was written." else: print "No data was written" print "\nDone." return 0
def main(sysargs): args = EasyArgs(sysargs) cfg = EasyConfig(args.config, group="evaluate") window_name = "EagleEye Evaluation Tool" if "help" in args: usage() return 0 # check output path if len(args) < 4: usage() return 1 path = args[3] # grab marks from args if len(args) > 5: mark_in = args[4] mark_out = args[5] # test integer-ness try: int(mark_in) and int(mark_out) except: print "Invalid marks" usage() return 1 else: print "marks are required!" usage() return 1 # open input files mapper_xml = Xmlset(args[1], readmode="mapper") annotated_xml = Xmlset(args[2], readmode="annotated") # status print "Evaluating Mapper: {} | Annoated: {}".format(os.path.basename(args[1]), os.path.basename(args[2])) print "" if mapper_xml.total != annotated_xml.total: print "Warning: Mismatched size of Mapper and Annotated: Mapper: {} | Annotated: {}".format(mapper_xml.total, annotated_xml.total) # Compare frames, start from the frame after 1st flash frameStart = mark_in +1 frameEnd = mark_out -1 # list of compared frames for export compare_frames = {} # vars for plots obj_plotdata = {} # id should be based on object, then frame number and its projection error print "Number of frames to compare {} | From Frame no. {} - {}".format((frameEnd) - (frameStart) + 1, frameStart, frameEnd) for f in range(mark_in+1, mark_out): sys.stdout.write("Reading Mapper Frame: {}".format(f) + " | XML Frame number: {}\r".format(f)) sys.stdout.flush() # check if frame exists in xml, if not skip to next if mapper_xml.data(f) is None: continue if annotated_xml.data(f) is None: continue mapper_data = mapper_xml.data(f) annotated_data = annotated_xml.data(f) # initialise frame compare_frames[f] = {} for obj in mapper_data.keys(): if obj not in obj_plotdata.keys(): obj_plotdata[obj] = {} # initialise obj in dictionary if obj in annotated_data.keys(): # check sides if mapper_data[obj]["lens"] == mapper_data[obj]["lens"]: mapper_x = int(float(mapper_data[obj]["centre"]["x"])) mapper_y = int(float(mapper_data[obj]["centre"]["y"])) annotated_x = int(float(annotated_data[obj]["centre"]["x"])) annotated_y = int(float(annotated_data[obj]["centre"]["y"])) mapper_centroid = (mapper_x, mapper_y) annotated_centroid = (annotated_x, annotated_y) reproj_err = calReprojError(mapper_centroid, annotated_centroid) # for export compare_frames[f][obj] = {} # initialise compared object compare_frames[f][obj]["lens"] = mapper_data[obj]["lens"] compare_frames[f][obj]["map_x"] = mapper_x compare_frames[f][obj]["map_y"] = mapper_y compare_frames[f][obj]["ann_x"] = annotated_x compare_frames[f][obj]["ann_y"] = annotated_y compare_frames[f][obj]["err"] = float(reproj_err) obj_plotdata[obj].update({f: reproj_err}) print "\n\nFound {} frames with matched objects".format(len(compare_frames)) print "Mean Error (Full Set): {} \n".format(calMean(compare_frames)) if path != "": if path.find(".xml") is not -1: print "\nOutputing comparion in xml to {}".format(path) writeXML(compare_frames, path, args) elif cfg.outputformat == "csv": path = path.replace(".xml",".csv") print "Outputing comparison in csv to {}".format(path) writeCSV(compare_frames, path) else: print "\nUnkown file format, please specify file extension as .xml or .csv" else: print "\nNo output path has been specified" # plot! if cfg.plot: print "\nPlotting frame by frame comparison..." plot("Difference between Annotated Centroid and Mapped Centroid (Ground Truth) \n {}".format(os.path.basename(path)), dict_data=obj_plotdata)
def main(sysargs): args = EasyArgs(sysargs) cfg = EasyConfig(args.cfg, group="compare_trainer") window_name = "EagleEye Comparator" if "help" in args: usage() return 0 # grab marks from args if len(args) > 5: mark_in = args[4] mark_out = args[5] # test integer-ness try: int(mark_in) and int(mark_out) except: usage() return 1 # or grab them from a marker tool elif len(args) > 3: ret, mark_in, mark_out = marker_tool(args[1], 50, window_name) if not ret: print "Not processing - exiting." return 1 else: usage() return 1 # determine sides side = Theta.resolve(args.side or 'buttonside') # open inouts files vid = BuffSplitCap(args[1], buff_max=cfg.buffer_size, side=Theta.Both) mapper_xml = Xmlset(args[2], offset=cfg.offset, offmode=Xmlset.offset_mode(cfg.offset_mode)) trainer_xml = Xmltrainer(args[3], side=side) reprojerror_list = {} # list of reprojection error of all frames lastframe = False # reject mapper_xml if it doesn't contain the trainer_target if cfg.trainer_target not in mapper_xml.data(0): print "Mapping file must contain training target:", cfg.trainer_target print "Target names in mapping file:", mapper_xml.data(0) print "Please specifiy correct target name in config" return 1 # also reject if it's lens data doesn't match the trainer_xml _test_lens = mapper_xml.data(0)[cfg.trainer_target]['lens'] if (_test_lens == Theta.NonDual and side != Theta.NonDual) \ or (side != Theta.NonDual and _test_lens == Theta.NonDual): print "Mapping file doesn't match training file" print "map:", Theta.name(_test_lens), "trainer:", Theta.name(side) return 1 # sync the video and xml vid.restrict(mark_in, mark_out) cropped_total = mark_out - mark_in mapper_xml.setRatio(cropped_total) # status print "ratio at:", mapper_xml.ratio() print "offset by:", cfg.offset, "in", cfg.offset_mode, "mode" print "" # open export (if specified) if args.video_export: in_fps = vid.get(cv2.CAP_PROP_FPS) in_size = (int(vid.get(cv2.CAP_PROP_FRAME_WIDTH)), int(vid.get(cv2.CAP_PROP_FRAME_HEIGHT))) out_vid = cv2.VideoWriter(args.video_export, cv2.VideoWriter_fourcc(*cfg.fourcc), in_fps, vid.shape[:2]) print "exporting to:", args.video_export else: cv2.namedWindow(window_name) print "interactive mode" # main loop while vid.isOpened(): frame = vid.frame() reprojerror_list = compareReproj(frame, vid.at(), mapper_xml, trainer_xml, reprojerror_list, cfg) # export or navigate if args.video_export: sys.stdout.write("Reading Video Frame: {} / {}\r".format( vid.at(), mark_out)) sys.stdout.flush() out_vid.write(frame) if vid.next(): reprojerror_list = compareReproj(frame, vid.at(), mapper_xml, trainer_xml, reprojerror_list, cfg) mapper_xml.next() else: calReprojList(reprojerror_list) print "\nend of video" break else: cv2.imshow(window_name, frame) key = cv2.waitKey(0) showAll = False # toggle to show all training points in one frame # controls if key == Key.esc: print "\nexiting." break elif key == Key.right: if vid.next(): mapper_xml.next() else: if lastframe is False: print "\nEnd of video" calReprojList(reprojerror_list) lastframe = True elif key == Key.left: if vid.back(): mapper_xml.back() elif key == Key.enter: while True: reprojerror_list = compareReproj(frame, vid.at(), mapper_xml, trainer_xml, reprojerror_list, cfg) cv2.imshow(window_name, frame) if vid.next(): mapper_xml.next() frame = vid.frame() # break when over else: break calReprojList(reprojerror_list) print "\nFast forwarded to end of video" if args.compare_export: print "Output to file" writeFile(args.compare_export, reprojerror_list) break elif key == Key.space: ''' TODO: display all training points, may be abandoned problems: frame is not refreshed after imshow if showAll is False: displayTrainPts(frame, mark_in, mark_out, trainer_xml, cfg) # #except: # print "Error in displaying training points. Exiting..." # return 1 # showAll = True else: frame, reprojerror_list = compareReproj(frame, vid.at(), mapper_xml, trainer_xml, reprojerror_list, cfg) showAll = False ''' pass # clean up vid.release() if args.video_export: out_vid.release() else: cv2.destroyAllWindows() return 0
def main(sysargs): # set arguments args = EasyArgs(sysargs) cfg = EasyConfig(args.config, group="capture") time = args.time or cfg.default_time output_folder = args.output or cfg.default_output outpath = os.path.join(output_folder, datetime.now().strftime(cfg.date_format)) num_frames = int(time * cfg.framerate) + (cfg.flash_delay * 2) flash_at = [cfg.flash_delay, num_frames - cfg.flash_delay] sleeper = Sleeper(1.0 / cfg.framerate) # data directory sanity check if not os.path.exists(output_folder): os.makedirs(output_folder) # start the serial listener if cfg.run_serial: try: serial = Serial(cfg.serial_device, 9600) serial.setRTS(0) # set at zero except OSError: print "Couldn't open serial device", cfg.serial_device return 1 else: print "Not listening to serial" # open Vicon connection print "Connecting to Vicon..." client = PyVicon() client.connect(cfg.ip_address, cfg.port) if not client.isConnected(): print "Failed to connect to Vicon! {}:{}".format( cfg.ip_address, cfg.port) return 1 csvfiles = [] csvwriters = {} # determine training or capture mode if args.training: # test target existance client.frame() if not cfg.trainer_target in client.subjects(): print "Cannot find:", cfg.trainer_target return 1 f = open(args.training, 'wb') csvfiles.append(f) csvwriters[cfg.trainer_target] = csv.writer( f, delimiter=cfg.output_delimiter, quoting=csv.QUOTE_MINIMAL) subjects = [cfg.trainer_target] else: client.frame() subjects = client.subjects() # open CSV files for sub in subjects: path = "{0}_{1}.csv".format(outpath, sub) f = open(path, 'wb') w = csv.writer(f, delimiter=cfg.output_delimiter, quoting=csv.QUOTE_MINIMAL) csvfiles.append(f) csvwriters[sub] = w # print status print "" print "Using config:", cfg._path print "Running for", time, "seconds ({} frames)".format(num_frames) print "Flash delay at:", cfg.flash_delay, " ({} seconds)".format( int(cfg.flash_delay / cfg.framerate)) print "Capturing at", cfg.framerate, "frames per second" if args.training: print "Recording training target:", cfg.trainer_target, "into:", args.training else: print "Saving data into:", output_folder print "Recording these subjects:\n", ", ".join(subjects) print "" # main loop for c in range(0, num_frames): sleeper.stamp() # run flash flash = "." if cfg.run_serial: if c in flash_at: serial.setRTS(1) flash = "F" sys.stdout.write("\r - - - - - - - Flash!\r") else: serial.setRTS(0) client.frame() for s in subjects: csvwriters[s].writerow([sleeper.getStamp(), flash] + list(client.translation(s)) + list(client.rotation(s)) + list(client.markerStatus(s))) # sleep until next timestamp sys.stdout.write("{}/{}\r".format(c, num_frames)) sleeper.sleep("\r - - - - - - - - - Late!\r") sys.stdout.flush() # clean up for f in csvfiles: f.close() client.disconnect() print "\nComplete." return 0