def perceive(self, force=False):
        """
        run the classifiers, put tags in memory

        Args:
            force (boolean): set to True to run all perceptual heuristics right now,
                as opposed to waiting for perceive_freq steps (default: False)

        """
        if self.perceive_freq == 0 and not force:
            return
        if self.perceive_freq > 0 and self.agent.count % self.perceive_freq != 0 and not force:
            return
        if self.subcomponent_classifier is None:
            return
        # TODO don't all_nearby_objects again, search in memory instead
        to_label = []
        # add all blocks in marked areas
        for pos, radius in self.agent.areas_to_perceive:
            for obj in all_nearby_objects(self.agent.get_blocks, pos, radius):
                to_label.append(obj)
        # add all blocks near the agent
        for obj in all_nearby_objects(self.agent.get_blocks, self.agent.pos):
            to_label.append(obj)

        for obj in to_label:
            self.subcomponent_classifier.block_objs_q.put(obj)

        # everytime we try to retrieve as many recognition results as possible
        while not self.subcomponent_classifier.loc2labels_q.empty():
            loc2labels, obj = self.subcomponent_classifier.loc2labels_q.get()
            loc2ids = dict(obj)
            label2blocks = {}

            def contaminated(blocks):
                """
                Check if blocks are still consistent with the current world
                """
                mx, Mx, my, My, mz, Mz = get_bounds(blocks)
                yzxb = self.agent.get_blocks(mx, Mx, my, My, mz, Mz)
                for b, _ in blocks:
                    x, y, z = b
                    if loc2ids[b][0] != yzxb[y - my, z - mz, x - mx, 0]:
                        return True
                return False

            for loc, labels in loc2labels.items():
                b = (loc, loc2ids[loc])
                for l in labels:
                    if l in label2blocks:
                        label2blocks[l].append(b)
                    else:
                        label2blocks[l] = [b]
            for l, blocks in label2blocks.items():
                ## if the blocks are contaminated we just ignore
                if not contaminated(blocks):
                    locs = [loc for loc, idm in blocks]
                    InstSegNode.create(self.memory, locs, [l])
Exemple #2
0
def get_nearby_airtouching_blocks(agent, location, radius=15):
    """Get all blocks in 'radius' of 'location'
    that are touching air on either side.
    Returns:
        A list of blocktypes
    """
    gh = ground_height(agent, location, 0)[0, 0]
    x, y, z = location
    ymin = int(max(y - radius, gh))
    yzxb = agent.get_blocks(x - radius, x + radius, ymin, y + radius,
                            z - radius, z + radius)
    xyzb = yzxb.transpose([2, 0, 1, 3]).copy()
    components = connected_components(xyzb, unique_idm=True)
    blocktypes = []
    for c in components:
        tags = None
        for loc in c:
            idm = tuple(xyzb[loc[0], loc[1], loc[2], :])
            for coord in range(3):
                for d in [-1, 1]:
                    off = [0, 0, 0]
                    off[coord] = d
                    l = (loc[0] + off[0], loc[1] + off[1], loc[2] + off[2])
                    if l[coord] >= 0 and l[coord] < xyzb.shape[coord]:
                        if xyzb[l[0], l[1], l[2], 0] == 0:
                            try:
                                blocktypes.append(idm)
                                type_name = BLOCK_DATA["bid_to_name"][idm]
                                tags = [type_name]
                                colours = COLOUR_DATA["name_to_colors"].get(
                                    type_name, [])
                                colours.extend(
                                    [c for c in COLOUR_LIST if c in type_name])
                                if colours:
                                    tags.extend(colours)
                                    tags.extend([{
                                        "has_colour": c
                                    } for c in colours])
                                tags.extend(
                                    BLOCK_PROPERTY_DATA["name_to_properties"].
                                    get(type_name, []))
                            except:
                                logging.debug(
                                    "I see a weird block, ignoring: ({}, {})".
                                    format(idm[0], idm[1]))
        if tags:
            shifted_c = [(l[0] + x - radius, l[1] + ymin, l[2] + z - radius)
                         for l in c]
            if len(shifted_c) > 0:
                InstSegNode.create(agent.memory, shifted_c, tags=tags)
    return blocktypes
Exemple #3
0
 def get_object_by_id(self, memid: str, table="BlockObjects") -> "VoxelObjectNode":
     if table == "BlockObjects":
         return BlockObjectNode(self, memid)
     elif table == "InstSeg":
         return InstSegNode(self, memid)
     else:
         raise ValueError("Bad table={}".format(table))
Exemple #4
0
 def get_object_by_id(self,
                      memid: str,
                      table="BlockObjects") -> "VoxelObjectNode":
     """
     Returns:
         The memory node for the given memid
     """
     if table == "BlockObjects":
         return BlockObjectNode(self, memid)
     elif table == "InstSeg":
         return InstSegNode(self, memid)
     else:
         raise ValueError("Bad table={}".format(table))
Exemple #5
0
def get_all_nearby_holes(agent, location, radius=15, store_inst_seg=True):
    """Returns:
        a list of holes. Each hole is tuple(list[xyz], idm)"""
    sx, sy, sz = location
    max_height = sy + 5
    map_size = radius * 2 + 1
    height_map = [[sz] * map_size for i in range(map_size)]
    hid_map = [[-1] * map_size for i in range(map_size)]
    idm_map = [[(0, 0)] * map_size for i in range(map_size)]
    visited = set([])
    global current_connected_comp, current_idm
    current_connected_comp = []
    current_idm = (2, 0)

    # helper functions
    def get_block_info(x, z):  # fudge factor 5
        height = max_height
        while True:
            B = agent.get_blocks(x, x, height, height, z, z)
            if ((B[0, 0, 0, 0] != 0) and (x != sx or z != sz or height != sy)
                    and (x != agent.pos[0] or z != agent.pos[2]
                         or height != agent.pos[1]) and
                (B[0, 0, 0, 0] !=
                 383)):  # if it's not a mobile block (agent, speaker, mobs)
                return height, tuple(B[0, 0, 0])
            height -= 1

    gx = [0, 0, -1, 1]
    gz = [1, -1, 0, 0]

    def dfs(x, y, z):
        """ Traverse current connected component and return minimum
        height of all surrounding blocks """
        build_height = 100000
        if (x, y, z) in visited:
            return build_height
        global current_connected_comp, current_idm
        current_connected_comp.append(
            (x - radius + sx, y, z - radius + sz))  # absolute positions
        visited.add((x, y, z))
        for d in range(4):
            nx = x + gx[d]
            nz = z + gz[d]
            if nx >= 0 and nz >= 0 and nx < map_size and nz < map_size:
                if height_map[x][z] == height_map[nx][nz]:
                    build_height = min(build_height, dfs(nx, y, nz))
                else:
                    build_height = min(build_height, height_map[nx][nz])
                    current_idm = idm_map[nx][nz]
            else:
                # bad ... hole is not within defined radius
                return -100000
        return build_height

    # find all holes
    blocks_queue = []
    for i in range(map_size):
        for j in range(map_size):
            height_map[i][j], idm_map[i][j] = get_block_info(
                i - radius + sx, j - radius + sz)
            heapq.heappush(blocks_queue, (height_map[i][j] + 1,
                                          (i, height_map[i][j] + 1, j)))
    holes = []
    while len(blocks_queue) > 0:
        hxyz = heapq.heappop(blocks_queue)
        h, (x, y, z) = hxyz  # NB: relative positions
        if (x, y, z) in visited or y > max_height:
            continue
        assert h == height_map[x][z] + 1, " h=%d heightmap=%d, x,z=%d,%d" % (
            h,
            height_map[x][z],
            x,
            z,
        )  # sanity check
        current_connected_comp = []
        current_idm = (2, 0)
        build_height = dfs(x, y, z)
        if build_height >= h:
            holes.append((current_connected_comp.copy(), current_idm))
            cur_hid = len(holes) - 1
            for n, xyz in enumerate(current_connected_comp):
                x, y, z = xyz
                rx, ry, rz = x - sx + radius, y + 1, z - sz + radius
                heapq.heappush(blocks_queue, (ry, (rx, ry, rz)))
                height_map[rx][rz] += 1
                if hid_map[rx][rz] != -1:
                    holes[cur_hid][0].extend(holes[hid_map[rx][rz]][0])
                    holes[hid_map[rx][rz]] = ([], (0, 0))
                hid_map[rx][rz] = cur_hid

    # A bug in the algorithm above produces holes that include non-air blocks.
    # Just patch the problem here, since this function will eventually be
    # performed by an ML model
    for i, (xyzs, idm) in enumerate(holes):
        blocks = fill_idmeta(agent, xyzs)
        xyzs = [xyz for xyz, (d, _) in blocks
                if d == 0]  # remove non-air blocks
        holes[i] = (xyzs, idm)

    # remove 0-length holes
    holes = [h for h in holes if len(h[0]) > 0]
    if store_inst_seg:
        for hole in holes:
            InstSegNode.create(agent.memory,
                               hole[0],
                               tags=["hole", "pit", "mine"])

    return holes