├── .github ├── .gitignore └── workflows │ └── R-CMD-check.yaml ├── .img ├── logo2.png └── logo.svg ├── LICENSE ├── cleanup ├── inst ├── modis │ └── filled │ │ ├── 2020068_18-04_kranj.tif │ │ ├── 2020069_18-04_kranj.tif │ │ ├── 2020070_18-04_kranj.tif │ │ ├── 2020071_18-04_kranj.tif │ │ ├── 2020072_18-04_kranj.tif │ │ ├── 2020073_18-04_kranj.tif │ │ ├── 2020074_18-04_kranj.tif │ │ ├── 2020075_18-04_kranj.tif │ │ ├── 2020076_18-04_kranj.tif │ │ ├── 2020077_18-04_kranj.tif │ │ ├── 2020078_18-04_kranj.tif │ │ ├── 2020079_18-04_kranj.tif │ │ ├── 2020080_18-04_kranj.tif │ │ ├── 2020081_18-04_kranj.tif │ │ ├── 2020082_18-04_kranj.tif │ │ ├── 2020083_18-04_kranj.tif │ │ ├── 2020084_18-04_kranj.tif │ │ ├── 2020085_18-04_kranj.tif │ │ ├── 2020086_18-04_kranj.tif │ │ ├── 2020087_18-04_kranj.tif │ │ ├── 2020088_18-04_kranj.tif │ │ ├── 2020089_18-04_kranj.tif │ │ ├── 2020090_18-04_kranj.tif │ │ ├── 2020091_18-04_kranj.tif │ │ ├── 2020092_18-04_kranj.tif │ │ └── 2020093_18-04_kranj.tif ├── landsat │ ├── unfilled │ │ ├── 2020068_191-28_kranj.tif │ │ ├── 2020077_190-28_kranj.tif │ │ ├── 2020093_190-28_kranj.tif │ │ └── 2020100_191-28_kranj.tif │ └── filled │ │ ├── 2020068_191-28.tif_filled_kranj.tif │ │ ├── 2020077_190-28.tif_filled_kranj.tif │ │ ├── 2020093_190-28.tif_filled_kranj.tif │ │ └── 2020100_191-28.tif_filled_kranj.tif └── Copyrights ├── CRAN-RELEASE ├── NEWS.md ├── .Rbuildignore ├── .gitignore ├── LICENSE.note ├── R ├── zzz.R ├── ImageFusion.R ├── internal.R └── RcppExports.R ├── NAMESPACE ├── src ├── utils │ └── imginterp │ │ ├── CMakeLists.txt │ │ ├── customopts.h │ │ ├── interpolation.h │ │ └── customopts.cpp ├── Makevars.in ├── LICENSE_imagefusion.txt ├── Makevars.win ├── include │ ├── filesystem.h │ ├── parallelizer_options.h │ ├── options.h │ ├── fitfc_options.h │ ├── proxy.h │ ├── datafusor.h │ ├── fileformat.h │ ├── estarfm_options.h │ ├── iterators.h │ ├── exceptions.h │ ├── imagefusion.h │ └── parallelizer.h ├── src │ ├── fileformat.cpp │ └── filesystem.cpp └── RcppExports.cpp ├── man ├── ImageFusion.Rd ├── imagefusion_task.Rd ├── fitfc_job.Rd ├── estarfm_job.Rd └── starfm_job.Rd ├── DESCRIPTION ├── tools └── winlibs.R ├── cran-comments.md └── Readme.md /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.img/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/.img/logo2.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2020 2 | COPYRIGHT HOLDER: Johannes Mast 3 | ORGANIZATION: Universität Würzburg -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | rm -f src/Makevars config.status config.log 2 | rm -rf autom4te.cache 3 | echo "Cleaning up!" -------------------------------------------------------------------------------- /inst/modis/filled/2020068_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020068_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020069_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020069_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020070_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020070_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020071_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020071_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020072_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020072_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020073_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020073_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020074_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020074_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020075_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020075_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020076_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020076_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020077_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020077_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020078_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020078_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020079_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020079_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020080_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020080_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020081_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020081_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020082_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020082_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020083_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020083_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020084_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020084_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020085_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020085_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020086_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020086_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020087_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020087_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020088_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020088_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020089_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020089_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020090_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020090_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020091_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020091_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020092_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020092_18-04_kranj.tif -------------------------------------------------------------------------------- /inst/modis/filled/2020093_18-04_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/modis/filled/2020093_18-04_kranj.tif -------------------------------------------------------------------------------- /CRAN-RELEASE: -------------------------------------------------------------------------------- 1 | This package was submitted to CRAN on 2021-05-14. 2 | Once it is accepted, delete this file and tag the release (commit ff106d5). 3 | -------------------------------------------------------------------------------- /inst/landsat/unfilled/2020068_191-28_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/landsat/unfilled/2020068_191-28_kranj.tif -------------------------------------------------------------------------------- /inst/landsat/unfilled/2020077_190-28_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/landsat/unfilled/2020077_190-28_kranj.tif -------------------------------------------------------------------------------- /inst/landsat/unfilled/2020093_190-28_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/landsat/unfilled/2020093_190-28_kranj.tif -------------------------------------------------------------------------------- /inst/landsat/unfilled/2020100_191-28_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/landsat/unfilled/2020100_191-28_kranj.tif -------------------------------------------------------------------------------- /inst/landsat/filled/2020068_191-28.tif_filled_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/landsat/filled/2020068_191-28.tif_filled_kranj.tif -------------------------------------------------------------------------------- /inst/landsat/filled/2020077_190-28.tif_filled_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/landsat/filled/2020077_190-28.tif_filled_kranj.tif -------------------------------------------------------------------------------- /inst/landsat/filled/2020093_190-28.tif_filled_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/landsat/filled/2020093_190-28.tif_filled_kranj.tif -------------------------------------------------------------------------------- /inst/landsat/filled/2020100_191-28.tif_filled_kranj.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohMast/ImageFusion/HEAD/inst/landsat/filled/2020100_191-28.tif_filled_kranj.tif -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | This is the third release, version 0.0.3 2 | 3 | C++ support for clang was fixed. Filesystem functions changed from std::filesystem to GDAL. 4 | As a result, portability, particularly for macOS, is improved. -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^cran-comments\.md$ 5 | ^errors.txt$ 6 | ^proj_conf_test$ 7 | ^proj_conf_test.c$ 8 | ^proj_conf_test.cpp$ 9 | ^.cran_comments\.md$ 10 | ^Readme\.md$ 11 | ^\.img$ 12 | ^CRAN-RELEASE$ 13 | ^windows$ 14 | ^\R\spstfm_job.R$ 15 | ^\.github$ 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | *.Rproj 6 | # Binaries 7 | *.so 8 | *.dll 9 | *.a 10 | *.o 11 | *.obj 12 | 13 | config.status 14 | config.log 15 | prof_conf_test3.c 16 | autom4te.cache 17 | 18 | src/Makevars 19 | windows 20 | inst/gdal 21 | inst/proj 22 | inst/share 23 | *.xml 24 | #.tif 25 | #*.png 26 | *.zip 27 | *.rar -------------------------------------------------------------------------------- /LICENSE.note: -------------------------------------------------------------------------------- 1 | The ImageFusion package as a whole is distributed under a BSD_3 license. 2 | The ImageFusion package wraps around parts the imagefusion framework contained in src/src src/include and src/utils. 3 | The imagefusion framework is also licensed under a BSD_3 license. Copyright holder of that license is Hochschule Bochum. See the original license of the imagefusion code in src/LICENSE_imagefusion.txt. 4 | 5 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(libname, pkgname) { 2 | # if(Sys.info()["sysname"]=="Windows"){ 3 | # path_to_proj <- file.path(.libPaths(),"Imagefusion","proj") 4 | # Sys.setenv(PROJ_LIB=path_to_proj) 5 | # } 6 | 7 | if (dir.exists(system.file("proj", package="ImageFusion"))) { 8 | Sys.setenv("PROJ_LIB" = system.file("proj", package="ImageFusion")) 9 | } 10 | if (dir.exists(system.file("gdal", package="ImageFusion"))) { 11 | Sys.setenv("GDAL_DATA" = system.file("gdal", package="ImageFusion")) 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(estarfm_job) 4 | export(fitfc_job) 5 | export(imagefusion_task) 6 | export(imginterp_task) 7 | export(starfm_job) 8 | import(assertthat) 9 | import(dplyr) 10 | import(ggplot2) 11 | import(magrittr) 12 | importFrom(assertthat,assert_that) 13 | importFrom(grDevices,rainbow) 14 | importFrom(raster,dataType) 15 | importFrom(raster,extent) 16 | importFrom(raster,res) 17 | importFrom(raster,stack) 18 | importFrom(stats,predict) 19 | useDynLib(ImageFusion, .registration = TRUE) 20 | -------------------------------------------------------------------------------- /src/utils/imginterp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # build target 2 | add_executable(imginterp main.cpp customopts.cpp ${SOURCES_HELPERS}) 3 | target_link_libraries(imginterp imagefusion) 4 | 5 | # installation 6 | install(TARGETS imginterp RUNTIME DESTINATION bin COMPONENT imginterp) 7 | 8 | # adding component to the group 9 | cpack_add_component(imginterp 10 | DISPLAY_NAME "Linear Interpolator" 11 | DESCRIPTION "Utility to fill the gaps caused by removing the cloud pixels from the images using linear interpolation" 12 | GROUP utils 13 | DEPENDS lib) 14 | -------------------------------------------------------------------------------- /src/Makevars.in: -------------------------------------------------------------------------------- 1 | VERSION = 0.0.3 2 | 3 | PKG_CXXFLAGS= @PKG_CPPFLAGS@ -I../src/utils/helpers -Iinclude -I../src/utils/imginterp -I../inst/ghc @OPENCV_FLAG@ -D_DATA_PREFIX=/usr @OPENMP_FLAG@ 4 | PKG_LIBS= @PKG_LIBS@ @PKG_LIBS_OPENCV@ -L/usr/include @OPENMP_FLAG@ 5 | CXX_STD=CXX17 6 | 7 | ######################### 8 | SOURCES=execture_imagefusor_jobs.cpp execture_imginterp_job.cpp RcppExports.cpp utils/helpers/utils_common.cpp utils/imginterp/customopts.cpp @SUBDIR_SOURCES@ 9 | # Obtain the object files 10 | OBJECTS=$(SOURCES:.cpp=.o) 11 | # Make the shared object 12 | all: $(SHLIB) 13 | # Provide recipe to remove all objects 14 | clean: 15 | @rm -f $(OBJECTS) 16 | -------------------------------------------------------------------------------- /src/utils/imginterp/customopts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "optionparser.h" 4 | 5 | #include 6 | 7 | 8 | extern const char* usageQLText; 9 | 10 | extern std::vector usageQL; 11 | 12 | struct Parse : public imagefusion::option::Parse { 13 | static imagefusion::option::ImageInput QL(std::string const& str, std::string const& optName = "", bool readImage = true, bool isDateOpt = false, bool isTagOpt = false); 14 | }; 15 | 16 | struct ArgChecker : public imagefusion::option::ArgChecker { 17 | template 18 | static imagefusion::option::ArgStatus QL(const imagefusion::option::Option& option) { 19 | if (option.arg.empty()) 20 | IF_THROW_EXCEPTION(imagefusion::invalid_argument_error("There was no image input quality layer argument given for option '" + option.name + "'")); 21 | 22 | Parse::QL(option.arg, option.name, /*readImage*/ false, isDateOpt, isTagOpt); 23 | return imagefusion::option::ArgStatus::OK; 24 | } 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /R/ImageFusion.R: -------------------------------------------------------------------------------- 1 | #' Imagefusion: A package for fusion of images 2 | #' 3 | #' @description Implementation of Time-Series fusion. 4 | #' @section Outline: 5 | #' \code{ImageFusion} provides implementations of the following time-series fusion algorithms: 6 | #' \itemize{ 7 | #' \item ESTARFM 8 | #' \item FITFC 9 | #' \item STARFM 10 | #' } 11 | #' More algorithms will be added over time. 12 | #' Also provides \link{imginterp_task}, a utility function for the linear interpolation of masked or missing values 13 | #' @section Implementation: 14 | #' The algorithms are implemented in C++ via 'GDAL', 'opencv' and 'Boost' and work from input images on disk without prior loading into R. 15 | #' @section Usage: 16 | #' Use the \link{imagefusion_task} function to set up a complete time-series fusion task. Use the algorithm-specific functions \link{fitfc_job} \link{estarfm_job} and \link{starfm_job} to execute individual jobs. 17 | #' 18 | #' @docType package 19 | #' @name ImageFusion 20 | #' @author Christof Kaufmann (C++) 21 | #' @author Johannes Mast (R) 22 | #' @useDynLib ImageFusion, .registration = TRUE 23 | #' @md 24 | NULL -------------------------------------------------------------------------------- /man/ImageFusion.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ImageFusion.R 3 | \docType{package} 4 | \name{ImageFusion} 5 | \alias{ImageFusion} 6 | \title{Imagefusion: A package for fusion of images} 7 | \description{ 8 | Implementation of Time-Series fusion. 9 | } 10 | \section{Outline}{ 11 | 12 | \code{ImageFusion} provides implementations of the following time-series fusion algorithms: 13 | \itemize{ 14 | \item ESTARFM 15 | \item FITFC 16 | \item STARFM 17 | } 18 | More algorithms will be added over time. 19 | Also provides \link{imginterp_task}, a utility function for the linear interpolation of masked or missing values 20 | } 21 | 22 | \section{Implementation}{ 23 | 24 | The algorithms are implemented in C++ via 'GDAL', 'opencv' and 'Boost' and work from input images on disk without prior loading into R. 25 | } 26 | 27 | \section{Usage}{ 28 | 29 | Use the \link{imagefusion_task} function to set up a complete time-series fusion task. Use the algorithm-specific functions \link{fitfc_job} \link{estarfm_job} and \link{starfm_job} to execute individual jobs. 30 | } 31 | 32 | \author{ 33 | Christof Kaufmann (C++) 34 | 35 | Johannes Mast (R) 36 | } 37 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: ImageFusion 2 | Type: Package 3 | Title: Temporal Fusion of Raster Images 4 | Version: 0.0.3 5 | Date: 2022-10-31 6 | Authors@R: c( 7 | person("Christof", "Kaufmann", email = "christof.kaufmann@hs-bochum.de", role = c("aut","cph"),comment=c("Author of included imagefusion C++ code", ORCID = "0000-0002-0191-3341")), 8 | person("Johannes", "Mast", email = "johannes.mast@stud-mail.uni-wuerzburg.de", role = c("aut", "cre","cph"),comment = c("Author of R code and wrappers", ORCID = "0000-0001-6595-5834")), 9 | person("Thorsten", "Dahms", email = "thorsten.dahms@uni-wuerzburg.de", role = "sad",comment = c(ORCID = "0000-0002-7073-5075")), 10 | person("Jakob", "Schwalb-Willmann", email = "movevis@schwalb-willmann.de", role = "sad",comment = c(ORCID = "0000-0003-2665-1509")), 11 | person("Dinesh", "Kumar Babu", email = "dinesh.kumar-babu@adwaiseo.eu", role = "ctb"), 12 | person("Hochschule Bochum", role="cph")) 13 | Description: Temporal fusion of raster image time series. Provides implementation of various fusion algorithms in C++. 14 | License: BSD_3_clause + file LICENSE 15 | Copyright: file inst/Copyrights 16 | Imports: Rcpp (>= 1.0.2), raster, parallel, ggplot2, assertthat, dplyr, magrittr 17 | LinkingTo: Rcpp, RcppArmadillo, BH 18 | Depends: R (>= 4.0) 19 | Encoding: UTF-8 20 | RoxygenNote: 7.1.1 21 | SystemRequirements: C++17 GDAL OPENCV PROJ 22 | NeedsCompilation: yes 23 | Roxygen: list(markdown=TRUE) 24 | Language: en-US 25 | -------------------------------------------------------------------------------- /tools/winlibs.R: -------------------------------------------------------------------------------- 1 | if(getRversion() < "4.0.0") { 2 | stop("Your version of R is too old. This package requires R-4.0.0 or newer on Windows.") 3 | } 4 | VERSION <- "4.4.0" 5 | 6 | 7 | # For details see: https://github.com/rwinlib/gdal2 8 | # For details see: https://github.com/rwinlib/netcdf 9 | 10 | if(!file.exists("../windows/gdal3-3.4.1/include/gdal.h")){ 11 | download.file("https://github.com/rwinlib/gdal3/archive/v3.4.1.zip", "lib.zip", quiet = TRUE) 12 | dir.create("../windows", showWarnings = FALSE) 13 | unzip("lib.zip", exdir = "../windows") 14 | unlink("lib.zip") 15 | } 16 | 17 | if(!file.exists("../windows/netcdf-4.4.1.1-dap/include/netcdf.h")){ 18 | download.file("https://github.com/rwinlib/netcdf/archive/v4.4.1.1-dap.zip", "lib.zip", quiet = TRUE) 19 | dir.create("../windows", showWarnings = FALSE) 20 | unzip("lib.zip", exdir = "../windows") 21 | unlink("lib.zip") 22 | } 23 | 24 | 25 | # if(!file.exists("../windows/opencv-%s/include/opencv4/opencv2/opencv.hpp")){ 26 | # download.file("https://github.com/rwinlib/opencv/archive/v4.0.1.zip", "lib.zip", quiet = TRUE) 27 | # dir.create("../windows", showWarnings = FALSE) 28 | # unzip("lib.zip", exdir = "../windows") 29 | # unlink("lib.zip") 30 | # } 31 | 32 | if(!file.exists(sprintf("../windows/opencv-%s/include/opencv4/opencv2/opencv.hpp", VERSION))){ 33 | download.file(sprintf("https://github.com/rwinlib/opencv/archive/v%s.zip", VERSION), "lib.zip", quiet = TRUE) 34 | dir.create("../windows", showWarnings = FALSE) 35 | unzip("lib.zip", exdir = "../windows") 36 | unlink("lib.zip") 37 | } -------------------------------------------------------------------------------- /src/LICENSE_imagefusion.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2020, Hochschule Bochum 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of ImageFusion nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /R/internal.R: -------------------------------------------------------------------------------- 1 | 2 | self_predict <- function(...,src_im,dst_im,method){ 3 | if(method=="fitfc"){ 4 | ImageFusion::fitfc_job(input_filenames = rep(src_im,3), 5 | input_resolutions = c("high","low","low"), 6 | input_dates = c(1,1,1), 7 | pred_dates = 1, 8 | pred_filenames = dst_im, 9 | verbose=FALSE, 10 | ... 11 | ) 12 | } 13 | if(method=="spstfm"){ 14 | # ImageFusion::spstfm_job(input_filenames = rep(src_im,5), 15 | # input_resolutions = c("high","low","high","low","low"), 16 | # input_dates = c(1,1,2,2,1), 17 | # pred_dates = 1, 18 | # pred_filenames = dst_im, 19 | # verbose=FALSE, 20 | # min_train_iter = 0, 21 | # max_train_iter = 0, 22 | # LOADDICT_options = "", 23 | # SAVEDICT_options = "", 24 | # REUSE_options = "clear", 25 | # ... 26 | # ) 27 | } 28 | if(method=="estarfm"){ 29 | ImageFusion::estarfm_job(input_filenames = rep(src_im,5), 30 | input_resolutions = c("high","low","high","low","low"), 31 | input_dates = c(1,1,2,2,1), 32 | pred_dates = 1, 33 | pred_filenames = dst_im, 34 | verbose=FALSE, 35 | ... 36 | ) 37 | } 38 | if(method=="starfm"){ 39 | ImageFusion::starfm_job(input_filenames = rep(src_im,3), 40 | input_resolutions = c("high","low","low"), 41 | input_dates = c(1,1,1), 42 | pred_dates = 1, 43 | pred_filenames = dst_im, 44 | verbose=FALSE, 45 | ... 46 | ) 47 | } 48 | 49 | 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | VERSION = 0.0.3 2 | OPENCVVERSION = 4.4.0 3 | TARGET = lib$(subst gcc,,$(COMPILED_BY))$(R_ARCH) 4 | RWINLIB = ../windows/opencv-$(OPENCVVERSION) 5 | RWINLIB_GDAL = ../windows/gdal3-3.4.1 6 | RWINLIB_BOOST= ../windows/boost_1_55_0/boost 7 | CXX_STD = CXX17 8 | 9 | PKG_CPPFLAGS = -I$(RWINLIB_GDAL)/include \ 10 | -I$(RWINLIB)/include/opencv4 \ 11 | -Iinclude \ 12 | -I../src/utils/helpers \ 13 | -I../src/utils/imginterp \ 14 | -DCURL_STATICLIB -DR_PACKAGE 15 | 16 | PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) 17 | 18 | PKG_LIBS = -lstdc++fs -L$(RWINLIB_GDAL)/lib$(R_ARCH) \ 19 | -lgdal -lsqlite3 -lspatialite -lproj -lgeos_c -lgeos \ 20 | -ljson-c -lnetcdf -lmariadbclient -lpq -lpgport -lpgcommon \ 21 | -lwebp -lcurl -lssh2 -lssl \ 22 | -lhdf5_hl -lhdf5 -lexpat -lfreexl -lcfitsio \ 23 | -lmfhdf -lhdf -lxdr -lpcre \ 24 | -lopenjp2 -ljasper -lpng -ljpeg -ltiff -lgeotiff -lgif -lxml2 -llzma -lz -lzstd \ 25 | -lodbc32 -lodbccp32 -liconv -lpsapi -lwldap32 -lsecur32 -lgdi32 -lnormaliz \ 26 | -lcrypto -lcrypt32 -lws2_32 -lshlwapi -lbcrypt \ 27 | -L$(RWINLIB)/$(TARGET) \ 28 | -L$(RWINLIB)/lib$(R_ARCH)-ucrt \ 29 | -lopencv_imgproc -lopencv_core -ltbb \ 30 | -ljpeg -lwebp -lpng -lz -ltiff \ 31 | -lcomctl32 -lgdi32 -lole32 -lws2_32 -lavifil32 -lavicap32 -lwinmm -lmsvfw32 \ 32 | -lopengl32 -lglu32 -lcomdlg32 -lOleAut32 -luuid \ 33 | $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) $(SHLIB_OPENMP_CXXFLAGS) 34 | 35 | all: clean winlibs 36 | 37 | winlibs: 38 | mkdir -p ../inst 39 | "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" --vanilla "../tools/winlibs.R" 40 | cp -r $(RWINLIB_GDAL)/share/gdal ../inst/ 41 | cp -r $(RWINLIB_GDAL)/share/proj ../inst/ 42 | "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R" 43 | cp -r $(RWINLIB)/share ../inst/ 44 | 45 | clean: 46 | rm -f $(SHLIB) $(OBJECTS) 47 | 48 | .PHONY: all winlibs clean 49 | 50 | 51 | CPPFILES = $(wildcard *.cpp src/*.cpp utils/helpers/*common.cpp utils/imginterp/customopts.cpp ) 52 | SOURCES = $(CPPFILES) 53 | OBJECTS = $(CPPFILES:.cpp=.o) -------------------------------------------------------------------------------- /inst/Copyrights: -------------------------------------------------------------------------------- 1 | =========================== 2 | File: src/include/optionparser.h src/include/optionparserimpl.h 3 | Copyright (c) 2012 Matthias S. Benkmann 4 | License: MIT 5 | Origin: https://sourceforge.net/projects/optionparser/ 6 | 7 | Modifications (c) 2020 Christof Kaufmann: 8 | - Major additions and modifications to the original optionparser code 9 | 10 | 11 | ========================== 12 | File: src/include/* src/src/* src/utils/* 13 | Copyright (c) 2016-2020 Hochschule Bochum 14 | License: BSD-3 15 | Origin: No public repository 16 | Modifications (c) 2020 Johannes Mast: 17 | - Removed or commented code that is not necessary for the implementation in R 18 | - Removed calls to std::cerr or std::cout with calls to Rcpp::Rcerr or Rcpp::Rcout to comply with cran policy. 19 | - Adapted to use gdal filesystem functionalities instead of std::filesystem (for portability) 20 | 21 | ========================== 22 | 23 | File: configure.ac sections PROJ and GDAL 24 | Copyright (C) 2021 Roger Bivand 25 | License: GPL (>= 2) 26 | Origin: https://github.com/cran/rgdal 27 | Modifications (c) 2021 Johannes Mast: 28 | - Removed sections which are not relevant for ImageFusion 29 | 30 | ========================== 31 | 32 | File: configure.ac section OPENCV 33 | Copyright (c) 2019 Jeroen Ooms 34 | License: MIT 35 | Origin: https://github.com/ropensci/opencv/blob/master/configure 36 | Modifications (c) 2020 Johannes Mast: 37 | - Removed checks for PKG_TEST_HEADER_XFEATURES2D which is not used in this package. 38 | 39 | 40 | 41 | ========================== 42 | 43 | File: configure.ac section OPENMP 44 | Copyright (C) 2016 - 2021 Dirk Eddelbuettel 45 | License: GPL-2 46 | Origin: https://github.com/RcppCore/RcppArmadillo/blob/master/configure.ac 47 | Modifications (c) 2017 Stackoverflow user hejseb: 48 | - see https://stackoverflow.com/q/46723854 49 | Modifications (c) 2020 Johannes Mast: 50 | - Added openmp_imagefusionflag (commented out, possible use for compatibility with imagefusion code) 51 | 52 | 53 | ========================== 54 | 55 | Files: include/filesystem.h and src/filesystem.cpp 56 | Copyright (C) 2019 Marius Appel 57 | Origin: https://github.com/appelmar/gdalcubes/blob/master/src/filesystem.cpp 58 | License: MIT 59 | Modifications (c) 2021 Johannes Mast: 60 | - Changed the namespace to imagefusion 61 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | execute_estarfm_job_cpp <- function(input_filenames, input_resolutions, input_dates, pred_dates, pred_filenames, pred_area, winsize, date1, date3, n_cores, use_local_tol, use_quality_weighted_regression, output_masks, use_nodata_value, verbose, uncertainty_factor, number_classes, data_range_min, data_range_max, hightag, lowtag, MASKIMG_options, MASKRANGE_options) { 5 | invisible(.Call(`_ImageFusion_execute_estarfm_job_cpp`, input_filenames, input_resolutions, input_dates, pred_dates, pred_filenames, pred_area, winsize, date1, date3, n_cores, use_local_tol, use_quality_weighted_regression, output_masks, use_nodata_value, verbose, uncertainty_factor, number_classes, data_range_min, data_range_max, hightag, lowtag, MASKIMG_options, MASKRANGE_options)) 6 | } 7 | 8 | execute_starfm_job_cpp <- function(input_filenames, input_resolutions, input_dates, pred_dates, pred_filenames, pred_area, winsize, date1, date3, n_cores, output_masks, use_nodata_value, use_strict_filtering, use_temp_diff_for_weights, do_copy_on_zero_diff, double_pair_mode, verbose, number_classes, logscale_factor, spectral_uncertainty, temporal_uncertainty, hightag, lowtag, MASKIMG_options, MASKRANGE_options) { 9 | invisible(.Call(`_ImageFusion_execute_starfm_job_cpp`, input_filenames, input_resolutions, input_dates, pred_dates, pred_filenames, pred_area, winsize, date1, date3, n_cores, output_masks, use_nodata_value, use_strict_filtering, use_temp_diff_for_weights, do_copy_on_zero_diff, double_pair_mode, verbose, number_classes, logscale_factor, spectral_uncertainty, temporal_uncertainty, hightag, lowtag, MASKIMG_options, MASKRANGE_options)) 10 | } 11 | 12 | execute_fitfc_job_cpp <- function(input_filenames, input_resolutions, input_dates, pred_dates, pred_filenames, pred_area, winsize, date1, n_neighbors, output_masks, use_nodata_value, verbose, resolution_factor, hightag, lowtag, MASKIMG_options, MASKRANGE_options) { 13 | invisible(.Call(`_ImageFusion_execute_fitfc_job_cpp`, input_filenames, input_resolutions, input_dates, pred_dates, pred_filenames, pred_area, winsize, date1, n_neighbors, output_masks, use_nodata_value, verbose, resolution_factor, hightag, lowtag, MASKIMG_options, MASKRANGE_options)) 14 | } 15 | 16 | execute_imginterp_job_cpp <- function(verbose, input_string) { 17 | invisible(.Call(`_ImageFusion_execute_imginterp_job_cpp`, verbose, input_string)) 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/include/filesystem.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2019 Marius Appel 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef FILESYSTEM_H 26 | #define FILESYSTEM_H 27 | 28 | #include 29 | #include 30 | 31 | #ifdef _WIN32 32 | #define DIR_SEPARATOR "\\" 33 | #else 34 | #define DIR_SEPARATOR "/" 35 | #endif 36 | 37 | namespace imagefusion { 38 | 39 | /** 40 | * @brief A simple wrapper class around GDAL's CPL and VSI interfaces for simple filesystem operations 41 | */ 42 | class filesystem { 43 | public: 44 | static bool exists(std::string p); 45 | static bool is_directory(std::string p); 46 | static bool is_regular_file(std::string p); 47 | static std::string stem(std::string p); 48 | static std::string filename(std::string p); 49 | static std::string extension(std::string p); 50 | static std::string directory(std::string p); 51 | static std::string get_working_dir(); 52 | static std::string make_absolute(std::string p); 53 | static std::string parent(std::string p); 54 | static std::string join(std::string p1, std::string p2); 55 | static void iterate_directory(std::string p, std::function f); 56 | static void iterate_directory_recursive(std::string p, std::function f); 57 | static void remove(std::string p); 58 | static void mkdir(std::string p); 59 | static void mkdir_recursive(std::string p); 60 | static bool is_relative(std::string p); 61 | static bool is_absolute(std::string p); 62 | static std::string get_tempdir(); 63 | static uint32_t file_size(std::string p); 64 | }; 65 | 66 | } // namespace imagefusion 67 | 68 | #endif //FILESYSTEM_H 69 | -------------------------------------------------------------------------------- /src/include/parallelizer_options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef _OPENMP 4 | #error "Sorry, if you want to use ParallelizerOptions, you need to install OpenMP first." 5 | #endif 6 | 7 | #include "options.h" 8 | 9 | #include 10 | 11 | namespace imagefusion { 12 | 13 | /** 14 | * @brief Options for the Parallelizer meta DataFusor 15 | * 16 | * The ParallelizerOptions add to the inherited prediction area the number of threads and nested 17 | * options for the underlying DataFusor algorithm. 18 | * 19 | * Note that although the nested options also have a prediction area like every Options sub class, 20 | * these are ignored and only the prediction area of the ParallelizerOptions are used. However, the 21 | * nested algorithm options are of course used for all other algorithm specific settings. 22 | */ 23 | template 24 | class ParallelizerOptions : public Options { 25 | public: 26 | 27 | /** 28 | * @brief Get the number of threads to use 29 | * @return number of threads 30 | */ 31 | unsigned int getNumberOfThreads() const; 32 | 33 | 34 | /** 35 | * @brief Set the number of threads to use 36 | * @param num is the number of threads ≤ number of processors 37 | * 38 | * The number of threads determines the number of the underlying DataFusor%s, which run in 39 | * parallel to predict an image. Choosing it greater than 40 | * [`omp_get_num_procs()`](https://gcc.gnu.org/onlinedocs/libgomp/omp_005fget_005fnum_005fprocs.html) 41 | * will set it to `omp_get_num_procs()`. 42 | * 43 | * By default (on construction) this is set to `omp_get_num_procs()`. 44 | */ 45 | void setNumberOfThreads(unsigned int num); 46 | 47 | 48 | /** 49 | * @brief Get the nested DataFusor algorithm options object 50 | * @return nested options 51 | */ 52 | AlgOpt const& getAlgOptions() const; 53 | 54 | 55 | /** 56 | * @brief Set the nested DataFusor algorithm options 57 | * @param o are the nested options of the algorithm. 58 | * 59 | * When processing the options in the Parallelizer, the prediction area is set to a horizontal 60 | * stripe according to the DataFusor%s thread number. The remaining options stay as set in `o`. 61 | */ 62 | void setAlgOptions(AlgOpt const& o); 63 | 64 | private: 65 | unsigned int numberThreads = omp_get_num_procs(); 66 | AlgOpt algOpt; 67 | }; 68 | 69 | 70 | 71 | 72 | template 73 | inline unsigned int ParallelizerOptions::getNumberOfThreads() const { 74 | return numberThreads; 75 | } 76 | 77 | 78 | template 79 | inline void ParallelizerOptions::setNumberOfThreads(unsigned int num) { 80 | numberThreads = std::min((int)num, std::max(omp_get_num_procs(), 1)); 81 | } 82 | 83 | 84 | template 85 | inline AlgOpt const& ParallelizerOptions::getAlgOptions() const { 86 | return algOpt; 87 | } 88 | 89 | 90 | template 91 | inline void ParallelizerOptions::setAlgOptions(AlgOpt const& o) { 92 | algOpt = o; 93 | } 94 | 95 | 96 | 97 | } /* namespace imagefusion */ 98 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | Dear CRAN-Team, 2 | 3 | This is our resubmission of our ImageFusion package. 4 | 5 | We have done our best to thoroughly test our code and follow all best practices. 6 | Thank you for your support. 7 | 8 | Johannes Mast (Package Maintainer) 9 | 10 | ## Changes 11 | 12 | In response to the comments by Uwe Ligges, we have made the following changes: 13 | 14 | To address general issues on platforms using clang: 15 | * DESCRIPTION: Added C++17 as a System Requirement. 16 | * configure.ac: Set C++ before include AC_LANG(). 17 | 18 | To address issues of macOS portability: 19 | configure.ac: Adapted the configuration process of PROJ from the recent version 20 | of rgdal to comply with the most recent requirements of PROJ. 21 | * Makevars.in: See changes above. 22 | * Makevars.win: See changes above. 23 | 24 | * src/include/filesystem.h: Now wraps around GDAL filesystem functions (path stem and extension) instead of relying on the std::filesystem which may not be provided on certain macOS. This is adapted from the r package gdalcubes by Marius Appel. 25 | * src/include/filesystem.cpp: See changes above. 26 | * src/image.cpp: See changes above. 27 | * src/utils/helpers/utils_common.cpp: See changes above. 28 | * src/utils/imginterp/interpolation.h: See changes above. 29 | * inst/Copyrights: Added rgdal author as original copyright holder for the GDAL and PROJ configure sections. Added Marius Appel as the source for the filesystem gdal wrapper. 30 | 31 | 32 | We have made further changes: 33 | * removed superfluous files of the imagefusion library to reduce the overall size of the package slightly. 34 | * Makevars.in: Increased Version number to 0.0.3. 35 | * Makevars.win: Increased Version number to 0.0.3. 36 | * DESCRIPTION: Increased Version number to 0.0.3. 37 | * NEWS.md: Updated news according to the changes. 38 | 39 | 40 | ## Test environments 41 | * local windows 10, R 4.0.3 42 | * local windows 10, R under development (unstable) (2021-02-17 r80023) 43 | * local ubuntu 20.04, R 4.0.2 44 | * win-builder R version 4.0.5 (2021-03-31) 45 | * win-builder R version 4.1.0 RC (2021-05-06´ r80288) 46 | 47 | ## R CMD check results 48 | 49 | ### ERRORS 50 | 51 | There were no ERRORs. 52 | 53 | ### WARNINGS 54 | 55 | There were no WARNINGs. 56 | 57 | ### NOTES 58 | 59 | #### NOTE 1: 60 | checking installed package size ... NOTE 61 | installed size is 61.3Mb 62 | sub-directories of 1Mb or more: 63 | libs 59.2Mb 64 | modis 1.4Mb 65 | 66 | The great size mostly due to our inclusion of the gdal library, 67 | which is required by the c++ library we are building on. 68 | Therefore, the library is not easily substituted. 69 | 70 | Other packages handling raster files, 71 | such as [sf](https://cran.r-project.org/web/packages/sf/index.html) or [gdalcubes](https://cran.r-project.org/web/packages/gdalcubes/index.html), 72 | are also affected by this issue. 73 | We appreciate any ideas on how to solve this note, 74 | as we have no influence over the size of the GDAL library. 75 | 76 | ## Downstream dependencies 77 | 78 | There are no downstream dependencies yet, 79 | although our intent is to produce some in the future. -------------------------------------------------------------------------------- /src/include/options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "image.h" 4 | 5 | namespace imagefusion { 6 | 7 | 8 | /** 9 | * @brief The Options class is the base class for algorithm specific option classes 10 | * 11 | * It has only the one attribute that every DataFusor algorithm will need: a prediction area. Sub 12 | * classes can add more attributes, like source resolution tags and dates, window size, etc. 13 | */ 14 | class Options { 15 | public: 16 | /** 17 | * @brief Construct an empty Options object 18 | * 19 | * This constructor sets the prediction area to offsets 0 and size 0. The output tag is empty. 20 | */ 21 | Options() = default; 22 | 23 | Options(Options const& f) = default; 24 | Options(Options&& f) = default; 25 | Options& operator=(Options const& f) = default; 26 | Options& operator=(Options&& f) = default; 27 | 28 | /** 29 | * @brief Default destructor virtual for inheritance 30 | */ 31 | virtual ~Options() = default; 32 | 33 | 34 | /** 35 | * @brief Get prediction area 36 | * @return prediction area, which should have been set with setPredictionArea(Rectangle r) 37 | */ 38 | Rectangle const& getPredictionArea() const; 39 | 40 | 41 | /** 42 | * @brief Set prediction area 43 | * 44 | * @param r is the prediction area, i. e. the part of the image that should be predicted by the 45 | * DataFusor. No DataFusor is required to predict the image outside of this area. 46 | * 47 | * This just saves the prediction area in the options object. To apply the option, see 48 | * DataFusor::processOptions. 49 | * 50 | * Note, when using Parallelizer only the prediction area in ParallelizerOptions will be used. 51 | * The prediction area in the nested options object in ParallelizerOptions will be ignored. 52 | * 53 | * @see predictionArea 54 | */ 55 | void setPredictionArea(Rectangle r); 56 | 57 | 58 | protected: 59 | 60 | /** 61 | * @brief Define size of the fused image and offset in the source images 62 | * 63 | * The prediction area defines the size of the resulting fused image. Additionally, it also 64 | * defines the offset in the corresponding source images. So in total the prediction area 65 | * defines how a resulting fused image is aligned to the source image. 66 | * 67 | * A DataFusor is only required to predict the resulting image in this region of the image. 68 | * Yet, the sourrounding image parts might be important for the algorithm. So defining a 69 | * prediction area is not a crop! 70 | * 71 | * As an example, assume a DataFusor that has a window size c and the window moves through the 72 | * image predicting one pixel in the center for each window position (like STARFM). Then the 73 | * prediction area should be offset by at least c/2 and have at most a width of w - c + 1 and a 74 | * height of h - c + 1 where w and h are the source image width and height, respectively. This 75 | * is illustrated in the following image: 76 | * @image html predarea.png 77 | * 78 | * Note, when using Parallelizer only the prediction area in ParallelizerOptions will be used. 79 | * The prediction area in the nested options object in ParallelizerOptions will be ignored. 80 | */ 81 | Rectangle predictionArea{0,0,0,0}; 82 | }; 83 | 84 | 85 | 86 | inline Rectangle const& Options::getPredictionArea() const { 87 | return predictionArea; 88 | } 89 | 90 | 91 | inline void Options::setPredictionArea(Rectangle r) { 92 | predictionArea = r; 93 | } 94 | 95 | 96 | } /* namespace imagefusion */ 97 | -------------------------------------------------------------------------------- /src/src/fileformat.cpp: -------------------------------------------------------------------------------- 1 | #include "fileformat.h" 2 | #include "../../include/filesystem.h" 3 | #include 4 | #include 5 | 6 | namespace imagefusion { 7 | 8 | FileFormat const FileFormat::unsupported{}; 9 | 10 | bool FileFormat::isSupported(std::string const& fmtStr) { 11 | GDALAllRegister(); 12 | GDALDriver* driver = GetGDALDriverManager()->GetDriverByName(fmtStr.c_str()); 13 | return driver != nullptr; 14 | } 15 | 16 | std::string FileFormat::fileExtension() const { 17 | GDALAllRegister(); 18 | GDALDriver* driver = GetGDALDriverManager()->GetDriverByName(driverName.c_str()); 19 | char const* fileExtension_c_str = driver->GetMetadataItem(GDAL_DMD_EXTENSION); 20 | if (fileExtension_c_str == nullptr) 21 | return ""; 22 | 23 | return fileExtension_c_str; 24 | } 25 | 26 | std::string FileFormat::allFileExtensions() const { 27 | GDALAllRegister(); 28 | GDALDriver* driver = GetGDALDriverManager()->GetDriverByName(driverName.c_str()); 29 | char const* fileExtensions_c_str = driver->GetMetadataItem(GDAL_DMD_EXTENSIONS); 30 | if (fileExtensions_c_str == nullptr) 31 | return fileExtension(); 32 | 33 | return fileExtensions_c_str; 34 | } 35 | 36 | std::string FileFormat::longName() const { 37 | GDALAllRegister(); 38 | GDALDriver* driver = GetGDALDriverManager()->GetDriverByName(driverName.c_str()); 39 | char const* longName_c_str = driver->GetMetadataItem(GDAL_DMD_LONGNAME); 40 | if (longName_c_str == nullptr) 41 | return ""; 42 | 43 | return longName_c_str; 44 | } 45 | 46 | FileFormat FileFormat::fromFileExtension(std::string fileExt) { 47 | std::transform(fileExt.begin(), fileExt.end(), fileExt.begin(), ::tolower); 48 | if (fileExt.front() == '.') 49 | fileExt = fileExt.substr(1); 50 | 51 | GDALAllRegister(); 52 | GDALDriverManager* dMng = GetGDALDriverManager(); 53 | int dCount = dMng->GetDriverCount(); 54 | for (int i = 0; i < dCount; ++i) { 55 | GDALDriver* d = dMng->GetDriver(i); 56 | char const* fileExtensions_c_str = d->GetMetadataItem(GDAL_DMD_EXTENSIONS); 57 | if (fileExtensions_c_str == nullptr) 58 | continue; 59 | 60 | std::string fileExtensions = fileExtensions_c_str; 61 | std::transform(fileExtensions.begin(), fileExtensions.end(), fileExtensions.begin(), ::tolower); 62 | 63 | std::istringstream stream{fileExtensions}; 64 | std::string singleExt; 65 | while (stream >> singleExt) { 66 | if (singleExt == fileExt) { 67 | FileFormat fileFormat; 68 | fileFormat.driverName = d->GetDescription(); 69 | return fileFormat; 70 | } 71 | } 72 | } 73 | return unsupported; 74 | } 75 | 76 | std::vector FileFormat::supportedFormats() { 77 | std::vector v; 78 | GDALAllRegister(); 79 | GDALDriverManager* dMng = GetGDALDriverManager(); 80 | int dCount = dMng->GetDriverCount(); 81 | for (int i = 0; i < dCount; ++i) { 82 | GDALDriver* d = dMng->GetDriver(i); 83 | FileFormat f; 84 | f.driverName = d->GetDescription(); 85 | v.push_back(f); 86 | } 87 | return v; 88 | } 89 | 90 | FileFormat FileFormat::fromFile(std::string filename) { 91 | // open file 92 | GDALAllRegister(); 93 | GDALDataset* gdal_img = (GDALDataset*) GDALOpen(filename.c_str(), GA_ReadOnly); 94 | if (!gdal_img) 95 | return unsupported; 96 | 97 | // get driver name 98 | FileFormat f; 99 | f.driverName = gdal_img->GetDriverName(); 100 | GDALClose(gdal_img); 101 | return f; 102 | } 103 | 104 | 105 | } /* namespace imagefusion */ 106 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. 2 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request: 9 | branches: 10 | - main 11 | - master 12 | 13 | name: R-CMD-check 14 | 15 | jobs: 16 | R-CMD-check: 17 | runs-on: ${{ matrix.config.os }} 18 | 19 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | config: 25 | - {os: windows-latest, r: 'release'} 26 | - {os: macOS-latest, r: 'release'} 27 | - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} 28 | - {os: ubuntu-20.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} 29 | 30 | env: 31 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true 32 | RSPM: ${{ matrix.config.rspm }} 33 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 34 | 35 | steps: 36 | - uses: actions/checkout@v2 37 | 38 | - uses: r-lib/actions/setup-r@v1 39 | with: 40 | r-version: ${{ matrix.config.r }} 41 | 42 | - uses: r-lib/actions/setup-pandoc@v1 43 | 44 | - name: Query dependencies 45 | run: | 46 | install.packages('remotes') 47 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) 48 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") 49 | shell: Rscript {0} 50 | 51 | - name: Restore R package cache 52 | if: runner.os != 'Windows' 53 | uses: actions/cache@v2 54 | with: 55 | path: ${{ env.R_LIBS_USER }} 56 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} 57 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- 58 | 59 | - name: Install system dependencies 60 | if: runner.os != 'Windows' 61 | run: if [ "$RUNNER_OS" == "Linux" ]; then sudo apt-get install -y libopencv-dev; else brew install opencv; fi 62 | 63 | - name: Install system dependencies 64 | if: runner.os == 'Linux' 65 | env: 66 | RHUB_PLATFORM: linux-x86_64-ubuntu-gcc 67 | run: | 68 | Rscript -e "remotes::install_github('r-hub/sysreqs')" 69 | sysreqs=$(Rscript -e "cat(sysreqs::sysreq_commands('DESCRIPTION'))") 70 | sudo -s eval "$sysreqs" 71 | # install spatial dependencies 72 | sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable 73 | sudo apt update 74 | sudo apt install \ 75 | libgdal-dev \ 76 | libgeos-dev \ 77 | libproj-dev 78 | 79 | 80 | - name: Install dependencies 81 | run: | 82 | remotes::install_deps(dependencies = TRUE) 83 | remotes::install_cran("rcmdcheck") 84 | shell: Rscript {0} 85 | 86 | - name: Check 87 | env: 88 | _R_CHECK_CRAN_INCOMING_REMOTE_: false 89 | run: | 90 | options(crayon.enabled = TRUE) 91 | rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check") 92 | shell: Rscript {0} 93 | 94 | - name: Upload check results 95 | if: failure() 96 | uses: actions/upload-artifact@main 97 | with: 98 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results 99 | path: check 100 | -------------------------------------------------------------------------------- /src/src/filesystem.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2019 Marius Appel 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include "filesystem.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | namespace imagefusion { 34 | 35 | bool filesystem::exists(std::string p) { 36 | VSIStatBufL s; 37 | return VSIStatL(p.c_str(), &s) == 0; 38 | } 39 | 40 | bool filesystem::is_directory(std::string p) { 41 | VSIStatBufL s; 42 | if (VSIStatL(p.c_str(), &s) != 0) 43 | return false; // File / directory does not exist 44 | return VSI_ISDIR(s.st_mode); 45 | } 46 | 47 | bool filesystem::is_regular_file(std::string p) { 48 | VSIStatBufL s; 49 | if (VSIStatL(p.c_str(), &s) != 0) 50 | return false; // File / directory does not exist 51 | return VSI_ISREG(s.st_mode); 52 | } 53 | 54 | std::string filesystem::stem(std::string p) { 55 | return CPLGetBasename(p.c_str()); 56 | } 57 | 58 | std::string filesystem::filename(std::string p) { 59 | return std::string(CPLGetFilename(p.c_str())); 60 | } 61 | 62 | std::string filesystem::extension(std::string p) { 63 | return std::string(CPLGetExtension(p.c_str())); 64 | } 65 | 66 | std::string filesystem::directory(std::string p) { 67 | return std::string(CPLGetPath(p.c_str())); 68 | } 69 | 70 | std::string filesystem::get_working_dir() { 71 | char* x = CPLGetCurrentDir(); 72 | std::string p; 73 | if (x) { 74 | p = join(std::string(x), p); 75 | CPLFree(x); 76 | } 77 | return p; 78 | } 79 | 80 | std::string filesystem::make_absolute(std::string p) { 81 | if (CPLIsFilenameRelative(p.c_str())) { 82 | char* x = CPLGetCurrentDir(); 83 | if (x) { 84 | p = join(std::string(x), p); 85 | CPLFree(x); 86 | } 87 | } 88 | return p; 89 | } 90 | 91 | std::string filesystem::parent(std::string p) { 92 | if (!is_directory(p)) { 93 | return directory(p); 94 | } 95 | return std::string(CPLGetPath(CPLCleanTrailingSlash(p.c_str()))); 96 | } 97 | 98 | std::string filesystem::join(std::string p1, std::string p2) { 99 | return p1 + DIR_SEPARATOR + p2; 100 | } 101 | 102 | void filesystem::iterate_directory(std::string p, std::function f) { 103 | char** y = VSIReadDir(p.c_str()); 104 | char** x = y; 105 | if (x != NULL) { 106 | while (*x != NULL) { 107 | f(join(p, std::string(*x))); 108 | ++x; 109 | } 110 | CSLDestroy(y); 111 | } 112 | } 113 | 114 | void filesystem::iterate_directory_recursive(std::string p, std::function f) { 115 | char** y = VSIReadDirRecursive(p.c_str()); 116 | char** x = y; 117 | if (x != NULL) { 118 | while (*x != NULL) { 119 | f(join(p, std::string(*x))); 120 | ++x; 121 | } 122 | CSLDestroy(y); 123 | } 124 | } 125 | 126 | void filesystem::remove(std::string p) { 127 | if (is_directory(p)) { 128 | VSIRmdir(p.c_str()); 129 | } 130 | else { 131 | VSIUnlink(p.c_str()); 132 | } 133 | } 134 | 135 | void filesystem::mkdir(std::string p) { 136 | VSIMkdir(p.c_str(), 0777); 137 | } 138 | 139 | void filesystem::mkdir_recursive(std::string p) { 140 | //VSIMkdirRecursive(p.c_str(), 0777); // available from GDAL 2.3 141 | if (p.empty()) return; 142 | 143 | if (is_directory(p)) { 144 | return; 145 | } 146 | 147 | std::string par = parent(p); 148 | 149 | if (par == p || par.length() >= p.length()) { 150 | return; 151 | } 152 | 153 | if (!exists(par)) { 154 | mkdir_recursive(par); 155 | } 156 | mkdir(p); 157 | } 158 | 159 | bool filesystem::is_relative(std::string p) { 160 | return CPLIsFilenameRelative(p.c_str()) != 0; 161 | } 162 | 163 | bool filesystem::is_absolute(std::string p) { 164 | return !is_relative(p); 165 | } 166 | 167 | std::string filesystem::get_tempdir() { 168 | std::vector env_vars = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", "USERPROFILE"}; 169 | for (uint16_t i = 0; i < env_vars.size(); ++i) { 170 | if (std::getenv(env_vars[i].c_str()) != NULL) { 171 | if (filesystem::is_directory(std::getenv(env_vars[i].c_str()))) 172 | return std::string(std::getenv(env_vars[i].c_str())); 173 | } 174 | } 175 | 176 | #ifdef _WIN32 177 | if (std::getenv("SYSTEMROOT") != NULL) { 178 | if (filesystem::is_directory(std::getenv("SYSTEMROOT"))) 179 | return std::string(std::getenv("SYSTEMROOT")); 180 | } 181 | return "C:\\Windows"; 182 | #else 183 | return "/tmp"; 184 | #endif 185 | } 186 | 187 | uint32_t filesystem::file_size(std::string p) { 188 | VSIStatBufL s; 189 | if (VSIStatL(p.c_str(), &s) != 0) 190 | return 0; // File / directory does not exist 191 | return s.st_size; 192 | } 193 | 194 | } // namespace imagefusion 195 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | [![CRAN version](https://www.r-pkg.org/badges/version/ImageFusion)](https://CRAN.R-project.org/package=ImageFusion) 3 | [![CRAN downloads](https://cranlogs.r-pkg.org/badges/last-month/ImageFusion?color=brightgreen)](https://CRAN.R-project.org/package=ImageFusion) 4 | 5 | 6 | # ImageFusion 7 | 8 | 9 | 10 | ## Introduction 11 | Temporal fusion of raster image time-Series. R interface for the imagefusion framework, which provides implementation of the FITFC, ESTARFM and STARFM algorithms in C++. 12 | 13 | 14 | ### Background 15 | 16 | When performing time-series analysis of remote-sensing data, one often faces the choice between the different sensors which produce freely available imagery. 17 | * *High-Resolution:* Images with a high spatial resolution but low temporal resolution (Sentinel, Landsat) 18 | * *Low-Resolution:* Images with a low spatial resolution and high temporal resolution (MODIS) 19 | This is a rough categorization, and the capabilities and number of platforms is great and ever increasing. This provides great opportunities but also the challenge on how to best combine different sources. 20 | 21 | ### Principle 22 | 23 | Fusion is a process by which we can combine information from two temporally overlapping time series to create a single time series with the temporal resolution of the *Low-Resolution* inputs and the spatial resolution of the *High-Resolution* inputs, resulting in an output time series with high spatial *and* high temporal resolution. 24 | 25 | The basic principle is to seek *pair-dates* on which images for both time series are available, and finding the relation between both images on that date. The relation is then applied to those dates for which only *Low_Resolution* images are available. The details vary depending on the fusion algorithm. A variety of algorithms exist, and the ImageFusion framework is intended to be continuously extended by users and scientists. 26 | 27 | So far, the following algorithms are implemented: 28 | 29 | * FITFC 30 | * ESTARFM 31 | * STARFM 32 | 33 | ## Installation 34 | 35 | The package can be installed from GitHub : 36 | 37 | ```r 38 | devtools::install_github("JohMast/ImageFusion") 39 | ``` 40 | 41 | ImageFusion is supported for and tested on Windows and Linux operating systems. Running ImageFusion on macOS is also possible, but may suffer from decreased performance and require additional work to install required dependencies. 42 | 43 | 44 | ## Usage 45 | 46 | 47 | ### Jobs 48 | 49 | The core of the package are functions for the algorithms ESTARFM, FITFC and STARFM. 50 | 51 | Individual *jobs* can be executed using the `estarfm_job`, `fitfc_job`and `starfm_job` functions. These jobs require one or two *pair dates* on which both high and low resolution images are available. The *pair dates* support an interval and the job offer the fusion of images for all dates within this interval for which only low resolution images are available. 52 | 53 | Some algorithms also offer a *singlepair mode* which allows fusion based on only a single pair. The FITFC algorithm operates exclusively in singlepair mode. 54 | ```r 55 | estarfm_job(input_filenames = list_of_input_filenames, 56 | input_resolutions = c("high","high","low","low","low","low", 57 | "low","low", "low","low","low","low"), 58 | input_dates = c(68,77,68,69,70,71,72,73,74,75,76,77), 59 | pred_dates = c(72,74)) 60 | ``` 61 | Here we pass all image filenames as a single input vector. The tags (whether they are high or low resolution) is a parallel vector of equal length and order. A third such vector passes the date for each image. Note how we have two dates (68 and 77) for which we have both "high" and "low" available. These dates will be used as pair dates. 62 | 63 | ### Tasks 64 | 65 | For the creation of long time series of many pair dates, the function `imagefusion_task`is available. This function automatically detects pair dates and splits the time-series *task* into as many *jobs* as is supported by the inputs. 66 | ```r 67 | imagefusion_task(filenames_high = list_of_high_resolution_filenames, 68 | dates_high = c(68,77,93,100), 69 | filenames_low = list_of_low_resolution_filenames, 70 | dates_low = 68:93, 71 | dates_pred = c(65,70,75,80,85,90,95)) 72 | ``` 73 | For the creation of a task, we pass the high and low filenames and dates separately. Note that here we have multiple high-resolution images (68, 77, 93, 100) and multiple pair dates (68, 77, 93). The task will therefore be split up into different jobs, one for each interval. 74 | 75 | ### Utilities 76 | 77 | ImageFusion also provides an additional utility function `imginterp_task` which allows for the linear interpolation of missing or masked values. We recommend to use this before the fusion to replace any missing or masked values, which usually results in a much better fusion result. 78 | 79 | ```r 80 | imginterp_task(filenames = list_of_input_images,dates = c(68,77,93,100)) 81 | ``` 82 | 83 | ### File Handling 84 | 85 | All functions in `ImageFusion`operate from disk to disk - Input images are read using [GDAL](https://gdal.org/drivers/raster/index.html) and output images are written into an output directory on disk. Note that the input images must be matching in spatial extent and resolution. We recommend to use [getSpatialData](https://github.com/16EAGLE/getSpatialData) package for automatized data download and the [raster](https://cran.r-project.org/web/packages/raster/index.html) package or [GDAL](https://gdal.org) for the preprocessing. 86 | 87 | ## Performance 88 | 89 | Fusion is expensive and can take a long time for long time series using large images. `ImageFusion` is intended to allow the processing to be done in a reasonable time. The core algorithms are implemented in C++, exposed to R via [Rcpp](http://rcpp.org/). If [OPENMP](https://www.openmp.org/) support is available, it can be used for parallelization. 90 | 91 | ## Outlook 92 | 93 | Additional packages are in development for the preprocessing before the fusion and the visualization and analysis of the fused time series. Check [our website](http://remote-sensing.org/) for latest developments. 94 | -------------------------------------------------------------------------------- /man/imagefusion_task.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/imagefusion_task.R 3 | \name{imagefusion_task} 4 | \alias{imagefusion_task} 5 | \title{Perform time-series image fusion} 6 | \usage{ 7 | imagefusion_task( 8 | ..., 9 | filenames_high, 10 | filenames_low, 11 | dates_high, 12 | dates_low, 13 | dates_pred, 14 | filenames_pred = NULL, 15 | singlepair_mode = "ignore", 16 | method = "starfm", 17 | high_date_prediction_mode = "ignore", 18 | verbose = FALSE, 19 | output_overview = FALSE, 20 | out_dir = NULL 21 | ) 22 | } 23 | \arguments{ 24 | \item{...}{Further arguments specific to the chosen \code{method}. See the documentation of the methods for a detailed description.} 25 | 26 | \item{filenames_high}{A character vector of the filenames of the high resolution input images.} 27 | 28 | \item{filenames_low}{A character vector of the filenames of the low resolution input images.} 29 | 30 | \item{dates_high}{Numeric. An integer vector of the dates associated with the \code{filenames_high}. Must match \code{filenames_high} in length and order.} 31 | 32 | \item{dates_low}{Numeric. An integer vector of the dates associated with the \code{filenames_low}. Must match \code{filenames_low} in length and order.} 33 | 34 | \item{dates_pred}{Numeric. An integer vector dates for which an output should be generated.} 35 | 36 | \item{filenames_pred}{(Optional) A character vector of the filenames for the predicted images. If unspecified, filenames will be created from \code{out_dir} and \code{pred_dates}.} 37 | 38 | \item{singlepair_mode}{(Optional) How should singlepair predictions (those \code{dates_pred}, which do not lie between two dates with a high&low pair) be handled? \itemize{ 39 | \item{ignore: No prediction will be performed for those dates. This is the default.} 40 | \item{mixed: Use doublepair mode where possible, and singlepair mode otherwise (only supported for \code{method} fitfc and starfm)} 41 | \item{all: Predict all dates in singlepair mode, using the closest pair date if between pairs (only supported for \code{method} fitfc and starfm)}}} 42 | 43 | \item{method}{(Optional) The algorithm which is used for the fusion. \itemize{ 44 | \item{starfm: STARFM stands for spatial and temporal adaptive reflectance fusion model. It requires a relatively low amount of computation time for prediction. Supports singlepair and doublepair modes. See \link[ImageFusion]{starfm_job}.} 45 | \item{estarfm: ESTARFM stands for enhanced spatial and temporal adaptive reflectance fusion model so it claims to be an enhanced STARFM. It can yield better results in some situations. Only supports doublepair mode. See \link[ImageFusion]{estarfm_job}.} 46 | \item{fitfc: Fit-FC is a three-step method consisting of regression model fitting (RM fitting), spatial filtering (SF) and residual compensation (RC). It requires a relatively low amount of computation time for prediction. Supports singlepair or a pseudo-doublepair mode(For predictions between two pair dates, predictions will be done twice, once for each of the pair dates). See \link[ImageFusion]{fitfc_job}. This is the default algorithm.} 47 | }} 48 | 49 | \item{high_date_prediction_mode}{(Optional) How to proceed for predictions on those dates which have high resolution images available? \itemize{ 50 | \item{ignore: Output nothing for those dates. This is the default.} 51 | \item{copy: Directly copy the high resolution input images to the output path.} 52 | \item{force: Use the chosen algorithm to predicts the high resolution input images on themselves. This takes additional computation time, but ensures that the outputs are consistent with the genuinely predicted outputs.} 53 | }} 54 | 55 | \item{verbose}{(Optional) Output additional intermediate progress reports? Default is "false".} 56 | 57 | \item{output_overview}{(Optional) Should a summary of the task be printed to console, and a \link[ggplot2]{ggplot} overview be returned? Default is "false".} 58 | 59 | \item{out_dir}{(Optional) A directory in which the predicted images will be saved. Will be created if it does not exist. By default, creates a directory "Outputs" in the R temp directory (see \link{tempdir}).} 60 | } 61 | \value{ 62 | A ggplot overview of the tasks (If \code{output_overview} is "true") 63 | } 64 | \description{ 65 | The main function of the ImageFusion Package, intended for the fusion of images based on a time-series of inputs. 66 | } 67 | \details{ 68 | The function firstly seeks among the inputs for pair dates, which are dates for which have both a high resolution image and a low resolution image are available. It then splits the task into a number of self-contained \emph{jobs} which handle the fusion between these pair dates using the paired images as anchors. These jobs can also be called directly via their respective functions, see \code{method}. 69 | } 70 | \examples{ 71 | # Load required libraries 72 | library(ImageFusion) 73 | library(raster) 74 | # Get filesnames of high resolution images 75 | landsat <- list.files( 76 | system.file("landsat/filled", 77 | package = "ImageFusion"), 78 | ".tif", 79 | recursive = TRUE, 80 | full.names = TRUE 81 | ) 82 | 83 | # Get filesnames of low resolution images 84 | modis <- list.files( 85 | system.file("modis", 86 | package = "ImageFusion"), 87 | ".tif", 88 | recursive = TRUE, 89 | full.names = TRUE 90 | ) 91 | # Create output directory in temporary folder 92 | out_dir <- file.path(tempdir(),"Outputs") 93 | if(!dir.exists(out_dir)) dir.create(out_dir, recursive = TRUE) 94 | # Run the fusion on the entire time series 95 | imagefusion_task(filenames_high = landsat, 96 | dates_high = c(68,77,93,100), 97 | filenames_low = modis, 98 | dates_low = 68:93, 99 | dates_pred = c(65,85,95), 100 | out_dir = out_dir) 101 | # remove the output directory 102 | unlink(out_dir,recursive = TRUE) 103 | 104 | 105 | } 106 | \references{ 107 | Gao, Feng, et al. "On the blending of the Landsat and MODIS surface reflectance: Predicting daily Landsat surface reflectance." IEEE Transactions on Geoscience and Remote sensing 44.8 (2006): 2207-2218. 108 | 109 | Wang, Qunming, and Peter M. Atkinson. "Spatio-temporal fusion for daily Sentinel-2 images." Remote Sensing of Environment 204 (2018): 31-42. 110 | 111 | Zhu, X., Chen, J., Gao, F., Chen, X., & Masek, J. G. (2010). An enhanced spatial and temporal adaptive reflectance fusion model for complex heterogeneous regions. Remote Sensing of Environment, 114(11), 2610-2623. 112 | } 113 | \author{ 114 | Christof Kaufmann (C++), Johannes Mast (R) 115 | } 116 | -------------------------------------------------------------------------------- /src/utils/imginterp/interpolation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../../include/filesystem.h" 8 | #include 9 | 10 | #include "type.h" 11 | #include "imagefusion.h" 12 | #include "image.h" 13 | #include "optionparser.h" 14 | #include "geoinfo.h" 15 | #include "multiresimages.h" 16 | #include "fileformat.h" 17 | 18 | // annonymous namespace is important for test configuration 19 | // all functions are only defined for the corresponding test 20 | namespace { 21 | 22 | struct InterpStats { 23 | std::string filename; 24 | int date; 25 | imagefusion::Size sz; 26 | unsigned int nChans; 27 | unsigned int nNoData; 28 | unsigned int nInterpBefore; 29 | unsigned int nInterpAfter; 30 | }; 31 | 32 | struct Interpolator { 33 | imagefusion::MultiResImages& imgs; 34 | imagefusion::MultiResImages& cloudmask; 35 | imagefusion::MultiResImages& maskimgs; 36 | std::string tag; 37 | int interpDate; 38 | bool doPreferCloudsOverNodata; 39 | 40 | template 41 | std::tuple operator()() const; 42 | }; 43 | 44 | enum class PixelState : uint8_t { 45 | nodata = 0, noninterpolated = 64, interpolated = 192, clear = 128 46 | }; 47 | 48 | template 49 | std::tuple Interpolator::operator()() const { 50 | using imgval_t = typename imagefusion::DataType::base_type; 51 | 52 | const unsigned int h = imgs.getAny().height(); 53 | const unsigned int w = imgs.getAny().width(); 54 | const unsigned int cn = imgs.getAny().channels(); 55 | 56 | imagefusion::Image interped = imgs.get(tag, interpDate); 57 | imagefusion::Image pixelState{interped.size(), imagefusion::getFullType(imagefusion::Type::uint8, interped.channels())}; 58 | pixelState.set(0); 59 | 60 | auto dates = imgs.getDates(tag); 61 | auto interpDateIt = std::find(std::begin(dates), std::end(dates), interpDate); 62 | std::array, 2> leftRightDates; 63 | leftRightDates[0] = std::vector(std::vector::reverse_iterator(interpDateIt), dates.rend()); // left (reversed) 64 | leftRightDates[1] = std::vector(interpDateIt + 1, std::end(dates)); // right 65 | 66 | imagefusion::ConstImage predMask; 67 | unsigned int maskChannels = 0; 68 | if (maskimgs.has(tag, interpDate) && !maskimgs.get(tag, interpDate).empty()) { 69 | predMask = maskimgs.get(tag, interpDate).constSharedCopy(); 70 | maskChannels = (unsigned int)(predMask.channels()); 71 | } 72 | 73 | unsigned int nNoData = 0, nInterpBefore = 0, nInterpAfter = 0; 74 | #pragma omp parallel for reduction(+:nNoData) reduction(+:nInterpBefore) reduction(+:nInterpAfter) 75 | for (unsigned int y = 0; y < h; y++) { 76 | for (unsigned int x = 0; x < w; x++) { 77 | for (unsigned int c = 0; c < cn; c++) { 78 | unsigned int maskChannel = maskChannels > c ? c : 0; 79 | bool isInvalid = maskChannels > 0 && !predMask.boolAt(x, y, maskChannel); 80 | bool isCloud = cloudmask.get(tag, interpDate).boolAt(x, y, 0); 81 | if (isInvalid && (!isCloud || !doPreferCloudsOverNodata)) { 82 | nNoData++; 83 | pixelState.at(x, y, c) = static_cast(PixelState::nodata); 84 | continue; 85 | } 86 | if (!isCloud) { 87 | pixelState.at(x, y, c) = static_cast(PixelState::clear); 88 | continue; 89 | } 90 | // ok, this is a pixel to interpolate 91 | pixelState.at(x, y, c) = static_cast(PixelState::interpolated); 92 | nInterpBefore++; 93 | 94 | std::array leftRightDate = {interpDate, interpDate}; 95 | for (int dir = 0; dir < 2; ++dir) { 96 | for (unsigned int date : leftRightDates.at(dir)) { 97 | if (maskimgs.has(tag, date)) { 98 | auto const& mask = maskimgs.get(tag, date); 99 | unsigned int maskChannel = mask.channels() > c ? c : 0; 100 | if (!mask.empty() && !mask.boolAt(x, y, maskChannel)) 101 | continue; 102 | } 103 | 104 | if (cloudmask.has(tag, date) && cloudmask.get(tag, date).boolAt(x, y, 0)) 105 | continue; 106 | 107 | leftRightDate.at(dir) = date; 108 | break; 109 | } 110 | } 111 | 112 | int dateLeft = leftRightDate.front(); 113 | int dateRight = leftRightDate.back(); 114 | if (dateRight == interpDate) { 115 | // right invalid 116 | if (dateLeft == interpDate) { 117 | // left invalid, too, leave value as it is for now, but mark location 118 | pixelState.at(x, y, c) = static_cast(PixelState::noninterpolated); 119 | nInterpAfter++; 120 | } 121 | else 122 | // only left valid 123 | interped.at(x, y, c) = imgs.get(tag, dateLeft).at(x, y, c); 124 | } 125 | else if (dateLeft == interpDate) 126 | // only right valid 127 | interped.at(x, y, c) = imgs.get(tag, dateRight).at(x, y, c); 128 | else { 129 | // both valid 130 | double yLeft = imgs.get(tag, dateLeft).at(x, y, c); 131 | double yRight = imgs.get(tag, dateRight).at(x, y, c); 132 | double yInt = (interpDate - dateLeft) * (yRight - yLeft) / (dateRight - dateLeft) + yLeft; 133 | interped.at(x, y, c) = cv::saturate_cast(yInt); 134 | } 135 | } /*c*/ 136 | } /*x*/ 137 | } /*y*/ 138 | 139 | InterpStats s{/*filename*/ "", /*date*/ interpDate, /*sz*/ imagefusion::Size(w, h), /*nChans*/ cn, /*nNoData*/ nNoData, /*nInterpBefore*/ nInterpBefore, /*nInterpAfter*/ nInterpAfter}; 140 | return {std::move(interped), std::move(pixelState), s}; 141 | } 142 | } /* annonymous namespace */ 143 | -------------------------------------------------------------------------------- /src/include/fitfc_options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "options.h" 4 | #include "exceptions.h" 5 | 6 | #ifdef _OPENMP 7 | #include 8 | #endif /* _OPENMP*/ 9 | 10 | namespace imagefusion { 11 | 12 | class FitFCOptions : public Options { 13 | public: 14 | 15 | /** 16 | * @brief Set the pair date 17 | * 18 | * @param pairDate of the input image pair. See also 19 | * \ref fitfc_3_image_structure "Fit-FC image structure with three images". 20 | * 21 | * @see getPairDate() 22 | */ 23 | void setPairDate(int pairDate) { 24 | date1 = pairDate; 25 | isDate1Set = true; 26 | } 27 | 28 | /** 29 | * @brief Get the date of the input pair 30 | * @returns the current input pair date. 31 | * @throws runtime_error if it has not been set yet. 32 | * @see setPairDate() 33 | */ 34 | int getPairDate() const { 35 | if (!isDate1Set) 36 | IF_THROW_EXCEPTION(runtime_error("The date of the input pair has not been set yet.")); 37 | return date1; 38 | } 39 | 40 | /** 41 | * @brief Set the window size in which will be searched for similar pixels 42 | * @param size for the search window. Must be an odd number. 43 | * @throws invalid_argument_error if size is even. 44 | * @see getWinSize() 45 | */ 46 | void setWinSize(unsigned int size = 51) { 47 | if (size % 2 == 0) 48 | IF_THROW_EXCEPTION(invalid_argument_error("The window size must be an odd number. You tried " + std::to_string(size))); 49 | winSize = size; 50 | } 51 | 52 | /** 53 | * @brief Get the window size in which is searched for similar pixels 54 | * @see setWinSize() 55 | */ 56 | unsigned int getWinSize() const { 57 | return winSize; 58 | } 59 | 60 | /** 61 | * @brief Get the resolution tag for high resolution 62 | * @return high resolution tag 63 | * @see setHighResTag() 64 | */ 65 | std::string const& getHighResTag() const { 66 | return highTag; 67 | } 68 | 69 | /** 70 | * @brief Set the resolution tag for high resolution 71 | * @param tag new high resolution tag 72 | * 73 | * This tag is used together with the input pair date to get the high resolution images from 74 | * `FitFCFusor::imgs`. 75 | * 76 | * @see getHighResTag(), setLowResTag(), setPairDate(), FitFCFusor::predict() 77 | */ 78 | void setHighResTag(std::string const& tag) { 79 | highTag = tag; 80 | } 81 | 82 | /** 83 | * @brief Get the resolution tag for low resolution 84 | * @return low resolution tag 85 | * @see setLowResTag() 86 | */ 87 | std::string const& getLowResTag() const { 88 | return lowTag; 89 | } 90 | 91 | /** 92 | * @brief Set the resolution tag for low resolution 93 | * @param tag new low resolution tag 94 | * 95 | * This tag is used together with the input pair date and the prediction date to get the low 96 | * resolution images from `FitFCFusor::imgs`. 97 | * 98 | * @see getLowResTag(), setHighResTag(), setPairDate(), FitFCFusor::predict() 99 | */ 100 | void setLowResTag(std::string const& tag) { 101 | lowTag = tag; 102 | } 103 | 104 | /** 105 | * @brief Set the number of neighbors used for correlation 106 | * @param n is the number of near pixels 107 | * 108 | * The pixel locations are selected from the high resolution image only inside the window. The 109 | * central pixel is compared to all pixels in the window over all channels with 110 | * \f[ D(x, y) := \frac 1 2 \sqrt{\sum_{b=1}^{n_b} \left( h_1(x, y, b) - h_1(x_c, y_c, b) \right)^2} 111 | * \quad \forall x, y. \f] 112 | * The `n` best pixels will be selected. Then these locations are used to collect the distance 113 | * weights, the regression model pixels from \f$ \hat F_{\mathrm{RM}} \f$ and the bicubic 114 | * interpolated residuals from \f$ r \f$. 115 | * 116 | * @see getNumberNeighbors() 117 | */ 118 | void setNumberNeighbors(unsigned int n = 10) { 119 | neighbors = n; 120 | } 121 | 122 | /** 123 | * @brief Get the number of neighbors used for correlation 124 | * @return n 125 | * @see setNumberNeighbors() 126 | */ 127 | unsigned int getNumberNeighbors() const { 128 | return neighbors; 129 | } 130 | 131 | 132 | /** 133 | * @brief Set the scale factor from low resolution to high resolution 134 | * @param f is the factor. 135 | * 136 | * Note, the low resolution images and high resolution images must have the same size and 137 | * resolution, when using FitFCFusor. So the low resolution must be upscaled before. FitFCFusor 138 | * will use this factor only to downscale (using averaging) and upscale (using bicubic 139 | * interpolation) the residuals to get a bicubic behavior. To disable this filtering step just 140 | * set the factor to 1. 141 | * 142 | * @see getResolutionFactor() 143 | */ 144 | void setResolutionFactor(double f = 30) { 145 | if (f <= 0) 146 | IF_THROW_EXCEPTION(invalid_argument_error("The Resolution factor must be a positive number. You tried " + std::to_string(f))); 147 | blocksize = f; 148 | } 149 | 150 | /** 151 | * @brief Get the scale factor from low resolution to high resolution 152 | * @return scaling factor. 153 | * @see setResolutionFactor() 154 | */ 155 | double getResolutionFactor() const { 156 | return blocksize; 157 | } 158 | 159 | 160 | #ifdef _OPENMP 161 | /** 162 | * @brief Set the number of threads to use 163 | * 164 | * @param t is the number of threads ≤ number of processors. Choosing it greater than 165 | * [`omp_get_num_procs()`](https://gcc.gnu.org/onlinedocs/libgomp/omp_005fget_005fnum_005fprocs.html) 166 | * will set it to `omp_get_num_procs()`. 167 | * 168 | * By default (on construction) this is set to `omp_get_num_procs()`. 169 | */ 170 | void setNumberThreads(unsigned int t) { 171 | threads = std::min((int)t, std::max(omp_get_num_procs(), 1)); 172 | } 173 | 174 | /** 175 | * @brief Get the number of threads used for parallelization 176 | * @return number of threads 177 | * @see setNumberThreads() 178 | */ 179 | unsigned int getNumberThreads() const { 180 | return threads; 181 | } 182 | #endif /* _OPENMP*/ 183 | 184 | protected: 185 | int date1; 186 | bool isDate1Set = false; 187 | 188 | unsigned int winSize = 51; 189 | std::string highTag; 190 | std::string lowTag; 191 | 192 | unsigned int neighbors = 10; 193 | 194 | double blocksize = 30; 195 | 196 | #ifdef _OPENMP 197 | unsigned int threads = omp_get_num_procs(); 198 | #endif /* _OPENMP*/ 199 | 200 | friend class FitFCFusor; 201 | }; 202 | 203 | } /* namespace imagefusion */ 204 | -------------------------------------------------------------------------------- /man/fitfc_job.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fitfc_job.R 3 | \name{fitfc_job} 4 | \alias{fitfc_job} 5 | \title{Execute a single self-contained self-contained time-series imagefusion job using FITFC} 6 | \usage{ 7 | fitfc_job( 8 | input_filenames, 9 | input_resolutions, 10 | input_dates, 11 | pred_dates, 12 | pred_filenames, 13 | pred_area, 14 | winsize, 15 | date1, 16 | date3, 17 | n_neighbors, 18 | hightag, 19 | lowtag, 20 | MASKIMG_options, 21 | MASKRANGE_options, 22 | output_masks, 23 | use_nodata_value, 24 | resolution_factor, 25 | verbose = TRUE 26 | ) 27 | } 28 | \arguments{ 29 | \item{input_filenames}{A string vector containing the filenames of the input images} 30 | 31 | \item{input_resolutions}{A string vector containing the resolution-tags (corresponding to the arguments \code{hightag} and \code{lowtag}, which are by default "high" and "low") of the input images.} 32 | 33 | \item{input_dates}{An integer vector containing the dates of the input images.} 34 | 35 | \item{pred_dates}{An integer vector containing the dates for which images should be predicted.} 36 | 37 | \item{pred_filenames}{A string vector containing the filenames for the predicted images. Must match \code{pred_dates} in length and order. Must include an extension relating to one of the \href{https://gdal.org/drivers/raster/index.html}{drivers supported by GDAL}, such as ".tif".} 38 | 39 | \item{pred_area}{(Optional) An integer vector containing parameters in image coordinates for a bounding box which specifies the prediction area. The prediction will only be done in this area. (x_min, y_min, width, height). By default will use the entire area of the first input image.} 40 | 41 | \item{winsize}{(Optional) Window size of the rectangle around the current pixel. Default is 51.} 42 | 43 | \item{date1}{(Optional) Set the date of the first input image pair. By default, will use the pair with the lowest date value.} 44 | 45 | \item{date3}{(Optional) For pseudo-doublepair mode: Set the date of the second input image pair. By default, will use the pair with the highest date value.} 46 | 47 | \item{n_neighbors}{(Optional) The number of near pixels (including the center) to use in the filtering step (spatial filtering and residual compensation). Default is 10.} 48 | 49 | \item{hightag}{(Optional) A string which is used in \code{input_resolutions} to describe the high-resolution images. Default is "high".} 50 | 51 | \item{lowtag}{(Optional) A string which is used in \code{input_resolutions} to describe the low-resolution images. Default is "low".} 52 | 53 | \item{MASKIMG_options}{(Optional) A string containing information for a mask image (8-bit, boolean, i. e. consists of 0 and 255). "For all input images the pixel values at the locations where the mask is 0 is replaced by the mean value." Example: \code{--mask-img=some_image.png}} 54 | 55 | \item{MASKRANGE_options}{(Optional) Specify one or more intervals for valid values. Locations with invalid values will be masked out. Ranges should be given in the format \code{'[,]'}, \code{'(,)'}, \code{'[,'}, or \code{',]'}. There are a couple of options:' \itemize{ 56 | \item{"--mask-valid-ranges"}{ Intervals which are marked as valid. Valid ranges can excluded from invalid ranges or vice versa, depending on the order of options.} 57 | \item{"--mask-invalid-ranges"}{ Intervals which are marked as invalid. Invalid intervals can be excluded from valid ranges or vice versa, depending on the order of options.} 58 | \item{"--mask-high-res-valid-ranges"}{ This is the same as --mask-valid-ranges, but is applied only for the high resolution images.} 59 | \item{"--mask-high-res-invalid-ranges"}{ This is the same as --mask-invalid-ranges, but is applied only for the high resolution images.} 60 | \item{"--mask-low-res-valid-ranges"}{ This is the same as --mask-valid-ranges, but is applied only for the low resolution images.} 61 | \item{"--mask-low-res-invalid-ranges"}{ This is the same as --mask-invalid-ranges, but is applied only for the low resolution images.} 62 | }} 63 | 64 | \item{output_masks}{(Optional) Write mask images to disk? Default is "false".} 65 | 66 | \item{use_nodata_value}{(Optional) Use the nodata value as invalid range for masking? Default is "true".} 67 | 68 | \item{resolution_factor}{(Optional) Scale factor with which the low resolution image has been upscaled. This will be used for cubic interpolation of the residuals. Setting it to 1 will disable it. Default: 30.} 69 | 70 | \item{verbose}{(Optional) Print progress updates to console? Default is "true".} 71 | } 72 | \value{ 73 | Nothing. Output files are written to disk. The Geoinformation for the output images is adopted from the first input pair images. 74 | } 75 | \description{ 76 | A wrapper function for \code{execute_fitfc_job_cpp}. Intended to execute a single job, that is a number of predictions based on the same input pair(s). It ensures that all of the arguments passed are of the correct type and creates sensible defaults. 77 | } 78 | \details{ 79 | Executes the FITFC Algorithm. If more than one pair is given, will perform prediction for the pred dates twice, once for each of the input pairs. 80 | } 81 | \examples{ 82 | 83 | # Load required libraries 84 | library(ImageFusion) 85 | library(raster) 86 | # Get filesnames of high resolution images 87 | landsat <- list.files( 88 | system.file("landsat/filled", 89 | package = "ImageFusion"), 90 | ".tif", 91 | recursive = TRUE, 92 | full.names = TRUE 93 | ) 94 | 95 | # Get filesnames of low resolution images 96 | modis <- list.files( 97 | system.file("modis", 98 | package = "ImageFusion"), 99 | ".tif", 100 | recursive = TRUE, 101 | full.names = TRUE 102 | ) 103 | 104 | #Select the first two landsat images 105 | landsat_sel <- landsat[1:2] 106 | #Select some corresponding modis images 107 | modis_sel <- modis[1:12] 108 | # Create output directory in temporary folder 109 | out_dir <- file.path(tempdir(),"Outputs") 110 | if(!dir.exists(out_dir)) dir.create(out_dir, recursive = TRUE) 111 | #Run the job, fusing two images 112 | fitfc_job(input_filenames = c(landsat_sel,modis_sel), 113 | input_resolutions = c("high","high", 114 | "low","low","low", 115 | "low","low","low", 116 | "low","low","low", 117 | "low","low","low"), 118 | input_dates = c(68,77,68,69,70,71,72,73,74,75,76,77,78,79), 119 | pred_dates = c(71,79), 120 | pred_filenames = c(file.path(out_dir,"fitfc_71.tif"), 121 | file.path(out_dir,"fitfc_79.tif")) 122 | ) 123 | # remove the output directory 124 | unlink(out_dir,recursive = TRUE) 125 | } 126 | \references{ 127 | Wang, Qunming, and Peter M. Atkinson. "Spatio-temporal fusion for daily Sentinel-2 images." Remote Sensing of Environment 204 (2018): 31-42. 128 | } 129 | \author{ 130 | Christof Kaufmann (C++) 131 | 132 | Johannes Mast (R) 133 | } 134 | -------------------------------------------------------------------------------- /src/include/proxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "datafusor.h" 4 | 5 | namespace imagefusion { 6 | 7 | 8 | /** 9 | * @brief Meta DataFusor, which acts as Proxy to the real DataFusor 10 | * 11 | * For usage with the Parallelizer a DataFusor must be copy constructible. This might be hard for 12 | * templated DataFusors, which require a factory for construction. Often this can be avoided by 13 | * using a pattern as shown in the documentation of Parallelizer. If it is not possible to make a 14 | * DataFusor copy constructible and parallelization is desired, this Proxy meta DataFusor can be 15 | * used to declare a proxy class that forwards the requests to the real DataFusor. The goal is a 16 | * class that is copy constructible and behaves like the DataFusor that is not. This allows usage 17 | * with the Parallelizer. 18 | * 19 | * The implementation of such a proxy can be done like shown in the following example. There an 20 | * ExampleFusor exists, which requires construction with a compile-time value of the enum @ref Type 21 | * (this is a requirement for the template parameter of this Proxy class). It likes to get the base 22 | * type. Proxy::SimpleFactory can do this. The tricky thing about implementing a 23 | * proxy is to care about the underlying object Proxy::df. This has to be considered when copying 24 | * from a sample. In the copy constructor below this is handled by delegating to the constructor to 25 | * make a new sample, which is saved in Proxy::df. In the copy / move assignment this is handled 26 | * using the Proxy's swap function in the ExampleProxy's swap. A move is optional, but if it is 27 | * specified, Proxy::df can simply be moved. 28 | * @code 29 | * template 30 | * class ExampleFusor; 31 | * 32 | * class ExampleProxy : public Proxy { 33 | * public: 34 | * // used for first construction to make a sample and for copying 35 | * ExampleProxy(Type t) 36 | * : Proxy{SimpleFactory::create(t)}, t{t} 37 | * { } 38 | * 39 | * // used by Parallelizer to make copies 40 | * ExampleProxy(ExampleProxy const& sample) 41 | * : ExampleProxy{sample.t} 42 | * { } 43 | * 44 | * ExampleProxy& operator=(ExampleProxy sample) noexcept { 45 | * swap(*this, sample); 46 | * return *this; 47 | * } 48 | * 49 | * friend void swap(ExampleProxy& first, ExampleProxy& second) noexcept { 50 | * using std::swap; 51 | * // call Proxy's swap to swap df, very important! 52 | * swap(static_cast&>(first), static_cast&>(second)); 53 | * swap(first.t, second.t); 54 | * } 55 | * 56 | * // move is not required, but nice to have 57 | * ExampleProxy(ExampleProxy&& sample) noexcept 58 | * : Proxy{std::move(sample.df)}, t{sample.t} 59 | * { } 60 | * 61 | * using options_type = ExampleFusor::options_type; 62 | * 63 | * private: 64 | * Type t; 65 | * }; 66 | * @endcode 67 | */ 68 | template