9
9
import shutil
10
10
import glob
11
11
import sys
12
+
12
13
if "/opt/ros/kinetic/lib/python2.7/dist-packages" in sys .path :
13
14
sys .path .remove ("/opt/ros/kinetic/lib/python2.7/dist-packages" )
14
15
import cv2
17
18
from pathlib import Path
18
19
import matplotlib .pyplot as plt
19
20
20
- #FIXME! do this better
21
+ # FIXME! do this better
21
22
from .hello_robot .rotation import yaw_pitch
22
23
23
24
MAX_PAN_RAD = np .pi / 4
@@ -102,6 +103,7 @@ def get_move_target_for_point(base_pos, target, eps=0.5):
102
103
103
104
return [targetx , targetz , yaw ]
104
105
106
+
105
107
def get_step_target_for_straightline_move (base_pos , target , step_size = 0.1 ):
106
108
"""
107
109
Heuristic to get step target of step_size for going to from base_pos to target
@@ -117,55 +119,64 @@ def get_step_target_for_straightline_move(base_pos, target, step_size=0.1):
117
119
dx = target [0 ] - base_pos [0 ]
118
120
dz = target [2 ] - base_pos [1 ]
119
121
120
- if dx == 0 : # vertical line
122
+ if dx == 0 : # vertical line
121
123
theta = math .radians (90 )
122
124
else :
123
- theta = math .atan (abs (dz / dx ))
124
-
125
+ theta = math .atan (abs (dz / dx ))
126
+
125
127
signx = 1 if dx >= 0 else - 1
126
128
signz = 1 if dz >= 0 else - 1
127
-
129
+
128
130
targetx = base_pos [0 ] + signx * step_size * math .cos (theta )
129
131
targetz = base_pos [1 ] + signz * step_size * math .sin (theta )
130
132
131
133
yaw , _ = get_camera_angles ([targetx , CAMERA_HEIGHT , targetz ], target )
132
-
134
+
133
135
return [targetx , targetz , yaw ]
134
136
137
+
135
138
def get_straightline_path_to (target , robot_pos ):
136
139
pts = []
137
140
cur_pos = robot_pos
138
- while np .linalg .norm (target [:2 ]- cur_pos [:2 ]) > 0.5 :
141
+ while np .linalg .norm (target [:2 ] - cur_pos [:2 ]) > 0.5 :
139
142
t = get_step_target_for_move (cur_pos , [target [0 ], CAMERA_HEIGHT , target [1 ]], step_size = 0.5 )
140
143
pts .append (t )
141
144
cur_pos = t
142
145
return np .asarray (pts )
143
146
147
+
144
148
def get_circle (r , n = 10 ):
145
- return [[math .cos (2 * math .pi / n * x )* r ,math .sin (2 * math .pi / n * x )* r ] for x in range (0 ,n + 1 )]
149
+ return [
150
+ [math .cos (2 * math .pi / n * x ) * r , math .sin (2 * math .pi / n * x ) * r ]
151
+ for x in range (0 , n + 1 )
152
+ ]
153
+
146
154
147
155
def get_circular_path (target , robot_pos , radius , num_points ):
148
156
"""
149
157
get a circular path with num_points of radius from x
150
158
xyz
151
159
"""
152
- pts = get_circle (radius , num_points ) # these are the x,z
160
+ pts = get_circle (radius , num_points ) # these are the x,z
161
+
153
162
def get_xyyaw (p , target ):
154
163
targetx = p [0 ] + target [0 ]
155
164
targetz = p [1 ] + target [2 ]
156
165
yaw , _ = get_camera_angles ([targetx , CAMERA_HEIGHT , targetz ], target )
157
166
return [targetx , targetz , yaw ]
158
-
167
+
159
168
pts = np .asarray ([get_xyyaw (p , target ) for p in pts ])
160
169
161
170
# find nearest pt to robot_pos as starting point
162
171
def find_nearest_indx (pts , robot_pos ):
163
- idx = np .asarray ([np .linalg .norm (np .asarray (p [:2 ]) - np .asarray (robot_pos [:2 ])) for p in pts ]).argmin ()
172
+ idx = np .asarray (
173
+ [np .linalg .norm (np .asarray (p [:2 ]) - np .asarray (robot_pos [:2 ])) for p in pts ]
174
+ ).argmin ()
164
175
return idx
165
176
166
177
idx = find_nearest_indx (pts , robot_pos )
167
178
# rotate the pts to begin at idx
168
- pts = np .concatenate ((pts [idx :,:], pts [:idx ,:]), axis = 0 )
179
+ pts = np .concatenate ((pts [idx :, :], pts [:idx , :]), axis = 0 )
169
180
170
181
# TODO: get step-wise move targets to nearest point? or capture move data?
171
182
# spath = get_straightline_path_to(pts[0], robot_pos)
@@ -174,9 +185,10 @@ def find_nearest_indx(pts, robot_pos):
174
185
175
186
return pts
176
187
188
+
177
189
class TrajectoryDataSaver :
178
190
def __init__ (self , root ):
179
- print (f' TrajectoryDataSaver saving to { root } ' )
191
+ print (f" TrajectoryDataSaver saving to { root } " )
180
192
self .save_folder = root
181
193
self .img_folder = os .path .join (self .save_folder , "rgb" )
182
194
self .img_folder_dbg = os .path .join (self .save_folder , "rgb_dbg" )
@@ -185,27 +197,33 @@ def __init__(self, root):
185
197
self .trav_folder = os .path .join (self .save_folder , "trav" )
186
198
187
199
if os .path .exists (self .save_folder ):
188
- print (f' rmtree { self .save_folder } ' )
200
+ print (f" rmtree { self .save_folder } " )
189
201
shutil .rmtree (self .save_folder )
190
202
191
- print (f' trying to create { self .save_folder } ' )
203
+ print (f" trying to create { self .save_folder } " )
192
204
Path (self .save_folder ).mkdir (parents = True , exist_ok = True )
193
205
194
- for x in [self .img_folder , self .img_folder_dbg , self .depth_folder , self .seg_folder , self .trav_folder ]:
206
+ for x in [
207
+ self .img_folder ,
208
+ self .img_folder_dbg ,
209
+ self .depth_folder ,
210
+ self .seg_folder ,
211
+ self .trav_folder ,
212
+ ]:
195
213
self .create (x )
196
214
197
215
self .pose_dict = {}
198
216
self .pose_dict_hab = {}
199
217
self .img_count = 0
200
218
self .dbg_str = "None"
201
219
self .init_logger ()
202
-
220
+
203
221
def init_logger (self ):
204
- self .logger = logging .getLogger (' trajectory_saver' )
222
+ self .logger = logging .getLogger (" trajectory_saver" )
205
223
self .logger .setLevel (logging .INFO )
206
- formatter = logging .Formatter (' %(filename)s:%(lineno)s - %(funcName)s(): %(message)s' )
224
+ formatter = logging .Formatter (" %(filename)s:%(lineno)s - %(funcName)s(): %(message)s" )
207
225
# Enable filehandler to debug logs
208
- fh = logging .FileHandler (f"trajectory_saver.log" , 'a' )
226
+ fh = logging .FileHandler (f"trajectory_saver.log" , "a" )
209
227
fh .setLevel (logging .INFO )
210
228
fh .setFormatter (formatter )
211
229
self .logger .addHandler (fh )
@@ -219,7 +237,7 @@ def create(self, d):
219
237
220
238
def set_dbg_str (self , x ):
221
239
self .dbg_str = x
222
-
240
+
223
241
def get_total_frames (self ):
224
242
return self .img_count
225
243
@@ -229,20 +247,21 @@ def save(self, rgb, depth, seg, pos, habitat_pos, habitat_rot):
229
247
print (f'saving { rgb .shape , depth .shape , seg .shape } ' )
230
248
# store the images and depth
231
249
rgb = cv2 .cvtColor (rgb , cv2 .COLOR_BGR2RGB )
232
- cv2 .imwrite (
233
- self .img_folder + "/{:05d}.jpg" .format (self .img_count ),
250
+ cv2 .imwrite (self .img_folder + "/{:05d}.jpg" .format (self .img_count ), rgb )
251
+
252
+ cv2 .putText (
234
253
rgb ,
254
+ str (self .img_count ) + " " + self .dbg_str ,
255
+ (40 , 40 ),
256
+ cv2 .FONT_HERSHEY_PLAIN ,
257
+ 1 ,
258
+ (0 , 0 , 255 ),
235
259
)
236
260
237
- cv2 .putText (rgb , str (self .img_count ) + ' ' + self .dbg_str , (40 ,40 ), cv2 .FONT_HERSHEY_PLAIN , 1 , (0 ,0 ,255 ))
238
-
239
261
# robot_dbg_str = 'robot_pose ' + str(np.round(self.get_robot_global_state(), 3))
240
262
# cv2.putText(rgb, robot_dbg_str, (40,60), cv2.FONT_HERSHEY_PLAIN, 1, (0,0,255))
241
263
242
- cv2 .imwrite (
243
- self .img_folder_dbg + "/{:05d}.jpg" .format (self .img_count ),
244
- rgb ,
245
- )
264
+ cv2 .imwrite (self .img_folder_dbg + "/{:05d}.jpg" .format (self .img_count ), rgb )
246
265
247
266
# store depth
248
267
np .save (self .depth_folder + "/{:05d}.npy" .format (self .img_count ), depth )
@@ -256,7 +275,7 @@ def save(self, rgb, depth, seg, pos, habitat_pos, habitat_rot):
256
275
self .pose_dict = json .load (fp )
257
276
258
277
self .pose_dict [self .img_count ] = copy (pos )
259
-
278
+
260
279
with open (os .path .join (self .save_folder , "data.json" ), "w" ) as fp :
261
280
json .dump (self .pose_dict , fp )
262
281
@@ -275,96 +294,34 @@ def save(self, rgb, depth, seg, pos, habitat_pos, habitat_rot):
275
294
276
295
277
296
def visualize_examine (agent , robot_poses , object_xyz , label , obstacle_map , save_path , gt_pts = None ):
278
- traj_visual_dir = os .path .join (save_path , ' traj_visual' )
297
+ traj_visual_dir = os .path .join (save_path , " traj_visual" )
279
298
if not os .path .isdir (traj_visual_dir ):
280
299
os .makedirs (traj_visual_dir )
281
- vis_count = len (glob .glob (traj_visual_dir + ' /*.jpg' ))
300
+ vis_count = len (glob .glob (traj_visual_dir + " /*.jpg" ))
282
301
if vis_count == 0 :
283
302
plt .figure ()
284
303
285
304
plt .title ("Examine Visual" )
286
305
# visualize obstacle map
287
306
if len (obstacle_map ) > 0 :
288
307
obstacle_map = np .asarray ([list (x ) for x in obstacle_map ])
289
- plt .plot (obstacle_map [:,1 ], obstacle_map [:,0 ], 'b+' )
290
-
291
- # visualize object
308
+ plt .plot (obstacle_map [:, 1 ], obstacle_map [:, 0 ], "b+" )
309
+
310
+ # visualize object
292
311
if object_xyz is not None :
293
- plt .plot (object_xyz [0 ], object_xyz [2 ], 'y*' )
312
+ plt .plot (object_xyz [0 ], object_xyz [2 ], "y*" )
294
313
plt .text (object_xyz [0 ], object_xyz [2 ], label )
295
-
314
+
296
315
# visualize robot pose
297
316
if len (robot_poses ) > 0 :
298
317
robot_poses = np .asarray (robot_poses )
299
- plt .plot (robot_poses [:,0 ], robot_poses [:,1 ], ' r--' )
318
+ plt .plot (robot_poses [:, 0 ], robot_poses [:, 1 ], " r--" )
300
319
301
320
if gt_pts is not None :
302
321
pts = np .asarray (gt_pts )
303
- plt .plot (pts [:,0 ], pts [:,1 ], 'y--' )
304
-
305
- # TODO: visualize robot heading
306
-
322
+ plt .plot (pts [:, 0 ], pts [:, 1 ], "y--" )
323
+
324
+ # TODO: visualize robot heading
307
325
308
326
plt .savefig ("{}/{:04d}.jpg" .format (traj_visual_dir , vis_count ))
309
327
vis_count += 1
310
-
311
- class ExaminedMap :
312
- """A helper static class to maintain the state representations needed to track active exploration.
313
- droidlet.interpreter.robot.tasks.CuriousExplore uses this to decide which objects to explore next.
314
- The core of this class is the ExaminedMap.can_examine method. This is a heuristic.
315
- Long term, this information should live in memory (#FIXME @anuragprat1k).
316
-
317
- It works as follows -
318
- 1. for each new candidate coordinate, it fetches the closest examined coordinate.
319
- 2. if this closest coordinate is within a certain threshold (1 meter) of the current coordinate,
320
- or if that region has been explored upto a certain number of times (2, for redundancy),
321
- it is not explored, since a 'close-enough' region in space has already been explored.
322
- """
323
- examined = {}
324
- examined_id = set ()
325
- last = None
326
-
327
- @classmethod
328
- def l1 (cls , xyz , k ):
329
- """ returns the l1 distance between two standard coordinates"""
330
- return np .linalg .norm (np .asarray ([xyz [0 ], xyz [2 ]]) - np .asarray ([k [0 ], k [2 ]]), ord = 1 )
331
-
332
- @classmethod
333
- def get_closest (cls , xyz ):
334
- """returns closest examined point to xyz"""
335
- c = None
336
- dist = 1.5
337
- for k , v in cls .examined .items ():
338
- if cls .l1 (k , xyz ) < dist :
339
- dist = cls .l1 (k , xyz )
340
- c = k
341
- if c is None :
342
- cls .examined [xyz ] = 0
343
- return xyz
344
- return c
345
-
346
- @classmethod
347
- def update (cls , target ):
348
- """called each time a region is examined. Updates relevant states."""
349
- cls .last = cls .get_closest (target ['xyz' ])
350
- cls .examined_id .add (target ['eid' ])
351
- cls .examined [cls .last ] += 1
352
-
353
- @classmethod
354
- def clear (cls ):
355
- cls .examined = {}
356
- cls .examined_id = set ()
357
- cls .last = None
358
-
359
- @classmethod
360
- def can_examine (cls , x ):
361
- """decides whether to examine x or not."""
362
- loc = x ['xyz' ]
363
- k = cls .get_closest (x ['xyz' ])
364
- val = True
365
- if cls .last is not None and cls .l1 (cls .last , k ) < 1 :
366
- val = False
367
- val = cls .examined [k ] < 2
368
- print (f"can_examine { x ['eid' ], x ['label' ], x ['xyz' ][:2 ]} , closest { k [:2 ]} , can_examine { val } " )
369
- print (f"examined[k] = { cls .examined [k ]} " )
370
- return val
0 commit comments