Exemplo n.º 1
0
 def getFrameScoreCurrent(self):
     ''' return the score or None. '''
     try:
         objScoring = ScoreSchema()
         objScoring.load(self.getFrameNoteCurrent().get('scoring', None))
         return objScoring.getAll()
     except:
         return None
Exemplo n.º 2
0
def test_ScoreSchema_addObj_number_type():

    # make sure all data gets converted to int-type

    # addCircle
    inp_data = [11.0, 12, float(15), float(0)]
    ss = ScoreSchema()
    ss.addCircle(inp_data, objEnum=0)
    ret_data = ss.getAll()['0']['data']
    assert all(map(lambda elem: type(elem) is int, ret_data))
    assert ret_data == [11, 12, 15, 0]

    # addRay
    inp_data = [[11.0, 12.9999], [float(15), float(0.1)]]
    ss = ScoreSchema()
    ss.addRay(inp_data, objEnum=0)
    ret_data = ss.getAll()['0']['data']
    assert all(map(lambda elem: type(elem) is int, ret_data[0]))
    assert all(map(lambda elem: type(elem) is int, ret_data[1]))
    assert ret_data == [[11, 12], [15, 0]]
Exemplo n.º 3
0
def test_ScoreSchema_load_number_type():

    # test that we coerce all data into int

    # circle
    inp_data = {'0': {'type': 'circle', 'data': [1.1, 2, float(15), 0.9999]}}
    ss = ScoreSchema()
    ss.load(inp_data)
    ret_data = ss.getAll()['0']['data']
    assert ret_data == [1, 2, 15, 0]
    assert all(map(lambda elem: type(elem) is int, ret_data))

    # ray
    inp_data = {'0': {'type': 'ray', 'data': [[1.1, 2], [float(15), 0.9999]]}}
    ss = ScoreSchema()
    ss.load(inp_data)
    ret_data = ss.getAll()['0']['data']
    assert ret_data == [[1, 2], [15, 0]]
    assert all(map(lambda elem: type(elem) is int, ret_data[0]))
    assert all(map(lambda elem: type(elem) is int, ret_data[1]))
Exemplo n.º 4
0
def test_fromScalarsAddObject():

    ss = ScoreSchema()
    assert ss.getAll() is None

    fields = {
        'objtype': 'circle',
        'data0': 100,
        'data1': 100,
        'data2': 40,
        'data3': 50,
        'misc': 'blah balh'
    }
    ss.fromScalarsAddObject(objEnum=0, **fields)
    assert ss.getAll() == {'0': {'type': 'circle', 'data': [100, 100, 40, 50]}}

    # test overwrite of objEnum=0
    ss.fromScalarsAddObject(objEnum=0, **fields)
    assert ss.getAll() == {'0': {'type': 'circle', 'data': [100, 100, 40, 50]}}

    # test multiple obj's
    fields2 = {
        'objtype': 'circle',
        'data0': 200,
        'data1': 100,
        'data2': 30,
        'data3': 20,
        'misc': 'blah balh'
    }
    ss.fromScalarsAddObject(objEnum=3, **fields2)
    assert ss.getAll() == {
        '0': {
            'type': 'circle',
            'data': [100, 100, 40, 50]
        },
        '3': {
            'type': 'circle',
            'data': [200, 100, 30, 20]
        }
    }
Exemplo n.º 5
0
class NotesFactory:
    ''' handle non-timelog data associated with each video, and and each frame '''
    def __init__(self):
        self.metalog = MetaDataLog()
        self.vidIsLoaded = False
        self.isProcessed = False
        self.dataVid = {}
        self.frameNoteFailed = False

        self.orientation = 0
        self.compression = -1

        self.bOverideFramenote = False
        self.framesDataExisting = []
        self.frameInd = None
        self.displayFrameScoring = ScoreSchema()

        self.frameLogInputPathFn = None
        self.defaultLogFrameInputPathFn = "notes/guiview.jsonc"
        self.defaultFrameNotePathFn = "notes/framenote.json"
        self.defaultFrameNoteOveridePathFn = "notes/framenote-override.jsonc"

    def setFrameLogInput(self, frameLogPathFn):
        ''' set the path to framelog input which is json template for creation
            of frameData-dict'''

        if frameLogPathFn == "":
            self.frameLogInputPathFn = self.defaultLogFrameInputPathFn
        else:
            self.frameLogInputPathFn = frameLogPathFn

        try:
            _f = open(self.frameLogInputPathFn, 'r')
            _f.close()
        except:
            print 'couldnt open frameLogInput at: ', frameLogPathFn
            self.frameLogInputPathFn = None

    def setFrameCurrent(self, frameInd):
        self.frameInd = frameInd

    def setDisplayScoring(self, scoringData):
        self.displayFrameScoring.load(scoringData)
        # if scoringData is None, displayFrameScoring get's reset

    def getOrientation(self):
        return self.orientation  #degrees clockwise

    def getCompression(self):
        if self.compression == 0:  # this is the code for lossless
            return 1
        return 0

    def getBallColor(self):
        try:
            return self.dataVid['notes']['details']['ball_color']
        except:
            return None

    def setCmd(self, switchOverideNote=None):

        if switchOverideNote is not None:
            self.bOverideFramenote = switchOverideNote
            # note: still need to read this below in
            # output.setCmd, don't alter global here.

    def loadMetaLog(self, metalogPathFn):

        try:
            self.dataVid = self.metalog.get_log_data(metalogPathFn)

            self.orientation = self.dataVid.get('notes',
                                                0).get('orientation', 0)

            self.compression = self.dataVid.get('fourcc_enum', -1)

            if isinstance(self.metalog.data, dict):
                if len(self.metalog.data.keys()) > 0:
                    self.vidIsLoaded = True

            if self.dataVid.get('processed', False):
                self.isProcessed = True
                self.loadFrameNotes()
            else:
                self.dataVid['processed'] = True
                self.dataVid['proc-data'] = {}  #e.g. datetime of processing

        except:
            self.dataVid = {}

    def getBaseMetaLog(self):

        fullLog = copy.deepcopy(self.dataVid)

        try:
            del fullLog["frames"]
        except:
            pass

        return fullLog

    def loadFrameNotes(self):
        ''' if video is processed it already has frame notes, load those '''
        try:
            assert len(self.dataVid['frames']) > 0
            assert isinstance(self.dataVid['frames'][0], dict)
            self.framesDataExisting = self.dataVid['frames']
        except:
            self.framesDataExisting = []

    def getFrameNoteCurrent(self):
        ''' return a dict representing frame data '''
        try:
            return self.framesDataExisting[self.frameInd]
        except:
            return {}

    def getFrameScoreCurrent(self):
        ''' return the score or None. '''
        try:
            objScoring = ScoreSchema()
            objScoring.load(self.getFrameNoteCurrent().get('scoring', None))
            return objScoring.getAll()
        except:
            return None

    def getFrameScoreCurrentDict(self):
        ''' return the score or empty dict; like a wrapper for getFrameScoreCurrent'''
        result = self.getFrameScoreCurrent()
        if result is None:
            return {}
        return result

    def checkFrameHasScore(self):
        ''' return True is there's anything stored in framenote.scoring '''
        return self.getFrameNoteCurrent().get('scoring', None) is not None

    def getFrameType(self):
        try:
            frameNote = self.getFrameNoteCurrent()
            return frameNote['frame_type']
        except:
            return None

    def getFrameScoreForTrack(self):
        ''' returns relevant params from metalog to tracking module '''
        try:
            return self.getFrameType(), self.getFrameScoreCurrent()
        except:
            return None, None

    def loadFrameLogCurrent(self):
        ''' load data from notepad '''
        if self.frameLogInputPathFn is not None:
            try:
                with open(self.frameLogInputPathFn, "r") as f:
                    lines = f.readlines()
                input_str = ''.join(lines)

                #remove comments
                input_str = re.sub(r'\\\n', '', input_str)
                input_str = re.sub(r'//.*\n', '\n', input_str)

                return json.loads(input_str)
            except:
                print 'couldnt parse framelog jsonc'
                return {}
        else:
            return {}

    def outputFrameNote(self):
        ''' write out current frame note into a text file; edit if needed'''
        if not (self.isProcessed):
            return
        try:
            with open(self.defaultFrameNotePathFn, 'w') as f:
                json.dump(self.getFrameNoteCurrent(), f, indent=4)

            self.frameNoteFailed = False

        except:
            self.frameNoteFailed = True

    def loadFrameNoteInput(self):
        ''' read in frame note input, this will absorb any edits you made'''
        if not (self.isProcessed):
            return
        try:
            with open(self.defaultFrameNotePathFn, 'r') as f:
                lines = f.readlines()
            lines = "".join(lines)

            frameNote = json.loads(lines)
            return frameNote
        except:
            return self.getFrameNoteCurrent()

    def loadFramenoteOveride(self):
        if not (self.isProcessed):
            return
        try:
            with open(self.defaultFrameNoteOveridePathFn, 'r') as f:
                lines = f.readlines()
            lines = "".join(lines)

            lines = re.sub(r'\\\n', '', lines)
            lines = re.sub(r'//.*\n', '\n', lines)

            return json.loads(lines)
        except:
            print 'failed to load ', str(self.defaultFrameNoteOveridePathFn)
            return {}

    def getFrameData(self):
        ''' Return frameData. If no existing data, create new frameData-dict. If 
            frameData already exists and was loaded; there are multiple opportunites
            to update/add/delete the existing data here, based on gui-cmd's and
            editing files in an editor. Data is ultimately consumed by output.
        '''

        if self.isProcessed:

            if not (self.frameNoteFailed):
                #override any param for this frame in notepad
                frameData = self.loadFrameNoteInput()
            else:
                #couldnt find/open txt file; keep the same
                frameData = self.getFrameNoteCurrent()

            if self.displayFrameScoring.checkHasContents():

                #gui-cmd: writeFrame+Score - update/add-to scoring dict
                #note: if gui-cmd is not called, displayFrameScoring has no contents

                frameData['scoring'] = self.mergeDicts(
                    main=self.getFrameScoreCurrentDict(),
                    update=self.displayFrameScoring.getAll(),
                    b_add=True)

            if self.bOverideFramenote:

                #gui-cmd: writeFrame+Override - add/overwrite params from notepad

                frameData = self.mergeDicts(main=frameData,
                                            update=self.loadFramenoteOveride(),
                                            b_add=False)

        else:

            #frameData is new; load the framedata from txt file
            frameData = self.loadFrameLogCurrent()

            frameData['orig_vid_index'] = self.frameInd

            frameData['scoring'] = self.displayFrameScoring.getAll()

        return frameData

    def getBaseNote(self):

        baseNote = copy.deepcopy(self.dataVid)
        try:
            del baseNote['frames']
        except:
            pass  #some metalogs don't have frames
        assert 'frames' not in baseNote.keys()
        return baseNote

    def getBaseFrameNote(self, frameNote):

        baseFrameNote = copy.deepcopy(frameNote)
        try:
            del baseFrameNote['scoring']
        except:
            pass  #some frameNotes don't have scoring
        assert 'scoring' not in baseFrameNote.keys()
        return baseFrameNote

    #TODO - refactor to separate module
    @classmethod
    def mergeDicts(cls, main, update, b_add=False):
        ''' 
            with terminal nodes in update(dict) overwrite the value at those
            nodes in main(dict) if they exist, or add them if b_add=True:
            
            b_add=False:
                main:   {"a": 1, "b": 2, "inner": {"z":1}} 
                update: {"b":99, "inner":{"z": -99}, "x":-55}
                ->      {"a": 1, "b": 99, "inner":{"z": -99}}
            b_add=True:
                main:   {"a": 1, "b": 2, "inner": {"z":1}} 
                update: {"b":99, "inner":{"z": -99}, "x":-55}
                ->      {"a": 1, "b": 99, "inner":{"z": -99}, "x":-55}
            
            (output should have updates and (possibly) adds but never deletes)
        '''

        try:
            assert isinstance(main, dict)
            assert isinstance(update, dict)
        except Exception as e:
            print e.message
            return main

        updateKeys, updateVals = cls.recurseKeys(update)

        newMain = cls.recurseUpdate(copy.deepcopy(main), updateKeys,
                                    updateVals)

        if b_add:

            newMain = cls.recurseAdd(copy.deepcopy(main), updateKeys,
                                     updateVals)

        return newMain

    @classmethod
    def recurseKeys(cls, inputDict):
        ''' build [nested] list for keys and vals in inputDict:
                inputDict:  {"a":1, "b":2, "c": {"c_a":17}}
                ->:         ["a", "b", ["c", "c_a"]],   [1, [None, 17], 2])
        '''
        keyList, valList = [], []

        for k in inputDict.keys():

            if isinstance(inputDict[k], dict):

                tmpKey, tmpVal = cls.recurseKeys(inputDict[k])

                nestedKey = [k]
                nestedVal = [None]

                if len(tmpKey) > 0:
                    nestedKey.extend(tmpKey)
                    nestedVal.extend(tmpVal)

                keyList.append(nestedKey)
                valList.append(nestedVal)

            else:
                keyList.append(k)
                valList.append(inputDict[k])

        return keyList, valList

    @classmethod
    def recurseUpdate(cls, inputDict, listKeys, listVals):
        ''' only update if key is in inputDict '''

        if inputDict is None:
            return None

        for _key, _val in zip(listKeys, listVals):

            if isinstance(_key, list):

                _dict = cls.recurseUpdate(
                    copy.deepcopy(inputDict.get(_key[0], None)), _key[1:],
                    _val[1:])

                inputDict[_key[0]] = _dict

            else:

                if inputDict.has_key(_key):
                    inputDict[_key] = _val
                else:
                    # main doesn't have that key
                    pass

        return inputDict

    @classmethod
    def recurseAdd(cls, inputDict, listKeys, listVals):

        if inputDict is None:
            inputDict = {}

        for _key, _val in zip(listKeys, listVals):

            if isinstance(_key, list):

                _dict = cls.recurseAdd(
                    copy.deepcopy(inputDict.get(_key[0], None)), _key[1:],
                    _val[1:])

                inputDict[_key[0]] = _dict

            else:

                inputDict[_key] = _val

        return inputDict
Exemplo n.º 6
0
class TrackFactory:
    ''' handles tracking processing and tracking-stored-data '''
    def __init__(self, on=False):
        self.on = on
        self.currentFrame = None
        self.currentFrameInd = -1

        self.trackingOnPrevious = None
        self.bTrackingOnChange = False

        self.currentTrackSuccess = False
        self.currentTrackScore = ScoreSchema()

        self.threshInitial = [(0, 0, 0), (255, 255, 255)]

        self.threshes = []

        self.lastFrame = None

        self.declaredBallColor = ""

        self.bPerformTrainOnNewData = False
        self.trainingData = []
        self.trainingThreshes = []

        self.bTrackTimer = False
        self.trackTimerData = {}

        self.savedParams = None

        # tp_: tracking parameters
        self.tp_trackAlgoEnum = 0
        self.tp_tracking_blur = 1
        self.tp_repair_iterations = 1
        self.tp_b_hsv = False

        # TrackingAlgo class inherits TrackingTemplate
        # and is instantiated here?

    def setInit(self, ballColor=""):
        self.declaredBallColor = ballColor

        if self.declaredBallColor == "green":
            self.threshInitial = [(29, 86, 6), (64, 255, 255)]

            self.threshes.append(tuple(self.threshInitial))
            self.threshes.append(((20, 60, 6), (40, 255, 255)))

        if self.declaredBallColor == "orange":

            thresh1 = ((6, 30, 120), (64, 255, 255))
            thresh2 = ((64, 100, 180), (90, 255, 255))
            thresh3 = ((90, 120, 200), (120, 255, 255))

            self.threshInitial = thresh1

            self.threshes = [thresh1, thresh2, thresh3]

    def setAlgoEnum(self, algoEnum):
        self.tp_trackAlgoEnum = algoEnum

    def setCmd(self,
               trackingOn,
               outputParams=None,
               alterParams=None,
               resetParams=None):

        self.on = trackingOn

        # this is for forcing a display "redraw" when track toggles On/Off
        if self.trackingOnPrevious is not None:
            if trackingOn != self.trackingOnPrevious:
                self.bTrackingOnChange = True
            else:
                self.bTrackingOnChange = False
        self.trackingOnPrevious = trackingOn

        if outputParams is not None:
            if outputParams:
                self.outputParams()
                g.switchOutputParams = False

        if alterParams is not None:
            if alterParams:
                self.saveParams()
                self.alterParams()
                g.switchAlterParams = False
                self.bTrackingOnChange = True

        if resetParams is not None:
            if resetParams:
                self.restParams()
                g.switchResetParams = False
                self.bTrackingOnChange = True

    def outputParams(self):
        try:
            with open("notes/tracking_params.json", "w") as f:
                json.dump(self.getTrackParams(), f, indent=4)
        except:
            print 'failed to output tracking params'

    def alterParams(self):
        try:
            with open("notes/tracking_params.json", "r") as f:
                d_params = json.load(f)
        except Exception as e:
            print 'failed to read in json'
            print e.message

        try:
            self.setTrackParams(**d_params)
        except Exception as e:
            print 'failed to set track params from json'
            print e

    def saveParams(self):
        self.savedParams = self.getTrackParams()

    def restParams(self):
        self.setTrackParams(**self.savedParams)

    def resetTracker(self):
        self.trackTimerData = {}

    def getTrackOnChange(self):
        ''' return True to make a pass thru inner loop of guiview
            only updating state related to tracking. This allows us to make
            changes immediately apparent in Display'''

        if self.bTrackingOnChange is None:
            return False
        else:
            return self.bTrackingOnChange

    def getTrackScore(self):
        if not (self.on): return None
        return self.currentTrackScore.getAll()

    def setFrameInd(self, frameInd):
        self.currentFrameInd = frameInd

    def setFrame(self, currentFrame):
        if not (self.on): return
        self.currentFrame = currentFrame

    def setFrameScore(self, frameScoreData):

        if not (self.on): return

        if frameScoreData is None: return
        if len(frameScoreData) != 2: return

        frameType, frameScore = frameScoreData

        objScoring = ScoreSchema()
        objScoring.load(frameScore)
        circleDataObj0 = objScoring.getData(objEnum=0)

        if frameType == "training":

            datum = self.buildTrainingDatum(circleDataObj0, self.currentFrame)

            if datum is not None:
                self.trainingData.append(datum)

                if self.bPerformTrainOnNewData:
                    self.trainProc()

        if frameType == "scoring":
            pass
            #do evaluation

    @classmethod
    def buildTrainingDatum(cls, cropRect, img):

        if cropRect is None or img is None:
            return None

        try:
            datum = {}
            datum['cropRect'] = cropRect
            datum['cropImg'] = crop_img(img.copy(), cls.absRect(cropRect))
            return datum
        except:
            return None

    def trainProc(self):
        ''' take training data and build thresh hi/lo from them '''

        if len(self.trainingData) < 1: return

        # only run iterthresh on latest img
        img = self.trainingData[len(self.trainingData) - 1].get(
            'cropImg', None)

        if img is None: return
        if img.shape[0] < 1 or img.shape[1] < 1: return

        circle_img = pixlist_to_pseduoimg(filter_pixels_circle(img))

        out_thresh = iterThreshA(circle_img, goal_pct=.95, steep=False)

        _lo, _hi = out_thresh[1][3], out_thresh[1][4]

        self.trainingThreshes.append((_lo, _hi))

        self.combine_threshes(self.trainingThreshes)

        self.threshInitial = (tuple(map(int, _lo)), tuple(map(int, _hi)))

        #TODO - update self.threshes, if necessary

    def setTrackTimer(self, bTrackTimer):
        if isinstance(bTrackTimer, bool):
            self.bTrackTimer = bTrackTimer

    def getTrackTimerData(self):
        return self.trackTimerData

    def getTrackTimerDataCurrent(self):
        return self.trackTimerData.get(self.currentFrameInd - 1, -1)

    def setTrackParams(self,
                       tracking_blur=None,
                       repair_iterations=None,
                       thresh_lo=None,
                       thresh_hi=None,
                       threshes=None):

        if tracking_blur is not None:
            self.tp_tracking_blur = tracking_blur

        if repair_iterations is not None:
            self.tp_repair_iterations = repair_iterations

        if thresh_lo is not None:
            self.threshInitial[0] = tuple(thresh_lo)

        if thresh_hi is not None:
            self.threshInitial[1] = tuple(thresh_hi)

        if threshes is not None:
            self.threshes = copy.copy(threshes)

    def getTrackParams(self):

        params = {}

        params['tracking_blur'] = self.tp_tracking_blur
        params['repair_iterations'] = self.tp_repair_iterations
        params['thresh_lo'] = self.threshInitial[0]
        params['thresh_hi'] = self.threshInitial[1]
        params['threshes'] = copy.copy(self.threshes)

        return params

    def trackFrame(self, b_log=False):
        '''
            Wrapper function for a particular trackAlgo:
                - unpack parameters
                - select the particular track algo to run
                - [possibly] time the function (if self.bTrackTimer)
                - [possibly] return log of img transform steps (if b_log)

            questions/todos:
                [ ] pass in objEnum to trackAlgo for multi-obj tracking

        '''

        if not (self.on): return

        tracking_blur = self.tp_tracking_blur
        repair_iterations = self.tp_repair_iterations

        thresh_lo = self.threshInitial[0]
        thresh_hi = self.threshInitial[1]

        threshes = copy.copy(self.threshes)

        last_frame = self.lastFrame

        if self.bTrackTimer:
            t0 = time.time()

        ret = None

        if self.tp_trackAlgoEnum == 0:

            ret = self.trackDefault(
                tracking_blur=tracking_blur,
                repair_iterations=repair_iterations,
                thresh_lo=thresh_lo,
                thresh_hi=thresh_hi,
                b_log=b_log,
                objEnum=0  #TODO-SS
            )

        elif self.tp_trackAlgoEnum == 1:

            ret = self.trackDemoNew(tracking_blur=tracking_blur,
                                    repair_iterations=repair_iterations,
                                    thresh_lo=thresh_lo,
                                    thresh_hi=thresh_hi,
                                    b_log=b_log
                                    # ,objEnum = 0
                                    )

        elif self.tp_trackAlgoEnum == 2:

            ret = self.trackMultiThresh1(tracking_blur=tracking_blur,
                                         repair_iterations=repair_iterations,
                                         threshes=threshes,
                                         b_log=b_log
                                         # ,objEnum = 0
                                         )

        elif self.tp_trackAlgoEnum == 3:

            ret = self.trackDummyRichLog(tracking_blur=tracking_blur,
                                         repair_iterations=repair_iterations,
                                         threshes=threshes,
                                         b_log=b_log,
                                         last_frame=last_frame
                                         # ,objEnum = 0
                                         )
        else:
            print 'trackAlgoEnum not recognized'

        if self.bTrackTimer:
            if self.currentFrameInd not in self.trackTimerData.keys():
                t_proc = time.time() - t0
                self.trackTimerData[self.currentFrameInd] = t_proc

        if ret is not None:
            return ret

    # tracker algos --------

    def trackDefault(self,
                     tracking_blur,
                     repair_iterations,
                     thresh_lo,
                     thresh_hi,
                     b_log=False,
                     objEnum=0):
        '''
            trackDefault:

                Template for writing a track algo.

                - add documentation notes, describing how this algo is different;
                  in this case we're describing the templating.

                 - organize all parameters used in func args; these are
                   retreived from the instance in parent function, trackFrame,
                   and thus read-only.
                    - add b_log and objEnum defaults to args

                 - write trackAlgo output data to instance properties:
                    self.currentTrackSuccess
                    self.currentTrackScore  (as a DataSchema.ScoreSchema)

                 - return None, unless b_log

                    - in which case, include a b_log section:
                        - add all possible transforms to 'keys' list.
                        - set 'data' for each possible key, mimicing control flow
                          for early return in the function
                        (this will be used to debug in notebooks, but is
                         not necessary for most purposes.)

            questions / todos:

                [ ] will we overwrite data before it hits b_log return data?

        '''

        img_t = transformA(self.currentFrame.copy(), tracking_blur)

        img_mask = threshA(img_t, threshLo=thresh_lo, threshHi=thresh_hi)

        if not (img_mask is None) and (img_mask.sum() != 0):

            img_mask_2 = repairA(img_mask, iterations=repair_iterations)

            x, y = find_xy(img_mask_2)
            radius = find_radius(img_mask_2)

            if radius > 0:
                self.currentTrackSuccess = True

                self.currentTrackScore.addCircle(self.circleToRect(
                    (x, y, radius)),
                                                 objEnum=objEnum)
            else:
                self.currentTrackSuccess = False
                self.currentTrackScore.reset()

        else:
            self.currentTrackSuccess = False
            self.currentTrackScore.reset()

        if b_log:

            keys = [
                'img_t', 'img_mask', 'img_repair', 'xy', 'radius',
                'scoreCircle'
            ]
            data = OrderedDict()
            for k in keys:
                data[k] = None

            data['img_t'] = img_t
            data['img_mask'] = img_mask

            if img_mask is not None:
                data['img_repair'] = img_mask_2
                data['xy'] = (x, y)
                data['radius'] = radius
                data['scoreCircle'] = self.currentTrackScore.getObjRect(0)

            return data

    def trackDemoNew(self,
                     tracking_blur,
                     repair_iterations,
                     thresh_lo,
                     thresh_hi,
                     b_log=False):
        '''
            trackDemoNew:

                Example for adding a non-default trackAlgo.

                Only a few small changes to this function:

                    - allow us to bypass repairA step by setting 
                      repair_iterations to 0

                    - early return when img_mask is blank
                
            questions / todos:

                [x] verify early return skips a section and verify the notebook
                    workflow process handles the missing data gracefully 
                    in mutliPlot()
                [ ] is a tracking_blur = 1 do any changes?
                [ ] does repair_iteration = 0 work in trackDefault()?

        '''

        img_t = transformA(self.currentFrame.copy(), tracking_blur)

        img_mask = threshA(img_t, threshLo=thresh_lo, threshHi=thresh_hi)

        if img_mask.sum() != 0:

            if repair_iterations > 0:
                img_repair = repairA(img_mask, iterations=repair_iterations)
                img_terminal = img_repair
            else:
                img_terminal = img_mask

            x, y = find_xy(img_terminal)
            radius = find_radius(img_terminal)

            if radius > 0:

                self.currentTrackSuccess = True

                self.currentTrackScore.addCircle(self.circleToRect(
                    (x, y, radius)),
                                                 objEnum=0)
            else:
                self.currentTrackSuccess = False
                self.currentTrackScore.reset()

        else:
            self.currentTrackSuccess = False
            self.currentTrackScore.reset()

        if b_log:

            keys = [
                'img_t', 'img_mask', 'img_repair', 'img_terminal', 'xy',
                'radius', 'scoreCircle'
            ]
            data = OrderedDict()
            for k in keys:
                data[k] = None

            data['img_t'] = img_t
            data['img_mask'] = img_mask

            if img_mask.sum() != 0:
                data['img_terminal'] = img_terminal
                data['xy'] = (x, y)
                data['radius'] = radius
                if repair_iterations > 0:
                    data['img_repair'] = img_repair
                if radius > 0:
                    data['scoreCircle'] = self.currentTrackScore.getObjRect(0)

            return data

    def trackMultiThresh1(self,
                          tracking_blur,
                          repair_iterations,
                          threshes,
                          b_log=False):
        '''
            trackMultiThresh1:

                Evolved from trackDemoNew; uses multiple thresh intervals
                
            questions / todos:

                [ ] multiple threshes

        '''

        img_t = transformA(self.currentFrame.copy(), tracking_blur)

        img_mask = threshMultiOr(img_t, threshes=threshes)

        if img_mask.sum() != 0:

            if repair_iterations > 0:
                img_repair = repairA(img_mask, iterations=repair_iterations)
                img_terminal = img_repair
            else:
                img_terminal = img_mask

            x, y = find_xy(img_terminal)
            radius = find_radius(img_terminal)

            if radius > 0:

                self.currentTrackSuccess = True

                self.currentTrackScore.addCircle(self.circleToRect(
                    (x, y, radius)),
                                                 objEnum=0)
            else:
                self.currentTrackSuccess = False
                self.currentTrackScore.reset()

        else:
            self.currentTrackSuccess = False
            self.currentTrackScore.reset()

        if b_log:

            keys = [
                'img_t', 'img_mask', 'img_repair', 'img_terminal', 'xy',
                'radius', 'scoreCircle'
            ]
            data = OrderedDict()
            for k in keys:
                data[k] = None

            data['img_t'] = img_t
            data['img_mask'] = img_mask

            if img_mask.sum() != 0:
                data['img_terminal'] = img_terminal
                data['xy'] = (x, y)
                data['radius'] = radius
                if repair_iterations > 0:
                    data['img_repair'] = img_repair
                if radius > 0:
                    data['scoreCircle'] = self.currentTrackScore.getObjRect(0)

            return data

    def trackDummyRichLog(self,
                          tracking_blur,
                          repair_iterations,
                          threshes,
                          last_frame,
                          b_log=False):
        '''
            trackDummyRichLog:

                copied from trackMultiThresh1; here we're just adding 
                extra track_log keys like img_diff and img_diff_repair
                to see how they'll impact reporting functions downstream.

                this is the start though of looking at adding a movement
                element to trackers and we're adding the last_frame input / 
                self.lastFrame output.

        '''

        img_t = transformA(self.currentFrame.copy(), tracking_blur)

        img_mask = threshMultiOr(img_t, threshes=threshes)

        # add new-lines in here:
        if last_frame is not None and False:

            img_diff = cv2.absdiff(self.currentFrame, last_frame)

            if repair_iterations > 0:
                img_diff_repair = repairA(img_diff,
                                          iterations=repair_iterations)

        self.lastFrame = self.currentFrame.copy()

        if img_mask.sum() != 0:

            if repair_iterations > 0:
                img_repair = repairA(img_mask, iterations=repair_iterations)
                img_terminal = img_repair
            else:
                img_terminal = img_mask

            x, y = find_xy(img_terminal)
            radius = find_radius(img_terminal)

            if radius > 0:

                self.currentTrackSuccess = True

                self.currentTrackScore.addCircle(self.circleToRect(
                    (x, y, radius)),
                                                 objEnum=0)
            else:
                self.currentTrackSuccess = False
                self.currentTrackScore.reset()

        else:
            self.currentTrackSuccess = False
            self.currentTrackScore.reset()

        if b_log:

            keys = [
                'img_t', 'img_mask', 'img_repair', 'img_dummy', 'img_dummy_2',
                'img_diff', 'img_diff_repair'
                'img_terminal', 'img_terminal_2'
                'xy', 'radius', 'scoreCircle'
            ]
            data = OrderedDict()
            for k in keys:
                data[k] = None

            data['img_t'] = img_t
            data['img_mask'] = img_mask

            data['img_dummy'] = transformA(self.currentFrame.copy(), 11)
            data['img_dummy_2'] = transformA(self.currentFrame.copy(), 5)

            if last_frame is not None and False:
                data['img_diff'] = img_diff
                data['img_diff_repair'] = img_diff_repair

            if img_mask.sum() != 0:
                data['img_terminal'] = img_terminal
                data['img_terminal_2'] = img_terminal
                data['xy'] = (x, y)
                data['radius'] = radius
                if repair_iterations > 0:
                    data['img_repair'] = img_repair
                if radius > 0:
                    data['scoreCircle'] = self.currentTrackScore.getObjRect(0)

            return data

    # helper functions ------

    @staticmethod
    def absRect(input_rect):
        ''' takes an (opencv style) relative rect, returns an absolute rect.
                (x0,y0, d_x, d_y) -> ((xo,y0),(x1, y1)) 
                note: must be tuples, not lists; to use in opencv functions
        '''

        x = copy.copy(input_rect)

        rect = ((int(x[0]), int(x[1])), (int(x[0] + x[2]), int(x[1] + x[3])))

        return rect

    @staticmethod
    def circleToRect(input_circle):
        ''' takes x,y, radius, fits to enclosing relative-format rect
            (x,y, radius)  -> (x0,y0, d_x, d_y) 
        '''

        x, y, radius = copy.copy(input_circle)

        x0 = int(x - radius)
        y0 = int(y - radius)
        dx = int(2 * radius)
        dy = int(2 * radius)

        return (x0, y0, dx, dy)

    @staticmethod
    def combine_threshes(data, liberal=True):
        ''' data is a list of (lo, hi) 3-ple's; find the union '''

        if len(data) < 1:
            return (np.array([0, 0, 0], dtype='uint8'),
                    np.array([255, 255, 255], dtype='uint8'))

        _lo, _hi = [[255, 255, 255], [0, 0, 0]]

        for row in data:

            lo, hi = row[0], row[1]

            for i, clr in enumerate(lo):
                if clr < _lo[i]:
                    _lo[i] = clr

            for i, clr in enumerate(hi):
                if clr > _hi[i]:
                    _hi[i] = clr

        return (np.array(_lo, dtype='uint8'), np.array(_hi, dtype='uint8'))
Exemplo n.º 7
0
def show_scoring_on_off_1(input_test_child_dir,
                          input_circle_data,
                          b_rebench=False):
    ''' test that turning show_scoring on/off affects main display panel
        test that show_scoring=on + no scoring data is handled
            
            input params:  - tests have dif size frames
                           - tests have dif scoring-data
    '''

    # setup ------
    TEST_CHILD_DIR = input_test_child_dir

    stub_frame = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "stubframe.png"))
    bench_yes_scoring = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_yes_score.png"))
    bench_no_scoring = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_no_score.png"))

    some_scoring = ScoreSchema()
    some_scoring.addCircle(input_circle_data)
    stub_some_score = some_scoring.getAll()

    none_scoring = ScoreSchema()
    stub_none_score = none_scoring.getAll()

    diff = ImgDiff(log_path=DIFF_LOG_DIR)

    # run test -----
    stage = StagingDisplay()
    stage.all_display_methods(b_showscoring=True,
                              stub_frame=stub_frame.copy(),
                              stub_scorecurrent=copy.deepcopy(stub_some_score))
    scoring_on_output = stage.mock_get_frame()

    stage = StagingDisplay()
    stage.all_display_methods(
        b_showscoring=False  #test-variable
        ,
        stub_frame=stub_frame.copy(),
        stub_scorecurrent=copy.deepcopy(stub_some_score))
    scoring_off_output = stage.mock_get_frame()

    stage = StagingDisplay()
    stage.all_display_methods(
        b_showscoring=True,
        stub_frame=stub_frame.copy(),
        stub_scorecurrent=copy.deepcopy(stub_none_score)  #test-variable
    )
    scoring_none_output = stage.mock_get_frame()

    #rebench ---
    if b_rebench:
        if verifyAction(prefix="\nrebench:" + input_test_child_dir):
            return
        cv2.imwrite(
            os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                         "bench_yes_score.png"), scoring_on_output)
        cv2.imwrite(
            os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                         "bench_no_score.png"), scoring_off_output)
        return

    # verify ----
    assert diff.diffImgs(bench_yes_scoring, scoring_on_output)

    assert diff.diffImgs(bench_no_scoring, scoring_off_output)

    assert diff.diffImgs(bench_no_scoring, scoring_none_output)

    assert diff.diffImgs(scoring_on_output, scoring_off_output,
                         noLog=True) == False
Exemplo n.º 8
0
def scoring_annotate_obj(input_test_child_dir, b_rebench=False):
    ''' test that we annotate score objects in main_display

            note: we can't initialize with annotateObjEnum=True or we get unhandled err
            
            input params:  - different scores (stored as json file in test dir)
    '''

    # setup ------
    TEST_CHILD_DIR = input_test_child_dir

    stub_frame = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "stubframe.png"))
    bench_main = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_main.png"))
    bench_score = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_score.png"))
    bench_naframe = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "naframe.png"))

    stub_score_obj = ScoreSchema()

    with open(os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "stubscore.json"),
              "r") as f:
        stub_score_obj.load(json.load(f))

    stub_score = stub_score_obj.getAll()

    diff = ImgDiff(log_path=DIFF_LOG_DIR)

    # run test -----

    stage = StagingDisplay()
    stage.some_display_methods(
        p_all=True,
        stub_frame=stub_frame.copy(),
        stub_scorecurrent=copy.deepcopy(stub_score),
        b_showscoring=True,
        annotateObjEnum=False  #note
    )
    stage.some_display_methods(p_all_byframe=True,
                               p_input=True,
                               stub_frame=stub_frame.copy(),
                               stub_scorecurrent=copy.deepcopy(stub_score),
                               b_showscoring=True,
                               annotateObjEnum=True)
    main1 = stage.mock_get_frame()
    score1 = stage.mock_get_score_frame()

    #rebench ---
    if b_rebench:

        if verifyAction(prefix="\nrebench:" + input_test_child_dir):
            return

        cv2.imwrite(
            os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_main.png"),
            main1)

        cv2.imwrite(
            os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_score.png"),
            score1)
        return

    # verify ----

    assert diff.diffImgs(bench_main, main1)
    assert diff.diffImgs(bench_score, score1)
Exemplo n.º 9
0
def scoring_obj_enum(input_test_child_dir,
                     input_obj_enum,
                     b_wrong=False,
                     b_rebench=False):
    ''' test that showscoring with properly formed is drawn to main_display and
        score_display
            
            input params:  - different scores (stored as json file in test dir)
                           - different scoringenum's to focus on with score_display
                           - b_wrong: if True, then there is no score with that
                                       input_obj_enum, thus no score_display
    '''

    # setup ------
    TEST_CHILD_DIR = input_test_child_dir

    stub_frame = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "stubframe.png"))
    bench_main = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_main.png"))
    bench_score = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_score.png"))
    bench_naframe = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "naframe.png"))

    stub_score_obj = ScoreSchema()

    with open(os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "stubscore.json"),
              "r") as f:
        stub_score_obj.load(json.load(f))

    stub_score = stub_score_obj.getAll()

    diff = ImgDiff(log_path=DIFF_LOG_DIR)

    # run test -----

    stage = StagingDisplay()
    stage.all_display_methods(
        stub_frame=stub_frame.copy(),
        stub_scorecurrent=copy.deepcopy(stub_score),
        b_showscoring=True,
        i_scoringenum=input_obj_enum  #test-variable
    )
    main1 = stage.mock_get_frame()
    score1 = stage.mock_get_score_frame()

    #rebench ---
    if b_rebench:

        if verifyAction(prefix="\nrebench:" + input_test_child_dir):
            return

        cv2.imwrite(
            os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "bench_main.png"),
            main1)

        if b_wrong:

            cv2.imwrite(
                os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "naframe.png"),
                score1)
        else:

            cv2.imwrite(
                os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                             "bench_score.png"), score1)
        return

    # verify ----

    assert diff.diffImgs(bench_main, main1)

    if b_wrong:
        assert diff.diffImgs(bench_naframe, score1)
    else:
        assert diff.diffImgs(bench_score, score1)
Exemplo n.º 10
0
def show_tracking_on_off_1(input_test_child_dir,
                           input_circle_data,
                           b_rebench=False):
    ''' test that turning tracking on/off affecta main_display
        and that it affects score_display
            
            input params:  - tests have dif size frames
                           - tests have dif scoring-data

        TODO:
            [x] modulo zero resize
    '''

    # setup ------
    TEST_CHILD_DIR = input_test_child_dir

    stub_frame = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR, "stubframe.png"))
    bench_yes_tracking = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                     "bench_yes_track_main.png"))
    bench_no_tracking = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                     "bench_no_track_main.png"))
    bench_score = cv2.imread(
        os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                     "bench_yes_track_score.png"))

    some_scoring = ScoreSchema()
    some_scoring.addCircle(input_circle_data)
    stub_some_score = some_scoring.getAll()

    none_scoring = ScoreSchema()
    stub_none_score = none_scoring.getAll()

    diff = ImgDiff(log_path=DIFF_LOG_DIR)

    # run test -----

    #1:
    stage = StagingDisplay()
    stage.all_display_methods(stub_frame=stub_frame.copy(),
                              stub_trackscore=copy.deepcopy(stub_some_score))
    main1 = stage.mock_get_frame()
    score1 = stage.mock_get_score_frame()

    #2:
    stage = StagingDisplay()
    stage.all_display_methods(
        stub_frame=stub_frame.copy(),
        stub_trackscore=copy.deepcopy(stub_none_score)  #test-variable
    )
    main2 = stage.mock_get_frame()
    score2 = stage.mock_get_score_frame()

    #3:
    stage = StagingDisplay()
    stage.all_display_methods(
        b_showscoring=True  #test-variable
        ,
        stub_frame=stub_frame.copy(),
        stub_trackscore=copy.deepcopy(stub_some_score))
    main3 = stage.mock_get_frame()
    score3 = stage.mock_get_score_frame()

    #rebench ---
    if b_rebench:

        if verifyAction(prefix="\nrebench:" + input_test_child_dir):
            return

        cv2.imwrite(
            os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                         "bench_yes_track_main.png"), main1)
        cv2.imwrite(
            os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                         "bench_no_track_main.png"), main2)
        cv2.imwrite(
            os.path.join(TEST_PARENT_DIR, TEST_CHILD_DIR,
                         "bench_yes_track_score.png"), score3)
        return

    # verify ----

    assert diff.diffImgs(bench_yes_tracking, main1)

    assert diff.diffImgs(bench_no_tracking, main2)

    assert diff.diffImgs(bench_yes_tracking, main3)

    assert diff.diffImgs(main1, main2, noLog=True) == False

    assert diff.diffImgs(bench_score, score1)

    assert score2 is None

    assert diff.diffImgs(bench_score, score3)