def find_behavior_end(self, sequence_dir, transition_point):
        """Find the frame at which the behavior ends given the transition point.

        Args:
            sequence_dir: Full path to the sequence directory.
            transition_point: Dict representing transition point with 'begin' and 'end' frames.

        Returns:
            end_frame_idx: 1-based index of the end behavior frame in the sequence.
            behavior_id: Behavior ID (e.g. 'oor').
        """
        transition_frame_path = transition_point['end']
        begin_frame = load_frame(transition_point['begin'])
        end_frame = load_frame(transition_point['end'])

        if not self.is_enter_room(begin_frame, end_frame):
            transition_yaw = self.get_transition_yaw(begin_frame, end_frame)

            transition_frame_path = {
                'transition_yaw': transition_yaw,
                'transition_frame_path': transition_frame_path
            }

            cur_frame_idx, behavior_id = self.find_turn(sequence_dir,
                                                        transition_frame_path,
                                                        forward_time=True)
        else:  # Special case for when entering a room, since turning after entering does not count
            cur_frame_idx = get_frame_idx(transition_frame_path)
            behavior_id = None
        if behavior_id is not None:
            last_frame_idx = len(get_frame_paths(sequence_dir))
            cur_frame_idx = min(cur_frame_idx + self.n_after_turn_frames,
                                last_frame_idx)

        return cur_frame_idx, behavior_id
    def find_turn(self, sequence_dir, transition_frame_path, forward_time):
        if not isinstance(transition_frame_path,
                          str):  # JunctionTurnBehaviorDetector special case
            input_yaw = transition_frame_path['transition_yaw']
            transition_frame_path = transition_frame_path[
                'transition_frame_path']
            use_input_yaw = True
        else:
            use_input_yaw = False
        transition_frame = load_frame(transition_frame_path)
        transition_quaternion = transition_frame['gt_odom']['orientation']
        if use_input_yaw is True:
            transition_yaw = input_yaw
        else:
            transition_yaw = euler_from_quaternion(transition_quaternion)[2]
        transition_pos = transition_frame['gt_odom']['position']
        cur_pos = transition_pos

        transition_frame_idx = get_frame_idx(transition_frame_path)

        # Frame at the start of find_turn
        if forward_time is True:
            begin_frame = transition_frame
        else:
            begin_frame_path = self.get_frame_path_at_idx(
                sequence_dir, transition_frame_idx - 1)
            begin_frame = load_frame(begin_frame_path)

        cur_frame_idx = transition_frame_idx
        frame_delta = 1
        in_turn_loop = True
        while (
                in_turn_loop and
            (np.linalg.norm(cur_pos - transition_pos) < self.max_turn_dist)):
            prev_frame_idx = cur_frame_idx
            if forward_time is True:  # Move forward in time
                cur_frame_idx = transition_frame_idx + frame_delta
            else:  # Move backwards in time
                cur_frame_idx = transition_frame_idx - frame_delta
            cur_frame_path = self.get_frame_path_at_idx(
                sequence_dir, cur_frame_idx)
            # Break if we have reached beginning/end of sequence
            if not os.path.isfile(cur_frame_path):
                cur_frame_idx = prev_frame_idx
                break
            cur_frame = load_frame(cur_frame_path)
            cur_quaternion = cur_frame['gt_odom']['orientation']
            cur_yaw = euler_from_quaternion(cur_quaternion)[2]
            cur_pos = cur_frame['gt_odom']['position']

            behavior_id = self.get_behavior(transition_yaw, cur_yaw,
                                            forward_time)
            if behavior_id is not None:
                return cur_frame_idx, behavior_id

            # Update counters
            in_turn_loop = self.in_turn_loop(begin_frame, cur_frame)
            frame_delta += 1
        return cur_frame_idx, None
 def process_sequence(self, sequence_dir):
     frame_paths = get_frame_paths(sequence_dir)
     for cur_frame_path in frame_paths:
         cur_frame = load_frame(cur_frame_path)
         is_cf = (cur_frame.get('behavior_id') is None) and self.in_room(cur_frame)
         if is_cf:
             cur_frame_idx = get_frame_idx(cur_frame_path)
             self.add_behavior_label(sequence_dir, cur_frame_idx, behavior_id='cf')
    def find_behavior_start(self, sequence_dir, transition_point):
        """Find the frame at which the behavior begins.

        Args:
            sequence_dir: Full path to the sequence directory.
            transition point: Dict representing transition point with 'begin' and 'end' frames.
        """
        transition_frame_path = transition_point['end']
        begin_frame = load_frame(transition_point['begin'])
        end_frame = load_frame(transition_point['end'])
        transition_yaw = self.get_transition_yaw(begin_frame, end_frame)

        transition_frame_path = {
            'transition_yaw': transition_yaw,
            'transition_frame_path': transition_frame_path
        }

        cur_frame_idx, behavior_id = self.find_turn(sequence_dir,
                                                    transition_frame_path,
                                                    forward_time=False)
        if behavior_id is not None:
            cur_frame_idx = max(cur_frame_idx - self.n_after_turn_frames, 1)
        return cur_frame_idx, behavior_id
 def get_frame_data(self, frame_fpath):
     data = load_frame(frame_fpath)
     if 'localized_behavior_id' in data:
         localized_node_name, localized_behavior_id = data[
             'localized_behavior_id'].split(' ')
     else:
         localized_node_name = self.NO_NODE_NAME
         localized_behavior_id = self.NO_BEHAVIOR_TOKEN
     processed = {
         'depth':
         self.depth_transform(data['depth']),
         'rgb':
         self.rgb_transform(data['rgb']),
         'vel':
         torch.from_numpy(data['vel']),
         'area_name':
         data.get('area_name'),
         'room_name':
         data['room_name'],
         'is_invalid':
         1 if data.get('is_invalid', False) is True else False,
         'position':
         data['gt_odom']['position'],  # For debugging only
         'orientation':
         data['gt_odom']['orientation'],  # For junction behavior detector
         'sequence_idx':
         data['sequence_idx'],  # For debugging only
         'behavior_id':
         data.get('behavior_id', self.NO_BEHAVIOR_TOKEN),
         'localized_node_name':
         localized_node_name,  # This is used as a sanity check and shouldn't actually be used (use node_name) instead
         'localized_behavior_id':
         localized_behavior_id,
         'affordance_vec':
         self.affordance_list2vec(
             data.get('affordance_list', self.NO_AFFORDANCES_TOKEN)),
         'node_name':
         data.get('node_name', self.NO_NODE_NAME),
         'phase':
         data.get('phase', -1.),
         'frame_path':
         frame_fpath,  # Used for building cache
     }
     if processed['localized_behavior_id'] != self.NO_BEHAVIOR_TOKEN:
         assert processed['localized_node_name'] == processed['node_name']
     return processed
    def find_transition_points(self, sequence_dir):
        """Finds the transition points and assembles them in a list.
        """
        frame_paths = get_frame_paths(sequence_dir)
        last_frame = None
        last_frame_path = None
        transition_points = []
        for cur_frame_path in frame_paths:
            cur_frame = load_frame(cur_frame_path)
            if self.is_transition_point(last_frame, cur_frame):
                transition_point = {
                    'begin': last_frame_path,
                    'end': cur_frame_path
                }
                transition_points.append(transition_point)

            # Update last frame
            last_frame = cur_frame
            last_frame_path = cur_frame_path

        return transition_points
    def process_transition_point(self, sequence_dir, transition_point):
        start, start_behavior_id = self.find_behavior_start(
            sequence_dir, transition_point)
        end, end_behavior_id = self.find_behavior_end(sequence_dir,
                                                      transition_point)

        # Begin frame (frame at transition point)
        begin_frame = load_frame(transition_point['begin'])

        # Start frame
        start_frame_path = self.get_frame_path_at_idx(sequence_dir, start)
        start_frame = load_frame(start_frame_path)
        if (start_behavior_id is not None) and (end_behavior_id is not None):
            # If the behaviors are different, "smartly" choose a behavior by seeing which one
            # (start vs. end) has greater yaw delta with transition point
            # However, if exiting a room, choose the end behavior instead of start

            # Start frame orientation
            start_quaternion = start_frame['gt_odom']['orientation']
            start_yaw = euler_from_quaternion(start_quaternion)[2]

            # End frame orientation
            end_frame_path = self.get_frame_path_at_idx(sequence_dir, end)
            end_frame = load_frame(end_frame_path)
            end_quaternion = end_frame['gt_odom']['orientation']
            end_yaw = euler_from_quaternion(end_quaternion)[2]

            if start_frame['room_name'] == end_frame['room_name']:
                # This is for an edge case where the robot goes from room A to room B to room A,
                # after spending like 0.5 seconds in room B. In this case, the start and end frames
                # are both in room A and the rooms are not adjacent, failing self.get_transition_yaw
                print('Rooms are not adjacent!')
                return start, end, None
            else:
                transition_yaw = self.get_transition_yaw(
                    start_frame, end_frame)

            # Choose a behavior
            start_delta = np.abs(compute_angle_delta(start_yaw,
                                                     transition_yaw))
            end_delta = np.abs(compute_angle_delta(end_yaw, transition_yaw))
            if start_delta > end_delta:
                behavior_id = start_behavior_id
            else:
                behavior_id = end_behavior_id

        if (start_behavior_id is None) and (end_behavior_id is None):
            # Determine whether robot is going straight into a room or not
            end_frame_path = self.get_frame_path_at_idx(sequence_dir, end)
            end_frame = load_frame(end_frame_path)
            if begin_frame['room_name'].startswith('hallway') and self.in_room(
                    end_frame):
                behavior_id = 's'
            else:
                # Let CorridorFollowBehaviorDetector take care of cf
                # We don't want to overwrite previous 'tr' frames by accident
                behavior_id = None
                # behavior_id = 'cf'
        if (start_behavior_id is not None) and (end_behavior_id is None):
            behavior_id = start_behavior_id
        elif (end_behavior_id is not None) and (start_behavior_id is None):
            behavior_id = end_behavior_id

        # If start frame is in room, choose end_behavior_id
        if self.in_room(begin_frame):
            if end_behavior_id is None:
                behavior_id = 'cf'
            else:
                behavior_id = end_behavior_id
        return start, end, behavior_id
 def add_behavior_label(self, sequence_dir, cur_frame_idx, behavior_id):
     cur_frame_path = self.get_frame_path_at_idx(sequence_dir,
                                                 cur_frame_idx)
     cur_frame = load_frame(cur_frame_path)
     cur_frame['behavior_id'] = behavior_id  # Overwrite behavior ID
     np.savez(cur_frame_path, cur_frame)  # Overwrite the .npz file