blob: 86bb6939f35b40cec8f5b99578dda7add221d876 [file] [log] [blame]
Milindda9723d2021-04-02 09:14:34 -07001#!/usr/bin/python3
2
3# Creates a UI for a user to select the regions in a camera image where the balls could be placed
4# for each field layout.
5# After the balls have been placed on the field and they submit the regions,
6# galactic_search_path.py will take another picture and based on the yellow regions
7# in that picture it will determine where the balls are.
8# This tells us which path the current field is. It then sends the Alliance and Letter of the path
9# with aos_send to the /camera channel for the robot to excecute the spline for that path.
10
11from galactic_search_path import *
12
13import getopt
14import glog
15import json
16import matplotlib.patches as patches
17import matplotlib.pyplot as plt
18from matplotlib.widgets import Button
19import numpy as np
20import os
21import sys
22
23_num_rects = 3 # can be 3 or 2, can be specified in commang line arg
24
25setup_if_pi()
26
27_path = Path(Letter.kA, Alliance.kRed, [Rect(None, None, None, None)])
28
29# current index in rects list
30_rect_index = 0
31
32_fig, _img_ax = plt.subplots()
33
34_txt = _img_ax.text(0, 0, "", size = 10, backgroundcolor = "white")
35
36_confirm = Button(plt.axes([0.7, 0.05, 0.1, 0.075]), "Confirm")
37_cancel = Button(plt.axes([0.81, 0.05, 0.1, 0.075]), "Cancel")
38_submit = Button(plt.axes([0.4, 0.4, 0.1, 0.1]), "Submit")
39
40def draw_txt(txt):
41 txt.set_text("Click on top left point and bottom right point for rect #%u" % (_rect_index + 1))
42 txt.set_color(_path.alliance.value)
43
44
45def on_confirm(event):
46 global _rect_index
47 if _path.rects[_rect_index].x1 != None and _path.rects[_rect_index].x2 != None:
48 _confirm.ax.set_visible(False)
49 _cancel.ax.set_visible(False)
50 _rect_index += 1
51 clear_rect()
52 if _rect_index == _num_rects:
53 _submit.ax.set_visible(True)
54 else:
55 draw_txt(_txt)
56 _path.rects.append(Rect(None, None, None, None))
57 plt.show()
58
59def on_cancel(event):
60 global _rect_index
61 if _rect_index < _num_rects:
62 _confirm.ax.set_visible(False)
63 _cancel.ax.set_visible(False)
64 clear_rect()
65 _path.rects[_rect_index].x1 = None
66 _path.rects[_rect_index].y1 = None
67 _path.rects[_rect_index].x2 = None
68 _path.rects[_rect_index].y2 = None
69 plt.show()
70
71def on_submit(event):
72 plt.close("all")
73 dict = None
74 with open(RECTS_JSON_PATH, 'r') as rects_json:
75 dict = json.load(rects_json)
76 if _path.letter.name not in dict:
77 dict[_path.letter.name] = {}
78 if _path.alliance.name not in dict[_path.letter.name]:
79 dict[_path.letter.name][_path.alliance.name] = []
80 dict[_path.letter.name][_path.alliance.name] = [rect.to_list() for rect in _path.rects]
81 with open(RECTS_JSON_PATH, 'w') as rects_json:
82 json.dump(dict, rects_json, indent = 2)
83
84# Clears rect on screen
85def clear_rect():
86 if len(_img_ax.patches) == 0:
87 glog.error("There were no patches found in _img_ax")
88 else:
89 _img_ax.patches[-1].remove()
90
91def on_click(event):
92 # This gets called for each click of the rectangle corners,
93 # but also gets called when the user clicks on the Submit button.
94 # At that time _rect_index will equal the length of rects, and so we'll ignore that click.
95 # If it checked the points of the rect at _rect_index, a list out of bounds exception would be thrown.
96 # Additionally, the event xdata or ydata will be None if the user clicks out of
97 # the bounds of the axis
98 if _rect_index < _num_rects and event.xdata != None and event.ydata != None:
99 if _path.rects[_rect_index].x1 == None:
100 _path.rects[_rect_index].x1, _path.rects[_rect_index].y1 = int(event.xdata), int(event.ydata)
101 elif _path.rects[_rect_index].x2 == None:
102 _path.rects[_rect_index].x2, _path.rects[_rect_index].y2 = int(event.xdata), int(event.ydata)
103 if _path.rects[_rect_index].x2 < _path.rects[_rect_index].x1:
104 tmp = _path.rects[_rect_index].x1
105 _path.rects[_rect_index].x1 = _path.rects[_rect_index].x2
106 _path.rects[_rect_index].x2 = tmp
107 if _path.rects[_rect_index].y2 < _path.rects[_rect_index].y1:
108 tmp = _path.rects[_rect_index].y1
109 _path.rects[_rect_index].y1 = _path.rects[_rect_index].y2
110 _path.rects[_rect_index].y2 = tmp
111
112 _img_ax.add_patch(patches.Rectangle((_path.rects[_rect_index].x1, _path.rects[_rect_index].y1),
113 _path.rects[_rect_index].x2 - _path.rects[_rect_index].x1,
114 _path.rects[_rect_index].y2 - _path.rects[_rect_index].y1,
115 edgecolor = 'r', linewidth = 1, facecolor="none"))
116 _confirm.ax.set_visible(True)
117 _cancel.ax.set_visible(True)
118 plt.show()
119 else:
120 glog.info("Either submitted or user pressed out of the bounds of the axis")
121
122def setup_button(button, on_clicked):
123 button.on_clicked(on_clicked)
124 button.ax.set_visible(False)
125
126def setup_ui():
127 _img_ax.imshow(capture_img())
128 release_stream()
129
130 _fig.canvas.mpl_connect("button_press_event", on_click)
131 setup_button(_confirm, on_confirm)
132 setup_button(_cancel, on_cancel)
133 setup_button(_submit, on_submit)
134 draw_txt(_txt)
135 plt.show()
136
137def main(argv):
138 global _num_rects
139
140 glog.setLevel("INFO")
141 opts = getopt.getopt(argv[1 : ], "a:l:n:",
142 ["alliance = ", "letter = ", "_num_rects = "])[0]
143 for opt, arg in opts:
144 if opt in ["-a", "--alliance"]:
145 _path.alliance = Alliance.from_value(arg)
146 elif opt in ["-l", "--letter"]:
147 _path.letter = Letter.from_value(arg.upper())
148 elif opt in ["-n", "--_num_rects"] and arg.isdigit():
149 _num_rects = int(arg)
150
151 setup_ui()
152
153
154if __name__ == "__main__":
155 main(sys.argv)