diff --git a/Common/geometry.py b/Common/geometry.py index 6d7397e9f97bd59ceb38ec0dc5de8b6abacf0f6d..235b30ed8b5ef60d0855417fac3c6943b807accd 100644 --- a/Common/geometry.py +++ b/Common/geometry.py @@ -1,3 +1,4 @@ +import os import sys import numpy as np @@ -10,6 +11,8 @@ from typing import List from tqdm import tqdm from datetime import * import multiprocessing as mp +import pickle +import rasterio def compute_overlap_matrix(_lst: List[otb.Application], out_param='out'): masks = [] @@ -388,3 +391,19 @@ def get_patch_centers(msk, patch_size, n_patches, min_coverage=0, min_cov_extent return np.asarray(out_coords), coverage, cov_extent else: return None, coverage, cov_extent + +def apply_shift_using_points(img, pts_file, separator=','): + with open(pts_file, 'r') as pts_f: + pts = pts_f.read().splitlines() + pts = [x.split(separator) for x in pts if x] + pts = [[float(x) for x in y] for y in pts] + pts = np.array(pts) + mns = np.array([pts[:,2]-pts[:,0],pts[:,3]-pts[:,1]]) + mns = np.mean(mns, axis=1) + with rasterio.open(img, 'r+') as ds: + tr = ds.transform + with open(os.path.splitext(img)[0]+'_transform_backup.pkl', 'wb') as f: + pickle.dump(tr, f) + ds.transform = rasterio.transform.Affine(tr[0], tr[1], tr[2] + mns[0], tr[3], tr[4], tr[5] + mns[1]) + return mns + diff --git a/Common/imagetools.py b/Common/imagetools.py new file mode 100644 index 0000000000000000000000000000000000000000..3a0900fd2ed4ac23d7c0b0f9a24d8f1c1e05fa79 --- /dev/null +++ b/Common/imagetools.py @@ -0,0 +1,18 @@ +import os +import otbApplication as otb +import rasterio + +def vhr_to_basemap(img,out,quantiles=[2,2], bands=[1,2,3], quality=75): + dc = otb.Registry.CreateApplication('DynamicConvert') + dc.SetParameterString('in',img) + dc.SetParameterInt('quantile.low', quantiles[0]) + dc.SetParameterInt('quantile.high', quantiles[1]) + dc.SetParameterString('channels', 'rgb') + dc.SetParameterInt('channels.rgb.red', bands[0]) + dc.SetParameterInt('channels.rgb.green', bands[1]) + dc.SetParameterInt('channels.rgb.blue', bands[2]) + dc.SetParameterString('out', out + '?&gdal:co:compress=jpeg&gdal:co:jpeg_quality={}'.format(quality)) + dc.SetParameterOutputImagePixelType('out', otb.ImagePixelType_uint8) + dc.ExecuteAndWriteOutput() + with rasterio.open(out,'r+') as ds: + ds.build_overviews(factors=[2,4,8,16,32,64]) diff --git a/Workflows/operations.py b/Workflows/operations.py index a80026c680a3d2d9620876e50f9d95c59332055e..a861c2e0f8dd5720a7391e5ed0f13683377c9026 100644 --- a/Workflows/operations.py +++ b/Workflows/operations.py @@ -3,6 +3,8 @@ import OBIA.segmentation import VHR.vhrbase from TimeSeries import s2theia, s2planetary, s1base, s1planetary, planet_mosaics, landsat_planetary from Common import demtools +from Common.geometry import apply_shift_using_points +from Common.imagetools import vhr_to_basemap def run_segmentation(img, threshold, cw, sw , out_seg, n_first_iter, margin, roi, n_proc, memory=None, @@ -124,3 +126,11 @@ def fetch(imagery, shp, out_fld, dt=None, auth=None, only_tiles=None): elif imagery == 'landsatplanetary': landsat_planetary.fetch(shp, dt, out_fld, auth) return + +def apply_shift(in_img, in_points): + apply_shift_using_points(in_img, in_points) + return + +def create_basemap(img, out, quantiles=[2,2], bands=[1,2,3], quality=75): + vhr_to_basemap(img, out, quantiles, bands, quality) + return \ No newline at end of file diff --git a/moringa.py b/moringa.py index c2a8b2189424ce31de47108da95c98e027bec439..771c3b52fed8f068645beb114d34a84149da8adc 100755 --- a/moringa.py +++ b/moringa.py @@ -90,6 +90,23 @@ def main(args): 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) @@ -127,6 +144,13 @@ def main(args): 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