탐색 건너뛰기

NAIP

AerialImagery AIforEarth USDA

NAIP(National Agricultural Imagery Program)의 항공 이미지입니다.

NAIP는 미국 전체의 고해상도 항공 이미지를 제공합니다. 이 프로그램은 USDA(미국 농무부) 내의 AFPO(Aerial Field Photography Office)에서 관리합니다. 이 데이터 세트는 농업 계획 및 토지 사용 분류의 다양한 적용 분야에 사용됩니다.

스토리지 리소스

데이터는 미국 동부 데이터 센터에 있는 다음 Blob 컨테이너의 Blob(이미지당 Blob 하나)에 저장됩니다.

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

해당 컨테이너 내에서 데이터는 다음에 따라 정리됩니다.

data/v1/[year]/states/[state]/[state]_[resolution]_[year]/[quadrangle]/filename

…예:

data/v1/2011/states/al/al_1m_2011/30085/m_3008501_ne_16_1_20110815.mrf

이 필드에 대한 자세한 정보:

  • Year: 4자리 연도입니다. 데이터는 각 주에서 3~5년마다 수집됩니다(지정된 연도는 일부(전부는 아님) 주를 포함함). 예를 들어 앨라배마의 경우 2011년과 2013년 데이터는 있지만 2012년 데이터는 없고, 캘리포니아의 경우 2012년 데이터는 있지만 2011년 또는 2013년 데이터는 없습니다. Esri는 대화형 NAIP 연간 범위 맵에서 NAIP 범위에 대한 정보를 제공합니다.
  • State: 2자로 된 주 코드입니다.
  • Resolution: 해상도의 문자열 사양입니다. 모든 데이터의 “1m”을 현재 이 컨테이너에서 사용할 수 있지만, 변경될 수 있습니다.
  • Quadrangle: 7.5분 x 7.5분 영역을 지정하는 USGS 사각형 식별자입니다.

파일은 .mrf(메타 래스터 형식) 이미지(형식 사양)로 저장됩니다. 여기서 각 이미지는 3가지 파일로 표현됩니다(.xml 형식으로 된 .mrf 메타데이터 파일, 이진 인덱스(.idx) 파일 및 픽셀 데이터를 포함하는 .lrc 파일). 이 파일은 USDA에서 제공한 원래 GeoTIFF 형식에서 생성되고 Esri에서 이 파일을 정리합니다. .mrf 형식은 클라우드에 최적화되었으며 GDAL에 의해 지원됩니다.

NAIP 이미지에 액세스하고 NAIP 이미지를 그리는 전체 Python 예제는 “데이터 액세스” 아래에서 제공되는 Notebook에서 사용할 수 있습니다.

또한 Blob 컨테이너를 드라이브로 탑재할 수 있게 해주는 BlobFuse 등을 통해 NAIP 데이터에 액세스할 수 있는 읽기 전용 SAS(공유 액세스 서명) 토큰을 제공합니다.

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

Linux용 탑재 지침은 여기에 있습니다.

NAIP 데이터는 수백 테라바이트를 소비할 수 있으므로 대규모 처리는 이미지가 저장된 미국 동부 Azure 데이터 센터에서 최상으로 수행됩니다. 환경 과학 응용 분야에 NAIP 데이터를 사용 중인 경우 컴퓨팅 요구 사항을 지원하려면 지구환경 AI(AI for Earth) 보조금 신청을 고려해 보세요.

색인

모든 NAIP 파일 목록은 다음 위치에서 압축 .txt 파일로 제공됩니다.

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

또한 Microsoft에서는 위치 및 시간별로 이미지를 쉽게 쿼리할 수 있도록 SQLite 데이터베이스를 유지 관리합니다. 자세한 내용은 샘플 Notebook을 참조하세요.

또한 여기에서 데이터를 찾아볼 수 있습니다.

멋진 사진


2017년 Microsoft Redmond Campus 근처 지역의 1m 해상도 이미지입니다.

연락처

이 데이터 세트에 대한 질문이 있는 경우 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 [1]:
# 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://naipindex.blob.core.windows.net/allnaipindex/'
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 [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 download_naip_tile(mrf_url):
    """
    Given the url of a NAIP .mrf file on Azure, download the mrf file along with 
    the associated .idx and .lrc files (which together constitute a NAIP tile) to
    a local temporary directory.  Returns the paths of all downloaded files.
    
    NAIP images consist of an .mrf file (xml-formatted metadata), a binary index
    (.idx) file, and a .lrc file containing the actual pixel data.  The .mrf and
    .idx files are very small; a typical .lrc file may be in the hundreds of MB.
    """
    
    mrf_filename = os.path.join(temp_dir,mrf_url.replace('://', '_').replace('/', '_'))
    
    source_urls = [mrf_url]
    destination_filenames = [mrf_filename]

    source_urls.append(mrf_url.replace('.mrf','.idx'))
    destination_filenames.append(mrf_filename.replace('.mrf','.idx'))
    source_urls.append(mrf_url.replace('.mrf','.lrc'))
    destination_filenames.append(mrf_filename.replace('.mrf','.lrc'))

    for iFile in range(0,3):
        download_url(source_urls[iFile], destination_filenames[iFile], 
                     progress_updater=DownloadProgressBar())
        
    return destination_filenames


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]/data/v1/[year]/states/[state]/[state]_[resolution]_[year]/[quadrangle]/[filename]

year = '2011'
state = 'al'
resolution = '1m'
quadrangle = '30085'
filename = 'm_3008501_ne_16_1_20110815.mrf'
mrf_url = blob_root + '/data/v1/' + year + '/states/' + state + '/' + state + '_' + resolution + \
  '_' + year + '/' + quadrangle + '/' + filename

# Download the image
image_filenames = download_naip_tile(mrf_url)

# Plot the image
print('Reading file:\n{}'.format(os.path.basename(image_filenames[0])))
assert os.path.isfile(image_filenames[0])
display_naip_tile(image_filenames[0])
Bypassing download of already-downloaded file m_3008501_ne_16_1_20110815.mrf
Bypassing download of already-downloaded file m_3008501_ne_16_1_20110815.idx
Bypassing download of already-downloaded file m_3008501_ne_16_1_20110815.lrc
Reading file:
https_naipblobs.blob.core.windows.net_naip_data_v1_2011_states_al_al_1m_2011_30085_m_3008501_ne_16_1_20110815.mrf
Resampling to 758,663