diff --git a/display/gui/tkinter_gui.py b/display/gui/tkinter_gui.py index c8f2425..17758dc 100644 --- a/display/gui/tkinter_gui.py +++ b/display/gui/tkinter_gui.py @@ -17,7 +17,7 @@ ALERT_DURATION = 5 LOGGER_WIDTH = 49 -PAD_MENU = 85 +PAD_MENU = 83 COLOR_LIGHT = '#4E4D4A' COLOR_DARK = '#353432' @@ -43,17 +43,18 @@ def __init__(self, name, image_processors={}): self.frame.grid(rowspan=3, sticky=(tk.N, tk.S)) ### Top Frame - self.top_frame = TopFrame(self.frame, bg=COLOR_DARK, padx=10, pady=10) + self.top_frame = TopFrame(self.frame, self, image_processors, + bg=COLOR_DARK, padx=0, pady=5) ### Bottom Frame self.bot_frame = BotFrame(self.frame, self, image_processors, - bg=COLOR_LIGHT, padx=10, pady=0) + bg=COLOR_DARK, padx=0, pady=0) self.bot_frame.addViewports() # Grid Frames self.top_frame.grid(row=0, column=0) # self.mid_frame.grid(row=1, column=0) - self.bot_frame.grid(row=2, column=0, pady=(0, 10)) + self.bot_frame.grid(row=2, column=0, pady=(0, 5)) self.root.bind("", lambda e: e.widget.quit()) @@ -235,11 +236,11 @@ def __init__(self, root): def createItems(self): self.label_text = tk.StringVar() - font = tkFont.Font(family="Arial", size=12) + font = tkFont.Font(family="Verdana", size=12, weight='bold') # Alert label alert_label = tk.Label(self.root, font=font, - textvariable=self.label_text, bg=COLOR_LIGHT) + textvariable=self.label_text, bg=COLOR_LIGHT, pady=5) alert_label.grid(row=0, column=0, columnspan=2, sticky=(tk.W+tk.E)) # Set scrollbar @@ -340,8 +341,11 @@ def apply(self): class TopFrame(tk.Frame): - def __init__(self, parent, **options): + def __init__(self, parent, ui, image_processors, **options): tk.Frame.__init__(self, parent, options) + self.parent = parent + self.ui = ui + self.image_processors = image_processors self.bg = self.cget('bg') self.menu_main = None @@ -353,7 +357,7 @@ def __init__(self, parent, **options): def createItems(self): # Main menu frame - self.menu_main = MenuMain(self, bg=self.bg, highlightthickness=0) + self.menu_main = MenuMain(self, self.ui, self.image_processors, bg=self.bg, highlightthickness=0) self.menu_main.pack(side=tk.LEFT, padx=PAD_MENU, fill=tk.X, expand=1) # Tactical frame @@ -361,7 +365,7 @@ def createItems(self): self.tactical_frame.pack(side=tk.LEFT, padx=0, fill=tk.BOTH, expand=1) # Calibration menu frame - self.menu_cal = MenuCal(self, bg=self.bg, highlightthickness=0) + self.menu_cal = MenuCal(self, self.ui, self.image_processors, bg=self.bg, highlightthickness=0) self.menu_cal.pack(side=tk.LEFT, padx=PAD_MENU, fill=tk.X, expand=1) class BotFrame(tk.Frame): @@ -416,7 +420,7 @@ def createCalLabels(self): # Frame for alert info label frame = tk.Frame(self, padx=0, pady=0, bg=self.bg) self.label_alert = tk.Label(frame, text="Alert Messages", - font=("Verdana", 21, "bold"), + font=("Verdana", 16, "bold"), bg=self.bg_light, fg="#353432") self.label_alert.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) frame.grid(row=0, column=1, sticky=(tk.W + tk.E)) @@ -440,64 +444,68 @@ def update(self): class MenuCal(tk.Frame): - def __init__(self, parent, **options): + def __init__(self, parent, ui, image_processors, **options): tk.Frame.__init__(self, parent, options) self.parent = parent + self.ui = ui + self.image_processors = image_processors self.method = None - self.size = None + self.zone = None # Build Menu Interface self.createItems() def createItems(self): - # Calibrate Button - tk.Button(self, text="Calibrate\nSystem", font=("Verdana", 12, "bold"), - pady=10, padx=2, bg='green', relief=tk.FLAT, - command=self.callbackCalibrate).pack(side=tk.TOP, pady=10) - - # Simple separator (Horizontal) - separator = tk.Frame(self, width=2, height=2, bd=1, relief=tk.FLAT) - separator.pack(side=tk.TOP, pady=10, padx=5, fill=tk.X) - - # Calibration Method - tk.Label(self, text="Calibration\nMethod", font=("Verdana", 10, "bold"), bg=COLOR_LIGHT).pack(side=tk.TOP, fill=tk.X) - self.method = MultiRadio(self, - text=("Point", "Color"), value=("POINT", "COLOR"), - callback=self.callbackCalibrate, - side=tk.TOP, fill=tk.X).pack(fill=tk.X, side=tk.TOP) - - # Simple separator (Horizontal) - separator = tk.Frame(self, width=2, height=2, bd=1, relief=tk.FLAT) - separator.pack(side=tk.TOP, pady=10, padx=5, fill=tk.X) +# # Calibrate Button +# tk.Button(self, text="Calibrate\nSystem", font=("Verdana", 12, "bold"), +# pady=10, padx=2, bg='green', relief=tk.FLAT, +# command=self.callbackCalibrate).pack(side=tk.TOP, pady=10) +# +# # Simple separator (Horizontal) +# separator = tk.Frame(self, width=2, height=2, bd=1, relief=tk.FLAT) +# separator.pack(side=tk.TOP, pady=10, padx=5, fill=tk.X) +# +# # Calibration Method +# tk.Label(self, text="Calibration\nMethod", font=("Verdana", 10, "bold"), bg=COLOR_LIGHT).pack(side=tk.TOP, fill=tk.X) +# self.method = MultiRadio(self, +# text=("Point", "Color"), value=("POINT", "COLOR"), +# callback=self.callbackCalibrate, +# side=tk.TOP, fill=tk.X).pack(fill=tk.X, side=tk.TOP) +# +# # Simple separator (Horizontal) +# separator = tk.Frame(self, width=2, height=2, bd=1, relief=tk.FLAT) +# separator.pack(side=tk.TOP, pady=10, padx=5, fill=tk.X) # Zone Type tk.Label(self, text="Zone Type", font=("Verdana", 10, "bold"), bg=COLOR_LIGHT).pack(side=tk.TOP, fill=tk.X) - self.size = MultiRadio(self, + self.zone = MultiRadio(self, text=("Normal", "Small"), value=("NORMAL", "SMALL"), callback=self.callbackSetZone, - side=tk.TOP, fill=tk.X).pack(fill=tk.X, side=tk.TOP) + side=tk.TOP, fill=tk.X) + self.zone.pack(fill=tk.X, side=tk.TOP) - def callbackCalibrate(self): - if self.method.variable == "POINT": - pass - else: - pass +# def callbackCalibrate(self): +# if self.method.variable == "POINT": +# pass +# else: +# pass def callbackSetZone(self): - if self.zone.variable == "NORMAL": - pass - else: - pass - + # Set zone distances + for img_proc in self.image_processors: + img_proc.scm.setCalibrationDistances(self.zone.variable.get()) + + logging.debug('setting zone distances %s' % self.zone.variable.get()) class MenuMain(tk.Frame): - def __init__(self, parent, **options): + def __init__(self, parent, ui, image_processors, **options): tk.Frame.__init__(self, parent, options) self.parent = parent + self.ui = ui self.power = False self.text_power = tk.StringVar() self.button_power = None diff --git a/display/tactical/tactical.py b/display/tactical/tactical.py index d1e9aee..ba17707 100644 --- a/display/tactical/tactical.py +++ b/display/tactical/tactical.py @@ -49,19 +49,21 @@ def update(self): #continue self.displayTarget(target) + + zone_distances = self.data_proc.tca.image_processors[0].scm.getCalibrationDistances() # Display alerts - if distance((0, 0), target.pos) < 4.8: + if distance((0, 0), target.pos) < zone_distances[0] - 0.2: target.left_safe = False - if distance((0, 0), target.pos) < 9.8: + if distance((0, 0), target.pos) < zone_distances[1] - 0.2: target.left_alert = False - if distance((0, 0), target.pos) >= 10 and target.left_alert == False: + if distance((0, 0), target.pos) >= zone_distances[1] and target.left_alert == False: self.data_proc.tca.ui.displayAlert("Target has left the ALERT zone!!!") self.data_proc.tca.ui.logAlert("Target has left the ALERT zone!!!") target.left_alert = True target.left_safe = True - elif distance((0, 0), target.pos) >= 5 and target.left_safe == False: + elif distance((0, 0), target.pos) >= zone_distances[0] and target.left_safe == False: self.data_proc.tca.ui.displayAlert("Target has entered the ALERT zone!!!") self.data_proc.tca.ui.logAlert("Target has entered the ALERT zone!!!") target.left_safe = True diff --git a/processors/data/target.py b/processors/data/target.py index e093591..0d1983c 100644 --- a/processors/data/target.py +++ b/processors/data/target.py @@ -6,7 +6,6 @@ from display.tactical.tactical import PERSIST_TIME, MAXLEN_DEQUE import prediction -from processors.image.calibration import DISTANCES_NORMAL, DISTANCES_SMALL ORIGIN = [0, 0] @@ -20,8 +19,9 @@ class Target(object): SAFE_RADIUS = 5 TURN_THRESHOLD_DEGREES = 4 - def __init__(self, pos, config=None): + def __init__(self, pos, config=None, ttm=None): self.pos = pos + self.ttm = ttm self.kalman = None self.prediction = None self.missed_updates = 0 @@ -48,12 +48,15 @@ def __init__(self, pos, config=None): Target.TIME_STEP = config.getfloat('track', 'time_step') Target.PREDICTION_RADIUS = config.getfloat('track', 'prediction_radius') Target.TURN_THRESHOLD_DEGREES = config.getfloat('track', 'turn_threshold') - if config.get('calibration', 'zone_size') == 'NORMAL': - Target.PREDICTION_RADIUS = DISTANCES_NORMAL[2] - Target.SAFE_RADIUS = DISTANCES_NORMAL[1] - elif config.get('calibration', 'zone_size') == 'SMALL': - Target.PREDICTION_RADIUS = DISTANCES_SMALL[2] - Target.SAFE_RADIUS = DISTANCES_SMALL[1] + zone_distances = self.ttm.data_processor.tca.image_processors[0].scm.getCalibrationDistances() + Target.PREDICTION_RADIUS = zone_distances[2] + Target.SAFE_RADIUS = zone_distances[1] +# if config.get('calibration', 'zone_size') == 'NORMAL': +# Target.PREDICTION_RADIUS = DISTANCES_NORMAL[2] +# Target.SAFE_RADIUS = DISTANCES_NORMAL[1] +# elif config.get('calibration', 'zone_size') == 'SMALL': +# Target.PREDICTION_RADIUS = DISTANCES_SMALL[2] +# Target.SAFE_RADIUS = DISTANCES_SMALL[1] def update(self, pos): @@ -82,6 +85,10 @@ def update(self, pos): self.kal_pred = cv.KalmanPredict(self.kalman) self.prediction = [self.kal_pred[0, 0], self.kal_pred[1, 0]] + + zone_distances = self.ttm.data_processor.tca.image_processors[0].scm.getCalibrationDistances() + Target.PREDICTION_RADIUS = zone_distances[2] + Target.SAFE_RADIUS = zone_distances[1] if self.valid: # Calculate prediction line when target is located in alert zone diff --git a/processors/data/track.py b/processors/data/track.py index 8b39316..4411758 100644 --- a/processors/data/track.py +++ b/processors/data/track.py @@ -18,9 +18,10 @@ class TargetTrackModule(object): UNKNOWN_GATE = 1.5 CONSTANTS_SET = False - def __init__(self, dataProcessor): + def __init__(self, data_processor): self.targets = [] - self.config = dataProcessor.config + self.data_processor = data_processor + self.config = data_processor.config if (TargetTrackModule.CONSTANTS_SET is False and self.config is not None): TargetTrackModule.CONSTANTS_SET = True @@ -66,7 +67,7 @@ def processDetections(self, unmatchedList): for pos in unmatchedList: logging.debug("New Target:") logging.debug(pos) - self.targets.append(Target(pos, self.config)) + self.targets.append(Target(pos, self.config, self)) def associateTrack(self, pos, target): # TODO reimplement diff --git a/processors/image/calibration.py b/processors/image/calibration.py index 25ffbc8..eccebb0 100644 --- a/processors/image/calibration.py +++ b/processors/image/calibration.py @@ -99,6 +99,7 @@ class SourceCalibrationModule(object): CAL_THRESHOLDS = CalibrationThreshold() DISPLAY_COLORS = False, False + ZONE_DISTANCES = [] def __init__(self, image_processor): self.image_processor = image_processor @@ -117,9 +118,6 @@ def __init__(self, image_processor): side_thresh_max = np.array(self.config.get ('calibration', 'side_color_max'). split(','), np.uint8) - -# self.colors = [[center_thresh_min, center_thresh_max], -# [side_thresh_min, side_thresh_max]] # Initialize calibration colors to those in config file # This is no longer needed, but must initialize to something @@ -139,9 +137,9 @@ def __init__(self, image_processor): # Set calibration target distances if self.config.get('calibration', 'zone_size') == 'NORMAL': - self.setCalibrationDistances(DISTANCES_NORMAL) + self.setCalibrationDistances('NORMAL') elif self.config.get('calibration', 'zone_size') == 'SMALL': - self.setCalibrationDistances(DISTANCES_SMALL) + self.setCalibrationDistances('SMALL') def calibrate(self, cal_points=None): """Calibrates the image processor @@ -366,13 +364,19 @@ def getDisplayColors(self): return SourceCalibrationModule.DISPLAY_COLORS - def setCalibrationDistances(self, zone_distances=(5, 10, 12)): + def setCalibrationDistances(self, zone_type='NORMAL'): """ Sets Distances for safe, alert, and prediction zone boundaries Arguments: zone_size -- Three element iterable containing boundary lengths """ + if zone_type == 'NORMAL': + zone_distances = DISTANCES_NORMAL + else: + zone_distances = DISTANCES_SMALL + + SourceCalibrationModule.ZONE_DISTANCES = zone_distances # Calibration point position calculations DISTANCES = [distance * SCALE for distance in zone_distances] @@ -383,6 +387,11 @@ def setCalibrationDistances(self, zone_distances=(5, 10, 12)): self.center_points = [[distance * coordinate for coordinate in CENTER_POINTS] for distance in DISTANCES] self.left_points = [[-1 * x, y, z] for x, y, z in self.right_points] + + def getCalibrationDistances(self): + """ Returns calibration distances in 3 element tuple """ + + return SourceCalibrationModule.ZONE_DISTANCES class CalibrationData(object): """Saves or loads calibration data to/from file.