Skip to content

Commit ec04c47

Browse files
authored
Merge pull request #16 from leftfield-geospatial/feature_image_config
Feature image config
2 parents 5b4bfcf + 4a2bb8b commit ec04c47

23 files changed

+895
-359
lines changed

README.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Orthority command line functionality is accessed with the ``oty`` command, and i
4949
- ``exif``: Orthorectify images with frame camera model(s) defined by image EXIF / XMP tags.
5050
- ``odm``: Orthorectify images in a processed OpenDroneMap dataset that includes a DSM.
5151
- ``rpc``: Orthorectify images with RPC camera models defined by image tags / sidecar files or parameter files.
52-
- ``sharpen``: Pan sharpen an image using the Gram-Schmidt method.
52+
- ``sharpen``: Pan-sharpen an image using the Gram-Schmidt method.
5353

5454
Get help on ``oty`` with:
5555

@@ -110,7 +110,7 @@ As above, but refine the RPC camera model with GCPs in ``source.tif`` tags:
110110
111111
oty rpc --dem dem.tif --gcp-refine tags source.tif
112112
113-
Pan sharpen the multispectral image ``ms.tif`` with the panchromatic image ``pan.tif``:
113+
Pan-sharpen the multispectral image ``ms.tif`` with the panchromatic image ``pan.tif``:
114114

115115
.. code-block:: bash
116116
@@ -144,7 +144,7 @@ Orthorectify an image using interior and exterior parameter files to generate th
144144
ortho.process('ortho.tif')
145145
146146
147-
Pan sharpen a multispectral image with the matching panchromatic image:
147+
Pan-sharpen a multispectral image with the matching panchromatic image:
148148

149149
.. below copied from docs/scripts/api_pan_sharp.py
150150
@@ -157,7 +157,7 @@ Pan sharpen a multispectral image with the matching panchromatic image:
157157
pan_file = url_root + 'pan_sharp/pan.tif' # panchromatic drone image
158158
ms_file = url_root + 'pan_sharp/ms.tif' # multispectral (RGB) drone image
159159
160-
# create PanSharpen object and pan sharpen
160+
# create PanSharpen object and pan-sharpen
161161
pan_sharp = oty.PanSharpen(pan_file, ms_file)
162162
pan_sharp.process('pan_sharp.tif')
163163

docs/api/pan_sharp.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Pan sharpening
1+
Pan-sharpening
22
===============
33

44
.. automodule:: orthority.pan_sharp

docs/getting_started/api/pan_sharp.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
Pan sharpening
1+
Pan-sharpening
22
==============
33

4-
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:
4+
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:
55

66
.. literalinclude:: ../../scripts/api_pan_sharp.py
77
:language: python

docs/getting_started/cli/ortho_config.rst

+27-5
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
Ortho image configuration
55
=========================
66

7-
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.
7+
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.
8+
9+
Resolution, data type and compression
10+
-------------------------------------
811

912
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``.
1013

11-
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.
14+
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.
1215

1316
.. note::
1417

@@ -20,11 +23,30 @@ The next example orthorectifies using EXIF / XMP tags, and configures the ortho
2023
2124
oty exif --dem odm/odm_dem/dsm.tif --res 0.2 --dtype uint8 --compress deflate odm/images/100_0005_0140.tif
2225
23-
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.
26+
Masking and overviews
27+
---------------------
28+
29+
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.
2430

25-
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:
31+
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:
2632

2733
.. code-block:: bash
2834
29-
oty exif --dem odm/odm_dem/dsm.tif --compress deflate --no-write-mask --no-build-ovw odm/images/100_0005_0140.tif
35+
oty exif --dem odm/odm_dem/dsm.tif --compress deflate --write-mask --no-build-ovw odm/images/100_0005_0140.tif
36+
37+
Custom creation options and driver
38+
----------------------------------
39+
40+
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.
41+
42+
The ortho can be formatted as a ``gtiff`` (GeoTIFF - the default) or ``cog`` (Cloud Optimised GeoTIFF) with ``--driver``.
43+
44+
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:
45+
46+
.. code-block:: bash
47+
48+
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
49+
50+
.. note::
3051

52+
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.

docs/getting_started/cli/pan_sharpening.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.. include:: ../../shared.txt
22
.. include:: shared.txt
33

4-
Pan sharpening
4+
Pan-sharpening
55
==============
66

77
.. toctree::

docs/getting_started/cli/sharp_config.rst

+29-5
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,48 @@
44
Output image configuration
55
==========================
66

7-
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.
7+
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.
88

9-
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.
9+
Data type and compression
10+
-------------------------
11+
12+
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.
1013

1114
.. note::
1215

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

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

1720
.. code-block:: bash
1821
1922
oty sharpen --pan pan_sharp/pan.tif --multispectral pan_sharp/ms.tif --out-file pan_sharp.tif --dtype int16 --compress deflate
2023
21-
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.
24+
Masking and overviews
25+
---------------------
26+
27+
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.
2228

23-
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:
29+
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:
2430

2531
.. code-block:: bash
2632
2733
oty sharpen --pan pan_sharp/pan.tif --multispectral pan_sharp/ms.tif --out-file pan_sharp.tif --compress deflate --write-mask --no-build-ovw
34+
35+
Custom creation options and driver
36+
----------------------------------
37+
38+
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.
39+
40+
The image can be formatted as a ``gtiff`` (GeoTIFF - the default) or ``cog`` (Cloud Optimised GeoTIFF) with ``--driver``.
41+
42+
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:
43+
44+
.. code-block:: bash
45+
46+
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
47+
48+
.. note::
49+
50+
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.
51+

docs/getting_started/cli/sharpen.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
``oty sharpen``
44
===============
55

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

88
.. code-block:: bash
99

docs/scripts/api_frame.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# TODO: change URL to main branch
21
# code for getting started->api->camera models->frame cameras
32
# [create camera]
43
import orthority as oty

docs/scripts/api_pan_sharp.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
pan_file = url_root + 'pan_sharp/pan.tif' # panchromatic drone image
66
ms_file = url_root + 'pan_sharp/ms.tif' # multispectral (RGB) drone image
77

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

orthority/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import logging
2626
import pathlib
2727

28-
from orthority.enums import Compress, Interp, RpcRefine
28+
from orthority.enums import Compress, Interp, RpcRefine, Driver
2929
from orthority.factory import FrameCameras, RpcCameras
3030
from orthority.ortho import Ortho
3131
from orthority.pan_sharp import PanSharpen

orthority/camera.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def rect_boundary(im_size: np.ndarray, num_pts: int) -> np.ndarray:
217217
perim = 2 * br.sum()
218218
cnr_ji = np.array([[0, 0], [br[0], 0], br, [0, br[1]], [0, 0]])
219219
dist = np.sum(np.abs(np.diff(cnr_ji, axis=0)), axis=1)
220-
return np.row_stack(
220+
return np.vstack(
221221
[
222222
np.linspace(
223223
cnr_ji[i],
@@ -754,7 +754,7 @@ def _get_rectangles(
754754
n = 9
755755
scale_j, scale_i = np.meshgrid(range(0, n), range(0, n))
756756
scale_j, scale_i = scale_j.ravel(), scale_i.ravel()
757-
ji = np.row_stack([scale_j * w / (n - 1), scale_i * h / (n - 1)])
757+
ji = np.vstack([scale_j * w / (n - 1), scale_i * h / (n - 1)])
758758
xy = self._pixel_to_camera(ji)[:2]
759759
outer = xy.min(axis=1), xy.max(axis=1) - xy.min(axis=1)
760760
inner_ul = np.array((xy[0][scale_j == 0].max(), xy[1][scale_i == 0].max()))
@@ -791,7 +791,7 @@ def _camera_to_pixel(self, xyz_: np.ndarray) -> np.ndarray:
791791

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

@@ -1237,7 +1237,7 @@ def _get_undistort_maps(self) -> tuple[np.ndarray, np.ndarray]:
12371237
# equivalent to the above, but using Camera methods (works out slower):
12381238
# j = np.arange(0, self.im_size[0], dtype='int32')
12391239
# i = np.zeros(self.im_size[0], dtype='int32')
1240-
# ji = np.row_stack((j, i))
1240+
# ji = np.vstack((j, i))
12411241
# undistort_maps = (
12421242
# np.zeros(self.im_size[::-1], dtype='float32'),
12431243
# np.zeros(self.im_size[::-1], dtype='float32'),
@@ -1258,7 +1258,7 @@ def _camera_to_pixel(self, xyz_: np.ndarray) -> np.ndarray:
12581258
def _pixel_to_camera(self, ji: np.ndarray) -> np.ndarray:
12591259
ji_cv = ji.T.astype('float64', copy=False)
12601260
xyz_ = cv2.undistortPoints(ji_cv, self._K, self._dist_param)
1261-
xyz_ = np.row_stack([xyz_[:, 0, :].T, np.ones((1, ji.shape[1]))])
1261+
xyz_ = np.vstack([xyz_[:, 0, :].T, np.ones((1, ji.shape[1]))])
12621262
return xyz_
12631263

12641264

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

14861486

0 commit comments

Comments
 (0)