SNAP Java API處理Sentinel-1數據


版權聲明:本文爲博主原創文章,轉載請註明原文出處!

作者:阿振

寫作時間:2020年4月14日 週二


使用SNAP JAVA API處理Sentinel-1數據

SNAP軟件使用Java語言開發,提供了Python接口snappy,官方教程中也多以Python接口進行示範。但是我在使用Python接口過程中,發現並不是很好用,你必須要同時懂Java語言才能很好地使用Python接口,在IDEA中使用Python接口的代碼基本上沒有提示,報錯了也是Java的錯誤提示。而且,Java本來是運行在虛擬機上的語言,效率不高,再用Python包一層,更加降低了運行效率。

所以,對於我來說,SNAP的Python接口就是雞肋,沒有使用的必要。直接使用Java接口,方便程序直接進行調試,有問題可以直接去看源代碼,解決了官方資料不足的問題。

SNAP GPF的使用範式

SNAP推薦使用GPF(Graph Processing Framework)進行數據處理。GPF的使用也很簡單,首先基於Operation創建Product,然後寫入Product。在寫入過程中會自動執行Operation完成你想要的數據處理流程,處理的算法是封裝在Operation中的。

使用GPF的好處是你可以進行多個Operation的流程處理,前一個處理結果直接進入後一個處理,不需要寫入磁盤,可以減少磁盤IO帶來的時間消耗。

對Sentinel-1 GRD數據的處理案例

下面以對Sentinel-1 GRD數據進行一系列預處理流程演示SNAP Java接口的使用。

預處理的流程包括:首先對GRD各個極化波進行段輻射校正輸出後向散射係數(Sigma nought),然後進行數據裁剪,最後進行地形校正的。

下面是使用Better Java (Kotlin)進行entinel-1 GRD數據處理的源碼。其中,GPF.createProduct方法需要傳入Operation的名稱和參數,這些信息都可以通過查看Java源代碼的方式找到。

代碼運行過程中需要下載DEM數據,可能會比較耗時。如果不對數據裁剪,由於原始數據太大,可能會造成內存溢出。我的筆記本根本跑不動。

package cn.demo

import java.nio.file.Paths
import org.apache.commons.io.FilenameUtils

import kotlin.collections.HashMap

import org.esa.snap.core.dataio.ProductIO
import org.esa.snap.core.gpf.GPF
import com.bc.ceres.core.PrintWriterConciseProgressMonitor

import org.locationtech.jts.io.WKTReader


fun main() {
    val srcPath =
    Paths.get("/Users/Demo/Desktop/S1A_IW_GRDH_1SDV_20200301T104455_20200301T104520_031481_03A00B_0A9F.zip")
    val srcProduct = ProductIO.readProduct(srcPath.toFile())

    val outDir = "/Users/Demo/Desktop"
    val baseName = FilenameUtils.getBaseName(srcPath.toString())
    GPF.getDefaultInstance().operatorSpiRegistry.loadOperatorSpis()
    for (polar in arrayOf("VV", "VH")) {
        // 首先進行輻射校正(CALIBRATION)
        // 對應是的org.esa.s1tbx.calibration.gpf.CalibrationOp類
        var parameters = HashMap<String, Any>()
        parameters["outputSigmaBand"] = true
        parameters["selectedPolarisations"] = polar
        val caliProduct = GPF.createProduct("Calibration", parameters, srcProduct)

        // 然後進行裁剪,如果不裁剪,圖像太大,容易OutOfMemory
        // 對應的是org.esa.snap.core.gpf.common.SubsetOp類
        val wktRect = "POLYGON((108.175 33.873,108.782 33.873,108.782 33.129,108.175 33.129,108.175 33.873))"
        parameters["geoRegion"] = WKTReader().read(wktRect)
        parameters["bandNames"] = "Sigma0_${polar}"
        val subsetProduct = GPF.createProduct("Subset", parameters, caliProduct)


        // 然後進行地形校正(TERRAIN CORRECTION)
        // 對應的是org.esa.s1tbx.sar.gpf.geometric.RangeDopplerGeocodingOp
        val corrPath = "${outDir}/${baseName}_Corrected_${polar}"
        parameters.clear()
        parameters["pixelSpacingInMeter"] = 10.0
        parameters["sourceBands"] = "Sigma0_${polar}"
        val corrProduct = GPF.createProduct("Terrain-Correction", parameters, subsetProduct)
        ProductIO.writeProduct(
            corrProduct, corrPath, "GeoTIFF",
            PrintWriterConciseProgressMonitor(System.out)
        )
				
      	// 最後進行對象銷燬,釋放內存空間
        caliProduct.dispose()
        subsetProduct.dispose()
        corrProduct.dispose()
    }
    srcProduct.dispose()
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章