All Projects → kongdd → Phenofit

kongdd / Phenofit

Licence: gpl-2.0
R package: A state-of-the-art Vegetation Phenology extraction package, phenofit

Programming Languages

r
7636 projects

Projects that are alternatives of or similar to Phenofit

Deeplabv3 Tensorflow
使用deeplab_v3模型对遥感图像进行分割
Stars: ✭ 270 (+770.97%)
Mutual labels:  remote-sensing
Notebooks
interactive notebooks from Planet Engineering
Stars: ✭ 339 (+993.55%)
Mutual labels:  remote-sensing
R2cnn faster Rcnn tensorflow
Rotational region detection based on Faster-RCNN.
Stars: ✭ 548 (+1667.74%)
Mutual labels:  remote-sensing
Datacube Core
Open Data Cube analyses continental scale Earth Observation data through time
Stars: ✭ 285 (+819.35%)
Mutual labels:  remote-sensing
Custom Scripts
A repository of custom scripts to be used with Sentinel Hub
Stars: ✭ 322 (+938.71%)
Mutual labels:  remote-sensing
Label Maker
Data Preparation for Satellite Machine Learning
Stars: ✭ 377 (+1116.13%)
Mutual labels:  remote-sensing
Torchsat
🔥TorchSat 🌏 is an open-source deep learning framework for satellite imagery analysis based on PyTorch.
Stars: ✭ 261 (+741.94%)
Mutual labels:  remote-sensing
Wetland Hydro Gee
Mapping wetland hydrological dynamics using Google Earth Engine (GEE)
Stars: ✭ 20 (-35.48%)
Mutual labels:  remote-sensing
Dota Doai
This repo is the codebase for our team to participate in DOTA related competitions, including rotation and horizontal detection.
Stars: ✭ 326 (+951.61%)
Mutual labels:  remote-sensing
Qgis Earthengine Examples
A collection of 300+ Python examples for using Google Earth Engine in QGIS
Stars: ✭ 482 (+1454.84%)
Mutual labels:  remote-sensing
Geospatial Machine Learning
A curated list of resources focused on Machine Learning in Geospatial Data Science.
Stars: ✭ 289 (+832.26%)
Mutual labels:  remote-sensing
Awesome Gee
A curated list of Google Earth Engine resources
Stars: ✭ 292 (+841.94%)
Mutual labels:  remote-sensing
Deepnetsforeo
Deep networks for Earth Observation
Stars: ✭ 393 (+1167.74%)
Mutual labels:  remote-sensing
Pyrosar
framework for large-scale SAR satellite data processing
Stars: ✭ 274 (+783.87%)
Mutual labels:  remote-sensing
Sentinelsat
Search and download Copernicus Sentinel satellite images
Stars: ✭ 576 (+1758.06%)
Mutual labels:  remote-sensing
Otb
Github mirror of https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb
Stars: ✭ 265 (+754.84%)
Mutual labels:  remote-sensing
Whitebox Tools
An advanced geospatial data analysis platform
Stars: ✭ 362 (+1067.74%)
Mutual labels:  remote-sensing
Pyint
Python&GAMMA based interfermetry toolbox for single or time-series of InSAR data processing.
Stars: ✭ 30 (-3.23%)
Mutual labels:  remote-sensing
Earthengine Py Notebooks
A collection of 360+ Jupyter Python notebook examples for using Google Earth Engine with interactive mapping
Stars: ✭ 807 (+2503.23%)
Mutual labels:  remote-sensing
Awesome Remote Sensing Change Detection
List of datasets, codes, and contests related to remote sensing change detection
Stars: ✭ 414 (+1235.48%)
Mutual labels:  remote-sensing

phenofit

Travis Build Status AppVeyor Build Status codecov License CRAN total monthly

A state-of-the-art remote sensing vegetation phenology extraction package: phenofit

  • phenofit combine merits of TIMESAT and phenopix
  • A simple and stable growing season dividing methods was proposed
  • Provide a practical snow elimination method, based on Whittaker
  • 7 curve fitting methods and 4 phenology extraction methods
  • We add parameters boundary for every curve fitting methods according to their ecological meaning.
  • optimx is used to select best optimization method for different curve fitting methods.

Task lists

  • [ ] Test the performance of phenofit in multiple growing season regions (e.g. the North China Plain);
  • [ ] Uncertainty analysis of curve fitting and phenological metrics;
  • [x] shiny app has been moved to phenofit.shiny;
  • [x] Complete script automatic generating module in shinyapp;
  • [x] Rcpp improve double logistics optimization efficiency by 60%;
  • [x] Support spatial analysis;
  • [x] Support annual season in curve fitting;
  • [x] flexible fine fitting input ( original time-series or smoothed time-series by rough fitting).
  • [x] Asymmetric of Threshold method

title

Figure 1. The flowchart of phenology extraction in phenofit.

Installation

You can install phenofit from github with:

# install.packages("devtools")
devtools::install_github("kongdd/phenofit")

Example

Here, we illustrate how to use phenofit to extract vegetation phenology from MOD13A1 in the sampled points. Regional analysis also can be conducted in the similar way.

1.1 Initial weights for input data

Load packages.

suppressMessages({
    library(data.table)
    library(magrittr)
    library(lubridate)
    library(purrr)
    library(plyr)
    library(ggplot2)
    library(phenofit)
})

Set global parameters for phenofit

# lambda   <- 5    # non-parameter Whittaker, only suit for 16-day. Other time-scale
# should assign a lambda.
ymax_min   <- 0.1  # the maximum ymax shoud be greater than `ymax_min` 
rymin_less <- 0.8  # trough < ymin + A*rymin_less
nptperyear <- 23   # How many points for a single year
wFUN       <- wBisquare #wTSM #wBisquare # Weights updating function, could be one of `wTSM`, 'wBisquare', `wChen` and `wSELF`. 
  • Add date according to composite day of the year (DayOfYear), other than image date.
  • Add weights according to SummaryQA.

For MOD13A1, Weights can by initialed by SummaryQA band (also suit for MOD13A2 and MOD13Q1). There is already a QC function for SummaryQA, i.e. qc_summary.

SummaryQA Pixel reliability summary QA weight
-1 Fill/No data Not processed wmin
0 Good data Use with confidence 1
1 Marginal data Useful but look at detailed QA for more information 0.5
2 Snow/ice Pixel covered with snow/ice wmin
3 Cloudy Pixel is cloudy wmin
data('MOD13A1')
df <- MOD13A1$dt 
st <- MOD13A1$st

df[, `:=`(date = ymd(date), year = year(date), doy = as.integer(yday(date)))]
df[is.na(DayOfYear), DayOfYear := doy] # If DayOfYear is missing
    
# In case of last scene of a year, doy of last scene could in the next year
df[abs(DayOfYear - doy) >= 300, t := as.Date(sprintf("%d-%03d", year+1, DayOfYear), "%Y-%j")] # last scene
df[abs(DayOfYear - doy) <  300, t := as.Date(sprintf("%d-%03d", year  , DayOfYear), "%Y-%j")]

df <- df[!duplicated(df[, .(site, t)]), ]

# MCD12Q1.006 land cover 1-17, IGBP scheme
IGBPnames_006 <- c("ENF", "EBF", "DNF", "DBF", "MF" , "CSH", 
              "OSH", "WSA", "SAV", "GRA", "WET", "CRO", 
              "URB", "CNV", "SNOW", "BSV", "water", "UNC")
# Initial weights
df[, c("QC_flag", "w") := qc_summary(SummaryQA)]
df <- df[, .(site, y = EVI/1e4, t, date, w, QC_flag)]
  • add_HeadTail is used to deal with such situation, e.g. MOD13A2 begins from 2000-02-08. We need to construct a series with complete year, which begins from 01-01 for NH, and 07-01 for SH. For example, the input data period is 20000218 ~ 20171219. After adding one year in head and tail, it becomes 19990101 ~ 20181219.

2.1 load site data

sites        <- unique(df$site)
sitename     <- sites[3]
d            <- df[site == sitename] # get the first site data
sp           <- st[site == sitename]

south      <- sp$lat < 0
print      <- FALSE # whether print progress
IsPlot     <- TRUE  # for brks

prefix_fig <- "phenofit"
titlestr   <- with(sp, sprintf('[%03d,%s] %s, lat = %5.2f, lon = %6.2f',
                                     ID, site, IGBPname, lat, lon))
file_pdf   <- sprintf('Figure/%s_[%03d]_%s.pdf', prefix_fig, sp$ID[1], sp$site[1])

If need night temperature (Tn) to constrain ungrowing season backgroud value, NA values in Tn should be filled.

d$Tn %<>% zoo::na.approx(maxgap = 4)
plot(d$Tn, type = "l"); abline(a = 5, b = 0, col = "red")

2.2 Check input data

dnew  <- add_HeadTail(d, south, nptperyear = 23) # add additional one year in head and tail
INPUT <- check_input(dnew$t, dnew$y, dnew$w, dnew$QC_flag,
                     nptperyear, south, 
                     maxgap = nptperyear/4, alpha = 0.02, wmin = 0.2)

2.3 Divide growing seasons

Simply treating calendar year as a complete growing season will induce a considerable error for phenology extraction. A simple growing season dividing method was proposed in phenofit.

The growing season dividing method rely on heavily in Whittaker smoother.

Procedures of initial weight, growing season dividing, curve fitting, and phenology extraction are conducted separately.

par(mar = c(3, 2, 2, 1), mgp = c(3, 0.6, 0))
lambda <- init_lambda(INPUT$y)
# The detailed information of those parameters can be seen in `season`.
# brks   <- season(INPUT, nptperyear,
#                FUN = smooth_wWHIT, wFUN = wFUN, iters = 2,
#                lambda = lambda,
#                IsPlot = IsPlot, plotdat = d,
#                south = d$lat[1] < 0,
#                rymin_less = 0.6, ymax_min = ymax_min,
#                max_MaxPeaksperyear =2.5, max_MinPeaksperyear = 3.5) #, ...
# get growing season breaks in a 3-year moving window
brks2 <- season_mov(INPUT, 
                   FUN = smooth_wWHIT, wFUN = wFUN,
                   maxExtendMonth = 6, r_min = 0.1,
                   IsPlot = IsPlot, IsPlot.OnlyBad = FALSE, print = print)

2.4 Curve fitting

fit  <- curvefits(INPUT, brks2,
                  methods = c("AG", "Zhang", "Beck", "Elmore"), #,"klos",, 'Gu'
                  wFUN = wFUN,
                  nextend = 2, maxExtendMonth = 3, minExtendMonth = 1, minPercValid = 0.2,
                  print = print, verbose = FALSE)

## check the curve fitting parameters
l_param <- get_param(fit)
print(str(l_param, 1))
# List of 4
#  $ AG    :Classes 'tbl_df', 'tbl' and 'data.frame':   18 obs. of  8 variables:
#  $ Beck  :Classes 'tbl_df', 'tbl' and 'data.frame':   18 obs. of  7 variables:
#  $ Elmore:Classes 'tbl_df', 'tbl' and 'data.frame':   18 obs. of  8 variables:
#  $ Zhang :Classes 'tbl_df', 'tbl' and 'data.frame':   18 obs. of  8 variables:
# NULL
print(l_param$AG)
# # A tibble: 18 x 8
#    flag      t0    mn    mx    rsp    a3    rau    a5
#    <fct>  <dbl> <dbl> <dbl>  <dbl> <dbl>  <dbl> <dbl>
#  1 2000_1  201. 0.168 0.407 0.0323  3.53 0.0151  5.83
#  2 2001_1  561. 0.173 0.407 0.0225  4.06 0.0162  6   
#  3 2002_1  931. 0.188 0.511 0.0383  2    0.0169  4.21
#  4 2003_1 1275. 0.167 0.434 0.0268  2    0.0122  3.37
#  5 2004_1 1660. 0.175 0.451 0.0363  2    0.0179  4.46
#  6 2005_1 2052. 0.180 0.466 0.0141  6    0.0314  2   
#  7 2006_1 2379. 0.174 0.436 0.0226  2.51 0.0131  3.26
#  8 2007_1 2752. 0.165 0.483 0.0208  2    0.0150  2.88
#  9 2008_1 3134. 0.177 0.492 0.0180  3.50 0.0199  6   
# 10 2009_1 3525. 0.172 0.480 0.0133  5.40 0.0313  2   
# 11 2010_1 3841. 0.181 0.493 0.0238  2    0.0148  2   
# 12 2011_1 4206. 0.190 0.464 0.0328  2    0.0135  6   
# 13 2012_1 4558. 0.167 0.510 0.0490  2    0.0109  3.64
# 14 2013_1 4966. 0.168 0.484 0.0140  6    0.0190  2   
# 15 2014_1 5303. 0.203 0.489 0.0344  2    0.0133  6   
# 16 2015_1 5690. 0.215 0.494 0.0182  6    0.0275  4.81
# 17 2016_1 6023. 0.194 0.484 0.0429  2    0.0126  4.99
# 18 2017_1 6406. 0.171 0.449 0.0201  6    0.0129  3.52

d_fit <- get_fitting(fit)
## Get GOF information
d_gof <- get_GOF(fit)
# fit$stat <- stat
print(head(d_gof))
#      flag   meth       RMSE       NSE         R       pvalue  n
# 1: 2000_1     AG 0.10058989 0.4952465 0.9016506 1.809700e-09 24
# 2: 2000_1   Beck 0.10059953 0.4951497 0.9036266 1.461349e-09 24
# 3: 2000_1 Elmore 0.10060466 0.4950983 0.9021757 1.710497e-09 24
# 4: 2000_1  Zhang 0.10059866 0.4951585 0.9036627 1.455586e-09 24
# 5: 2001_1     AG 0.08808864 0.5879431 0.9037624 3.439665e-09 23
# 6: 2001_1   Beck 0.08817911 0.5870963 0.9047721 3.093164e-09 23

# print(fit$fits$AG$`2002_1`$ws)
print(fit$`2002_1`$fFIT$AG$ws)
# $iter1
#  [1] 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.5 1.0 1.0 1.0 1.0 0.5 1.0 1.0
# [18] 1.0 1.0 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 1.0 1.0
# 
# $iter2
#  [1] 0.2000000 0.2000000 0.2000000 0.2000000 0.2000000 0.2000000 0.2000000
#  [8] 0.2000000 0.2000000 0.5000000 1.0000000 1.0000000 0.7893075 1.0000000
# [15] 0.4984446 0.8873205 1.0000000 1.0000000 1.0000000 0.2000000 0.2000000
# [22] 0.2000000 0.2000000 0.2000000 0.2000000 0.2000000 0.2000000 0.2000000
# [29] 0.2000000 0.2000000 0.2000000 1.0000000 1.0000000
## visualization
g <- plot_phenofit(d_fit, brks2, NULL, title.ylab = "NDVI", "Time",
                   theme = coord_cartesian(xlim = c(ymd("2000-04-01"), ymd("2017-07-31"))))
grid::grid.newpage(); grid::grid.draw(g)# plot to check the curve fitting
# write_fig(g, "Figure1_phenofit_curve_fitting.pdf", 10, 6)

2.5 Extract phenology

# pheno: list(p_date, p_doy)
l_pheno <- get_pheno(fit, IsPlot = F) #%>% map(~melt_list(., "meth"))

# ratio = 1.15
# file <- "Figure5_Phenology_Extraction_temp.pdf"
# cairo_pdf(file, 8*ratio, 6*ratio)
# temp <- get_pheno(fit$fits$ELMORE[2:6], IsPlot = T)
# dev.off()
# file.show(file)

## check the extracted phenology
pheno <- get_pheno(fit[1:6], "Elmore", IsPlot = T)
# print(str(pheno, 1))
head(l_pheno$doy$AG)
#      flag     origin TRS2.sos TRS2.eos TRS5.sos TRS5.eos TRS6.sos TRS6.eos
# 1: 2000_1 2000-01-01      167      273      175      264      177      261
# 2: 2001_1 2001-01-01      145      263      155      254      158      251
# 3: 2002_1 2002-01-01      168      268      179      256      182      252
# 4: 2003_1 2003-01-01      133      273      149      253      153      246
# 5: 2004_1 2004-01-01      166      262      178      251      181      248
# 6: 2005_1 2005-01-01      150      266      159      252      162      248
#    DER.sos DER.pop DER.eos  UD  SD  DD  RD Greenup Maturity Senescence
# 1:     174     203     266 164 186 249 280     157      193        243
# 2:     154     196     256 141 170 240 268     133      177        234
# 3:     183     202     257 164 195 238 274     157      201        223
# 4:     153     180     254 128 170 225 283     118      179        196
# 5:     181     201     253 162 193 236 268     154      200        226
# 6:     157     225     248 143 175 233 272     136      181        279
#    Dormancy
# 1:      287
# 2:      275
# 3:      282
# 4:      298
# 5:      276
# 6:       NA

References

[1] Dongdong Kong, R package: A state-of-the-art Vegetation Phenology extraction package, phenofit version 0.2.2, https://github.com/kongdd/phenofit

[2] Zhang, Q., Kong, D., Shi, P., Singh, V.P., Sun, P., 2018. Vegetation phenology on the Qinghai-Tibetan Plateau and its response to climate change (1982–2013). Agric. For. Meteorol. 248, 408–417. https://doi.org/10.1016/j.agrformet.2017.10.026

Acknowledgements

Keep in mind that this repository is released under a GPL2 license, which permits commercial use but requires that the source code (of derivatives) is always open even if hosted as a web service.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].