跳到主要內容

農業溫室氣體排放估算 - 水田甲烷(參數篇)

基本概念可參考上一篇文章 https://learncropmodel.blogspot.com/2025/05/blog-post.html 上一篇文章提及碳排係數在Tier1當中的拆解方式如下,我們來看看文獻裡的參數吧 $EF_i = EF_c \cdot SF_w \cdot SF_p \cdot SF_o$ EF i : i條件的每日排放係數 EF c : 無施用有機肥料下持續灌溉水田的排放係數 SF w : 不同水分管理區域的調整因子(表 5.12) SF p : 不同種植前水分管理調整因子(表 5.13) SF o : 有機質肥料型態或施用量之調整因子(Eq. 5.3, 表5.14) Baseline emission factor 也就是EF c 的預設係數來自於表5.1 (page 5.53) 表5.1 預設水田甲烷排放係數,假設水稻栽培時間小於180天、連續淹水、未施用有機質 World Regional Emission factor (kg CH 4 ha -1 d -1 ) Error range (kg CH 4 ha -1 d -1 ) Region Emission factor (kg CH 4 ha -1 d -1 ) Error range (kg CH 4 ha -1 d -1 ) 1.19 0.80 - 1.76 Africa 1.19 0.80 - 1.76 East Asia 1.32 0.89 - 1.96 Southeast Asia 1.22 0.83 - 1.81 South Asia 0.85 0.58 - 1.26 Europe 1.56 1.06 - 2.31 ...

Python 解析多光譜 (2)

接下來我們就試著用Python畫出NDVI的作品

一樣的,先載入必要的套件,並設定working directory

import os 
import matplotlib.pyplot as plt
import numpy as np
import rasterio as rio
import geopandas as gpd
import earthpy as et
from earthpy import spatial as es
from earthpy import plot as ep
path = "D:\Python\multispectral"
os.chdir(path)

接著,利用rasterio載入影像,用shape函式查看影像基本特性

pine_path = os.path.join("pineapple","pineapple0808.tif")
with rio.open(pine_path) as msi:
pine0808 = msi.read()

pine0808.shape

(6, 4604, 9634)

再來就利用earthpy 的 normalized_diff 函式來算 NDVI,再使用ep.plot_bands來畫圖

pine_ndvi = es.normalized_diff(pine0808[4], pine0808[2])
ep.plot_bands(pine_ndvi,
cmap='PiYG',
scale=True,
vmin=-1,vmax=1,
title="NDVI of Pineapple 0808")
plt.show()



我們來觀察一下 es.normalized_diff 這一個函式吧。

help(es.normalized_diff)
normalized_diff(b1, b2)
    Take two n-dimensional numpy arrays and calculate the normalized
    difference.
    
    Math will be calculated (b1-b2) / (b1 + b2).
    
    Parameters
    ----------
    b1, b2 : numpy arrays
        Two numpy arrays that will be used to calculate the normalized
        difference. Math will be calculated (b1-b2) / (b1+b2).
    
    Returns
    ----------
    n_diff : numpy array
        The element-wise result of (b1-b2) / (b1+b2) calculation. Inf values
        are set to nan. Array returned as masked if result includes nan values.

看起來他是利用numpy 資料進行向量運算,這個函示已經指定好第1個變數一定要是NIR,第2個變數是 Red band,不然算出來的資料會剛好相反。

儲存圖層

Python 需要建立出檔案,再把資料寫入到檔案當中。
先設定meta data黨,載入原本圖層的meta data

with rio.open(pine_path) as msi: 
pine_data = msi.read()
pine_meta = msi.profile

接著檢視 meta data

pine_meta

{'driver': 'GTiff', 'dtype': 'uint16', 'nodata': None, 'width': 9634, 'height': 4604, 'count': 6, 'crs': CRS.from_dict(init='epsg:3824'), 'transform': Affine(2.2059400000054369e-07, 0.0, 120.470607193754, 0.0, -2.0339900000014106e-07, 23.5296130451426), 'blockxsize': 256, 'blockysize': 256, 'tiled': True, 'compress': 'lzw', 'interleave': 'pixel'}

這邊可以看到,count 6 表示圖層有6個波段,資料型態是 16位元無符號整數 (uint 16)。我們必須把圖層改成只有1個波段,資料型態改為64位浮點數 (float64)。


pine_meta['count'] = 1 
pine_meta['dtype'] = "float64"

接著,我們就可以建立圖層,利用rasterio把資料寫入檔案中。

pine_ndvi_outpath = os.path.join("pineapple","pineapple0808_ndvi.tif") 
with rio.open(pine_ndvi_outpath, 'w', **pine_meta) as dst:
dst.write(pine_ndvi, 1)


最後,我們來觀察一下earhpy的原始碼,https://earthpy.readthedocs.io/en/latest/_modules/earthpy/spatial.html

def normalized_diff(b1, b2):
    """Take two n-dimensional numpy arrays and calculate the normalized
    difference.

    Math will be calculated (b1-b2) / (b1 + b2).

    Parameters
    ----------
    b1, b2 : numpy arrays
        Two numpy arrays that will be used to calculate the normalized
        difference. Math will be calculated (b1-b2) / (b1+b2).

    Returns
    ----------
    n_diff : numpy array
        The element-wise result of (b1-b2) / (b1+b2) calculation. Inf values
        are set to nan. Array returned as masked if result includes nan values.

    Examples
    --------
    >>> import numpy as np
    >>> import earthpy.spatial as es
    >>> # Calculate normalized difference vegetation index
    >>> nir_band = np.array([[6, 7, 8, 9, 10], [16, 17, 18, 19, 20]])
    >>> red_band = np.array([[1, 2, 3, 4, 5], [11, 12, 13, 14, 15]])
    >>> ndvi = es.normalized_diff(b1=nir_band, b2=red_band)
    >>> ndvi
    array([[0.71428571, 0.55555556, 0.45454545, 0.38461538, 0.33333333],
           [0.18518519, 0.17241379, 0.16129032, 0.15151515, 0.14285714]])

    >>> # Calculate normalized burn ratio
    >>> nir_band = np.array([[8, 10, 13, 17, 15], [18, 20, 22, 23, 25]])
    >>> swir_band = np.array([[6, 7, 8, 9, 10], [16, 17, 18, 19, 20]])
    >>> nbr = es.normalized_diff(b1=nir_band, b2=swir_band)
    >>> nbr
    array([[0.14285714, 0.17647059, 0.23809524, 0.30769231, 0.2       ],
           [0.05882353, 0.08108108, 0.1       , 0.0952381 , 0.11111111]])
    """
    if not (b1.shape == b2.shape):
        raise ValueError("Both arrays should have the same dimensions")

    # Ignore warning for division by zero
    with np.errstate(divide="ignore"):
        n_diff = (b1 - b2) / (b1 + b2)

    # Set inf values to nan and provide custom warning
    if np.isinf(n_diff).any():
        warnings.warn(
            "Divide by zero produced infinity values that will be replaced "
            "with nan values",
            Warning,
        )
        n_diff[np.isinf(n_diff)] = np.nan

    # Mask invalid values
    if np.isnan(n_diff).any():
        n_diff = np.ma.masked_invalid(n_diff)

    return n_diff

參考網頁

https://www.earthdatascience.org/courses/use-data-open-source-python/multispectral-remote-sensing/vegetation-indices-in-python/calculate-NDVI-python/

留言