Exemplo n.º 1
0
def get_input():
    ''' Method called for POST `/getInput`
    '''
    bottle.response.content_type = 'application/json'
    data = bottle.request.json
    data["remote_address"] = bottle.request.client_ip

    SESSION_HANDLER.get_session(bottle.request.session.id).add_entry(
        data)  # record this interaction

    # Inputs
    extent = data["extent"]
    dataset = data["dataset"]

    if dataset not in DATASETS:
        raise ValueError(
            "Dataset doesn't seem to be valid, please check Datasets.py")

    naip_data, naip_crs, naip_transform, naip_bounds, naip_index = DATASETS[
        dataset]["data_loader"].get_data_from_extent(extent)
    naip_data = np.rollaxis(naip_data, 0, 3)

    naip_data, new_bounds = warp_data_to_3857(naip_data, naip_crs,
                                              naip_transform, naip_bounds)
    naip_data = crop_data_by_extent(naip_data, new_bounds, extent)

    naip_img = naip_data[:, :, :3].copy().astype(
        np.uint8)  # keep the RGB channels to save as a color image

    naip_img = cv2.imencode(".png",
                            cv2.cvtColor(naip_img,
                                         cv2.COLOR_RGB2BGR))[1].tostring()
    naip_img = base64.b64encode(naip_img).decode("utf-8")
    data["input_naip"] = naip_img

    bottle.response.status = 200
    return json.dumps(data)
Exemplo n.º 2
0
def pred_tile():
    ''' Method called for POST `/predTile`'''
    bottle.response.content_type = 'application/json'
    data = bottle.request.json
    data["remote_address"] = bottle.request.client_ip

    SESSION_HANDLER.get_session(bottle.request.session.id).add_entry(
        data)  # record this interaction

    # Inputs
    geom = data["polygon"]
    class_list = data["classes"]
    name_list = [item["name"] for item in class_list]
    color_list = [item["color"] for item in class_list]
    dataset = data["dataset"]
    zone_layer_name = data["zoneLayerName"]

    if dataset not in DATASETS:
        raise ValueError(
            "Dataset doesn't seem to be valid, do the datasets in js/tile_layers.js correspond to those in TileLayers.py"
        )

    try:
        naip_data, raster_profile, raster_transform, raster_bounds, raster_crs = DATASETS[
            dataset]["data_loader"].get_data_from_shape(geom["geometry"])
        naip_data = np.rollaxis(naip_data, 0, 3)
        shape_area = get_area_from_geometry(geom["geometry"])
    except NotImplementedError as e:
        bottle.response.status = 400
        return json.dumps({
            "error":
            "Cannot currently download imagery with 'Basemap' based datasets"
        })

    output = SESSION_HANDLER.get_session(bottle.request.session.id).model.run(
        naip_data, geom, True)
    output_hard = output.argmax(axis=2)
    print("Finished, output dimensions:", output.shape)

    # apply nodata mask from naip_data
    nodata_mask = np.sum(naip_data == 0, axis=2) == naip_data.shape[2]
    output_hard[nodata_mask] = 255
    vals, counts = np.unique(output_hard[~nodata_mask], return_counts=True)

    # ------------------------------------------------------
    # Step 4
    #   Convert images to base64 and return
    # ------------------------------------------------------
    tmp_id = get_random_string(8)
    img_hard = np.round(
        class_prediction_to_img(output, True, color_list) * 255,
        0).astype(np.uint8)
    img_hard = cv2.cvtColor(img_hard, cv2.COLOR_RGB2BGRA)
    img_hard[nodata_mask] = [0, 0, 0, 0]

    img_hard, img_hard_bounds = warp_data_to_3857(img_hard,
                                                  raster_crs,
                                                  raster_transform,
                                                  raster_bounds,
                                                  resolution=10)

    cv2.imwrite(os.path.join(ROOT_DIR, "downloads/%s.png" % (tmp_id)),
                img_hard)
    data["downloadPNG"] = "downloads/%s.png" % (tmp_id)

    new_profile = raster_profile.copy()
    new_profile['driver'] = 'GTiff'
    new_profile['dtype'] = 'uint8'
    new_profile['compress'] = "lzw"
    new_profile['count'] = 1
    new_profile['transform'] = raster_transform
    new_profile['height'] = naip_data.shape[0]
    new_profile['width'] = naip_data.shape[1]
    new_profile['nodata'] = 255
    f = rasterio.open(os.path.join(ROOT_DIR, "downloads/%s.tif" % (tmp_id)),
                      'w', **new_profile)
    f.write(output_hard.astype(np.uint8), 1)
    f.close()
    data["downloadTIFF"] = "downloads/%s.tif" % (tmp_id)

    f = open(os.path.join(ROOT_DIR, "downloads/%s.txt" % (tmp_id)), "w")
    f.write("Class id\tClass name\tPercent area\tArea (km^2)\n")
    for i in range(len(vals)):
        pct_area = (counts[i] / np.sum(counts))
        if shape_area is not None:
            real_area = shape_area * pct_area
        else:
            real_area = -1
        f.write("%d\t%s\t%0.4f%%\t%0.4f\n" %
                (vals[i], name_list[vals[i]], pct_area * 100, real_area))
    f.close()
    data["downloadStatistics"] = "downloads/%s.txt" % (tmp_id)

    bottle.response.status = 200
    return json.dumps(data)
Exemplo n.º 3
0
def pred_patch():
    ''' Method called for POST `/predPatch`'''
    bottle.response.content_type = 'application/json'
    data = bottle.request.json
    data["remote_address"] = bottle.request.client_ip

    SESSION_HANDLER.get_session(bottle.request.session.id).add_entry(
        data)  # record this interaction

    # Inputs
    extent = data["extent"]
    dataset = data["dataset"]
    class_list = data["classes"]
    name_list = [item["name"] for item in class_list]
    color_list = [item["color"] for item in class_list]

    # ------------------------------------------------------
    # Step 1
    #   Transform the input extent into a shapely geometry
    #   Find the tile assosciated with the geometry
    # ------------------------------------------------------

    # ------------------------------------------------------
    # Step 2
    #   Load the input data sources for the given tile
    # ------------------------------------------------------

    if dataset not in DATASETS:
        raise ValueError(
            "Dataset doesn't seem to be valid, do the datasets in js/tile_layers.js correspond to those in TileLayers.py"
        )

    naip_data, naip_crs, naip_transform, naip_bounds, naip_index = DATASETS[
        dataset]["data_loader"].get_data_from_extent(extent)
    naip_data = np.rollaxis(
        naip_data, 0, 3
    )  # we do this here instead of get_data_by_extent because not all GeoDataTypes will have a channel dimension
    SESSION_HANDLER.get_session(
        bottle.request.session.id).current_transform = (naip_crs,
                                                        naip_transform,
                                                        naip_index)

    # ------------------------------------------------------
    # Step 3
    #   Run a model on the input data
    #   Apply reweighting
    #   Fix padding
    # ------------------------------------------------------
    output = SESSION_HANDLER.get_session(bottle.request.session.id).model.run(
        naip_data, extent, False)
    assert len(
        output.shape
    ) == 3, "The model function should return an image shaped as (height, width, num_classes)"
    assert (
        output.shape[2] < output.shape[0] and output.shape[2] < output.shape[1]
    ), "The model function should return an image shaped as (height, width, num_classes)"  # assume that num channels is less than img dimensions

    # ------------------------------------------------------
    # Step 4
    #   Warp output to EPSG:3857 and crop off the padded area
    # ------------------------------------------------------
    output, output_bounds = warp_data_to_3857(output, naip_crs, naip_transform,
                                              naip_bounds)
    output = crop_data_by_extent(output, output_bounds, extent)

    # ------------------------------------------------------
    # Step 5
    #   Convert images to base64 and return
    # ------------------------------------------------------
    img_soft = np.round(
        class_prediction_to_img(output, False, color_list) * 255,
        0).astype(np.uint8)
    img_soft = cv2.imencode(".png",
                            cv2.cvtColor(img_soft,
                                         cv2.COLOR_RGB2BGR))[1].tostring()
    img_soft = base64.b64encode(img_soft).decode("utf-8")
    data["output_soft"] = img_soft

    img_hard = np.round(
        class_prediction_to_img(output, True, color_list) * 255,
        0).astype(np.uint8)
    img_hard = cv2.imencode(".png",
                            cv2.cvtColor(img_hard,
                                         cv2.COLOR_RGB2BGR))[1].tostring()
    img_hard = base64.b64encode(img_hard).decode("utf-8")
    data["output_hard"] = img_hard

    bottle.response.status = 200
    return json.dumps(data)