diff --git a/CHANGES.rst b/CHANGES.rst index 4614c61e2..2434f39e0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -58,10 +58,16 @@ refpix resample -------- + - Implement resampling step. [#787] - Use resampled exposure time images to compute image exposure times. [#959] +scripts +------- + +- added ``roman_static_preview`` script to generate static previews of ASDF images [#953] + stpipe ------ @@ -73,7 +79,6 @@ tweakreg - Fix a bug due to which source catalog may contain sources outside of the bounding box. [#947] - 0.12.0 (2023-08-18) =================== diff --git a/pyproject.toml b/pyproject.toml index 57e75195e..0edd94cf3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,9 @@ dev = [ 'tox > 4', 'pre-commit > 3' ] +sdp = [ + 'stpreview>=0.5.1', +] [project.urls] 'tracker' = 'https://github.com/spacetelescope/romancal/issues' @@ -73,6 +76,7 @@ dev = [ pytest11 = {webbpsf = 'pytest_plugin.webbpsf_plugin'} [project.scripts] +roman_static_preview = 'romancal.scripts.static_preview:command' okify_regtests = 'romancal.scripts.okify_regtests:main' schema_editor = 'romancal.scripts.schema_editor:main' schemadoc = 'romancal.scripts.schemadoc:main' diff --git a/romancal/scripts/static_preview.py b/romancal/scripts/static_preview.py new file mode 100644 index 000000000..784738541 --- /dev/null +++ b/romancal/scripts/static_preview.py @@ -0,0 +1,101 @@ +from pathlib import Path +from typing import Optional + +import asdf +import numpy +from typing_extensions import Annotated + +try: + import typer + from stpreview.downsample import downsample_asdf_to + from stpreview.image import north_pole_angle, percentile_normalization, write_image +except (ImportError, ModuleNotFoundError): + raise ImportError( + 'SDP requirements not installed; do `pip install "romancal[sdp]"`' + ) + +app = typer.Typer() + + +@app.command() +def preview( + input: Annotated[Path, typer.Argument(help="path to ASDF file with 2D image data")], + output: Annotated[ + Optional[Path], typer.Argument(help="path to output image file") + ] = None, + shape: Annotated[ + Optional[tuple[int, int]], + typer.Argument(help="desired pixel resolution of output image"), + ] = (1080, 1080), + compass: Annotated[ + Optional[bool], typer.Option(help="whether to draw a north arrow on the image") + ] = True, +): + """ + create a preview image with a north arrow overlay indicating orientation + """ + + if output is None: + output = Path.cwd() + if output.is_dir(): + output = output / f"{input.stem}.png" + + with asdf.open(input) as file: + model = file["roman"]["meta"]["model_type"] + if "image" not in model.lower(): + raise NotImplementedError(f'"{model}" model not supported') + wcs = file["roman"]["meta"]["wcs"] + + data = downsample_asdf_to(input=input, shape=shape, func=numpy.nanmean) + + write_image( + data, + output, + shape=shape, + normalization=percentile_normalization(data, percentile=90), + colormap="afmhot", + north_arrow_angle=north_pole_angle(wcs).degree - 90, + ) + + +@app.command() +def thumbnail( + input: Annotated[Path, typer.Argument(help="path to ASDF file with 2D image data")], + output: Annotated[ + Optional[Path], typer.Argument(help="path to output image file") + ] = None, + shape: Annotated[ + Optional[tuple[int, int]], + typer.Argument(help="desired pixel resolution of output image"), + ] = (300, 300), + compass: Annotated[ + Optional[bool], typer.Option(help="whether to draw a north arrow on the image") + ] = False, +): + if output is None: + output = Path.cwd() + if output.is_dir(): + output = output / f"{input.stem}_thumb.png" + + with asdf.open(input) as file: + model = file["roman"]["meta"]["model_type"] + if "image" not in model.lower(): + raise NotImplementedError(f'"{model}" model not supported') + + data = downsample_asdf_to(input=input, shape=shape, func=numpy.nanmean) + + write_image( + data, + output, + shape=shape, + normalization=percentile_normalization(data, percentile=90), + colormap="afmhot", + ) + + +def command(): + app() + + +if __name__ == "__main__": + command() diff --git a/romancal/tests/test_import.py b/romancal/tests/test_import.py index 5c731a017..e8fb6cc85 100644 --- a/romancal/tests/test_import.py +++ b/romancal/tests/test_import.py @@ -18,7 +18,7 @@ def dependencies(package, exclude: [str]): ] -MODULES = dependencies(romancal, exclude=["test", "time"]) +MODULES = dependencies(romancal, exclude=["test", "time", "static_preview"]) @pytest.mark.parametrize(