예제 #1
0
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
예제 #2
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
예제 #3
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
예제 #4
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
예제 #5
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
예제 #6
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
예제 #7
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
예제 #8
0
파일: evaluate.py 프로젝트: gwillz/EagleEye
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) 
예제 #9
0
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
예제 #10
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