Example #1
0
    def test_start_out_of_range(self):
        img = np.zeros((10, 10), dtype=bool)
        path = find_path(img, (200, 0), [(3, 3), (5, 5)])
        self.assertIsNone(path)

        img = np.zeros((10, 10, 5), dtype=bool)
        path = find_path(img, (0, 0, 13), [(3, 3, 0)])
        self.assertIsNone(path)
Example #2
0
    def test_usage(self):
        img = np.zeros((10, 10), dtype=bool)
        img[5,:] = True
        img[:, 0] = True
        self.assertTrue(img[0][0])
        self.assertTrue(img[5][5])
        self.assertFalse(img[3][3])

        self.assertIsNone(find_path(img, (3, 3), [(3, 3)]))

        path = find_path(img, (0, 0), [(5, 5)])
        self.assertEqual(path[0], (0, 0, 0))
        self.assertEqual(path[-1], (5, 5, 0))
        self.assertEqual(len(path), 5 + 1 + 5)
Example #3
0
    def test_multiple_goals(self):
        img = np.zeros((10, 10), dtype=bool)
        img[5,:] = True
        img[:, 0] = True

        path = find_path(img, (0, 0), [(3, 3), (5, 5)])
        self.assertEqual(path[-1], (5, 5, 0))
        self.assertEqual(len(path), 5 + 1 + 5)
Example #4
0
 def test_3d_planner(self):
     mimg = np.zeros((10, 10, 5), dtype=bool)
     mimg[5, :, 3] = True
     mimg[:, 7, 2] = True
     path = find_path(mimg, (0, 5, 3), [(7, 9, 2)])
     self.assertIsNotNone(path)
Example #5
0
def frontiers(img, start, draw=False):
    """
    Find path to the best frontier (free-unknown transition)
    :param img: color image with free=white, unknown=green
    :param start: start pixel
    :param draw: debug frontiers in pyplot
    :return: extended image with drawn start and path, path
    """
    size = img.shape
    green = img[:, :, :] == STATE_UNKNOWN
    white = img[:, :, :] == STATE_FREE

    mask_right = green[:, 2:, :] & white[:, 1:-1, :]
    mask_left = green[:, :-2, :] & white[:, 1:-1, :]
    mask = mask_left | mask_right
    z = np.zeros((size[0], 1, size[2]), dtype=np.bool)
    mask = np.hstack([z, mask, z])

    mask_up = green[2:, :, :] & white[1:-1, :, :]
    mask_down = green[:-2, :, :] & white[1:-1, :, :]
    z = np.zeros((1, size[1], size[2]), dtype=np.bool)
    mask2 = mask_up | mask_down
    mask = np.vstack([z, mask2, z]) | mask

    z_mask_up = green[:, :, 2:] & white[:, :, 1:-1]
    z_mask_down = green[:, :, :-2] & white[:, :, 1:-1]
    z = np.zeros((size[0], size[1], 1), dtype=np.bool)
    mask3 = z_mask_up | z_mask_down
    #    mask = np.concatenate([z, mask3, z], axis=2) | mask

    xy = np.where(mask)
    if len(xy[0]) == 0:
        # there are no frontiers, i.e. no exploration path
        return img, None

    score = np.zeros(len(xy[0]))
    for i in range(len(xy[0])):
        x, y = xy[1][
            i] - SLICE_OCTOMAP_SIZE // 2, SLICE_OCTOMAP_SIZE // 2 - xy[0][i]
        if x > 4:  # TODO - resolution and detect gate as one way only (0 is not sufficient due to impecise position
            score[i] = math.hypot(x, y) * 0.03
        else:
            score[
                i] = 0  # too cruel cut for X positive semi-space, but let's move INSIDE!

    for i in range(len(xy[0])):
        x, y = xy[1][
            i] - SLICE_OCTOMAP_SIZE // 2, SLICE_OCTOMAP_SIZE // 2 - xy[0][i]
        for j in range(len(xy[0])):
            x2, y2 = xy[1][
                j] - SLICE_OCTOMAP_SIZE // 2, SLICE_OCTOMAP_SIZE // 2 - xy[0][j]
            dist = math.hypot(x - x2, y - y2)
            if dist < 10 and score[i] > 0:  # ~ 5 meters, only inside
                score[i] += 1.0

    if draw:
        import matplotlib.pyplot as plt
        line = plt.plot(xy[1] - SLICE_OCTOMAP_SIZE // 2,
                        SLICE_OCTOMAP_SIZE // 2 - xy[0], 'bo')
        m = score > 3 * max(score) / 4
        plt.plot(xy[1][m] - SLICE_OCTOMAP_SIZE // 2,
                 SLICE_OCTOMAP_SIZE // 2 - xy[0][m], 'ro')

        plt.axes().set_aspect('equal', 'datalim')
        plt.show()

    drivable = white

    # use 1 pixel surrounding
    drivable_safe_y = drivable[2:, :] & drivable[1:-1, :] & drivable[:-2, :]
    drivable_safe_xy = drivable_safe_y[:,
                                       2:] & drivable_safe_y[:, 1:
                                                             -1] & drivable_safe_y[:, :
                                                                                   -2]
    # add non-drivable frame to match original image size
    z = np.zeros((size[0] - 2, 1, size[2]), dtype=np.bool)
    tmp = np.hstack([z, drivable_safe_xy, z])
    z = np.zeros((1, size[1], size[2]), dtype=np.bool)
    drivable = np.vstack([z, tmp, z])

    for limit_score in [3 * max(score) / 4, max(score) / 4, 0]:
        # select goal positions above the limit_score
        # note, that the "safe path" does not touch external boundary so it would never find path
        # to frontier. As a workaround add also all 8-neighbors of frontiers.
        goals = []
        xy2 = np.array(xy)[:, score > limit_score]
        for dx in [-1, 0, 1]:
            for dy in [-1, 0, 1]:
                for dz in [0]:  #[-1, 0, 1]:
                    goals.append(xy2 + np.repeat(
                        np.asarray([[dy], [dx], [dz]]), xy2.shape[1], axis=1))
        goals = np.hstack(goals).T[:, [1, 0, 2]]

        # the path planner currently expects goals as tuple (x, y) and operation "in"
        goals = set(map(tuple, goals))
        path = find_path(drivable, start, goals, verbose=False)
        if path is not None:
            break

    img[mask] = STATE_FRONTIER

    if path is not None:
        for x, y, z in path:
            img[y][x] = STATE_PATH
    else:
        print('Path not found!')

    return img, path