blob: 90988e3f8102198f6eba23d5cd09b0df75a1021b [file] [log] [blame]
milind upadhyay1a4663c2021-04-03 19:41: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
25_path = Path(Letter.kA, Alliance.kRed, [Rect(None, None, None, None)])
26
27# current index in rects list
28_rect_index = 0
29
30_fig, _img_ax = plt.subplots()
31
32_txt = _img_ax.text(0, 0, "", size = 10, backgroundcolor = "white")
33
34_confirm = Button(plt.axes([0.7, 0.05, 0.1, 0.075]), "Confirm")
35_cancel = Button(plt.axes([0.81, 0.05, 0.1, 0.075]), "Cancel")
36_submit = Button(plt.axes([0.4, 0.05, 0.1, 0.1]), "Submit")
37
38def draw_txt(txt):
39 txt.set_text("Click on top left point and bottom right point for rect #%u" % (_rect_index + 1))
40 txt.set_color(_path.alliance.value)
41
42
43def on_confirm(event):
44 global _rect_index
45 if _path.rects[_rect_index].x1 != None and _path.rects[_rect_index].x2 != None:
46 _confirm.ax.set_visible(False)
47 _cancel.ax.set_visible(False)
48 _rect_index += 1
49 clear_rect()
50 if _rect_index == _num_rects:
51 _submit.ax.set_visible(True)
52 else:
53 draw_txt(_txt)
54 _path.rects.append(Rect(None, None, None, None))
55 plt.show()
56
57def on_cancel(event):
58 global _rect_index
59 if _rect_index < _num_rects:
60 _confirm.ax.set_visible(False)
61 _cancel.ax.set_visible(False)
62 clear_rect()
63 _path.rects[_rect_index].x1 = None
64 _path.rects[_rect_index].y1 = None
65 _path.rects[_rect_index].x2 = None
66 _path.rects[_rect_index].y2 = None
67 plt.show()
68
69def on_submit(event):
70 plt.close("all")
71 dict = None
72 dict = load_json()
73 if _path.letter.name not in dict:
74 dict[_path.letter.name] = {}
75 if _path.alliance.name not in dict[_path.letter.name]:
76 dict[_path.letter.name][_path.alliance.name] = []
77 dict[_path.letter.name][_path.alliance.name] = [rect.to_list() for rect in _path.rects]
78 with open(RECTS_JSON_PATH, 'w') as rects_json:
79 json.dump(dict, rects_json, indent = 2)
80
81# Clears rect on screen
82def clear_rect():
83 if len(_img_ax.patches) == 0:
84 glog.error("There were no patches found in _img_ax")
85 else:
86 _img_ax.patches[-1].remove()
87
88def on_click(event):
89 # This gets called for each click of the rectangle corners,
90 # but also gets called when the user clicks on the Submit button.
91 # At that time _rect_index will equal the length of rects, and so we'll ignore that click.
92 # If it checked the points of the rect at _rect_index, a list out of bounds exception would be thrown.
93 # Additionally, the event xdata or ydata will be None if the user clicks out of
94 # the bounds of the axis
95 if _rect_index < _num_rects and event.xdata != None and event.ydata != None:
96 if _path.rects[_rect_index].x1 == None:
97 _path.rects[_rect_index].x1, _path.rects[_rect_index].y1 = int(event.xdata), int(event.ydata)
98 elif _path.rects[_rect_index].x2 == None:
99 _path.rects[_rect_index].x2, _path.rects[_rect_index].y2 = int(event.xdata), int(event.ydata)
100 if _path.rects[_rect_index].x2 < _path.rects[_rect_index].x1:
101 tmp = _path.rects[_rect_index].x1
102 _path.rects[_rect_index].x1 = _path.rects[_rect_index].x2
103 _path.rects[_rect_index].x2 = tmp
104 if _path.rects[_rect_index].y2 < _path.rects[_rect_index].y1:
105 tmp = _path.rects[_rect_index].y1
106 _path.rects[_rect_index].y1 = _path.rects[_rect_index].y2
107 _path.rects[_rect_index].y2 = tmp
108
109 _img_ax.add_patch(patches.Rectangle((_path.rects[_rect_index].x1, _path.rects[_rect_index].y1),
110 _path.rects[_rect_index].x2 - _path.rects[_rect_index].x1,
111 _path.rects[_rect_index].y2 - _path.rects[_rect_index].y1,
112 edgecolor = 'r', linewidth = 1, facecolor="none"))
113 _confirm.ax.set_visible(True)
114 _cancel.ax.set_visible(True)
115 plt.show()
116 else:
117 glog.info("Either submitted or user pressed out of the bounds of the axis")
118
119def setup_button(button, on_clicked):
120 button.on_clicked(on_clicked)
121 button.ax.set_visible(False)
122
123def setup_ui():
124 _img_ax.imshow(capture_img())
125 release_stream()
126
127 _fig.canvas.mpl_connect("button_press_event", on_click)
128 setup_button(_confirm, on_confirm)
129 setup_button(_cancel, on_cancel)
130 setup_button(_submit, on_submit)
131 draw_txt(_txt)
132 plt.show()
133
134def view_rects():
135
136 rects_dict = load_json()
137 if (_path.letter.name in rects_dict and
138 _path.alliance.name in rects_dict[_path.letter.name]):
139 _confirm.ax.set_visible(False)
140 _cancel.ax.set_visible(False)
141 _submit.ax.set_visible(False)
142 _img_ax.imshow(capture_img())
143
144 for rect_list in rects_dict[_path.letter.name][_path.alliance.name]:
145 rect = Rect.from_list(rect_list)
146 _img_ax.add_patch(patches.Rectangle((rect.x1, rect.y1),
147 rect.x2 - rect.x1, rect.y2 - rect.y1,
148 edgecolor = 'r', linewidth = 1, facecolor="none"))
149 plt.show()
150 else:
151 glog.error("Could not find path %s %s in rects.json",
152 _path.alliance.value, _path.letter.value)
153
154def main(argv):
155 global _num_rects
156
157 glog.setLevel("INFO")
158 opts = getopt.getopt(argv[1 : ], "a:l:n:",
159 ["alliance = ", "letter = ", "_num_rects = ", "view"])[0]
160 view = False
161 for opt, arg in opts:
162 if opt in ["-a", "--alliance"]:
163 _path.alliance = Alliance.from_value(arg)
164 elif opt in ["-l", "--letter"]:
165 _path.letter = Letter.from_value(arg.upper())
166 elif opt in ["-n", "--_num_rects"] and arg.isdigit():
167 _num_rects = int(arg)
168 elif opt == "--view":
169 view = True
170
171 if view:
172 view_rects()
173 else:
174 setup_ui()
175
176
177if __name__ == "__main__":
178 main(sys.argv)