點擊圖片上方藍色字體「慧天地」即可訂閱
衛星遙感影像下載是擋在地學及相關學科科研道路上的攔路虎,在國外可以通過對Google Earth Engine(GEE)中的Landsat,MODIS,哨兵二號衛星(Sentinel-2)等眾多衛星影像數據直接進行雲上處理獲取感興趣區域結果。它是如此之好,只可惜啊,像我這樣的人,囊中羞澀怎會為其支付昂貴費用呢?特別是當領導要結果時,還是需要經過Google Driver box下載到本地的,而這也又是一筆不菲的費用。當然,這裡就不點名那些同行們利用這個心理大勢宣傳GEE如何牛逼的複雜經濟背景問題了。做研究嘛,還是要看在哪個國家的。至於道理,大家都懂,在國內下載影像數據,會有成千上萬個草泥馬從腦袋裡面跑出來。不得不說,國家隊的XX圖發布的高分免費下載服務帶來了巨大震撼,但那又如何,像我這樣的科研貧民不還是搞不到被他們宣傳成極品的數據麼?怎麼幹掉這個攔路虎,怎麼不再擔心遙感數據下載、質量檢查的事情呢?團隊成員一直鼓勵我探索,我想現在是時候誠心奉獻哨兵影像數據高速下載方法了。
歐空局的哨兵數據自然是精品,如果非要槓精地說美國航空航天局出品的Landsat系列衛星數據也很好,那也無可厚非。廢話不多說,本文後續包含四個部分。在第一部分,在簡要介紹哨兵影像數據的概況之後,以Sentinel-2數據為例,介紹如何通過ESA的API hub查詢指定地理空間範圍的Sentinel-2影像數據。在第二部分介紹如何通過通過配置aria2下載工具下載查詢到的Sentinel-2影像數據,重點介紹python守護進程用於監控和管理aria2工具的重啟。第三部分,介紹如何通過python程序更新Aria2的Sentinel-2數據下載清單。最後,一部分是題外話部分,不感興趣可以不看。(篇幅較長,需多點耐心)
第一部分:哨兵數據介紹及使用API查詢的兩種方式(含代碼)
哨兵一號(Sentinel-1)是由兩顆極軌衛星組成的,通過C波段合成孔徑雷達成像儀,不受天氣影響情況下獲取圖像。它是歐空局為哥白尼計劃開發的五個任務中的第一個衛星計劃。
哨兵二號(Sentinel-2)也是由兩顆極軌衛星組成的星座,兩顆衛星在同一太陽同步軌道上,主要任務是監控陸地地表變化。幅寬是290km²,兩顆衛星在無雲條件下重訪中緯度地區需要2~3天時間。官網上給出的覆蓋區域描述:
The Sentinel-2 mission will provide systematic coverage over the following areas:
all continental land surfaces (including inland waters) between latitudes 56° south and 84° north(在北緯56° 和南緯84°之間的地表區域)
all coastal waters up to 20 km from the shore
all islands greater than 100 km²
all EU islands(整個歐洲大陸區域)
the Mediterranean Sea (地中海)
all closed seas (e.g. Caspian Sea).
In addition, the Sentinel-2 observation scenario includes observations following member states or Copernicus Services requests (e.g. Antarctica, Baffin Bay).
圖1 Sentinel-2(哨兵二號)衛星的重訪周期
(圖片來源:https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/revisit-coverage)
兩顆衛星Sentinel-2A和Sentinel-2B在相同視角條件下,每5天重訪陸地地表的大部分區域。由於相鄰軌道的不同條帶會重疊,重訪部分區域的周期在不同視角條件下會不相同,但最多不超過10天。
圖2 因鄰近軌道重疊導致的重訪周期差異
(圖片來源:https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi/revisit-coverage)
哨兵三號(Sentinel-3)是有歐空局和歐洲氣象組織聯合運營,提供可操作的海洋和陸地觀測服務,主要目標是以高精度和可靠性測量海面地形、海陸表面溫度和海陸表面顏色,以支持海洋預報系統、環境監測和氣候監測。在哨兵三號衛星上通過海洋和陸地彩色儀器(OLCI)、海洋和陸地表面溫度輻射計(SLSTR)、合成孔徑雷達高度計(SRAL)、微波輻射計(MWR)和精密定軌(POD)儀器獲得圖像。
哨兵五號(Sentinel-5)先驅者主要用於進行大氣測量,用於空氣品質、臭氧和紫外線輻射以及氣候監測和預報,該衛星採用推掃式成像,對地球表面的掃描帶寬度約為2600公裡。除了UV1波段(7x28km²)和SWIR波段(7x7km²),所有光譜波段的典型像素大小(接近最低點)約為7x3.5km²。
歐空局通過OpenHub和的API Hub向外提供數據服務,前面一個提供交互式地圖查詢數據,後一個通過API服務查詢哨兵數據。這裡重點介紹後面一個。第一種通過指定的Tile編號查詢,直接上完整的python程序,首先用在歐空局官網上註冊的帳號密碼作為參數傳遞到SentinelAPI函數中。
敲重點:
import argparseimport datetimeimport globimport numpy as npimport osimport reimport timeimport sentinelsatimport zipfileimport timeimport pdbimport pandasfrom sentinelsat import SentinelAPI, read_geojson, geojson_to_wktfrom pandas import DataFrameimport pandas as pdimport hashlib
#用於獲取下載哨兵二指定tile或者指定矢量的哨兵影像所需的URL地址、# md5校驗碼及長度#用於檢驗那些未下載完的連結,#以獲取2019年全年武漢覆蓋武漢區域的哨兵二號衛星2A級產品為例,# 黑色標註的startdate ,enddate ,level ,specify_tiles # 分別代表了所要查詢的數據開始時間、結束時間、影像產品級別、指定的空間範圍。(武漢剛好跨越5個tiles)
def getSentinelUrlByTiles():scihub_api = SentinelAPI('用戶名', '密碼', 'scihub.copernicus.eu/dh')startdate = sentinelsat.format_query_date('20190101')enddate = sentinelsat.format_query_date('20191231')# Search data, filtering by options.level = '2A'# tile = '50RLV'specify_tiles = ['49RGQ', '49RGP', '50RKU', '50RKV', '50RLV'] # 指定需要下載的tiles
final_urls = DataFrame()url_list = []md5_list = []for tile in specify_tiles:products = scihub_api.query(beginposition=(startdate, enddate),platformname='Sentinel-2',producttype='S2MSI%s' % level,cloudcoverpercentage=(0, 100), filename='*T%s*' % tile)
products_df = scihub_api.to_dataframe(products)#使用print(products_df)會看到下面的結果,其中id,md5,url最為重要
# {'id': 'd9c11a08-9548-423a-9d5b-3790bdd1949b', # 'title': 'S2B_MSIL1C_20180322T031539_N0206_R118_T49SCS_20180322T080731', # 'size': 557305492, # 'md5': 'A4DEE331BABF5D81FEEFED7E8F152E1A', # 'date': datetime.datetime(2018, 3, 22, 3, 15, 39, 27000), # 'footprint': 'POLYGON((109.12450894645511 32.434247217341294,109.15551946020656 32.55886040012398,109.19500574164893 32.7064511260414,109.23422411890954 32.85418162235375,109.27416742227145 33.00170389409306,109.31402177718599 33.149262433169554,109.35311404383268 33.297123960618194,109.38830946718173 33.42770696377061,110.02964494156487 33.435778798872015,110.04040193865697 32.44547285973725,109.12450894645511 32.434247217341294))', 'url': "scihub.copernicus.eu/dh('d9c11a08-9548-423a-9d5b-3790bdd1949b')/$value", 'Online': False, 'Creation Date': datetime.datetime(2018, 3, 22, 11, 36, 6, 645000), 'Ingestion Date': datetime.datetime(2018, 3, 22, 11, 25, 45, 119000)}
for i in range(len(products_df)):product = scihub_api.get_product_odata(products_df.iloc[i]['uuid'])print(product['url'])url_list.append(product['url'])print(product['md5'])md5_list.append((product['md5']))
final_urls['url'] = url_listfinal_urls['md5'] = md5_list
final_urls.to_csv("finale_urls_md5.csv", index=False)# 這裡的md5一定要記錄下來
# 第二種方式是,通過geojson指定的空間範圍對影像數據進行查詢,# 如何獲得geojson這個事情就不在這裡介紹了。# 同樣得到一個pandas products_df 和之前是樣的。# 最後的記過可以輸出到csv文件中。# footprint = geojson_to_wkt(read_geojson('test.geojson'))# products = scihub_api.query(footprint,# beginposition=(startdate, enddate),# platformname='Sentinel-2')
# convert to Pandas DataFrame# products_df = scihub_api.to_dataframe(products)# print("..")# print(products_df)# pass第二部分:Aria2下載工具配置(以windows下面的配置文件為例)最重要的就是aria2.conf這個配置文件,標註黑色的地方,dir,input-file,http-user,http-passwd 分別表示目錄、要下載數據的連結地址(存儲在文本文件中),第三個是用戶名,第四個是訪問密碼。其它配置包括自動續傳、不覆蓋之前已下載的文件等。如果不是因為知乎需要XX度帳號上傳附件,我還真是會全部上傳aria2的配程序包。(XX度總是那麼坑爹,這裡不多說了)## '#'開頭為注釋內容, 選項都有相應的注釋說明, 根據需要修改 #### 被注釋的選項填寫的是默認值, 建議在需要修改時再取消注釋 #### 文件保存相關 ### 文件的保存路徑(可使用絕對路徑或相對路徑), 默認: 當前啟動位置dir=GPPinput-file=5368574491-download_GPP.txt# 啟用磁碟緩存, 0為禁用緩存, 需1.16以上版本, 默認:16Mdisk-cache=32M# 文件預分配方式, 能有效降低磁碟碎片, 默認:prealloc# 預分配所需時間: none < falloc < trunc < prealloc# NTFS建議使用fallocfile-allocation=none# 斷點續傳continue=trueallow-overwrite=false## 下載連接相關 ### 最大同時下載任務數, 運行時可修改, 默認:5max-concurrent-downloads=10# 同一伺服器連接數, 添加時可指定, 默認:1max-connection-per-server=5# 最小文件分片大小, 添加時可指定, 取值範圍1M -1024M, 默認:20M# 假定size=10M, 文件為20MiB 則使用兩個來源下載; 文件為15MiB 則使用一個來源下載min-split-size=10M# 單個任務最大線程數, 添加時可指定, 默認:5split=20# 整體下載速度限制, 運行時可修改, 默認:0#max-overall-download-limit=0# 單個任務下載速度限制, 默認:0#max-download-limit=0# 整體上傳速度限制, 運行時可修改, 默認:0max-overall-upload-limit=1M# 單個任務上傳速度限制, 默認:0#max-upload-limit=1000000# 禁用IPv6, 默認:falsedisable-ipv6=falsemax-download-result=1000000max-tries=50http-user=XXXXXhttp-passwd=YYYY# 從會話文件中讀取下載任務always-resume=truemax-file-not-found=100# 在Aria2退出時保存`錯誤/未完成`的下載任務到會話文件save-session=aria2.session# 定時保存會話, 0為退出時才保存, 需1.16.1以上版本, 默認:0#save-session-interval=60## RPC相關設置 ### 啟用RPC, 默認:falseenable-rpc=true# 允許所有來源, 默認:falserpc-allow-origin-all=true# 允許非外部訪問, 默認:falserpc-listen-all=true# 事件輪詢方式, 取值:[epoll, kqueue, port, poll, select], # 不同系統默認值不同#event-poll=select# RPC監聽埠, 埠被佔用時可以修改, 默認:6800#rpc-listen-port=6800# 設置的RPC授權令牌, v1.18.4新增功能, # 取代 --rpc-user 和 --rpc-passwd 選項#rpc-secret=mivm.cn# 設置的RPC訪問用戶名, 此選項新版已廢棄, 建議改用 --rpc-secret 選項#rpc-user=<USER># 設置的RPC訪問密碼, 此選項新版已廢棄, 建議改用 --rpc-secret 選項#rpc-passwd=<PASSWD>## BT/PT下載相關 ### 當下載的是一個種子(以.torrent結尾)時, 自動開始BT任務, 默認:truefollow-torrent=true# BT監聽埠, 當埠被屏蔽時使用, 默認:6881-6999listen-port=51413# 單個種子最大連接數, 默認:55#bt-max-peers=55# 打開DHT功能, PT需要禁用, 默認:trueenable-dht=true# 打開IPv6 DHT功能, PT需要禁用#enable-dht6=false# DHT網絡監聽埠, 默認:6881-6999#dht-listen-port=6881-6999# 本地節點查找, PT需要禁用, 默認:false#bt-enable-lpd=true# 種子交換, PT需要禁用, 默認:trueenable-peer-exchange=true# 每個種子限速, 對少種的PT很有用, 默認:50K#bt-request-peer-speed-limit=50K# 客戶端偽裝, PT需要peer-id-prefix=-TR2770-user-agent=Transmission/2.77# 當種子的分享率達到這個數時, 自動停止做種, 0為一直做種, 默認:1.0seed-ratio=0.1# 強制保存會話, 即使任務已經完成, 默認:false# 較新的版本開啟後會在任務完成後依然保留.aria2文件#force-save=false# BT校驗相關, 默認:true#bt-hash-check-seed=true# 繼續之前的BT任務時, 無需再次校驗, 默認:falsebt-seed-unverified=true# 保存磁力連結元數據為種子文件(.torrent文件), 默認:false#bt-save-metadata=true以本地電腦的D盤目錄為例,說明下載步驟,首先要點擊和運行EasyWebSvr.exe這個可執行程序,做一個web服務層。按照之前的配置文件配置好aria2.conf,如圖3所示:
圖3. aria2文件夾中的有關文件
打開EasyWebSrc.exe的配置界面,如圖4所示,設置主目錄為當前aria2配置文件所在目錄,確定其已打開。
圖4.EasyWebSrc.exe的配置界面
之前提到過,通過api hub訪問哨兵數據集會有一些約束:The API Hub is managed with the same quota restrictions, ie. a limit of two parallel downloads per user. The site is publishing precisely the same data content as the Scientific Data Hub (both Sentinel-1 and Sentinel-2). (也就是一個用戶最大的並行下載速度是有限制的,而且還有約束條件,例如經常用一個機器一個帳戶下載,機器的IP會被鎖定,帳號會受到限制)
aria2雖然下載速度挺快,但是在嘗試多次下載失敗後,不會重新下載對應的連結了。因此,我在這裡使用一個downloadermanagy.py的文件,這個文件在圖3所示的目錄中有顯示。具體給出python代碼,這個代碼通過子進程模塊,調用aria2c.exe這個可執行文件,從子進程的標準輸出中查看下載數據的列印信息,如果發現最後一條列印信息一直不發生變化,則調用terminate()函數終止該子進程,然後重新執行循環。(需要注意的是python沒有goto語句,可以安裝一個with-go模塊實現循環跳轉)
#!/usr/bin/env python#coding : utf-8import subprocessimport hashlibimport os,timeimport sysfrom subprocess import Popen, PIPEimport timefrom goto import with_gotodef getMd5OfFile(fname):if not os.path.exists(fname):return Nonetry:f = file(fname, 'rb')md5 = hashlib.md5()while True:# 每次讀16Kd = f.read(16384)if not d:breakmd5.update(d)f.close()return md5.hexdigest()except Exception :return None@with_gotodef start_download():label .begininput_file = "user2.txt"image_count = len(open(input_file, 'rU').readlines())last_line = ""sleep_total_second = 60#print(image_count)with Popen("D:\\aria2\\aria2c.exe --conf-path=aria2.conf", shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=20000, universal_newlines=True) as p:for line in p.stdout:#如果最後一行一直沒有發生變化,則向原來的進程發中止信號,並退出#print(line)#print(len(line))if (line == '\n' and last_line==""):continueelse:if last_line == "":last_line = linecontinueelse:#line = line.strip()if last_line == line:sleep_total_second = sleep_total_second - 1time.sleep(1)if sleep_total_second == 0:p.terminate()breakelse:if line == '\n':continueelse:print(line)last_line = linecontinuegoto .beginif __name__ == "__main__":#cmd = 'cmd.exe D:\\aria2\\Start.bat'#首先看需要下載多少個文件start_download() 也可以通過點擊EasyWebSrc.exe的右鍵,找到瀏覽主頁,看到如圖5所示的數據下載界面。圖5 aria2數據下載界面
經過這樣的折騰,aira2下載工具就能快速下載那些失敗的連結了。ESA會定期維護數據集下載伺服器,因此,連結暫時失效是難以避免的。我們認為,這個小程序會比較好的解決這個問題。
第三部分:更新aria2下載工具的下載清單。
aria2的失效連結自動重啟配置好後,另一個比較重要的問題是,它內部循環迭代查詢是否還有未下載的影像。這就使得一個包含一萬個連結的文件,總會從開頭一直掃描到結尾,比較浪費時間。因此,繼續用python程序進行判斷,將已經完成的哨兵數據連結從未完成的哨兵數據連結中剔除,代碼如下:
import argparseimport datetimeimport globimport numpy as npimport osimport reimport timeimport sentinelsatimport zipfileimport timeimport pdbimport pandasfrom sentinelsat import SentinelAPI, read_geojson, geojson_to_wktfrom pandas import DataFrameimport pandas as pdimport hashlib#printPath功能是列印所有當前目錄下的文件名def printPath(level, path):allFileNum = 0
dirList = []fileList = []files = os.listdir(path)dirList.append(str(level))for f in files:if (os.path.isdir(path + '/' + f)):if (f[0] == '.'):passelse:dirList.append(f)if (os.path.isfile(path + '/' + f)):fileList.append(f)i_dl = 0for dl in dirList:if (i_dl == 0):i_dl = i_dl + 1else:printPath((int(dirList[0]) + 1), path + '/' + dl)final_list=[]for fl in fileList:allFileNum = allFileNum + 1final_list.append(os.path.join(path, fl))return final_list#checkwhichURL_not_done接受兩個參數,第一個參數是通過上一個函數獲得#的影像文件名#第二個參數是包含ur和mdf信息的csv文件,#之前第一個python代碼就是獲得了這兩個有效信息,#使用md5_hash = hashlib.md5()進行計算文件的md5值,#然後設置要對比的連結下載文件csv中是否有該md5信息,#如果有則將dataframe的flag例置為1,#最後列印出來的url文件就是未下載完的哨兵影像連結,#繼續按照第二和第三部分的說明進行下載即可。#def checkwhichURL_not_done(tmp_filelist, urls_list_df):not_download_url=[] df = urls_list_df.copy()for file in tmp_filelist:md5_hash = hashlib.md5()with open(file, "rb") as f:# Read and update hash in chunks of 4Kfor byte_block in iter(lambda: f.read(40960), b""):md5_hash.update(byte_block)md5=str.upper(md5_hash.hexdigest())#print("..")#print(md5)mask = (df['md5'] == md5)df.loc[mask, 'flag'] = 1df = df.copy()
df=df.fillna(0).copy()#最後找到所有那些flag=0.0的mask = (df['flag'] =="0.0")df_extra = df.loc[mask]df_extra = df.copy()print(df_extra['url'])passif __name__ == "__main__":strPath=r"D:\test_MODIS"tmp_filelist=printPath(1,r"D:\test_MODIS")#print(tmp_filelist)urls_list_df = pd.read_csv("finale_urls_md5.csv")checkwhichURL_not_done(tmp_filelist,urls_list_df )pass在詳細介紹了如何快速下載哨兵衛星數據之後,我們聊點別的。實際上對遙感數據的獲取和查詢一直是個火熱的話題。例如,當我們想研究全球湖泊水庫的面積變化時,我想這種難度是極其高的,主要原因是,數據的下載會浪費我們足夠多的時間。另外一方面,小範圍小區域的遙感影像數據查詢下載其實更加重要。例如,我們只需要武漢東湖的衛星遙感影像數據,結果不得不下載整個整個武漢區域甚至更大範圍的數據。也許對於GIS和遙感專業的人來說,遙感數據本身就是大範圍的,但站在普通用戶的角度,有可能我們需要的僅僅是某塊小試驗田的單像素長序列數據。這樣的話,本身的那種大範圍的思想就不一樣了。可以很明確的告訴大家,時至完稿日我大天朝尚無一個衛星遙感機構考慮到這個問題。為了解決這個問題,我們團隊研發一套衛星遙感數據服務平臺,致力於解決遙感數據下載難使用難的問題。我們的目標是:讓小範圍遙感影像數據下載如泉湧,讓小區域遙感影像數據交易成主流。誠摯希望大家繼續關注我們善睞(Satellive)團隊。最後,願大家收穫數據下載技能的同時幫忙轉載此文。與此同時,我們呼籲大家都能把下載的數據分享在善睞(Satellive)衛星遙感數據服務平臺上,本平臺預計2020年5月4日青年節上線,敬請關注。我們的願望是讓其他科研用戶不再痛苦地等待數據下載。在轉載前,記得聯繫我們關注本公眾號(Satellive)並在後臺留言或郵件至huangwei0316@hust.edu.cn。我們保留對所轉載圖文內容和代碼的所有權利。謝謝大家!
微信號:huitiandi321
郵箱:geomaticshtd@163.com
歡迎關注慧天地同名新浪微博:
《慧天地》敬告
《慧天地》公眾號聚焦國內外時空信息科技前沿、行業發展動態、跨界融合趨勢,探索企業核心競爭力,傳播測繪地理信息文化,為測繪、地信、遙感等相關專業的同學提供日常學習、考研就業一站式服務,旨在打造政產學研用精準對接的平臺。《慧天地》高度重視版權,對於原創、委託發布的稿件,會煩請作者、委託方親自審核通過後才正式推發;對於來自網站、期刊、書籍、微博、微信公眾號等媒介的稿件,會在作者欄或者文章開頭顯著標明出處,以表達對作者和推文引用平臺版權的充分尊重和感謝;對於來源於網絡作者不明的優質作品,轉載時如出現侵權,請後臺留言,我們會及時刪除。感謝大家一直以來對《慧天地》的關注和支持!