Hoppa över navigering

NAIP

AerialImagery AIforEarth USDA

Flygfoton från National Agricultural Imagery Program (NAIP).

NAIP tar flygfoton med hög upplösning av hela USA. Programmet administreras av Aerial Field Photography Office (AFPO) vid US Department of Agriculture (USDA). Den här datamängden används för landskapsplanering och klassificering av mark.

Lagringsresurser

Data lagras i molnoptimerade GeoTIFF-filer i Azure Blob Storage i datacentret Östra USA, i följande blobcontainer:

https://naipblobs.blob.core.windows.net/naip

I containern organiseras datan efter:

v002/[state]/[year]/[state]_[resolution]_[year]/[quadrangle]/filename

… till exempel:

v002/al/2015/al_100cm_2015/30086/m_3008601_ne_16_1_20150804.tif

Mer information om dessa fält:

  • År: År med fyra siffror. Bilder samlas in i varje delstat var 3:e till 5:e år, där några (men inte alla) delstater bearbetas ett visst år. Exempelvis finns det data om Alabama från 2011 och 2013 men inte 2012, medan det finns data om Kalifornien från 2012 men inte 2011 eller 2013. ESRI tillhandahåller information om NAIP-täckningen i sin årliga interaktiva NAIP-karta.
  • Delstat: Delstatskod med två bokstäver.
  • Upplösning: Strängspecifikation av bildupplösning, som har varierat i NAIP:s historik. Beroende på år och delstat kan detta vara “050 cm”, “060 cm” eller “100 cm”.
  • Fyrhörning: USGS-identifiering av fyrhörning som anger ett område på 7,5 × 7,5 minut.

Filer lagras som molnoptimerade GeoTIFF-bilder, med filnamnstillägget .tif. Filerna producerades (i det ursprungliga formatet från USDA) och organiserades av ESRI.

Små miniatyrbilder är också tillgängliga för varje bild. Ersätt bara “.tif” med “.200.jpg” för att hämta miniatyrbilden. Exempel:

https://naipblobs.blob.core.windows.net/naip/v002/al/2013/al_100cm_2013/30086/m_3008601_ne_16_1_20130928.200.jpg

Ett komplett Python-exempel som visar hur du kommer åt och ritar ut en NAIP-bild finns i anteckningsboken under “Data Access”.

Vi tillhandahåller också en skrivskyddad SAS-token (signatur för delad åtkomst) som ger åtkomst till NAIP-data via exempelvis BlobFuse, vilket innebär att du kan montera blobcontainrar som enheter:

st=2019-07-18T03%3A53%3A22Z&se=2035-07-19T03%3A53%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=2RIXmLbLbiagYnUd49rgx2kOXKyILrJOgafmkODhRAQ%3D

Monteringsanvisningarna för Linux finns här.

NAIP-data kan förbruka hundratals terabyte, så bearbetning i stor skala utförs bäst i Azures datacenter Östra USA där bilderna lagras. Om du använder NAIP-data i miljövetenskapsprogram kan du ansöka om AI for Earth Grant som kan vara till hjälp vid dina beräkningar.

Index

En lista med alla NAIP-filer finns som en komprimerad CSV-fil här:

https://naipblobs.blob.core.windows.net/naip-index/naip_v002_index.zip

Det finns också ett rtree-objekt som gör det enklare för Python-användare att köra spatialfrågor. Mer information finns i denna exempel-notebook.

Du kan också söka efter data här.

Vad har hänt med MRF-filerna?

I juni 2020 uppdaterade vi hela vårt NAIP-arkiv för att förbättra såväl täckning som underhåll. Vi bytte även från MRF-format till molnoptimerade GeoTIFF, och gjorde vissa ändringar i sökvägsstrukturen. Vi kommer att bevara MRF-kopian av data i ungefär sex månader så att användarna har tid att genomföra övergången.

Fin bild


Bilder med en upplösning på 1 m av området nära Microsofts Redmond Campus 2017.

Kontakt

Om du har frågor om den här datamängden är du välkommen att kontakta aiforearthdatasets@microsoft.com.

Access

Available inWhen to use
Azure Notebooks

Quickly explore the dataset with Jupyter notebooks hosted on Azure or your local machine.

Select your preferred service:

Azure Notebooks

Azure Notebooks

Package: Language: Python

Demo notebook for accessing NAIP data on Azure

This notebook provides an example of accessing NAIP data from blob storage on Azure, displaying an image using the rasterio library.

We will demonstrate how to access and plot a tile given a known tile filename, as well as how to access tiles by lat/lon.

NAIP data are stored in the East US data center, so this notebook will run most efficiently on Azure compute located in East US. We recommend that substantial computation depending on NAIP data also be situated in East US. You don't want to download hundreds of terabytes to your laptop! If you are using NAIP data for environmental science applications, consider applying for an AI for Earth grant to support your compute requirements.

Imports and environment

In [7]:
# Standard packages
import tempfile
import warnings
import urllib
import shutil
import os

# Less standard, but still pip- or conda-installable
import matplotlib.pyplot as plt
import numpy as np
import rasterio
import rtree
import shapely
import pickle

# pip install progressbar2, not progressbar
import progressbar

from geopy.geocoders import Nominatim

latest_wkid = 3857
crs = "EPSG:4326"

# Storage locations are documented at http://aka.ms/ai4edata-naip
blob_root = 'https://naipblobs.blob.core.windows.net/naip'

index_files = ["tile_index.dat", "tile_index.idx", "tiles.p"]
index_blob_root = 'https://naipblobs.blob.core.windows.net/naip-index/rtree/'
temp_dir = os.path.join(tempfile.gettempdir(),'naip')
os.makedirs(temp_dir,exist_ok=True)

# Spatial index that maps lat/lon to NAIP tiles; we'll load this when we first 
# need to access it.
index = None

warnings.filterwarnings("ignore")
%matplotlib inline

Functions

In [8]:
class DownloadProgressBar():
    """
    https://stackoverflow.com/questions/37748105/how-to-use-progressbar-module-with-urlretrieve
    """
    
    def __init__(self):
        self.pbar = None

    def __call__(self, block_num, block_size, total_size):
        if not self.pbar:
            self.pbar = progressbar.ProgressBar(max_value=total_size)
            self.pbar.start()
            
        downloaded = block_num * block_size
        if downloaded < total_size:
            self.pbar.update(downloaded)
        else:
            self.pbar.finish()
            

class NAIPTileIndex:
    """
    Utility class for performing NAIP tile lookups by location.
    """
    
    tile_rtree = None
    tile_index = None
    base_path = None
    
    def __init__(self, base_path=None):
        
        if base_path is None:
            
            base_path = temp_dir
            os.makedirs(base_path,exist_ok=True)
            
            for file_path in index_files:
                download_url(index_blob_root + file_path, base_path + '/' + file_path,
                             progress_updater=DownloadProgressBar())
                
        self.base_path = base_path
        self.tile_rtree = rtree.index.Index(base_path + "/tile_index")
        self.tile_index = pickle.load(open(base_path  + "/tiles.p", "rb"))
      
    
    def lookup_tile(self, lat, lon):
        """"
        Given a lat/lon coordinate pair, return the list of NAIP tiles that contain
        that location.

        Returns an array containing [mrf filename, idx filename, lrc filename].
        """

        point = shapely.geometry.Point(float(lon),float(lat))
        intersected_indices = list(self.tile_rtree.intersection(point.bounds))

        intersected_files = []
        tile_intersection = False

        for idx in intersected_indices:

            intersected_file = self.tile_index[idx][0]
            intersected_geom = self.tile_index[idx][1]
            if intersected_geom.contains(point):
                tile_intersection = True
                intersected_files.append(intersected_file)

        if not tile_intersection and len(intersected_indices) > 0:
            print('''Error: there are overlaps with tile index, 
                      but no tile completely contains selection''')   
            return None
        elif len(intersected_files) <= 0:
            print("No tile intersections")
            return None
        else:
            return intersected_files
        
            
def download_url(url, destination_filename=None, progress_updater=None, force_download=False):
    """
    Download a URL to a temporary file
    """
    
    # This is not intended to guarantee uniqueness, we just know it happens to guarantee
    # uniqueness for this application.
    if destination_filename is None:
        url_as_filename = url.replace('://', '_').replace('/', '_')    
        destination_filename = \
            os.path.join(temp_dir,url_as_filename)
    if (not force_download) and (os.path.isfile(destination_filename)):
        print('Bypassing download of already-downloaded file {}'.format(os.path.basename(url)))
        return destination_filename
    print('Downloading file {} to {}'.format(os.path.basename(url),destination_filename),end='')
    urllib.request.urlretrieve(url, destination_filename, progress_updater)  
    assert(os.path.isfile(destination_filename))
    nBytes = os.path.getsize(destination_filename)
    print('...done, {} bytes.'.format(nBytes))
    return destination_filename
    

def display_naip_tile(filename):
    """
    Display a NAIP tile using rasterio.
    
    For .mrf-formatted tiles (which span multiple files), 'filename' should refer to the 
    .mrf file.
    """
    
    # NAIP tiles are enormous; downsize for plotting in this notebook
    dsfactor = 10
    
    with rasterio.open(filename) as raster:

        # NAIP imagery has four channels: R, G, B, IR
        #
        # Stack RGB channels into an image; we won't try to render the IR channel
        #
        # rasterio uses 1-based indexing for channels.
        h = int(raster.height/dsfactor)
        w = int(raster.width/dsfactor)
        print('Resampling to {},{}'.format(h,w))
        r = raster.read(1, out_shape=(1, h, w))
        g = raster.read(2, out_shape=(1, h, w))
        b = raster.read(3, out_shape=(1, h, w))        
    
    rgb = np.dstack((r,g,b))
    fig = plt.figure(figsize=(7.5, 7.5), dpi=100, edgecolor='k')
    plt.imshow(rgb)
    raster.close()
    
    
def get_coordinates_from_address(address):
    """
    Look up the lat/lon coordinates for an address.
    """
    
    geolocator = Nominatim(user_agent="NAIP")
    location = geolocator.geocode(address)
    print('Retrieving location for address:\n{}'.format(location.address))
    return location.latitude, location.longitude

Access and plot a NAIP tile by constructing a path

In [9]:
# Tiles are stored at:
#
# [blob root]/v002/[state]/[year]/[state]_[resolution]_[year]/[quadrangle]/filename

year = '2015'
state = 'al'
resolution = '100cm'
quadrangle = '30086'
filename = 'm_3008601_ne_16_1_20150804.tif'
tile_url = blob_root + '/v002/' + state + '/' + year + '/' + state + '_' + resolution + \
    '_' + year + '/' + quadrangle + '/' + filename

print(tile_url)

# Download the image
image_filename = download_url(tile_url,progress_updater=DownloadProgressBar())

# Plot the image
print('Reading file:\n{}'.format(os.path.basename(image_filename)))
assert os.path.isfile(image_filename)
display_naip_tile(image_filename)
https://naipblobs.blob.core.windows.net/naip/v002/al/2015/al_100cm_2015/30086/m_3008601_ne_16_1_20150804.tif
Bypassing download of already-downloaded file m_3008601_ne_16_1_20150804.tif
Reading file:
https_naipblobs.blob.core.windows.net_naip_v002_al_2015_al_100cm_2015_30086_m_3008601_ne_16_1_20150804.tif
Resampling to 753,657