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
def test_checkHasValid_1(): score = { "0": { "type": "circle", "data": [20, 40, 50, 60] }, "1": { "type": "circle", "data": [-10, -20, 40, 40] } } ss = ScoreSchema() ss.load(score) assert ss.checkHasValid() score = { "0": { "type": "circle", "data": [-10, 20, 40, 40] }, "1": { "type": "circle", "data": [10, 20, -40, 40] } } ss = ScoreSchema() ss.load(score) assert ss.checkHasValid() == False
def test_getObjRect_1(): score = { "0": { "type": "ray", "data": [[100, 50], [200, 75]] }, "1": { "type": "ray", "data": [[200, 75], [100, 50]] } } ss = ScoreSchema() ss.load(score) assert ss.getObjRect(0) == ss.getObjRect(1) assert ss.getObjRect(0) == (100, 50, 100, 25) score = {"0": {"type": "ray", "data": [[100, 50], [200, 25]]}} ss.load(score) ss.getObjRect(0) == (100, 25, 100, 25)
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 test_getObjRect_2(): score = {"1": {"type": "circle", "data": [100, 50, 99, 99]}} ss = ScoreSchema() ss.load(score) assert ss.getObjRect(1) == (100, 50, 99, 99)
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]))
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
def test_toScalars(): # test basic method score = {"0": {"type": "circle", "data": [100, 150, 60, 58]}} ss = ScoreSchema() ss.load(score) scalarsDict = ss.toScalars() ANSWER = { 'obj_exists_0': True, 'obj_type_0': 'circle', 'data0_0': 100, 'data1_0': 150, 'data2_0': 60, 'data3_0': 58 } assert cmp(scalarsDict, ANSWER) == 0 # test method on ray-type object score = {"0": {"type": "ray", "data": [[100, 150], [60, 58]]}} ss = ScoreSchema() ss.load(score) scalarsDict = ss.toScalars() ANSWER = { 'obj_exists_0': True, 'obj_type_0': 'ray', 'data0_0': 100, 'data1_0': 150, 'data2_0': 60, 'data3_0': 58 } assert cmp(scalarsDict, ANSWER) == 0 # test multi-obj's + non-traditional objEnums score = { "1": { "type": "circle", "data": [100, 150, 60, 58] }, "3": { "type": "ray", "data": [[100, 150], [60, 58]] } } ss = ScoreSchema() ss.load(score) scalarsDict = ss.toScalars() ANSWER = { 'obj_exists_1': True, 'obj_type_1': 'circle', 'data0_1': 100, 'data1_1': 150, 'data2_1': 60, 'data3_1': 58, 'obj_exists_3': True, 'obj_type_3': 'ray', 'data0_3': 100, 'data1_3': 150, 'data2_3': 60, 'data3_3': 58 } assert cmp(scalarsDict, ANSWER) == 0 # test non-default num_data_cols argument score = {"0": {"type": "circle", "data": [100, 150, 60, 58]}} ss = ScoreSchema() ss.load(score) scalarsDict = ss.toScalars(num_data_cols=6) ANSWER = { 'obj_exists_0': True, 'obj_type_0': 'circle', 'data0_0': 100, 'data1_0': 150, 'data2_0': 60, 'data3_0': 58, 'data4_0': None, 'data5_0': None } assert cmp(scalarsDict, ANSWER) == 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)
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)