Example #1
0
    def outputState(self, display, frameFactory, trackFactory, timeFactory,
                    notesFactory):

        if self.db is None:
            self.db = DBInterface(self.dbPathFn)

        if self.bDeleteState:
            self.db.deleteAll()
            print 'deleting all states...'

        bProceed = False

        if self.bBatchState:

            bProceed = self.checkCriteriaOutput(display, frameFactory,
                                                trackFactory, timeFactory,
                                                notesFactory)

            if bProceed: self.batchOutputCounter += 1

        if self.bOutputState or bProceed:

            state = GuiviewState()
            state.setState(display, frameFactory, trackFactory, timeFactory,
                           notesFactory)
            s_state = state.save()
            self.db.insertState(s_state)

            if not (bProceed):
                print 'outputting state...'
Example #2
0
def test_applyTracker_2():
    ''' test applyTracker; roiSelectFunc=None '''

    #load data
    tracker = TrackFactory(on=True)
    tracker.setAlgoEnum(0)
    tracker.setInit(ballColor="green")

    test_data = "applyTracker.db"
    test_dir = os.path.join(TEST_PARENT_DIR, 'applyTracker')
    testDB = DBInterface(os.path.join(test_dir, test_data))

    listGS = [pickle.loads(record[1]) for record in testDB.selectAll()]

    #check input data validity
    assert [_gs.frameCounter for _gs in listGS] == [0, 189, 312]
    assert tracker.getTrackParams()['thresh_lo'] == (29, 86, 6)
    assert tracker.getTrackParams()['repair_iterations'] == 1

    #test function
    data = applyTracker(listGS, tracker)

    #check outcome
    assert len(data['listPlts']) == 3
    assert len(data['listPlts'][0]) == 3
    assert data['listPlts'][0][0].shape == (480, 640, 3)
    assert data['listPlts'][0][1].shape == (480, 640)
    assert data['listTransformTitles'] == ['img_t', 'img_mask', 'img_repair']
    assert data['listFrameTitles'] == ['0', '189', '312']
    assert len(data['listScore']) == 3
    assert data['listScore'][0]['0']['data'] == [209, 168, 35, 35]
    assert data['listScore'][1] == None
Example #3
0
def test_applyTracker_3():
    ''' test applyTracker; roiSelectFunc=roiSelectZoomWindow.
        test_data has guiview states with a zoomRect '''

    #load data
    tracker = TrackFactory(on=True)
    tracker.setAlgoEnum(0)
    tracker.setInit(ballColor="green")

    test_data = "applyTracker.db"
    test_dir = os.path.join(TEST_PARENT_DIR, 'applyTracker')
    testDB = DBInterface(os.path.join(test_dir, test_data))

    listGS = [pickle.loads(record[1]) for record in testDB.selectAll()]

    #check input data validity
    assert [_gs.frameCounter for _gs in listGS] == [0, 189, 312]

    #test function
    data = applyTracker(listGS, tracker, roiSelectZoomWindow)

    #check outcome
    assert data['listPlts'][0][0].shape == (68, 66, 3)
    assert data['listPlts'][0][1].shape == (68, 66)
    assert data['listPlts'][1][0].shape == (22, 22, 3)
    assert data['listPlts'][1][1].shape == (22, 22)

    assert len(data['listScore']) == 3
    assert data['listScore'][0]['0']['data'] == [17, 18, 35, 35]
    assert data['listScore'][1] == None
Example #4
0
    def setBatchState(self,
                      bBatchState,
                      iEnumBatchCriteria,
                      lBatchIndexList=None,
                      sBatchDbPathFn=""):

        self.bBatchState = bBatchState
        self.enumBatchCriteria = iEnumBatchCriteria

        if lBatchIndexList is not None:
            self.batchIndexList = copy.copy(lBatchIndexList)

        if sBatchDbPathFn != "":
            self.dbPathFn = sBatchDbPathFn

        if bBatchState:
            print '\nSTART - running batch output ...'
            try:
                if self.db is None:
                    self.db = DBInterface(self.dbPathFn)
                self.db.deleteAll()
                self.db = None
                print '...deleting all exisiting %s records...' % str(
                    self.dbPathFn)
            except:
                print 'failed to delete exisitng records'
Example #5
0
def test_load_gs_1():

    path_test = '''data/test/evalhelpers/EvalDataset_2/'''
    path_gs = os.path.join('..', path_test, 'input_gs.db')

    db = DBInterface(path_gs)
    listGS = [pickle.loads(d[1]) for d in db.selectAll()]

    #validate frameCounter
    ANSWER = [0, 1, 5]
    assert [gs.frameCounter for gs in listGS] == ANSWER

    #validate frame/origFrame exists
    assert listGS[0].getOrigFrame().shape == (480, 640, 3)
    assert listGS[1].getOrigFrame().shape == (480, 640, 3)

    #validate displayInputScore exists in some/ not in others
    ANSWER = {
        u'0': {
            u'data': [107, 214, 54, 52],
            u'type': u'circle'
        },
        u'1': {
            u'data': [111, 218, 46, 44],
            u'type': u'circle'
        }
    }
    assert cmp(listGS[0].displayInputScore, ANSWER) == 0
    assert listGS[1].displayInputScore is None
Example #6
0
def test_EvalDataset_buildDataset_2():

    # unlike previous test, this listGS has some non-inputframes gs's.

    path_test = '''data/test/evalhelpers/EvalDataset_2/'''
    path_gs = os.path.join('..', path_test, 'input_gs.db')
    path_answer = os.path.join('..', path_test, 'answer_outcome.pickle')

    #load listGS
    db = DBInterface(path_gs)
    listGS = [pickle.loads(d[1]) for d in db.selectAll()]
    print[_gs.frameCounter for _gs in listGS]

    # init tracker
    my_tracker = TrackFactory(on=True)
    my_tracker.setInit(ballColor="orange")
    my_tracker.setAlgoEnum(0)

    # apply method
    evd = EvalDataset()
    evd.buildDataset(listGS, my_tracker)
    output = evd.df.copy()

    answer = pd.read_pickle(path_answer)

    # validate
    try:
        assert output.equals(answer)
    except:
        print diff_pd(output, answer)
        raise Exception
Example #7
0
def test_EvalDataset_buildDataset():
    ''' rebenched 2.10.19'''

    path_test = '''data/test/evalhelpers/EvalDataset/'''
    path_gs = os.path.join('..', path_test, 'input_gs.db')
    path_answer = os.path.join('..', path_test, 'answer_outcome.pickle')

    #load listGS
    db = DBInterface(path_gs)
    listGS = [pickle.loads(d[1]) for d in db.selectAll()]
    print[_gs.frameCounter for _gs in listGS]

    # init tracker
    my_tracker = TrackFactory(on=True)
    my_tracker.setInit(ballColor="orange")
    my_tracker.setAlgoEnum(0)

    # apply method
    evd = EvalDataset()
    evd.buildDataset(listGS, my_tracker)
    output = evd.df.copy()

    # validate
    answer = pd.read_pickle(path_answer)
    d_output, d_answer = output.to_dict(), answer.to_dict()

    assert cmp(d_output, d_answer) == 0
Example #8
0
def test_compareTrackers_1():
    '''
        functionality test for:
             basic functionality
             roiSelectWindow
             bMarkedFrame
             success calling multiPlot
             multiplot_params
    '''

    # build listTrackers
    listTrackers = []
    for _algoenum in [0, 1]:
        _tracker = TrackFactory(on=True)
        _tracker.setAlgoEnum(_algoenum)
        _tracker.setInit(ballColor="orange")
        listTrackers.append(_tracker)

    # build listGS
    test_data = "compareTrackers_orange.db"
    test_dir = os.path.join(TEST_PARENT_DIR, 'compareTrackers')
    testDB = DBInterface(os.path.join(test_dir, test_data))
    listGS = [pickle.loads(record[1]) for record in testDB.selectAll()]

    # run method with test_mock flag
    data_dict = compareTrackers(listGS, listTrackers, test_stub=True)

    # checks
    print data_dict['row_titles']
    assert data_dict['row_titles'] == [
        'marked_frame', 'img_t', 'img_mask', 'img_repair', 'img_terminal'
    ]
    assert data_dict['col_titles'] == ['AlgoEnum=0', 'AlgoEnum=1']
    assert data_dict['plot_data'][0][1].shape == (480, 640, 3
                                                  )  # since roiSelectFunc=None

    # run 1. without markedFrame at the top, 2. with selectRoiFunc
    data_dict = compareTrackers(listGS,
                                listTrackers,
                                roiSelectFunc=True,
                                bMarkedFrame=False,
                                test_stub=True)

    assert data_dict['row_titles'] == [
        'img_t', 'img_mask', 'img_repair', 'img_terminal'
    ]
    assert data_dict['plot_data'][0][1].shape != (480, 640, 3)

    # don't run with test_stub; thus sending data into multiPlot() to see
    # if any exceptions are thrown. use bSupressDisplay to prevent matplotlib output
    # from popping-up during the tests
    compareTrackers(listGS,
                    listTrackers,
                    test_stub=False,
                    multiplot_params={
                        'figsize': (20, 20),
                        'bSupressDisplay': True
                    })
Example #9
0
def test_compareTrackers_3():
    '''
        test functionality:
            aligning algo's with different num of diagnostic-plots
    '''

    # build listTrackers
    listTrackers = []
    for _algoenum in [2, 3]:
        _tracker = TrackFactory(on=True)
        _tracker.setAlgoEnum(_algoenum)
        _tracker.setInit(ballColor="orange")
        listTrackers.append(_tracker)

    # build listGS
    test_data = "compareTrackers_orange.db"
    test_dir = os.path.join(TEST_PARENT_DIR, 'compareTrackers')
    testDB = DBInterface(os.path.join(test_dir, test_data))
    listGS = [pickle.loads(record[1]) for record in testDB.selectAll()]

    # run two separate functions with different params, compare their output

    data_dict_1 = compareTrackers(listGS,
                                  listTrackers,
                                  roiSelectFunc=True,
                                  test_stub=True)

    data_dict_2 = compareTrackers(listGS,
                                  listTrackers,
                                  roiSelectFunc=True,
                                  expand_factor=0.5,
                                  blend_rowtitles=True,
                                  test_stub=True)

    # checks

    assert data_dict_1['row_titles'] == [
        'marked_frame', 'img_t', 'img_mask', 'img_repair', 'img_dummy',
        'img_dummy_2', 'img_terminal', 'img_terminal_2'
    ]
    print data_dict_2['row_titles']
    assert data_dict_2['row_titles'] == [
        'marked_frame\nmarked_frame', 'img_t\nimg_t', 'img_mask\nimg_mask',
        'img_repair\nimg_repair', 'img_terminal\nimg_dummy',
        'n/a\nimg_dummy_2', 'n/a\nimg_terminal', 'n/a\nimg_terminal_2'
    ]

    assert sum(sum(sum(data_dict_1['plot_dict']['img_t'][0]))) > 0
    assert data_dict_1['plot_dict']['img_dummy'][0] is None
    assert sum(sum(sum(data_dict_1['plot_dict']['img_dummy'][1]))) > 0

    assert data_dict_2['plot_dict']['img_dummy'][0] is None
    assert sum(sum(sum(data_dict_2['plot_dict']['img_dummy'][1]))) > 0

    assert data_dict_1['plot_data'][0][7] is None
Example #10
0
def test_compareTrackers_5():
    '''
        test functionality:
            blend_rowtitles
    '''

    # build listTrackers
    listTrackers = []
    for _algoenum in [2, 3]:
        _tracker = TrackFactory(on=True)
        _tracker.setAlgoEnum(_algoenum)
        _tracker.setInit(ballColor="orange")
        listTrackers.append(_tracker)

    # build listGS
    test_data = "compareTrackers_orange.db"
    test_dir = os.path.join(TEST_PARENT_DIR, 'compareTrackers')
    testDB = DBInterface(os.path.join(test_dir, test_data))
    listGS = [pickle.loads(record[1]) for record in testDB.selectAll()]

    # run with blend_rowtitles

    data_dict_2 = compareTrackers(listGS,
                                  listTrackers,
                                  roiSelectFunc=True,
                                  expand_factor=0.5,
                                  blend_rowtitles=True,
                                  test_stub=True)

    # checks
    print data_dict_2['row_titles']
    assert data_dict_2['row_titles'] == [
        'marked_frame\nmarked_frame', 'img_t\nimg_t', 'img_mask\nimg_mask',
        'img_repair\nimg_repair', 'img_terminal\nimg_dummy',
        'n/a\nimg_dummy_2', 'n/a\nimg_terminal', 'n/a\nimg_terminal_2'
    ]

    # verify plots in blend_rowtitles is in correct order
    data_dict_2['plot_data'][0][4] is not None
    try:
        data_dict_2['plot_data'][0][5] is None
        assert False  # this should be out-of-index
    except:
        pass
    data_dict_2['plot_data'][1][4] is not None
    data_dict_2['plot_data'][1][5] is not None
Example #11
0
def test_compareTrackers_4():
    '''
        test functionality:
            bFirstTrackerRoi
    '''

    # build listTrackers: place algo_enum=2 in first position
    listTrackers = []
    for _algoenum in [2, 0]:
        _tracker = TrackFactory(on=True)
        _tracker.setAlgoEnum(_algoenum)
        _tracker.setInit(ballColor="orange")
        listTrackers.append(_tracker)

    # build listGS - these foi's are specifically chosen as the roi from track_score
    # from algo_enum=0 and algo_enum=2 are very different
    test_data = "compareTrackers_disparateRoi.db"
    test_dir = os.path.join(TEST_PARENT_DIR, 'compareTrackers')
    testDB = DBInterface(os.path.join(test_dir, test_data))
    listGS = [pickle.loads(record[1]) for record in testDB.selectAll()]

    # run two separate functions with different params, compare their output

    data_indv_roi = compareTrackers(
        listGS,
        listTrackers,
        roiSelectFunc=True,
        bTrackScore=True,
        bFirstTrackerRoi=False  # var-of-interest
        ,
        expand_factor=2.0,
        test_stub=True)

    data_first_roi = compareTrackers(
        listGS,
        listTrackers,
        roiSelectFunc=True,
        bTrackScore=True,
        bFirstTrackerRoi=True  # var-of-interest
        ,
        expand_factor=2.0,
        test_stub=True)

    #compare col_titles - extract window-roi from string
    assert data_indv_roi['col_titles'] == [
        'AlgoEnum=2\n(373, 277, 10, 10)', 'AlgoEnum=0\n(395, -7, 16, 16)'
    ]
    assert data_first_roi['col_titles'] == [
        'AlgoEnum=2\n(373, 277, 10, 10)', 'AlgoEnum=0\n(373, 277, 10, 10)'
    ]

    #make sure empty plot is in correct position - the second position
    plot_row = data_indv_roi['plot_dict']['img_terminal']
    assert sum(sum(plot_row[0])) > 0
    assert plot_row[1] is None
    plot_row = data_first_roi['plot_dict']['img_terminal']
    assert sum(sum(plot_row[0])) > 0
    assert plot_row[1] is None

    # use shape to verify the same roi is being applied across all trackers

    assert (data_indv_roi['plot_dict']['img_t'][0].shape !=
            data_indv_roi['plot_dict']['img_t'][1].shape)

    assert (data_first_roi['plot_dict']['img_t'][0].shape ==
            data_first_roi['plot_dict']['img_t'][1].shape)
Example #12
0
def test_compareTrackers_2():
    '''
        test functionality:
            col_titles
            expand_factor
            blend_rowtitles
            pixel-comparison
    '''

    # build listTrackers
    listTrackers = []
    for _algoenum in [0, 1]:
        _tracker = TrackFactory(on=True)
        _tracker.setAlgoEnum(_algoenum)
        _tracker.setInit(ballColor="orange")
        listTrackers.append(_tracker)

    # build listGS
    test_data = "compareTrackers_orange.db"
    test_dir = os.path.join(TEST_PARENT_DIR, 'compareTrackers')
    testDB = DBInterface(os.path.join(test_dir, test_data))
    listGS = [pickle.loads(record[1]) for record in testDB.selectAll()]

    # run two separate functions with different params, compare their output

    data_dict_1 = compareTrackers(listGS,
                                  listTrackers,
                                  roiSelectFunc=True,
                                  col_titles=['my_col_1', 'my_col_2'],
                                  test_stub=True)

    data_dict_2 = compareTrackers(listGS,
                                  listTrackers,
                                  roiSelectFunc=True,
                                  expand_factor=0.5,
                                  blend_rowtitles=True,
                                  test_stub=True)

    # checks
    assert data_dict_1['row_titles'] == [
        'marked_frame', 'img_t', 'img_mask', 'img_repair', 'img_terminal'
    ]
    assert data_dict_2['row_titles'] == [
        'marked_frame\nmarked_frame', 'img_t\nimg_t', 'img_mask\nimg_mask',
        'img_repair\nimg_repair', 'n/a\nimg_terminal'
    ]

    assert data_dict_1['col_titles'] == ['my_col_1', 'my_col_2']
    assert data_dict_2['col_titles'] == ['AlgoEnum=0', 'AlgoEnum=1']

    assert (data_dict_1['plot_dict']['img_t'][0].shape[0] <
            data_dict_2['plot_dict']['img_t'][0].shape[0])

    # verify plots in blend_rowtitles is in correct order
    # data_dict_2['plot_data'][col][row] is None
    # data_dict_2['plot_data'][col][row] is not None

    # pixel-wise comparison
    DIFF_LOG_DIR = "../data/test/guiview/displayclass/log/"
    diff = ImgDiff(log_path=DIFF_LOG_DIR)

    loaded_mf1 = cv2.imread(
        os.path.join(test_dir, 'benchmark_markedframe_1.png'))
    loaded_mf2 = cv2.imread(
        os.path.join(test_dir, 'benchmark_markedframe_2.png'))

    mf1 = data_dict_1['plot_dict']['marked_frame'][0]
    mf2 = data_dict_2['plot_dict']['marked_frame'][0]

    assert diff.diffImgs(mf1, loaded_mf1)
    assert diff.diffImgs(mf2, loaded_mf2)
Example #13
0
class OutputFactory:
    ''' Handles logic for outputting a video '''
    def __init__(self):
        self.outputDir = ""
        self.vidwriter = None
        self.timewriter = None
        self.metawriter = None
        self.writeVidFn = None
        self.writeTimeFn = None
        self.writeMetaFn = None
        self.bWriteVidOn = False
        self.bWriteFrameCmd = False
        self.bWriteFrameSnap = False
        self.bWriteScoreSnap = False
        self.bAllowDuplicates = False
        self.bInitWriteVid = False
        self.bOutputState = False
        self.bDeleteState = False
        self.bBatchState = False
        self.enumBatchCriteria = 0
        self.batchIndexList = None
        self.batchOutputCounter = 0
        self.advanceFrame = False
        self.compressionEnum = 0
        self.framesData = []
        self.framesInd = []
        self.frameCounter = None
        self.db = None
        self.dbPathFn = "data/usr/interproc.db"

    def setOutputDir(self, outputDir):
        self.outputDir = outputDir

    def resetFramesData(self):
        self.framesData = []

    def resetFramesInd(self):
        self.framesInd = []
        self.frameCounter = None

    def setBatchState(self,
                      bBatchState,
                      iEnumBatchCriteria,
                      lBatchIndexList=None,
                      sBatchDbPathFn=""):

        self.bBatchState = bBatchState
        self.enumBatchCriteria = iEnumBatchCriteria

        if lBatchIndexList is not None:
            self.batchIndexList = copy.copy(lBatchIndexList)

        if sBatchDbPathFn != "":
            self.dbPathFn = sBatchDbPathFn

        if bBatchState:
            print '\nSTART - running batch output ...'
            try:
                if self.db is None:
                    self.db = DBInterface(self.dbPathFn)
                self.db.deleteAll()
                self.db = None
                print '...deleting all exisiting %s records...' % str(
                    self.dbPathFn)
            except:
                print 'failed to delete exisitng records'

    def checkBatchExit(self):
        ''' return True to exit guiview inner loop; for once-thru 
            batch-output / batch-eval runs '''

        if self.bBatchState:

            print 'FINISH - batch output with %s outputs.' % str(
                self.batchOutputCounter)
            return True

        return False

    def setCmd(self,
               duplicatesEnum=None,
               initWriteVid=None,
               compressionEnum=None,
               writevidOn=None,
               switchWriteFrame=None,
               switchWriteScoring=None,
               switchOverideNote=None,
               switchOutputState=None,
               switchDeleteState=None):

        if duplicatesEnum is not None:
            self.bAllowDuplicates = True if duplicatesEnum == 1 else False

        if initWriteVid:
            self.bInitWriteVid = True
            g.initWriteVid = False
        else:
            self.bInitWriteVid = False

        if compressionEnum is not None:
            self.compressionEnum = compressionEnum

        if writevidOn is not None:
            self.bWriteVidOn = writevidOn

        self.advanceFrame = False

        if switchWriteFrame is not None:
            self.bWriteFrameSnap = switchWriteFrame
            if switchWriteFrame:
                g.switchWriteVid = False
                self.advanceFrame = True

        if switchWriteScoring is not None:
            self.bWriteScoreSnap = switchWriteScoring
            if switchWriteScoring:
                g.switchWriteScoring = False
                self.advanceFrame = True

        if switchOverideNote is not None:
            self.bWriteOverideSnap = switchOverideNote
            if switchOverideNote:
                g.switchOverideNote = False
                self.advanceFrame = True

        if switchOutputState is not None:
            self.bOutputState = switchOutputState
            if switchOutputState:
                g.switchOutputState = False

        if switchDeleteState is not None:
            self.bDeleteState = switchDeleteState
            if switchDeleteState:
                g.switchDeleteState = False

    def getAdvanceFrame(self):
        return self.advanceFrame

    def checkWriteVid(self):
        return self.bInitWriteVid

    def setWriteFrameCmd(self, bWriteFrame):
        self.bWriteFrameCmd = bWriteFrame

    def setFrameCounter(self, iFrameCounter):
        self.frameCounter = iFrameCounter

    def checkDuplicateFrame(self):
        ''' return True if not duplicate / "already in output" '''
        if self.frameCounter not in self.framesInd:
            self.framesInd.append(self.frameCounter)
            return True
        else:
            return False

    def isDuplicate(self):
        ''' return False if it's not-duplicate or you allow duplicates '''
        if self.bAllowDuplicates:
            return False
        else:
            if self.checkDuplicateFrame():
                return False
            else:
                return True

    def checkWriteFrame(self):
        if ((self.bWriteVidOn and self.bWriteFrameCmd) or self.bWriteFrameSnap
                or self.bWriteScoreSnap or self.bWriteOverideSnap):

            return True
        return False

    def needScore(self):
        ''' return true if this frames notes should include scoring '''
        return self.bWriteScoreSnap

    def checkOutputState(self):
        if self.bOutputState or self.bDeleteState or self.bBatchState:
            return True
        return False

    def checkCriteriaOutput(self, display, frameFactory, trackFactory,
                            timeFactory, notesFactory):
        ''' evaluate if criteria is met and return if so'''

        if self.enumBatchCriteria == 0:
            return False

        elif self.enumBatchCriteria == 1:

            # check the list
            if ((display.origFrame is not None)
                    and (self.batchIndexList is not None)
                    and (len(self.batchIndexList) > 0)
                    and (frameFactory.frameCounter in self.batchIndexList)):

                return True

        elif self.enumBatchCriteria == 2:

            # example criteria using objects
            if ((display.origFrame is not None)
                    and (frameFactory.frameCounter > -1)
                    and (frameFactory.frameCounter < 20)):

                return True

        elif self.enumBatchCriteria == 3:

            # all frames that contain a scoring
            if ((display.origFrame is not None)
                    and (frameFactory.frameCounter > -1)
                    and (display.inputScore.checkHasContents())):

                return True

        return False

    def outputState(self, display, frameFactory, trackFactory, timeFactory,
                    notesFactory):

        if self.db is None:
            self.db = DBInterface(self.dbPathFn)

        if self.bDeleteState:
            self.db.deleteAll()
            print 'deleting all states...'

        bProceed = False

        if self.bBatchState:

            bProceed = self.checkCriteriaOutput(display, frameFactory,
                                                trackFactory, timeFactory,
                                                notesFactory)

            if bProceed: self.batchOutputCounter += 1

        if self.bOutputState or bProceed:

            state = GuiviewState()
            state.setState(display, frameFactory, trackFactory, timeFactory,
                           notesFactory)
            s_state = state.save()
            self.db.insertState(s_state)

            if not (bProceed):
                print 'outputting state...'

    @staticmethod
    def stripExt(fn):
        return ".".join(fn.split(".")[:-1])

    def initVidWriter(self, frameSize, vidFn):

        ext = "avi"
        fourcc = "h264"
        if self.compressionEnum == 1:
            fourcc = 0  #request lossless encoding

        if self.vidwriter is not None:
            self.vidwriter.release()
            self.vidwriter = None

        fnBase = self.stripExt(vidFn)

        self.writeVidFn = uniqueFn(fn_base=fnBase + ".proc",
                                   fn_dir=self.outputDir,
                                   fn_ext=ext)

        self.vidwriter = VidWriter(savefn=os.path.join(self.outputDir,
                                                       self.writeVidFn),
                                   fourcc=fourcc,
                                   outshape=frameSize)

        if self.timewriter is not None:
            self.timewriter.close()
            self.timewriter = None

        self.writeTimeFn = self.stripExt(self.writeVidFn) + ".txt"

        self.timewriter = open(os.path.join(self.outputDir, self.writeTimeFn),
                               'w')

        self.writeMetaFn = self.stripExt(self.writeVidFn) + ".metalog"

        _f = open(os.path.join(self.outputDir, self.writeMetaFn), 'w')
        _f.close()
        self.metawriter = True

    def getWritevidFn(self):
        return self.writeVidFn

    def writeFrame(self, frame, timelogEntry, baseNote, frameData):
        ''' on advance or play, write previous frame '''

        _bDuplicate = self.isDuplicate()

        if self.vidwriter is not None and not (_bDuplicate):

            self.vidwriter.write(frame)

        if self.timewriter is not None and not (_bDuplicate):

            self.timewriter.write(str(timelogEntry) + "\n")

        if self.metawriter is not None:

            # overwrite existing framenote. only for new score; other
            # framenote attr are not updated. to update other framenote
            # attr's use a new output.
            if _bDuplicate:

                try:
                    currentFrameData = self.framesData[self.frameCounter]
                except:
                    currentFrameData = {}

                #TODO-SS
                if (currentFrameData.get('scoring', None) is not None
                        and frameData.get('scoring', -1) in (None, -1)):

                    # The problem here is frameData is already populated with score
                    # before this function, we want score as a separate arg here

                    # if there's already a score, don't update this record
                    return

                else:
                    try:
                        self.framesData[self.frameCounter] = frameData
                    except:
                        self.framesData.append(frameData)

            else:
                self.framesData.append(frameData)

            fullNotes = baseNote

            proc_data = fullNotes.get('proc-data', {})
            proc_data['last_write_compression_enum'] = g.compressionEnum

            fullNotes['proc-data'] = proc_data

            fullNotes['frames'] = self.framesData

            fullNotes = self.orderDict(copy.copy(fullNotes),
                                       last_keys=["frames"])

            metalogEntire = json.dumps(fullNotes, indent=4)

            _f = open(os.path.join(self.outputDir, self.writeMetaFn), 'w')
            _f.truncate(0)
            _f.write(metalogEntire)
            _f.close()

    @staticmethod
    def orderDict(dict, first_keys=[], last_keys=[]):

        _keys = [k for k in dict.keys()]
        _order = [0 for _ in range(len(_keys))]

        for i in range(len(_keys)):
            if _keys[i] in first_keys:
                _order[i] = -1
            if _keys[i] in last_keys:
                _order[i] = 1

        _temp = [(a, b) for a, b in zip(_keys, _order)]
        _temp.sort(key=lambda tup: tup[1])

        sorted_keys = [elem[0] for elem in _temp]

        output = OrderedDict()
        for k in sorted_keys:
            output[k] = dict[k]

        return output