From a42dbf11ad20971d3921ec38e185c1cf741c5249 Mon Sep 17 00:00:00 2001 From: drduhe Date: Fri, 27 Oct 2023 11:17:31 -0600 Subject: [PATCH] feat: add script to conert tiff to target ntf formats --- bin/run_test.sh | 105 ------------------------------ bin/translate_images.py | 137 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 105 deletions(-) delete mode 100755 bin/run_test.sh create mode 100644 bin/translate_images.py diff --git a/bin/run_test.sh b/bin/run_test.sh deleted file mode 100755 index 75329fe..0000000 --- a/bin/run_test.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/bash - -# -# Copyright 2023 Amazon.com, Inc. or its affiliates. -# - -# This is a utility script to help building and uploading the OSML default test model to an accounts ECR -# repository deployed by the AWSOversightMLCDK package. While this script can be run without providing inputs, -# a user can pass in the following optional parameters to modify default behavior: -# $1 = test_image = image to run test against -# $2 = MODEL = options: < centerpoint | flood | process | aircraft > -# $2 = test_tile_format = tile format to use -# $3 = test_tile_compression = tile compression to use -# $4 = region = region OSML is deployed in -# $5 = account = account to test with -# $6 = remote account = see description below - -# If you want to test cross account access provide a remote account (ex. 555986723962) -# If the value is set it will use images from the gamma integ account -# and will write results to the stream and bucket located in that account -# You'll need to run the tests using creds for the gamma deployment account or -# add your account as a trusted principal to the necessary roles in the remote account - - -# Grab user inputs or set default values -export TARGET_IMAGE=${1} -export MODEL=${2:-centerpoint} -export TEST_TILE_FORMAT=${3:-NITF} -export TEST_TILE_COMPRESSION=${4:-J2K} -export REGION=${5:-us-west-2} -export ACCOUNT=${6:-$(aws sts get-caller-identity --query Account --output text)} -export REMOTE_ACCOUNT=${7:-} - -# Standard test images deployed by CDK currently -case $TARGET_IMAGE in - "small") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/small.tif" - ;; - - "large") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/large.tif" - TEST_TILE_COMPRESSION=NONE - ;; - - "meta") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/meta.ntf" - ;; - - "tile_tif") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/tile.tif" - ;; - - "tile_ntf") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/tile.ntf" - ;; - - "tile_jpeg") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/tile.jpeg" - ;; - - "tile_png") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/tile.png" - ;; - - "sicd_capella_chip_ntf") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/sicd-capella-chip.ntf" - TEST_TILE_COMPRESSION=NONE - ;; - - "sicd_umbra_chip_ntf") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/sicd-umbra-chip.ntf" - TEST_TILE_COMPRESSION=NONE - ;; - - "sicd_interferometric_hh_ntf") - TARGET_IMAGE="s3://test-images-${ACCOUNT}/sicd-interferometric-hh.nitf" - TEST_TILE_COMPRESSION=NONE - ;; - -esac - -# Expected values from our CDK package -export IMAGE_QUEUE_NAME=ImageRequestQueue -export TEST_RESULTS_BUCKET=test-results-${ACCOUNT} -export TEST_STREAM=test-stream-${ACCOUNT} -export JOB_STATUS_TABLE=ImageProcessingJobStatus -export REGION_REQUEST_TABLE=RegionProcessingJobStatus -export FEATURE_TABLE=ImageProcessingFeatures -export SM_CENTER_POINT_MODEL=centerpoint -export SM_FLOOD_MODEL=flood -export SM_AIRCRAFT_MODEL=aircraft -export TILE_FORMAT=${TEST_TILE_FORMAT} -export TILE_COMPRESSION=${TEST_TILE_COMPRESSION} -export TEST_STATUS_QUEUE=ImageStatusQueue -export TARGET_MODEL=${MODEL} - -# Call into root directory of this pacakge so that we can -# run this script from anywhere. -LOCAL_DIR="$( dirname -- "$0"; )" -cd "${LOCAL_DIR}/.." || exit 1 - -export PYTHONPATH="${PYTHONPATH}:./src/" - -# Run integration tests with pytest -time python3 -m pytest -o log_cli=true -vv src/aws/osml/integ/"${MODEL}"/test_"${MODEL}"_model.py diff --git a/bin/translate_images.py b/bin/translate_images.py new file mode 100644 index 0000000..894aed3 --- /dev/null +++ b/bin/translate_images.py @@ -0,0 +1,137 @@ +# Copyright 2023 Amazon.com, Inc. or its affiliates. + +""" +################################################################################################### + +This script provides functionality to convert GeoTIFF images to NITF (National Imagery Transmission Format) format. +The script supports two target NITF formats: GREYSCALE (16bit) and WBID (Wideband Image Data). +It uses the GDAL (Geospatial Data Abstraction Library) library for the conversion process. + +The script defines three main functions: 1. `Translate_to_greyscale`: Converts a GeoTIFF dataset to a greyscale NITF +format. 2. `Translate_to_wibd`: Converts a GeoTIFF dataset to a NITF file in the WBID format. 3. +`Convert_geotiff_to_nitf`: Converts GeoTIFF files in a specified input directory to the desired NITF format (either +greyscale or WBID) and saves them in an output directory. + +The script accepts command-line arguments for specifying input and output directories, target format, inclusion of +XML metadata, and compression method. + +Usage: python script_name.py --input_dir input_directory --output_format {GREYSCALE/WIBD} [--output_dir +output_directory] [--include_xml {NO/YES}] [--compression compression_method] + +Example Usage: python3 translate_images.py --input_dir input_data --output_format GREYSCALE --output_dir output_data +--include_xml YES --compression LZW + +Please ensure you have the GDAL library and its Python bindings (osgeo.gdal) installed before running this script. +You can customize the script's behavior by modifying the function parameters and GDAL options as needed. +###################################################################################################""" + +import argparse +import glob +import os +from enum import Enum, auto +from typing import Optional + +from osgeo import gdal, gdalconst +from osgeo.gdal import Translate + + +class TargetFormat(Enum): + """ + Enum for specifying the target NITF format for conversion. + """ + + GREYSCALE = auto() + WBID = auto() + + +def translate_to_greyscale(out_file: str, ds: gdal.Dataset) -> gdal.Dataset: + """ + Translate a GeoTIFF dataset to a greyscale NITF format. + + :param out_file: The path to the output NITF file to be created. + :param ds: The input GeoTIFF dataset to be translated. + :return: The translated NITF dataset. + """ + return Translate( + destName=out_file, + srcDS=ds, + bandList=[float(1)], + format="NITF", + outputType=gdalconst.GDT_Int16, + creationOptions=["IC=C8", "PROFILE=NPJE_NUMERICALLY_LOSSLESS"], + ) + + +def translate_to_wbid(out_file: str, ds: gdal.Dataset) -> gdal.Dataset: + """ + Converts a GeoTIFF dataset to a NITF file in the WBID format. + + :param out_file: The path to the output NITF file to be created. + :param ds: The input GeoTIFF dataset to be converted. + :return: The converted NITF dataset. + """ + return Translate( + destName=out_file, + srcDS=ds, + bandList=[1], + format="NITF", + outputType=gdalconst.GDT_Byte, + creationOptions=["IC=C8", "PROFILE=NPJE_NUMERICALLY_LOSSLESS"], + ) + + +def convert_geotiff_to_nitf(input_dir: str, target_format: TargetFormat, output_dir: Optional[str] = None) -> None: + """ + Convert GeoTIFF files in the input directory to NITF format (either greyscale or WIBD). + + :param input_dir: The directory containing the input GeoTIFF files. + :param target_format: The target format for conversion, either GREYSCALE or WIBD. + :param output_dir: The directory where converted NITF files will be saved. + If not provided, a default 'output' directory will be created + inside the input directory. + :raises Exception: If an invalid target format is provided. + """ + if output_dir is None: + output_dir = os.path.join(input_dir, "output") + + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + input_files = glob.glob(os.path.join(input_dir, "*.tif")) + + for input_file in input_files: + output_file = os.path.join(output_dir, os.path.splitext(os.path.basename(input_file))[0] + ".ntf") + src_ds = gdal.Open(input_file) + + if target_format == TargetFormat.GREYSCALE: + translate_to_greyscale(output_file, src_ds) + elif target_format == TargetFormat.WBID: + translate_to_wbid(output_file, src_ds) + else: + raise Exception(f"Invalid target format: {target_format}") + + print("Conversion completed.") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Convert GeoTIFF images to a target NITF format.") + parser.add_argument("input_dir", help="Input directory containing GeoTIFF images") + parser.add_argument("--output_format", help="Target format to convert to (options: GREYSCALE/WIBD)") + parser.add_argument( + "--output_dir", help="Output directory for NITF images (default: input_dir/output)", type=str, default=None + ) + parser.add_argument( + "--include_xml", help="Output directory for NITF images (default: NO, options: NO/YES)", type=str, default="NO" + ) + parser.add_argument( + "--compression", help="Target compression to use for imagery (default: LZW)", type=str, default="LZW" + ) + args = parser.parse_args() + + gdal.SetConfigOption("COMPRESS_OVERVIEW", args.compression) + gdal.SetConfigOption("GDAL_PAM_ENABLED", args.include_xml) + + usr_input_dir = args.input_dir + usr_output_dir = args.output_dir + + convert_geotiff_to_nitf(usr_input_dir, TargetFormat[args.output_format], usr_output_dir)