Ejemplo n.º 1
0
def download_images(dest_folder,
                    classes,
                    imagery,
                    ml_type,
                    background_ratio,
                    imagery_offset=False,
                    **kwargs):
    """Download satellite images specified by a URL and a label.npz file
    Parameters
    ------------
    dest_folder: str
        Folder to save labels, tiles, and final numpy arrays into
    classes: list
        A list of classes for machine learning training. Each class is defined as a dict
        with two required properties:
          - name: class name
          - filter: A Mapbox GL Filter.
        See the README for more details
    imagery: str
        Imagery template to download satellite images from.
        Ex: http://a.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.jpg?access_token=ACCESS_TOKEN
    ml_type: str
        Defines the type of machine learning. One of "classification", "object-detection", or "segmentation"
    background_ratio: float
        Determines the number of background images to download in single class problems. Ex. A value
        of 1 will download an equal number of background images to class images.
    imagery_offset: list
        An optional list of integers representing the number of pixels to offset imagery. Ex. [15, -5] will
        move the images 15 pixels right and 5 pixels up relative to the requested tile bounds
    **kwargs: dict
        Other properties from CLI config passed as keywords to other utility functions
    """
    # open labels file
    labels_file = op.join(dest_folder, 'labels.npz')
    tiles = np.load(labels_file)

    # create tiles directory
    tiles_dir = op.join(dest_folder, 'tiles')
    if not op.isdir(tiles_dir):
        makedirs(tiles_dir)

    # find tiles which have any matching class
    def class_test(value):
        """Determine if a label matches a given class index"""
        if ml_type == 'object-detection':
            return len(value)
        elif ml_type == 'segmentation':
            return np.sum(value) > 0
        elif ml_type == 'classification':
            return value[0] == 0
        return None

    class_tiles = [tile for tile in tiles.files if class_test(tiles[tile])]

    # for classification problems with a single class, we also get background
    # tiles up to len(class_tiles) * config.get('background_ratio')
    background_tiles = []
    limit = len(class_tiles) * background_ratio
    if ml_type == 'classification' and len(classes) == 1:
        background_tiles_full = [
            tile for tile in tiles.files if tile not in class_tiles
        ]
        shuffle(background_tiles_full)
        background_tiles = background_tiles_full[:limit]

    # download tiles
    tiles = class_tiles + background_tiles
    print('Downloading {} tiles to {}'.format(len(tiles), tiles_dir))

    # get image acquisition function based on imagery string
    image_function = get_image_function(imagery)
    kwargs['imagery_offset'] = imagery_offset

    for tile in tiles:
        image_function(tile, imagery, tiles_dir, kwargs)
Ejemplo n.º 2
0
def preview(dest_folder,
            number,
            classes,
            imagery,
            ml_type,
            imagery_offset=False,
            **kwargs):
    """Produce imagery examples for specified classes

    Parameters
    ------------
    dest_folder: str
        Folder to save labels and example tiles into
    number: int
        Number of preview images to download per class
    classes: list
        A list of classes for machine learning training. Each class is defined as a dict
        with two required properties:
          - name: class name
          - filter: A Mapbox GL Filter.
        See the README for more details
    imagery: str
        Imagery template to download satellite images from.
        Ex: http://a.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.jpg?access_token=ACCESS_TOKEN
    ml_type: str
        Defines the type of machine learning. One of "classification", "object-detection", or "segmentation"
    imagery_offset: list
        An optional list of integers representing the number of pixels to offset imagery. Ex. [15, -5] will
        move the images 15 pixels right and 5 pixels up relative to the requested tile bounds
    **kwargs: dict
        Other properties from CLI config passed as keywords to other utility functions
    """
    # open labels file
    labels_file = op.join(dest_folder, 'labels.npz')
    tiles = np.load(labels_file)

    # create example tiles directory
    examples_dir = op.join(dest_folder, 'examples')
    if not op.isdir(examples_dir):
        makedirs(examples_dir)

    # find examples tiles for each class and download
    print('Writing example images to {}'.format(examples_dir))

    # get image acquisition function based on imagery string
    image_function = get_image_function(imagery)

    for i, cl in enumerate(classes):
        # create class directory
        class_dir = op.join(dest_folder, 'examples', cl.get('name'))

        if not op.isdir(class_dir):
            makedirs(class_dir)

        class_tiles = (t for t in tiles.files
                       if class_match(ml_type, tiles[t], i + 1))
        print('Downloading at most {} tiles for class {}'.format(
            number, cl.get('name')))
        for n, tile in enumerate(class_tiles):
            if n >= number:
                break

            kwargs['imagery_offset'] = imagery_offset
            tile_img = image_function(tile, imagery, class_dir, kwargs)

            if ml_type == 'object-detection':
                img = Image.open(tile_img)
                draw = ImageDraw.Draw(img)
                for box in tiles[tile]:
                    draw.rectangle(((box[0], box[1]), (box[2], box[3])),
                                   outline='red')
                img.save(tile_img)
            elif ml_type == 'segmentation':
                final = Image.new('RGB', (256, 256))
                img = Image.open(tile_img)
                mask = Image.fromarray(tiles[tile] * 255)
                final.paste(img, mask)
                final.save(tile_img)