def _extract_candidate_attributes( whole_scene_perception_graph: PerceptionGraph, object_with_attribute: ObjectSemanticNode, ) -> Sequence[PerceptionGraph]: perception_digraph = whole_scene_perception_graph.copy_as_digraph() # For now, we assume all attributes are based on properties. properties = immutableset( [ node for _, node, label in perception_digraph.out_edges( object_with_attribute, data="label" ) if label == HAS_PROPERTY_LABEL ] ) # Furthermore, we limit the search space to the even smaller set of hypotheses # where we consider only single properties as possible attributes. # Otherwise there are too many hypotheses for the pursuit learner to search through # and it's unlikely to converge on the correct hypothesis # in any reasonable amount of time or number of examples. candidate_attribute_subgraph_node_sets = [ immutableset([object_with_attribute, property]) for property in properties ] return immutableset( [ whole_scene_perception_graph.subgraph_by_nodes( candidate_attribute_subgraph_nodes ) for candidate_attribute_subgraph_nodes in candidate_attribute_subgraph_node_sets ] )
def extract_candidate_objects( whole_scene_perception_graph: PerceptionGraph ) -> Sequence[PerceptionGraph]: """ Pulls out distinct objects from a scene. We will attempt to recognize only these and will ignore other parts of the scene. """ scene_digraph = whole_scene_perception_graph.copy_as_digraph() def is_part_of_label(label) -> bool: return label == PART_OF or (isinstance( label, TemporallyScopedEdgeLabel) and label.attribute == PART_OF) # We first identify root object nodes, which are object nodes with no part-of # relationship with other object nodes. def is_root_object_node(node) -> bool: if isinstance(node, ObjectPerception): for (_, _, edge_label) in scene_digraph.out_edges(node, data="label"): if is_part_of_label(edge_label): # This object node is part of another object and cannot be a root. return False return True return False candidate_object_root_nodes = [ node for node in scene_digraph.nodes if is_root_object_node(node) and node not in (GROUND_PERCEPTION, LEARNER_PERCEPTION) ] candidate_objects: List[PerceptionGraph] = [] for root_object_node in candidate_object_root_nodes: # Having identified the root nodes of the candidate objects, # we now gather all sub-object nodes. object_nodes_in_object_list = [] nodes_to_examine = [root_object_node] # This would be clearer recursively # but I'm betting this implementation is a bit faster in Python. nodes_visited: Set[PerceptionGraphNode] = set() while nodes_to_examine: node_to_examine = nodes_to_examine.pop() if node_to_examine in nodes_visited: continue nodes_visited.add(node_to_examine) object_nodes_in_object_list.append(node_to_examine) for (next_node, _, edge_label) in scene_digraph.in_edges(node_to_examine, data="label"): if is_part_of_label(edge_label): nodes_to_examine.append(next_node) object_nodes_in_object = immutableset(object_nodes_in_object_list) # Now we know all object nodes for this candidate object. # Finally, we find the sub-graph to match against which could possibly correspond # to this candidate object # by performing a BFS over the graph # but *stopping whenever we encounter an object node # which is not part of this candidate object*. # This is a little more generous than we need to be, but it's simple. nodes_to_examine = [root_object_node] candidate_subgraph_nodes = [] nodes_visited.clear() while nodes_to_examine: node_to_examine = nodes_to_examine.pop() is_allowable_node = ( not isinstance(node_to_examine, (ObjectPerception, ObjectSemanticNode)) or node_to_examine in object_nodes_in_object) if node_to_examine not in nodes_visited and is_allowable_node: nodes_visited.add(node_to_examine) candidate_subgraph_nodes.append(node_to_examine) nodes_to_examine.extend( out_neighbor for (_, out_neighbor ) in scene_digraph.out_edges(node_to_examine) if not (isinstance(out_neighbor, tuple) and isinstance( out_neighbor[0], Region) and out_neighbor[0]. reference_object == GROUND_PERCEPTION)) nodes_to_examine.extend( in_neighbor for (in_neighbor, _) in scene_digraph.in_edges(node_to_examine) # Avoid in-edges from Regions as they can come from other objects regions (e.g ground). if not ( # isinstance(node_to_examine, GeonAxis) isinstance(in_neighbor, tuple) and isinstance(in_neighbor[0], Region))) candidate_objects.append( whole_scene_perception_graph.subgraph_by_nodes( immutableset(candidate_subgraph_nodes))) return candidate_objects