Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature image config #16

Merged
merged 16 commits into from
Sep 15, 2024
Merged
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Orthority command line functionality is accessed with the ``oty`` command, and i
- ``exif``: Orthorectify images with frame camera model(s) defined by image EXIF / XMP tags.
- ``odm``: Orthorectify images in a processed OpenDroneMap dataset that includes a DSM.
- ``rpc``: Orthorectify images with RPC camera models defined by image tags / sidecar files or parameter files.
- ``sharpen``: Pan sharpen an image using the Gram-Schmidt method.
- ``sharpen``: Pan-sharpen an image using the Gram-Schmidt method.

Get help on ``oty`` with:

Expand Down Expand Up @@ -110,7 +110,7 @@ As above, but refine the RPC camera model with GCPs in ``source.tif`` tags:

oty rpc --dem dem.tif --gcp-refine tags source.tif

Pan sharpen the multispectral image ``ms.tif`` with the panchromatic image ``pan.tif``:
Pan-sharpen the multispectral image ``ms.tif`` with the panchromatic image ``pan.tif``:

.. code-block:: bash

Expand Down Expand Up @@ -144,7 +144,7 @@ Orthorectify an image using interior and exterior parameter files to generate th
ortho.process('ortho.tif')


Pan sharpen a multispectral image with the matching panchromatic image:
Pan-sharpen a multispectral image with the matching panchromatic image:

.. below copied from docs/scripts/api_pan_sharp.py

Expand All @@ -157,7 +157,7 @@ Pan sharpen a multispectral image with the matching panchromatic image:
pan_file = url_root + 'pan_sharp/pan.tif' # panchromatic drone image
ms_file = url_root + 'pan_sharp/ms.tif' # multispectral (RGB) drone image

# create PanSharpen object and pan sharpen
# create PanSharpen object and pan-sharpen
pan_sharp = oty.PanSharpen(pan_file, ms_file)
pan_sharp.process('pan_sharp.tif')

Expand Down
2 changes: 1 addition & 1 deletion docs/api/pan_sharp.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Pan sharpening
Pan-sharpening
===============

.. automodule:: orthority.pan_sharp
Expand Down
4 changes: 2 additions & 2 deletions docs/getting_started/api/pan_sharp.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pan sharpening
Pan-sharpening
==============

The :class:`~orthority.pan_sharp.PanSharpen` class implements Gram-Schmidt pan sharpening. Panchromatic and multispectral images are required to instantiate. The :meth:`~orthority.pan_sharp.PanSharpen.process` method pan sharpens:
The :class:`~orthority.pan_sharp.PanSharpen` class implements Gram-Schmidt pan-sharpening. Panchromatic and multispectral images are required to instantiate. The :meth:`~orthority.pan_sharp.PanSharpen.process` method pan-sharpens:

.. literalinclude:: ../../scripts/api_pan_sharp.py
:language: python
Expand Down
32 changes: 27 additions & 5 deletions docs/getting_started/cli/ortho_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
Ortho image configuration
=========================

Ortho images are created as GeoTIFFs. Image resolution and format (data type, compression, nodata / internal mask and overviews) can be configured. Configuration options are common to all |oty|_ orthorectification sub-commands and default to sensible values when not supplied.
Ortho image resolution and format can be configured. Configuration options are common to all |oty|_ orthorectification sub-commands and default to sensible values when not supplied.

Resolution, data type and compression
-------------------------------------

Ortho resolution defaults to an estimate of the `ground sampling distance <https://en.wikipedia.org/wiki/Ground_sample_distance>`__. This can be changed with ``--res``. The ortho data type defaults to the source image data type, and can be changed with ``--dtype``.

Compression can be configured with ``--compress`` as either ``deflate`` (with any ortho data type) or ``jpeg`` (with the ``uint8`` or ``uint16`` ortho data types). If ``--compress`` is not specified, compression defaults to ``jpeg`` when the ortho data type is ``uint8``, otherwise it defaults to ``deflate``. When ``jpeg`` compression is used with the ``uint16`` data type, the ortho is 12 bit ``jpeg`` compressed.
Compression can be configured with ``--compress`` as either ``deflate`` or ``lzw`` (with any ortho data type), or ``jpeg`` (with the ``uint8`` or ``uint16`` ortho data types). If ``--compress`` is not specified, compression defaults to ``jpeg`` when the ortho data type is ``uint8``, and to ``deflate`` otherwise. When ``jpeg`` compression is used with the ``uint16`` data type, the ortho is 12 bit ``jpeg`` compressed.

.. note::

Expand All @@ -20,11 +23,30 @@ The next example orthorectifies using EXIF / XMP tags, and configures the ortho

oty exif --dem odm/odm_dem/dsm.tif --res 0.2 --dtype uint8 --compress deflate odm/images/100_0005_0140.tif

Valid ortho pixels are masked with either an internal mask band or a nodata value. By default, an internal mask is used when the ortho image is ``jpeg`` compressed. This avoids ``jpeg`` artefacts in invalid areas. When the ortho is ``deflate`` compressed, the default is use to a nodata value based on the data type. Masking behaviour can be changed with ``--write-mask`` to write an internal mask, or ``--no-write-mask`` to use a nodata value.
Masking and overviews
---------------------

Valid ortho pixels are masked with either an internal mask band or a nodata value. By default, an internal mask is used when the ortho image is ``jpeg`` compressed. This avoids ``jpeg`` artefacts in invalid areas. When the ortho is ``deflate`` or ``lzw`` compressed, the default is use to a nodata value based on the data type. Masking behaviour can be changed with ``--write-mask`` to write an internal mask, or ``--no-write-mask`` to use a nodata value.

Internal overviews are added by default. This can be changed with ``--no-build-ovw``. In this example, we create an ortho image with ``deflate`` compression, nodata rather than internal masking, and no internal overviews:
Internal overviews are added by default. This can be changed with ``--no-build-ovw``. In this example, we create an ortho image with ``deflate`` compression, internal masks, and no internal overviews:

.. code-block:: bash

oty exif --dem odm/odm_dem/dsm.tif --compress deflate --no-write-mask --no-build-ovw odm/images/100_0005_0140.tif
oty exif --dem odm/odm_dem/dsm.tif --compress deflate --write-mask --no-build-ovw odm/images/100_0005_0140.tif

Custom creation options and driver
----------------------------------

For ortho image configurations not possible with the above options, custom creation options can be specified with ``--creation-option``. The ``--compress`` option is ignored, and no other creation options are set by Orthority when this is supplied.

The ortho can be formatted as a ``gtiff`` (GeoTIFF - the default) or ``cog`` (Cloud Optimised GeoTIFF) with ``--driver``.

This example formats the ortho as a GeoTIFF with internal masks, and specifies custom creation options for tiled YCbCr JPEG compression with a quality of 90:

.. code-block:: bash

oty exif --dem odm/odm_dem/dsm.tif --write-mask --driver gtiff --creation-option tiled=yes --creation-option compress=jpeg --creation-option photometric=ycbcr --creation-option jpeg_quality=90 odm/images/100_0005_0140.tif

.. note::

Each driver has its own creation options. See the GDAL `GeoTIFF <https://gdal.org/en/latest/drivers/raster/gtiff.html#creation-options>`__ and `COG <https://gdal.org/en/latest/drivers/raster/cog.html#creation-options>`__ docs for details.
2 changes: 1 addition & 1 deletion docs/getting_started/cli/pan_sharpening.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.. include:: ../../shared.txt
.. include:: shared.txt

Pan sharpening
Pan-sharpening
==============

.. toctree::
Expand Down
34 changes: 29 additions & 5 deletions docs/getting_started/cli/sharp_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,48 @@
Output image configuration
==========================

Pan sharpened images are created as GeoTIFFs. Image format (data type, compression, nodata / internal mask and overviews) can be configured. Configuration options are shared with the |oty|_ orthorectification sub-commands, and default to sensible values when not supplied.
The pan-sharpened image format can be configured. Configuration options are shared with the |oty|_ orthorectification sub-commands, and default to sensible values when not supplied.

The image data type defaults to the multispectral image data type, and can be changed with ``--dtype``. Compression can be configured with ``--compress`` as either ``deflate`` (with any image data type) or ``jpeg`` (with the ``uint8`` or ``uint16`` image data types). If ``--compress`` is not specified, compression defaults to ``jpeg`` when the image data type is ``uint8``, otherwise it defaults to ``deflate``. When ``jpeg`` compression is used with the ``uint16`` data type, the image is 12 bit ``jpeg`` compressed.
Data type and compression
-------------------------

The image data type defaults to the multispectral image data type, and can be changed with ``--dtype``. Compression can be configured with ``--compress`` as either ``deflate`` or ``lzw`` (with any image data type), or ``jpeg`` (with the ``uint8`` or ``uint16`` image data types). If ``--compress`` is not specified, compression defaults to ``jpeg`` when the image data type is ``uint8``, and to ``deflate`` otherwise. When ``jpeg`` compression is used with the ``uint16`` data type, the image is 12 bit ``jpeg`` compressed.

.. note::

Support for 12 bit JPEG compression is Rasterio_ build / package dependent.

The next example creates a pan sharpened image with the ``int16`` data type, and ``deflate`` compression:
The next example creates a pan-sharpened image with the ``int16`` data type, and ``deflate`` compression:

.. code-block:: bash

oty sharpen --pan pan_sharp/pan.tif --multispectral pan_sharp/ms.tif --out-file pan_sharp.tif --dtype int16 --compress deflate

Valid image pixels are masked with either an internal mask band or a nodata value. By default, an internal mask is used when the image image is ``jpeg`` compressed. This avoids ``jpeg`` artefacts in invalid areas. When the image is ``deflate`` compressed, the default is use to a nodata value based on the data type. Masking behaviour can be changed with ``--write-mask`` to write an internal mask, or ``--no-write-mask`` to use a nodata value.
Masking and overviews
---------------------

Valid image pixels are masked with either an internal mask band or a nodata value. By default, an internal mask is used when the image is ``jpeg`` compressed. This avoids ``jpeg`` artefacts in invalid areas. When the image is ``deflate`` or ``lzw`` compressed, the default is use to a nodata value based on the data type. Masking behaviour can be changed with ``--write-mask`` to write an internal mask, or ``--no-write-mask`` to use a nodata value.

Internal overviews are added by default. This can be changed with ``--no-build-ovw``. In this example, we create an pan sharpened image with ``deflate`` compression, internal masking rather than nodata, and no internal overviews:
Internal overviews are added by default. This can be changed with ``--no-build-ovw``. In this example, we create an pan-sharpened image with ``deflate`` compression, internal masking rather than nodata, and no internal overviews:

.. code-block:: bash

oty sharpen --pan pan_sharp/pan.tif --multispectral pan_sharp/ms.tif --out-file pan_sharp.tif --compress deflate --write-mask --no-build-ovw

Custom creation options and driver
----------------------------------

For pan-sharpened image configurations not possible with the above options, custom creation options can be specified with ``--creation-option``. The ``--compress`` option is ignored, and no other creation options are set by Orthority when this is supplied.

The image can be formatted as a ``gtiff`` (GeoTIFF - the default) or ``cog`` (Cloud Optimised GeoTIFF) with ``--driver``.

This example formats the pan-sharpened image as a COG with internal masks, and specifies custom creation options for JPEG compression with a quality of 90:

.. code-block:: bash

oty sharpen --pan pan_sharp/pan.tif --multispectral pan_sharp/ms.tif --out-file pan_sharp.tif --write-mask --driver cog --creation-option compress=jpeg --creation-option quality=90

.. note::

Each driver has its own creation options. See the GDAL `GeoTIFF <https://gdal.org/en/latest/drivers/raster/gtiff.html#creation-options>`__ and `COG <https://gdal.org/en/latest/drivers/raster/cog.html#creation-options>`__ docs for details.

2 changes: 1 addition & 1 deletion docs/getting_started/cli/sharpen.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
``oty sharpen``
===============

|oty sharpen|_ implements the Gram-Schmidt pan sharpening method. This example pan sharpens a multispectral (RGB) drone image with its matching panchromatic image:
|oty sharpen|_ implements the Gram-Schmidt pan-sharpening method. This example pan-sharpens a multispectral (RGB) drone image with its matching panchromatic image:

.. code-block:: bash

Expand Down
1 change: 0 additions & 1 deletion docs/scripts/api_frame.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# TODO: change URL to main branch
# code for getting started->api->camera models->frame cameras
# [create camera]
import orthority as oty
Expand Down
2 changes: 1 addition & 1 deletion docs/scripts/api_pan_sharp.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
pan_file = url_root + 'pan_sharp/pan.tif' # panchromatic drone image
ms_file = url_root + 'pan_sharp/ms.tif' # multispectral (RGB) drone image

# create PanSharpen object and pan sharpen
# create PanSharpen object and pan-sharpen
pan_sharp = oty.PanSharpen(pan_file, ms_file)
pan_sharp.process('pan_sharp.tif')
2 changes: 1 addition & 1 deletion orthority/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import logging
import pathlib

from orthority.enums import Compress, Interp, RpcRefine
from orthority.enums import Compress, Interp, RpcRefine, Driver
from orthority.factory import FrameCameras, RpcCameras
from orthority.ortho import Ortho
from orthority.pan_sharp import PanSharpen
Expand Down
12 changes: 6 additions & 6 deletions orthority/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def rect_boundary(im_size: np.ndarray, num_pts: int) -> np.ndarray:
perim = 2 * br.sum()
cnr_ji = np.array([[0, 0], [br[0], 0], br, [0, br[1]], [0, 0]])
dist = np.sum(np.abs(np.diff(cnr_ji, axis=0)), axis=1)
return np.row_stack(
return np.vstack(
[
np.linspace(
cnr_ji[i],
Expand Down Expand Up @@ -754,7 +754,7 @@ def _get_rectangles(
n = 9
scale_j, scale_i = np.meshgrid(range(0, n), range(0, n))
scale_j, scale_i = scale_j.ravel(), scale_i.ravel()
ji = np.row_stack([scale_j * w / (n - 1), scale_i * h / (n - 1)])
ji = np.vstack([scale_j * w / (n - 1), scale_i * h / (n - 1)])
xy = self._pixel_to_camera(ji)[:2]
outer = xy.min(axis=1), xy.max(axis=1) - xy.min(axis=1)
inner_ul = np.array((xy[0][scale_j == 0].max(), xy[1][scale_i == 0].max()))
Expand Down Expand Up @@ -791,7 +791,7 @@ def _camera_to_pixel(self, xyz_: np.ndarray) -> np.ndarray:

def _pixel_to_camera(self, ji: np.ndarray) -> np.ndarray:
"""Transform 2D pixel to homogenous 3D camera coordinates."""
ji_ = np.row_stack([ji.astype('float64', copy=False), np.ones((1, ji.shape[1]))])
ji_ = np.vstack([ji.astype('float64', copy=False), np.ones((1, ji.shape[1]))])
xyz_ = self._K_undistort_inv.dot(ji_)
return xyz_

Expand Down Expand Up @@ -1237,7 +1237,7 @@ def _get_undistort_maps(self) -> tuple[np.ndarray, np.ndarray]:
# equivalent to the above, but using Camera methods (works out slower):
# j = np.arange(0, self.im_size[0], dtype='int32')
# i = np.zeros(self.im_size[0], dtype='int32')
# ji = np.row_stack((j, i))
# ji = np.vstack((j, i))
# undistort_maps = (
# np.zeros(self.im_size[::-1], dtype='float32'),
# np.zeros(self.im_size[::-1], dtype='float32'),
Expand All @@ -1258,7 +1258,7 @@ def _camera_to_pixel(self, xyz_: np.ndarray) -> np.ndarray:
def _pixel_to_camera(self, ji: np.ndarray) -> np.ndarray:
ji_cv = ji.T.astype('float64', copy=False)
xyz_ = cv2.undistortPoints(ji_cv, self._K, self._dist_param)
xyz_ = np.row_stack([xyz_[:, 0, :].T, np.ones((1, ji.shape[1]))])
xyz_ = np.vstack([xyz_[:, 0, :].T, np.ones((1, ji.shape[1]))])
return xyz_


Expand Down Expand Up @@ -1480,7 +1480,7 @@ def _camera_to_pixel(self, xyz_: np.ndarray) -> np.ndarray:
def _pixel_to_camera(self, ji: np.ndarray) -> np.ndarray:
ji_cv = ji.T[None, :].astype('float64', copy=False)
xyz_ = cv2.fisheye.undistortPoints(ji_cv, self._K, self._dist_param, None, None)
xyz_ = np.row_stack([xyz_[0].T, np.ones((1, ji.shape[1]))])
xyz_ = np.vstack([xyz_[0].T, np.ones((1, ji.shape[1]))])
return xyz_


Expand Down
Loading
Loading