Commit 8e07c77a authored by Commandre Benjamin's avatar Commandre Benjamin
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request benjamin.commandre/sentinel-3a!3
1 merge request!3Develop
Showing with 325 additions and 471 deletions
+325 -471
This diff is collapsed.
#!/bin/env python3 #!/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys
import argparse import argparse
import logging import logging
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
...@@ -9,6 +10,10 @@ from contextlib import contextmanager ...@@ -9,6 +10,10 @@ from contextlib import contextmanager
import inspect import inspect
from osgeo import gdal from osgeo import gdal
import app.Constantes as Constantes import app.Constantes as Constantes
import configparser
import ast
from datetime import datetime
import app.Satellites as Satellites
class Fusion(argparse.Action): class Fusion(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs): def __init__(self, option_strings, dest, nargs=None, **kwargs):
...@@ -77,25 +82,25 @@ class TimeoutException(Exception): pass ...@@ -77,25 +82,25 @@ class TimeoutException(Exception): pass
@contextmanager @contextmanager
def limitation_temporelle(secondes): def limitation_temporelle(secondes):
def signal_handler(signum, frame):
raise TimeoutException
signal.signal(signal.SIGALRM, signal_handler) def signal_handler(signum, frame):
signal.alarm(secondes) raise TimeoutException
try: signal.signal(signal.SIGALRM, signal_handler)
yield signal.alarm(secondes)
finally:
signal.alarm(0) try:
yield
finally:
signal.alarm(0)
# Utilisation : # Utilisation :
# #
# try: # try:
# with limitation_temporelle(temps_en_seconde): # with limitation_temporelle(temps_en_seconde):
# appel_fonction() # appel_fonction()
# except TimeoutException: # except TimeoutException:
# pass # pass
def clip(image, cut, form="Mem", dst="", type_sortie=gdal.GDT_Float32, nodata="NaN"): def clip(image, cut, form="Mem", dst="", type_sortie=gdal.GDT_Float32, nodata="NaN"):
""" """
...@@ -118,4 +123,126 @@ def clip(image, cut, form="Mem", dst="", type_sortie=gdal.GDT_Float32, nodata="N ...@@ -118,4 +123,126 @@ def clip(image, cut, form="Mem", dst="", type_sortie=gdal.GDT_Float32, nodata="N
option_clip = gdal.WarpOptions(cropToCutline=True,\ option_clip = gdal.WarpOptions(cropToCutline=True,\
cutlineDSName=cut, outputType=type_sortie , format=form, dstNodata=nodata) cutlineDSName=cut, outputType=type_sortie , format=form, dstNodata=nodata)
return gdal.Warp(dst, image, options=option_clip) return gdal.Warp(dst, image, options=option_clip)
\ No newline at end of file
def str2bool(v):
return v.lower() in (["false"])
def checkDate(date):
d = date.split('-')
try:
if not date :
annee = datetime.now().year
if datetime.now().month < 10 :
mois = "0{}".format(datetime.now().month)
else :
mois = datetime.now().month
if datetime.now().day < 10 :
jour = "0{}".format(datetime.now().day)
else :
jour = datetime.now().day
elif len(d) == 1 :
annee = d[0]
mois = "01"
jour = "01"
elif len(d) == 2 :
annee = d[0]
mois = d[1]
jour = "01"
elif len(d) == 3 :
annee = d[0]
mois = d[1]
jour = d[2]
datetime(int(annee), int(mois), int(jour))
return "{annee}-{mois}-{jour}".format(annee=annee, mois=mois, jour=jour)
except ValueError:
print("Format invalide")
sys.exit(1)
except IndexError:
print("La date doit être au format 'AAAA-MM-JJ', 'AAAA-MM' ou 'AAAA'")
sys.exit(1)
def get_variable(self, config):
"""
Récupération des variables dans le fichier de configuration
"""
configfile = configparser.ConfigParser()
configfile.read(config)
self.requete = dict()
self.requete["lang"] = "fr"
self.requete["_pretty"] = "true"
self.requete["maxRecord"] = 500
# Capteur utilisé
self.capteur = configfile["satellite"]["capteur"]
self.bandes = configfile["satellite"]["bandes"]
self.requete["processingLevel"] = configfile["satellite"]["processingLevel"]
# Dossier contenant les résultats
self.dossier_sortie = configfile["sortie"]["chemin"]
try:
if str2bool(configfile["sortie"]["extraction"]):
self.extraction = False
else :
self.extraction = True
except :
self.extraction = True
self.groupe = configfile["sortie"]["groupe"]
# Date de début et de fin de la recherche
try:
# self.date_debut = configfile["donnees"]["date_debut"]
self.requete["startDate"] = checkDate(configfile["donnees"]["date_debut"])
except Exception as e:
raise "L'année de départ est requise."
self.requete["completionDate"] = checkDate(configfile["donnees"]["date_fin"])
self.seuil_nuage = float(configfile["donnees"]["seuil_nuage"])/100.0 if configfile["donnees"]["seuil_nuage"] else 0.0
# Emprise et zone de l'étude
self.emprise = configfile["donnees"]["chemin_emprise"]
if self.emprise :
self.zone_etude = configfile["donnees"]["chemin_zone_etude"]
if not self.zone_etude :
self.zone_etude = self.emprise
else :
try:
self.liste_tuiles = list(ast.literal_eval(configfile["donnees"]["liste_tuiles"]))
except Exception as e:
raise "Aucune emprise ni aucune tuile n'a été renseigné."
self.nombre_image = configfile["donnees"]["nombre_image"]
# Identifiant, mot de passe et proxy pour le téléchargement des images Théia
self.id = configfile["theia"]["identifiant"]
self.mdp = configfile["theia"]["mdp"]
self.proxy = configfile["theia"]["proxy"]
if self.bandes == "RGB" :
self.extent_img = Satellites.SATELLITE[self.capteur][self.requete["processingLevel"]][:-1]
else :
self.extent_img = Satellites.SATELLITE[self.capteur][self.requete["processingLevel"]]
if self.requete["processingLevel"] == "LEVEL2A" :
self.nuage = Satellites.SATELLITE[self.capteur]["NUAGE"]
else :
self.nuage = None
self.serveur = Satellites.SATELLITE[self.capteur]["serveur"]
self.resto = Satellites.SATELLITE[self.capteur]["resto"]
self.token_type = Satellites.SATELLITE[self.capteur]["token_type"]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import configparser
import datetime
import glob
from osgeo import gdal
import otbApplication as otb
from app import Archive
def str2bool(v):
return v.lower() in ("true")
class Processing(object):
def __init__(self):
pass
def i_download(self):
"""
Méthode pour télécharger les images sur le site Theia Land.
"""
if not self.annee_fin :
self.annee_fin = datetime.datetime.now().year
self.check_download = Archive.Archive(self.capteur, self.bandes, self.niveau, self.emprise, self.zone_etude,\
self.resultats, self.annee_debut, int(self.annee_fin), self.seuil_nuage)
self.check_download.listing()
self.check_download.download_auto(self.id, self.mdp, self.proxy, extraction=self.extraction, groupe=self.groupe)
self.liste_dossier = dict()
for annee in os.listdir(self.resultats):
with open("{}/{}/dates.txt".format(self.resultats, annee), "w") as fichier :
for image in sorted(glob.glob("{}/{}/Images/*".format(self.resultats, annee))) :
fichier.write("{}\n".format(os.path.basename(image)[:-4]))
self.liste_dossier[annee] = sorted([x for x in glob.glob("{}/{}/Images/*".format(self.resultats, annee)) if x.endswith(".tif")])
def otbPhenologie(self):
"""
Appel le module OTB : 'SigmoFitting' sur l'image composée de l'empilement des NDVI
"""
otb_Phenologie = otb.Registry.CreateApplication("SigmoFitting")
otb_Phenologie.SetParameterString("mode", "metrics")
for annee in self.liste_dossier :
otb_Phenologie.SetParameterString("in", "{}/{}/NDVI/stack_ndvi.tif".format(self.resultats, annee))
otb_Phenologie.SetParameterString("dates", "{}/{}/dates.txt".format(self.resultats, annee))
otb_Phenologie.SetParameterString("out", "{}/{}/metrics.tif".format(self.resultats, annee))
otb_Phenologie.ExecuteAndWriteOutput()
def calcul_ndvi(self):
"""
Méthode effectuant le calcul du NDVI via le module OTB : 'RadiometricIndices'
"""
options_vrt = gdal.ParseCommandLine('-resolution highest -separate')
otb_NDVI = otb.Registry.CreateApplication("RadiometricIndices")
otb_NDVI.SetParameterInt("channels.blue", 1)
otb_NDVI.SetParameterInt("channels.green", 2)
otb_NDVI.SetParameterInt("channels.red", 3)
otb_NDVI.SetParameterInt("channels.nir", 4)
otb_NDVI.SetParameterStringList("list", ["Vegetation:NDVI"])
sauvegarde = configparser.ConfigParser()
for annee in self.liste_dossier :
sauvegarde.read("{}/{}/sauvegarde.ini".format(self.resultats, annee))
dossier_NDVI = "{}/{}/NDVI".format(self.resultats, annee)
if not os.path.exists(dossier_NDVI) :
os.makedirs(dossier_NDVI)
for img in self.liste_dossier[annee] :
chemin_ndvi = "{}/ndvi_{}".format(dossier_NDVI, os.path.basename(img))
if not str2bool(sauvegarde[os.path.basename(img)[:-4]]["NDVI"]):
otb_NDVI.SetParameterString("in", img)
otb_NDVI.SetParameterString("out", chemin_ndvi)
otb_NDVI.ExecuteAndWriteOutput()
sauvegarde[os.path.basename(img)[:-4]]["NDVI"] = "True"
liste_ndvi = sorted([x for x in glob.glob("{}/*".format(dossier_NDVI)) if x.endswith(".tif") and "stack" not in x])
vrt = gdal.BuildVRT("", liste_ndvi, options=options_vrt)
gdal.Translate("{}/{}/NDVI/stack_ndvi.tif".format(self.resultats, annee), vrt)
with open("{}/{}/sauvegarde.ini".format(self.resultats, annee), 'w') as configfile:
sauvegarde.write(configfile)
def i_images_processing(self):
"""
Calul le ndvi, fusionnne en une seule image puis lance le module OTBPhenology
"""
self.calcul_ndvi()
self.otbPhenologie()
...@@ -6,27 +6,38 @@ chemin_emprise = ...@@ -6,27 +6,38 @@ chemin_emprise =
# Si vide, zone d'étude = emprise # Si vide, zone d'étude = emprise
chemin_zone_etude = chemin_zone_etude =
# Année à partir de laquelle les images ont été prises # Liste des tuiles Sentinel2 à télécharger
annee_debut = # Si une emprise est spécifiée, celle-ci est privilégié
# Ex : ["T30ABC", "T31ABC", "T30DEF"]
liste_tuiles =
# Année limite d'acquisition des images # Nombre d'images à télécharger par tuile
# Si vide, l'année de fin correspond à l'année actuelle # Si vide, télécharge toutes les images disponibles
annee_fin = nombre_image =
# Date à partir de laquelle les images ont été prises
# La date doit être au format AAAA-MM-JJ, AAAA-MM ou AAAA
date_debut =
# Date limite d'acquisition des images
# La date doit être au format AAAA-MM-JJ, AAAA-MM ou AAAA
# Si vide, la date de fin correspond au jour actuel
date_fin =
# Pourcentage maximal d'ennuagement # Pourcentage maximal d'ennuagement
seuil_nuage = 5.0 seuil_nuage = 5.0
[sortie] [sortie]
# chemin/dossier/resultats # chemin/dossier/resultats
chemin = chemin =
# Manière de regrouper les images/archives # Manière de regrouper les images/archives
# Possibilités :- Date (Regroupe les images selon leurs date d'acquisition) # Possibilités :- Date (Regroupe les images selon leurs date d'acquisition)
# - Tuile (Regroupe les images en fonction de la tuile sentinel2 auquelle elles correspondent ) # - Tuile (Regroupe les images en fonction de la tuile sentinel2 auquelle elles correspondent )
groupe = Date groupe = Tuile
# Vrai si extraction des images des archives, faux si téléchagement de celles-ci # Vrai si extraction des images des archives, faux si téléchagement de celles-ci
extraction = True extraction = False
[theia] [theia]
# Identifiant Theia-land # Identifiant Theia-land
...@@ -47,7 +58,7 @@ capteur = SENTINEL2 ...@@ -47,7 +58,7 @@ capteur = SENTINEL2
# Niveau de traitement des images satellites # Niveau de traitement des images satellites
# Possibilités :- LEVEL2A (Acquisition standard) # Possibilités :- LEVEL2A (Acquisition standard)
# - LEVEL3A (Synthèse mensuelle) # - LEVEL3A (Synthèse mensuelle)
processingLevel= LEVEL2A processingLevel= LEVEL3A
# Bandes d'intêrets # Bandes d'intêrets
# Possibilités :- RGB (Bandes Rouge, Verte, Bleue) # Possibilités :- RGB (Bandes Rouge, Verte, Bleue)
......
#!/bin/bash
# =========================================
# Script d'installation
# =========================================
function erreur {
echo "Usage : $0 [--libs --maj --compil --all]"
echo "--libs : Installation des bibliothèques python"
echo "--maj : Téléchargement des fichiers sources pour OTB"
echo "--compil : Compilation d'OTB"
echo "--all : Téléchargement des sources et des bibliothèques python puis compilation d'OTB"
exit
}
function confirme {
read -r -p "${1}Êtes-vous sûr de vouloir continuer ? [O/N] " response
if [[ $response == "o" || $response = "O" || $response == "y" || $response = "Y" ]]; then
echo -e "${ROUGE}\e[1mLauching generation in $prefix_dir\e[0m"
else
exit
fi
}
set -e
#Couleur 'Rouge' pour le terminal
ROUGE='\033[0;31m'
# Dossier courant du script
CMD="$(readlink -e "${BASH_SOURCE[0]}")"
SH_DIR="$(dirname "$CMD")"
prefix_dir=$SH_DIR
if [ ! -z $CXX ]; then
echo "Version du compilateur : $CXX"
else
CXX=`type -p g++`
fi
CXXVersion=`${CXX} -dumpversion`
version_compilateur="5.0.0"
if [ "$(printf '%s\n' "$version_compilateur" "$CXXVersion" | sort -V | head -n1)" = "$CXXVersion" ]; then
echo "Gcc version too old"
echo "Actual: ${CXXVersion}"
echo "Needed: ${version_compilateur}"
exit
fi
# Erreur si manque ou mauvais argument
if [[ "$#" != "1" ]]; then
erreur
fi
if [[ "$1" != "--libs" ]] && [[ "$1" != "--maj" ]] && [[ "$1" != "--compil" ]] && [[ "$1" != "--all" ]]; then
erreur
fi
if [[ "$1" == "--libs" ]]; then
echo "Installation des bibliothèques python3"
sudo apt-get update
sudo apt-get install aptitude -y
sudo aptitude install python3-pip -y
sudo pip3 install -r "dépendances.txt"
fi
echo $prefix_dir/OTB
if [[ "$1" != "--libs" ]]; then
echo "Installation de la bibliothèque OTB dans : ${prefix_dir}"
confirme
#----------------------------------------
# Récupération des sources
if [[ "$1" == "--maj" ]] || [[ "$1" == "--all" ]]; then
# Clonage du repertoire OTB
if [ -d "OTB" ]; then
echo "Le répertoire OTB existe déjà."
else
echo "Clonage OTB ..."
mkdir -p $prefix_dir/OTB
cd $prefix_dir/OTB
git clone https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb.git
fi
fi
#----------------------------------------
# Compilation
if [[ "$1" != "--compil" ]] || [[ "$1" == "--all" ]] ; then
sudo aptitude install make cmake-curses-gui build-essential libtool automake git libbz2-dev python-dev libboost-dev libboost-filesystem-dev libboost-serialization-dev libboost-system-dev zlib1g-dev libcurl4-gnutls-dev swig libgdal-dev
echo "Compilation d'OTB ..."
cd $prefix_dir/
mkdir -p build
mkdir -p build
cd build
# Compilation d'OTB
cmake -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_CXX_FLAGS:STRING=-std=c++14 -DUSE_SYSTEM_BOOST=ON -DUSE_SYSTEM_CURL=ON -DUSE_SYSTEM_ZLIB=ON -DUSE_SYSTEM_GDAL=ON -DCMAKE_BUILD_TYPE=Release -DOTB_WRAP_PYTHON3:BOOL=ON -DGDAL_SB_EXTRA_OPTIONS:STRING="--with-python" -DCMAKE_INSTALL_PREFIX=$prefix_dir/OTB/install/ -DOTB_USE_QWT=OFF -DOTB_USE_GLEW=OFF -DOTB_USE_GLFW=OFF -DOTB_USE_GLUT=OFF -DOTB_USE_OPENGL=OFF -DOTB_USE_QT=OFF -DOTB_USE_QWT=OFF $prefix_dir/OTB/otb/SuperBuild/
make --jobs=12
# Compilation des modules
cd $prefix_dir/OTB/build/OTB/build
cmake -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_CXX_FLAGS:STRING=-std=c++14 -DModule_OTBPhenology:BOOL=ON -DModule_OTBTemporalGapFilling:BOOL=ON $prefix_dir/OTB/otb
make --jobs=12
make install
fi
echo "Installation terminée."
fi
...@@ -2,73 +2,21 @@ ...@@ -2,73 +2,21 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys, time import sys, time
from osgeo import ogr
import configparser import configparser
from app.Processing import Processing import argparse
import app.Constantes as Constantes
import app.Outils as Outils
def str2bool(v):
return v.lower() in (["false"])
class Telechargement(Processing):
def __init__(self, parent=None): from app.Archive import Archive
super(Processing, self).__init__() import app.Constantes as Constantes
Processing.__init__(self)
self.logger = Outils.Log("log", "Téléchargement")
self.get_variable()
def get_variable(self):
"""
Récupération des variables dans le fichier de configuration
"""
configfile = configparser.ConfigParser()
configfile.read("config.ini")
# Capteur utilisé
self.capteur = configfile["satellite"]["capteur"]
self.niveau = configfile["satellite"]["processingLevel"]
self.bandes = configfile["satellite"]["bandes"]
# Dossier contenant les résultats
self.resultats = configfile["sortie"]["chemin"]
try:
if str2bool(configfile["sortie"]["extraction"]):
self.extraction = False
else :
self.extraction = True
except :
self.extraction = True
self.groupe = configfile["sortie"]["groupe"]
# Date de début et de fin de la recherche
try:
self.annee_debut = int(configfile["donnees"]["annee_debut"])
except Exception as e:
raise "L'année de départ est requise."
self.annee_fin = configfile["donnees"]["annee_fin"] from app.Outils import Log
self.seuil_nuage = float(configfile["donnees"]["seuil_nuage"])/100.0 if configfile["donnees"]["seuil_nuage"] else 0.0
# Emprise et zone de l'étude class Telechargement(object):
self.emprise = configfile["donnees"]["chemin_emprise"]
self.zone_etude = configfile["donnees"]["chemin_zone_etude"]
if not self.zone_etude : def __init__(self, config):
self.zone_etude = self.emprise super(Telechargement, self).__init__()
# Identifiant, mot de passe et proxy pour le téléchargement des images Théia self.logger = Log("log", "Téléchargement")
self.id = configfile["theia"]["identifiant"] self.config = config
self.mdp = configfile["theia"]["mdp"]
self.proxy = configfile["theia"]["proxy"]
def run(self): def run(self):
""" """
...@@ -77,11 +25,9 @@ class Telechargement(Processing): ...@@ -77,11 +25,9 @@ class Telechargement(Processing):
# Début du processus # Début du processus
debut = time.time() debut = time.time()
# Recherche de nouvelles images non traitées et téléchargement de celles-ci le cas échéant prog = Archive(self.config)
self.i_download() prog.listing()
prog.download_auto()
# Traitement des images
self.i_images_processing()
# Fin du processus # Fin du processus
fin = time.time() fin = time.time()
...@@ -92,5 +38,9 @@ class Telechargement(Processing): ...@@ -92,5 +38,9 @@ class Telechargement(Processing):
if __name__ == "__main__": if __name__ == "__main__":
app = Telechargement() parser = argparse.ArgumentParser()
parser.add_argument("-config", dest="config", help="Chemin du fichier de config", required=True)
args = parser.parse_args()
app = Telechargement(args.config)
sys.exit(app.run()) sys.exit(app.run())
#!/bin/bash
# Dossier courant du script.
CMD="$(readlink -e "${BASH_SOURCE[0]}")"
SH_DIR="$(dirname "$CMD")"
prefix_dir=$SH_DIR
export PATH=$PATH:$prefix_dir/OTB/install/bin
export PYTHONPATH=$prefix_dir/OTB/install/lib/otb/python3
export ITK_AUTOLOAD_PATH=$prefix_dir/OTB/install/lib/otb/applications
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment