Land cover mapping API (v2) demo

This notebook demonstrates v2 of our public Land Cover Mapping API, which processes images from the National Agricultural Imaging Program and classifies individual pixels as water, forest, field, or built structures. This version of the API does not require you to upload an image; rather you specify a geographic location and retrieve cached results, computed on the most recent NAIP data. For more information, see http://aka.ms/landcovermapping.

The API is hosted via the AI for Earth API Platform.

Download the notebook (.ipynb).

Imports and constants

In [1]:
import math
import requests
import io
import base64
import matplotlib.pyplot as plt
from pyproj import Proj, transform
from imageio import imread
from geopy.geocoders import Nominatim
import landcover_v2_config as cfg
import reverse_geocoder as rg 
import random

%autosave 0

host_url= 'https://aiforearth.azure-api.net/landcover'
base_url = host_url + '/v2'
health_url = base_url + "/"

api_header = {'Ocp-Apim-Subscription-Key': cfg.SUBSCRIPTION_KEY, 'Content-Type':'application/json'}

patch_size = 500
weights = [0.25, 0.25, 0.25, 0.25]

print(str(requests.get(health_url, headers=api_header).text))
Autosave disabled
Health check OK

Functions

In [2]:
def get_location_from_address(address):
    
    geolocator = Nominatim(user_agent="landcover")
    location = geolocator.geocode(address)
    print(location.address)
    return location.latitude, location.longitude

def get_random_location_in_USA():
    
    # US points
    NORTHERNMOST = 40.
    SOUTHERNMOST = 30.
    EASTERNMOST = -90.
    WESTERNMOST = -100.    
    country_code = None
    
    # Pick random coordinates in this box until one lands in the US
    while country_code != 'US':
        lat = round(random.uniform(SOUTHERNMOST, NORTHERNMOST), 6)
        lon = round(random.uniform(EASTERNMOST, WESTERNMOST), 6)
        results = get_location_details(lat, lon)
        country_code = results['cc']
        
    print_location_details(results)

    return lat, lon

def get_location_details(lat, lon):
    
    results = rg.search((lat,lon))[0]
    country_code = results['cc']
    return results

def print_location_details(results):
    
    print("Location details:")
    print(results['name'])
    print(results['admin1'])
    print(results['admin2'])
    print(results['cc'])
     
def get_projected(lat, lng):
    
    P3857 = Proj(init='epsg:3857', preserve_units = True)
    P4326 = Proj(init='epsg:4326')
    x,y= transform(P4326, P3857, lng, lat)
    
    return x, y   

def get_unprojected(x, y):
    
    P3857 = Proj(init='epsg:3857', preserve_units = True)
    P4326 = Proj(init='epsg:4326')

    
    lat,lng = transform(P3857,P4326,x,y)
    
    return lng, lat

def get_polygon(latitude, longitude):
    
    latlonProjected = get_projected(latitude, longitude)
    x = latlonProjected[0];
    y = latlonProjected[1];
    
    top = y + patch_size/2;
    bottom = y - patch_size/2;
    left = x - patch_size/2;
    right = x + patch_size/2;

    top = int(round(top));
    bottom = int(round(bottom));
    left = int(round(left));
    right = int(round(right));
    
    topleft = get_unprojected(left, top);
    bottomright = get_unprojected(right, bottom);
                
    return( [
            [topleft[0], topleft[1]],
            [topleft[0], bottomright[1]] ,
            [bottomright[0], bottomright[1]] ,
            [bottomright[0], topleft[1]]
           ] )

def get_extent_values(polygon):
    
    topleft = [polygon[0][0], polygon[0][1]]
    topleftProjected = get_projected(topleft[0], topleft[1])
    bottomright = [polygon[2][0], polygon[2][1]]
    bottomrightProjected = get_projected(bottomright[0], bottomright[1])
    
    xmax =  bottomrightProjected[0]
    xmin =  topleftProjected[0]
    ymax =  topleftProjected[1]
    ymin =  bottomrightProjected[1]
    
    return {"xmax": xmax, "xmin" : xmin, "ymax" :ymax, "ymin": ymin }
    
def get_input_naip_by_extent(extent):  
    
    r = requests.post(base_url + "/tilebyextent", json=extent, headers=api_header)    
    input_naip = imread(io.BytesIO(base64.b64decode(r.json()['input_naip'])))
    return input_naip

def predict_patch_by_extent(extent):
    
    r = requests.post(base_url + "/classifybyextent", json=extent, headers=api_header).json()
    output_image = imread(io.BytesIO(base64.b64decode(r['output_hard'])))
    
    return output_image

def get_tile(latitude, longitude):
        
    request_data = {
                    'lat': latitude, 
                    'lon': longitude, 
                    'patchSize':patch_size, 
                    'latestWkid': 3857, 
                   }
    
    r = requests.post(base_url + '/tile', json=request_data, headers=api_header)
    input_naip = imread(io.BytesIO(base64.b64decode(r.json()['input_naip'])))
    
    return input_naip
    
def predict_patch_by_latlong(latitude, longitude):
        
    request_data = {
                    'lat': latitude, 
                    'lon': longitude, 
                    'patchSize':patch_size, 
                    'latestWkid': 3857, 
                    'weights': weights
                   }
    
    r = requests.post(base_url + "/classify", json=request_data, headers=api_header)
    
    output_image = imread(io.BytesIO(base64.b64decode(r.json()['output_hard'])))
    
    return output_image

def plot_image(image):
    
    plt.figure(figsize=(8,8))
    imgplot=plt.imshow(image, aspect='auto')
    plt.show()    

Specify target location by address

In [ ]:
# Get latitude and longitude for a US address location
address = '15255 NE 40th St, Redmond, WA 98052'
latitude,longitude = get_location_from_address(str(address))

...or choose a random US location

In [6]:
latitude,longitude = get_random_location_in_USA()
Location details:
Liberty
Mississippi
Amite County
US

Retrieve and display source image (using lat/lon)

In [7]:
print("Retrieving input image from API...")
image = get_tile(latitude, longitude)
                                
print("\nPlotting image...")
plot_image(image)
Retrieving input image from API...

Plotting image...

Retrieve and display results (using lat/lon)

In [8]:
print("Retrieving output image from API...")
output_image = predict_patch_by_latlong(latitude, longitude)

print("\nPlotting image...")
plot_image(output_image)
Retrieving output image from API...

Plotting image...

Retrieve and display source image (using extent values)

In [9]:
polygon = get_polygon(latitude,longitude)
     
values = get_extent_values(polygon)

extent = {
    "extent": {
    "xmax": values["xmax"],
    "xmin": values["xmin"],
    "ymax": values["ymax"],
    "ymin": values["ymin"],
    "spatialReference": {
        "latestWkid": 3857
     },
    }
}

print("Retrieving input image from API...")
image = get_input_naip_by_extent(extent)
                                
print("\nPlotting image...")                              
plot_image(image)
Retrieving input image from API...

Plotting image...