From 6d7c870be328a8f9f4b1d9e88ac0dfcbc55397fc Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Sat, 5 May 2018 23:27:52 +0200 Subject: [PATCH] Storing metrics + displaying table --- python_scripts/heatmap.py | 57 ++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/python_scripts/heatmap.py b/python_scripts/heatmap.py index 3a6e798..8976a15 100644 --- a/python_scripts/heatmap.py +++ b/python_scripts/heatmap.py @@ -15,13 +15,18 @@ import subprocess import json from threading import Thread import termios, fcntl, os +import glob +import os class Heatmap: - def __init__(self, metricsSize, logger, coordinates_filename): + def __init__(self, metricsSize, logger, coordinates_filename, tag): self.coordinates_filename = coordinates_filename self.logger = logger self.metricsSize = metricsSize - self.metrics = np.zeros((metricsSize[1], metricsSize[0])) # (y, x) + self.tag = tag + self.metricSaveDiff = 60*5 # save metrics every 5 minutes + self.loadMetrics() + self.screenDrawCorners = np.array([ [0,0], [metricsSize[0]-1,0], @@ -32,15 +37,17 @@ class Heatmap: self.loadCoordinates() self.windowRoot = Tk.Tk() self.windowRoot.geometry('800x600+4000+0') + self.windowRoot.title('Heatmap') self.windowRoot.attributes("-fullscreen", True) imageWindowSize = tuple(metricsSize) # self.windowRoot.geometry('%dx%d+%d+%d' % (imageWindowSize[0],imageWindowSize[1],0,0)) # we go full screen so not needed self.canvas = Tk.Canvas(self.windowRoot,width=imageWindowSize[0],height=imageWindowSize[1],bd=0, highlightthickness=0, relief='ridge') self.canvas.pack(fill="both", expand=True) - self.mapSize = [1200,400] + self.mapSize = [1600,600] self.mapWindowRoot = Tk.Toplevel(master=self.windowRoot) - self.mapWindowRoot.geometry('%dx%d' % tuple(self.mapSize)) + self.mapWindowRoot.geometry('%dx%d+0+800' % tuple(self.mapSize)) + self.mapWindowRoot.title("Tracking Overview") self.mapCanvas = Tk.Canvas(self.mapWindowRoot,width=self.mapSize[0],height=self.mapSize[1],bd=0, highlightthickness=0, relief='ridge') self.mapCanvas.create_rectangle(20, 50, 22, 350, fill="black", width=0, tags="screenTop") self.mapCanvas.create_rectangle(600, 50, 602, 300, fill="black", width=0, tags="screenSide") @@ -79,6 +86,25 @@ class Heatmap: self.logger.info("Window size: %s", self.windowGeometry) self.updateWindow() + def getOutputPrefix(self): + return "output/metrics-%s-%dx%d-" % (self.tag, self.metricsSize[0], self.metricsSize[1]) + + def loadMetrics(self): + list_of_files = glob.glob('%s*.p' % self.getOutputPrefix()) + if len(list_of_files) < 1: + self.metrics = np.zeros((self.metricsSize[1], self.metricsSize[0])) # (y, x) + else: + latest_file = max(list_of_files, key=os.path.getctime) + with open(latest_file, "rb") as f: + self.metrics = pickle.load(f) + self.lastMetricSave = time.time() + + def saveMetrics(self): + name = "{}{}.p".format(self.getOutputPrefix(), time.strftime("%Y-%m-%d %H:%M:%S")) + with open(name, "wb") as fp: + pickle.dump(self.metrics, fp) + self.lastMetricSave = time.time() + def onKeyPress(self, event=None, charachter=None): if event is None and charachter is not None: k = charachter @@ -124,6 +150,8 @@ class Heatmap: def keepWindowUpdated(self): while True: self.updateWindow() + if time.time() - self.lastMetricSave > self.metricSaveDiff: + self.saveMetrics() def updateFromJson(self, frame): t1 = time.time() @@ -168,7 +196,7 @@ class Heatmap: dz = face['head_pos'][2]/mmPerPixel # front/back p1x = int(20 + dz) - p1y = int(virtualWidth / 2 + 50 + dx) + p1y = int(virtualWidth / 2 + 50 - dx) p2x = int(600 + dz) p2y = int(virtualHeight / 2 + 50 + dy) @@ -176,7 +204,7 @@ class Heatmap: self.mapCanvas.create_oval(p2x-3, p2y-3, p2x+3, p2y+3, fill="red", width=0, tags="figure") p3x = int(20) - p3y = int(float(face['target'][0]) / self.metricsSize[0] * virtualWidth + 50) + p3y = int(virtualWidth + 50 - (float(face['target'][0]) / self.metricsSize[0] * virtualWidth)) p4x = int(600) p4y = int(float(face['target'][1]) / self.metricsSize[1] * virtualHeight + 50) @@ -185,7 +213,13 @@ class Heatmap: self.logger.debug("DRAW FACE TO", face, (p1x,p1y), "AND", (p2x,p2y)) - + def updateTable(self): + # clear terminal + os.system('cls' if os.name == 'nt' else 'clear') + print("{} gazes".format(len(self.currentTargets))) + print("{:>5} {:>10} {:>10} {:>10} {:>5} {:>5}".format(" ", "x", "y", "z", "angle", "angle", )) + for face in self.currentTargets: + print(u"{:>5} {:>10} mm {:>10} mm {:>10} mm {:>5.2f}\xb0 {:>5.2f}\xb0".format(face['fid'], face['head_pos'][0], face['head_pos'][1], face['head_pos'][2], face['gaze_angle'][0], face['gaze_angle'][1])) def updateWindow(self): t1 = time.time() @@ -193,9 +227,11 @@ class Heatmap: # convert to colormap, thanks to: https://stackoverflow.com/a/10967471 colormap = cm.plasma colormap = cm.CMRmap + colormap = cm.nipy_spectral normalisedMetrics = np.uint8(colormap(normalisedMetrics)*255) image = Image.fromarray(normalisedMetrics) self.updateMap() + self.updateTable() # Too clunky for now: # if len(self.currentTargets) > 0: # c = ImageDraw.Draw(image) @@ -264,7 +300,7 @@ class Heatmap: -def main(openface_exec, coordinates_filename, device=0): +def main(openface_exec, coordinates_filename, tag, device=0): logging.basicConfig( format='%(asctime)-15s %(name)s %(levelname)s: %(message)s' ) logger = logging.getLogger(__name__) @@ -285,7 +321,7 @@ def main(openface_exec, coordinates_filename, device=0): metricsSize = [1920/2,1080/2] metricsSize = [800,600] - heatmap = Heatmap(metricsSize, logger, coordinates_filename) + heatmap = Heatmap(metricsSize, logger, coordinates_filename, tag) # heatmap.runCam(openface_exec, device) thread = Thread(target=heatmap.runCam, args=(openface_exec, device)) thread.start() @@ -416,7 +452,8 @@ if __name__ == '__main__': parser.add_argument('--of', default="../build/bin/FaceLandmarkVidMulti", help='The modified version of OpenFace\'s FaceLandmarkVidMulti') parser.add_argument('--coordinates', default="coordinates.p", help='Use a specific coordinates.p file') parser.add_argument('--device', type=int, default=0, help='Webcam device nr. to use') + parser.add_argument('--tag', type=str, default="default", help='Heatmap instance. Determines the name of saved (& thus loaded) files') args = parser.parse_args() - main(openface_exec=args.of, coordinates_filename=args.coordinates, device=args.device) + main(openface_exec=args.of, coordinates_filename=args.coordinates, device=args.device, tag=args.tag)