in server.py [0:0]
def pred_tile():
bottle.response.content_type = 'application/json'
data = bottle.request.json
current_session = SESSION_HANDLER.get_session(bottle.request.session.id)
current_session.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"]
model_idx = data["modelIdx"]
if dataset not in DATALOADERS:
raise ValueError("Dataset doesn't seem to be valid, do the datasets in js/tile_layers.js correspond to those in TileLayers.py")
else:
current_data_loader = DATALOADERS[dataset]
try:
input_raster = current_data_loader.get_data_from_geometry(geom["geometry"])
shape_area = get_area_from_geometry(geom["geometry"])
except NotImplementedError as e: # Example of how to handle errors from the rest of the server
bottle.response.status = 400
return json.dumps({"error": "Cannot currently download imagery with 'Basemap' based datasets"})
output_raster = current_session.pred_tile(input_raster)
if output_raster.shape[2] > len(color_list):
LOGGER.warning("The number of output channels is larger than the given color list, cropping output to number of colors (you probably don't want this to happen")
output_raster.data = output_raster.data[:,:,:len(color_list)]
output_hard = output_raster.data.argmax(axis=2)
nodata_mask = np.sum(input_raster.data == 0, axis=2) == input_raster.shape[2]
output_hard[nodata_mask] = 255
class_vals, class_counts = np.unique(output_hard[~nodata_mask], return_counts=True)
img_hard = class_prediction_to_img(output_raster.data, True, color_list)
img_hard = cv2.cvtColor(img_hard, cv2.COLOR_RGB2BGRA)
img_hard[nodata_mask] = [0,0,0,0]
# replace the output predictions with our image data because we are too lazy to make a new InMemoryRaster
output_raster.data = img_hard
output_raster.shape = img_hard.shape
warped_output_raster = warp_data_to_3857(output_raster) # warp output to 3857
cropped_warped_output_raster = crop_data_by_geometry(warped_output_raster, geom["geometry"], "epsg:4326") # crop to the desired shape
img_hard = cropped_warped_output_raster.data
tmp_id = get_random_string(8)
cv2.imwrite("tmp/downloads/%s.png" % (tmp_id), img_hard)
data["downloadPNG"] = "tmp/downloads/%s.png" % (tmp_id)
new_profile = {}
new_profile['driver'] = 'GTiff'
new_profile['dtype'] = 'uint8'
new_profile['compress'] = "lzw"
new_profile['count'] = 1
new_profile['transform'] = output_raster.transform
new_profile['height'] = output_hard.shape[0]
new_profile['width'] = output_hard.shape[1]
new_profile['nodata'] = 255
new_profile['crs'] = output_raster.crs
with rasterio.open("tmp/downloads/%s.tif" % (tmp_id), 'w', **new_profile) as f:
f.write(output_hard.astype(np.uint8), 1)
data["downloadTIFF"] = "tmp/downloads/%s.tif" % (tmp_id)
data["classStatistics"] = []
f = open("tmp/downloads/%s.txt" % (tmp_id), "w")
f.write("Class id\tClass name\tPercent area\tArea (km^2)\n")
for i in range(len(class_vals)):
pct_area = (class_counts[i] / np.sum(class_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" % (class_vals[i], name_list[class_vals[i]], pct_area*100, real_area))
data["classStatistics"].append({
"Class ID": int(class_vals[i]),
"Class Name": name_list[class_vals[i]],
"Percent Area": float(pct_area),
"Area (km2)": float(real_area)
})
f.close()
data["downloadStatistics"] = "tmp/downloads/%s.txt" % (tmp_id)
bottle.response.status = 200
return json.dumps(data)