Pomiń nawigację

NAIP

AerialImagery AIforEarth USDA

Zdjęcia lotnicze z programu NAIP (National Agricultural Imagery Program — krajowy program zdjęć rolniczych).

Program NAIP ma na celu udostępnienie zdjęć lotniczych o wysokiej rozdzielczości obejmujących cały obszar USA. Jest to program prowadzony przez biuro ds. fotografii lotniczej (AFPO) w amerykańskim Departamencie Rolnictwa (USDA). Dane są dostępne od roku 2010 do dziś.

Zasoby magazynu

Dane są przechowywane w plikach GeoTIFF zoptymalizowanych pod kątem chmury w usłudze Azure Blob Storage w centrum danych Wschodnie stany USA w następującym kontenerze obiektów blob:

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

W tym kontenerze dane zorganizowane są w następujący sposób:

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

Na przykład:

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

Więcej szczegółów na temat tych pól:

  • Rok: Cztery cyfry oznaczające rok. W każdym roku zbierane są obrazy dotyczące części stanów (nie wszystkich), a w jednym stanie dane zbierane są co 3–5 lat. Dostępne są na przykład dane dotyczące stanu Alabama z roku 2011 i 2013, ale nie 2012, a stanu Kalifornia — z roku 2012, ale nie 2011 ani 2013. Firma Esri udostępnia informacje dotyczące zakresu danych programu NAIP w postaci interaktywnej mapy rocznego zakresu programu NAIP.
  • Stan: Dwuliterowy kod stanu.
  • Rozdzielczość: Specyfikacja ciągu rozdzielczości obrazu, która ulegała zmianom w historii programu NAIP. W zależności od roku i stanu mogła wynosić “050 cm”, “060 cm” lub “100 cm”.
  • Czworobok: Identyfikator czworoboku agencji USGS określający obszar o wymiarach 7,5 x 7,5 minuty kątowej.

Pliki są przechowywane jako obrazy GeoTIFF zoptymalizowane pod kątem chmury z rozszerzeniem tif. Te pliki zostały wygenerowane (na podstawie oryginalnego formatu udostępnianego przez USDA) i zorganizowane przez firmę Esri.

Dla każdego obrazu są również dostępne małe miniatury — zamień “.tif” na “.200.jpg”, aby pobrać miniaturę. Na przykład:

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

Pełny przykład w języku Python uzyskiwania dostępu do obrazu NAIP i kreślenia go jest dostępny w notesie udostępnionym w obszarze “dostęp do danych”.

Udostępniamy również token sygnatury dostępu współdzielonego tylko do odczytu na potrzeby dostępu do danych z programu NAIP na przykład za pomocą narzędzia BlobFuse, umożliwiającego instalowanie kontenerów obiektów blob jako dysków:

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

Instrukcje instalacji dla systemu Linux są dostępne tutaj.

Dane z programu NAIP mogą zajmować kilkaset terabajtów, dlatego przetwarzanie na dużą skalę najlepiej jest wykonywać w centrum danych platformy Azure Wschodnie stany USA, w którym przechowywane są również obrazy. W przypadku korzystania z danych z programu NAIP w nauce o środowisku warto rozważyć złożenie wniosku o grant w ramach programu AI for Earth w celu sfinansowania wymaganych zasobów obliczeniowych.

Indeks

Lista wszystkich plików programu NAIP jest dostępna tutaj w postaci skompresowanego pliku csv:

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

Utrzymujemy również obiekt rtree wspomagający zapytania przestrzenne dla użytkowników języka Python. Aby poznać szczegóły, zobacz przykładowy notes.

Dane można przeglądać także tutaj.

Co się stało z plikami mrf?

W czerwcu 2020 r. zaktualizowaliśmy całe nasze archiwum NAIP, aby ulepszyć zarówno pokrycie, jak i łatwość utrzymania. Przeprowadziliśmy także przejście z formatu mrf na format GeoTIFF zoptymalizowany pod kątem chmury i wprowadziliśmy pewne zmiany w strukturach ścieżek. Pliki MRF są tymczasowo nadal dostępne w innym kontenerze. Jeśli są ważne dla Twojej pracy i potrzebujesz dostępu, skontaktuj się z aiforearthdatasets@microsoft.com.

Ładny obraz


Obraz z rozdzielczością 1 m obszaru w pobliżu kampusu firmy Microsoft w Redmond z 2017 r.

Kontakt

Jeśli masz pytania na temat tego zestawu danych, napisz na adres 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. Finally, we'll demonstrate how to retrieve only the patches you care about from our cloud-optimized image files.

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 [1]:
# Standard packages
import tempfile
import warnings
import urllib
import shutil
import os

# Workaround for a problem in older rasterio versions
os.environ["CURL_CA_BUNDLE"] = "/etc/ssl/certs/ca-certificates.crt" 

# 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
from rasterio.windows import Window 
from tqdm import tqdm

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

# URL where we've stashed a geojson file with the boundaries of Maryland.  Why do we
# need the boundaries of Maryland?  It's a surprise, you'll have to keep reading to find
# out.
maryland_boundary_url = 'https://ai4edatasetspublicassets.blob.core.windows.net/assets/maryland.json'

warnings.filterwarnings("ignore")
%matplotlib inline

Functions

In [2]:
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 [3]:
# 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