moringa.py 13.5 KB
Newer Older
import sys
import argparse
from Common.timetools import periodic_date_generator
Gaetano Raffaele's avatar
Gaetano Raffaele committed
from Workflows.basic import basic
from Workflows.operations import *
def main(args):
    parser = argparse.ArgumentParser(prog="moringa", add_help=False)
    subpar = parser.add_subparsers(dest="cmd")

    prepr = subpar.add_parser("preprocess_s2", help="Performs Moringa preset time series preprocessing for Sentinel-2.",
                              formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    prepr.add_argument("in_folder", type=str, help="Path to the folder containing (de-zipped) S2 images.")
    prepr.add_argument("out_folder", type=str, help="Path to the folder in which preprocessed stacks will be stored.")
Gaetano Raffaele's avatar
Gaetano Raffaele committed
    prepr.add_argument("--output_dates_file", type=str, default=None, help="Path to the text file containing output dates for temporal interpolation.")
    prepr.add_argument("--roi", type=str, default=None, help="Path to the ROI vector file.")
    prepr.add_argument("--align_to", type=str, default=None, help="Optional strategy for S2 spatial alignment (self/<date>/path to reference image).")
    prepr.add_argument("--align_to_band", type=int, default=3, help="Band of reference image used for co-registration.")
    prepr.add_argument("--align_using_band", type=int, default=3, help="Band of current stack used for co-registration.")
    prepr.add_argument("--provider", type=str, default='theia', help="S2 image provider. Currently supported: 'theia', 'planetary'")

    segmt = subpar.add_parser("segment", help="Performs (large scale Baatz-Shape) segmentation of an input image.",
                              formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    segmt.add_argument("img", type=str, help="Path to the image to segment.")
    segmt.add_argument("threshold", type=float, help="Threshold for the heterogeneity criterion in Baatz-Shape.")
    segmt.add_argument("outimg", type=str, help="Path to the output segmentation file (.tif, .shp, .gpkg, .gml).")
    segmt.add_argument("--cw", type=float, default=0.5, help="Color weight in Baatz-Shape criterion.")
    segmt.add_argument("--sw", type=float, default=0.5, help="Spatial weight in Baatz-Shape criterion.")
    segmt.add_argument("--n_first_iter", type=int, default=12, help="Number of iterations for parallel tile processing (no use in light mode).")
    segmt.add_argument("--tile_margin", type=int, default=100, help="Margin for tile overlap.")
    segmt.add_argument("--roi", type=str, default=None, help="Vector file containing an ROI.")
    segmt.add_argument("--n_proc", type=int, help="Number of cores to use.")
    segmt.add_argument("--mem_limit", type=int, help="Memory limit in MB.")
    segmt.add_argument("--use_light_alg", help="Use the sub-obtimal version of the algorithm. Faster but may have artefacts.", action='store_true')
    segmt.add_argument("--keep_graph", help="Keep the graph files (.bin) after segmentation.", action='store_true')
Gaetano Raffaele's avatar
Gaetano Raffaele committed
    segmt.add_argument("--force_parallel", help="Force the spot6/7 preprocess one-liner parallelization of the process even if the full graph fits in memory.", action='store_true')
    vhrprep = subpar.add_parser("preprocess_spot67", help="Perform baseline pre-processing of a SPOT6/7 scene in raster sensor.",
                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    vhrprep.add_argument("fld", type=str, help="Path to the root folder containing PAN and MS subfolders.")
    vhrprep.add_argument("out_fld", type=str, help="Path to the output folder for preprocessed images.")
    vhrprep.add_argument("dem_fld", type=str, help="Path to the folder containing DEM covering the scene in WGS84 projection.")
    vhrprep.add_argument("geoid", type=str, help="Path to the geoid file.")
    vhrprep.add_argument("--clip", type=str, default=None, help="Path to a vector file for clipping.")
    vhrprep.add_argument("--align_to", type=str, default=None, help="Path to a reference image to which the image must be aligned (rigid).")
    vhrprep.add_argument("--align_to_band", type=int, default=3, help="Band of reference image used for alignment.")
    vhrprep.add_argument("--align_using_band", type=int, default=1, help="Band of current image used for alignment.")
    vhrprep.add_argument("--skip_ps", help="Skip pansharpening step.", action='store_true')
    vhrprep.add_argument("--compress", help="Use lossless compression on outputs.", action='store_true')
    plprep = subpar.add_parser("preprocess_pleiades", help="Perform baseline pre-processing of a Pleaides ortho scene.",
                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    plprep.add_argument("fld", type=str, help="Path to the root folder containing PAN and MS subfolders.")
    plprep.add_argument("out_fld", type=str, help="Path to the output folder for preprocessed images.")
    plprep.add_argument("--clip", type=str, default=None, help="Path to a vector file for clipping.")
    plprep.add_argument("--align_to", type=str, default=None, help="Path to a reference image to which the image must be aligned (rigid).")
    plprep.add_argument("--align_to_band", type=int, default=3, help="Band of reference image used for alignment.")
    plprep.add_argument("--align_using_band", type=int, default=1, help="Band of current image used for alignment.")
    plprep.add_argument("--skip_ps", help="Skip pansharpening step.", action='store_true')
    plprep.add_argument("--compress", help="Use lossless compression on outputs.", action='store_true')

    plmprep = subpar.add_parser("preprocess_pleiades_mosaic", help="Perform baseline pre-processing and auto-mosaic of Pleaides ortho scenes.",
                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    plmprep.add_argument("fld", type=str, help="Path to the root folder containing Pleaides acquisitions.")
    plmprep.add_argument("pattern", type=str, help="File pattern to collect scene folders within in_fld.")
    plmprep.add_argument("out_fld", type=str, help="Path to the output folder for preprocessed images.")

    s1prepr = subpar.add_parser("preprocess_s1", help="Performs Moringa preset time series preprocessing for Sentinel-1.",
                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    s1prepr.add_argument("in_folder", type=str, help="Path to the folder containing (de-zipped) S1 images.")
    s1prepr.add_argument("roi", type=str, default=None, help="Path to an image whose geometry has to be fit (e.g. a S2 scene).")
    s1prepr.add_argument("out_folder", type=str, help="Path to the folder in which preprocessed stacks will be stored.")
    s1prepr.add_argument("--dem_fld", type=str, default=None, help="Path to the folder containing DEM covering the scene in WGS84 projection.")
    s1prepr.add_argument("--geoid", type=str, default=None, help="Path to the geoid file.")
    s1prepr.add_argument("--direction", type=str, default=None, help="Filter direction (ascending/descending)")
    s1prepr.add_argument("--satellite", type=str, default=None, help="Filter satellite (s1a/s1b)")
    s1prepr.add_argument("--skip_despeckle", help="Skip despeckling step", action='store_true')
    s1prepr.add_argument("--provider", type=str, default='native',
                         help="S1 image provider. Currently supported: 'native' (e.g. esa/peps), 'planetary'")
    planet_pr = subpar.add_parser("preprocess_planet", help="Performs Moringa preset time series preprocessing for Planet Mosaics (NICFI).",
                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    planet_pr.add_argument("in_folder", type=str, help="Path to the folder containing images (using Moringa's fetch command).")
    planet_pr.add_argument("out_folder", type=str, help="Path to the folder in which preprocessed stacks will be stored.")

    fetchp = subpar.add_parser("fetch", help="Query and download products from the imagery-specific providers.",
                              formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    fetchp.add_argument("imagery", type=str, help="Name of the images to fetch. "
                        "Supported: s2theia, s2planetary, s1grd, s1rtc, planetmosaics, nasadem, cop-dem-glo-30, landsatplanetary.")
    fetchp.add_argument("roi", type=str, help="Path to a vector GIS file whose extent will be used for spatial query.")
    fetchp.add_argument("out_folder", type=str, help="Output folder where fetched data will be downloaded.")
    fetchp.add_argument("--date_range", type=str, help="Date query in the YYYY-MM-DD/YYYY-MM-DD format.")
    fetchp.add_argument("--auth", type=str, default=None, help="Authentication information (credentials file, API key, etc.)")
    fetchp.add_argument("--only_tiles", type=str, default=None, help="Colon separated list of tiles to download (where applicable).")
Gaetano Raffaele's avatar
Gaetano Raffaele committed
    chain = subpar.add_parser("launch_chain", help="Launch a Moringa workflow using a JSON config file.",
                             formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    chain.add_argument("config_file", type=str, help="Path to the MORINGA JSON config file.")
    chain.add_argument("--workflow", type=str, default='basic', help="Workflow choice (only 'basic' implemented).")
    chain.add_argument("--runlevel", type=int, default=1, help="Starting step of the chain to process.")
    chain.add_argument("--single_step", action="store_true", help="Stop after a single step is processed.")

    dategen = subpar.add_parser("gen_date_file", help="Generate an output date file for classic gapfilling.",
                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    dategen.add_argument("output_file", type=str, help="Path to the output date file.")
    dategen.add_argument("start_date", type=str, help="Start date in YYYY-MM-DD format.")
    dategen.add_argument("end_date", type=str, help="End date in YYYY-MM-DD format.")
    dategen.add_argument("step", type=int, help="Number of days between two dates.")

    applyshift = subpar.add_parser("apply_shift", help="Apply a rigid geotransform shift using a set of tie points.",
                                   formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    applyshift.add_argument("input_image", type=str, help="Path to the input image. Shift is applied in-place.")
    applyshift.add_argument("input_points", type=str, help="Path to the tie points file (x_img,y_img,x_ref,y_ref)")

    basemap = subpar.add_parser("create_basemap", help="Generate a browsing optimized version of an image.",
                                   formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    basemap.add_argument("input_image", type=str, help="Path to the input image.")
    basemap.add_argument("output_image", type=str, help="Path to the tie points file (x_img,y_img,x_ref,y_ref)")
    basemap.add_argument("--low_quantile", type=int, default=2, help="Low quantile for dynamic conversion.")
    basemap.add_argument("--high_quantile", type=int, default=2, help="High quantile for dynamic conversion.")
    basemap.add_argument("--red", type=int, default=1, help="Band for red channel.")
    basemap.add_argument("--green", type=int, default=2, help="Band for green channel.")
    basemap.add_argument("--blue", type=int, default=3, help="Band for blue channel.")
    basemap.add_argument("--quality", type=int, default=75, help="Quality (0-100) for jpeg conversion.")


    if len(args) == 1:
        parser.print_help()
        sys.exit(0)

    arg = parser.parse_args()

    if arg.cmd == "preprocess_s2":
        preprocess_s2(arg.in_folder, arg.out_folder, output_dates_file=arg.output_dates_file, roi=arg.roi,
                      align_to=arg.align_to, align_to_band=arg.align_to_band, align_using_band=arg.align_using_band,
                      provider=arg.provider)

    if arg.cmd == "segment":
        run_segmentation(arg.img, arg.threshold, arg.cw, arg.sw, arg.outimg, arg.n_first_iter, arg.tile_margin,
                         arg.roi, arg.n_proc, arg.mem_limit, not arg.keep_graph, arg.force_parallel, arg.use_light_alg)
    if arg.cmd == "preprocess_spot67":
        preprocess_spot67(arg.fld, arg.out_fld, arg.dem_fld, arg.geoid, arg.skip_ps, arg.compress,
                          arg.clip, arg.align_to, arg.align_to_band, arg.align_using_band)
    
    if arg.cmd == "preprocess_pleiades":
        preprocess_pleiades(arg.fld, arg.out_fld, arg.skip_ps, arg.compress, arg.clip, 
                          arg.align_to, arg.align_to_band, arg.align_using_band)
        
    if arg.cmd == "preprocess_pleiades_mosaic":
        preprocess_pleiades_mosaic(arg.fld, arg.out_fld, arg.pattern)
    if arg.cmd == "preprocess_s1":
        preprocess_s1(arg.in_folder, arg.roi, arg.out_folder, arg.dem_fld, arg.geoid, arg.direction, arg.satellite,
    if arg.cmd == "preprocess_planet":
        preprocess_planet(arg.in_folder, arg.out_folder)

    if arg.cmd == "fetch":
        fetch(arg.imagery, arg.roi, arg.out_folder, arg.date_range, arg.auth, arg.only_tiles)
Gaetano Raffaele's avatar
Gaetano Raffaele committed
    if arg.cmd == "launch_chain":
        if arg.workflow == 'basic':
            basic(arg.config_file, arg.runlevel, arg.single_step)
        else:
            raise ValueError('Workflow not implemented.')

    if arg.cmd == "gen_date_file":
        periodic_date_generator(arg.output_file, arg.start_date, arg.end_date, arg.step)
    
    if arg.cmd == "apply_shift":
        apply_shift(arg.input_image, arg.input_points)

    if arg.cmd == "create_basemap":
        create_basemap(arg.input_image, arg.output_image, quantiles=[arg.low_quantile, arg.high_quantile],
                       bands=[arg.red,arg.green,arg.blue], quality=arg.quality)
    return 0

if __name__ == "__main__":
    main(sys.argv)