Using the Transform pane with an image, which contains a single data channel for terrain elevation data for land together with bathymetry data for oceans, we set all pixels with values less than zero to zero. This takes all below-zero elevations and sets them to zero, in effect removing bathymetry effects so that ocean areas are represented with zero elevation.
The data set we will use is US government space shuttle SRTM data that was combined with bathymetry data to show terrain elevations as well as ocean depths. The data uses sea level as the zero mark so terrain elevations are positive numbers while negative numbers represent depths. The data imports into Manifold as an image that is made up of a single data channel. SRTM data is published as rectangles that tile the Earth. The particular data set we use shows a region centered approximately on the Red Sea.
The image appears below in a map window. The Info pane to the right shows that the image is 4800 x 6000 pixels in size, and that the elevation values are sixteen bit signed integers that use data type int16.
The image has been Styled to color it with a palette as seen below. In addition, the Options tab of the Style pane has been used to apply hill shading.
The Pixel size is reported in the native units of the coordinate system used by the image. The image uses Latitude / Longitude, so the native units are degrees, which are a particularly nutty system of measure to use since the linear size of a degree varies depending on the location on Earth. The readout indicated is the average size of a degree in approximately the middle of the image.
If we want to use more sensible units of measure, we can quickly reproject the image into the Pseudo-Mercator coordinate system, so it uses meters as units of measure. We click on the coordinate picker button, choose Reproject Component and then in the subsequent dialogs reproject into Pseudo-Mercator (a one-click favorite) to create a new image that we will call e020n40.Bathymetry.srtm PM, to remind us it is in Pseudo-Mercator (PM) projection.
The result is a new image, shown above as a layer in the same map, that uses meters as a unit of measure, with the Pixel size being reported in more understandable form, 930 meters by 930 meters in size. Each pixel is approximately a kilometer square.
In what follows we will be working with the values within each pixel, so it doesn't matter what coordinate system is used, whether we work with the original SRTM data in Latitude / Longitude or as reprojected into Pseudo-Mercator.
Scrolling up and down through the palette intervals list in the Style pane, we see the data ranges from -5868 to 5778. For this particular example we would like to replace all the negative numbers, that is, all depths, with a value of 0, thus removing all relief below sea level. The thematic format in use may seem to fudge heights slightly, but since the data set uses integers for heights, anything less than 1 in the data set is zero or less.
The task is a common one in spatial engineering or spatial ETL (Extract, Transform, Load) work, and it occurs for various reasons. For example, we might need to use this data with a GIS or other package, such as a 3D modeling package, that cannot work with negative numbers for terrain elevations. Or we might be creating a data set for use in a modelling process that will use a 3D printer to create a tabletop model of the terrain but which requires ocean regions to be flat. For whatever reason, our task is to replace all negative numbers, that is, depths, with a value of 0.
An experienced Manifold operator would just do that in a single step using a single expression. Since this is a tutorial example we will do the job the way a beginner might approach the task, doing it in a few simple steps that allow checking the workflow along the way.
We begin by zooming in to a region right off the tip of the Horn of Africa, with the Gulf of Aden seen at the top and the Arabian Sea to the right and lower right. We draw a selection box with a Ctrl-drag to Select the tiles in the center of the view. The rectangular region of the selected tiles is shown by a red selection border and translucent fill.
We will first apply the transform operation to only the selected tiles. That will give us a chance to see what the transform does in a setting that allows comparing the results of the operation to regions where the transform operation has not been applied. It also demonstrates how to apply a transform to only part of an image. After applying the transform only to selected tiles, we next will apply the same transform to the entire image.
With the focus on the map window, in the Transform pane we choose the Tile field and then we double-click the Limit template to launch the template.
In the Limit template we choose limit minimum as the Operation We enter an At least value of 0.
For the Result destination, we choose New Field and then enter Tile_zeroed as the name of the new tile field to add to the table. For the new image name we enter Zeroed bathymetry. We could use whatever names we want for the names of the new tile and image, but it is wise to use names that remind us of what they are supposed to be.
Instead of saving the results to a new table and image, choosing New Field creates an additional tile field within the same table, and then creates a new image to visualize that tile field. We end up with two images that both show data from the same table, using two different tile fields in that table. This is a useful technique when creating alternate versions of data sets that we would like to store together in the same table.
We check the Transform selection only box. This applies the transform operation to only selected tiles.
A new image called Zeroed bathymetry appears in the Project pane. We drag and drop the new Zeroed bathymetry image as a layer into the map window.
The new Zeroed bathymetry image appears in default styling for images, with Manifold estimating a grayscale range to use from a sampling of minimum and maximum values. The Zeroed bathymetry image appears to cover only part of the original image, that part where selected tiles were located, but it actually extends further with pixels outside the selected tiles area having NULL values, since no transform operation applied to those pixels.
To style the new image the same as the original image, we copy the StylePixel property from the original image to the new Zeroed bathymetry image.
In the Project pane, we right-click on the original e020n40.Bathymetry.srtm image and choose Properties in the context menu. In the Properties dialog we right-click on the value for the StylePixel property and choose Copy. That copies the JSON string that specifies style for pixels to the clipboard. Press Cancel to close the dialog.
In the Project pane, we right-click on the new Zeroed bathymetry image and choose Properties in the context menu. In the Properties dialog we double-click on the empty cell next to the new record asterisk * character, and we enter StylePixel to add a new property. We then right-click into the empty value cell next to the new StylePixel property and we choose Paste.
That pastes the JSON string that we copied from the properties for the original drawing. Press OK to apply the changes.
The new Zeroed bathymetry image updates to use exactly the same styling as the original e020n40.Bathymetry.srtm image.
We can see that regions where elevation values were negative, that is, depths in ocean regions, have indeed been all set to zero elevation, and are now displayed using the same light blue palette color, the first interval below a height of 1. At the same time, elevation values over land that are at height 1 or greater have not been changed.
Looking at the display in the lower layer, in regions outside the new Zeroed bathymetry image, we can see how bathymetry in those regions has been flattened to zero within the Zeroed bathymetry image.
We will now apply the same transform to the entire image.
The Transform pane is still loaded with all parameters exactly as we have last left them, with the original e020n40.Bathymetry.srtm image and the Tile field chosen for Field and Channel.
We uncheck the Transform selection only option box. This time, for the Result destination we choose New Table, to create a new table and image for the result. We enter the name Bathymetry for the New image and an analogous name for the New table.
A new image called Bathymetry and its table appear in the Project pane. We drag and drop the new Bathymetry image into the map window.
In the illustration above we have removed the Zeroed bathymetry layer.
Zooming out to see the entire data set we see the transform has indeed been applied to all the data and has not modified any land regions, that is, regions where elevations were already above zero.
In the above sequence we applied the transform expression to the image by pressing the Update Field button in the Transform pane. As an alternative we could have pressed the Edit Query button to launch the Command Window with a query automatically generated by Manifold that executes the expression and updates the image.
Doing so is a great way to learn SQL and how to utilize various functions. The query generated follows below. It has three major sections:
-- Layer: e020n40.Bathymetry.srtm
-- Field: Tile
-- Channel: channel 0
-- Operation: limit minimum
-- At least: 0
-- Result: (new table)
-- Channel type: int16
-- New image: Bathymetry
-- New table: Bathymetry Tiles
-- Resources: all CPU cores, all GPU cores
-- Transform selection only: FALSE
-- prepare begin
CREATE TABLE [Bathymetry Tiles] (
INDEX [mfd_id_x] BTREE ([mfd_id]),
INDEX [X_Y_Tile_x] RTREE ([X], [Y], [Tile] TILESIZE (128, 128) TILETYPE INT16),
PROPERTY 'FieldCoordSystem.Tile' ComponentFieldCoordSystem([e020n40.Bathymetry.srtm Tiles], 'Tile'),
PROPERTY 'FieldTileSize.Tile' '[ 128, 128 ]',
PROPERTY 'FieldTileType.Tile' 'int16'
CREATE IMAGE [Bathymetry] (
PROPERTY 'Table' '[Bathymetry Tiles]',
PROPERTY 'FieldX' 'X',
PROPERTY 'FieldY' 'Y',
PROPERTY 'FieldTile' 'Tile',
PROPERTY 'Rect' CAST(ComponentFieldBounds([e020n40.Bathymetry.srtm Tiles], 'Tile', FALSE) AS NVARCHAR)
-- prepare end
DELETE FROM [Bathymetry Tiles];
INSERT INTO [Bathymetry Tiles] (
CASTV(TileMax([Tile], 0) AS INT16)
FROM [e020n40.Bathymetry.srtm Tiles];
TABLE CALL TileUpdateFieldPyramids([Bathymetry Tiles], 'Tile');
ALTER IMAGE [Bathymetry] (
ADD PROPERTY 'Rect' Coalesce(
CAST(ComponentFieldBounds([Bathymetry Tiles], 'Tile', TRUE) AS NVARCHAR),
The actual computation happens in a single line within a SELECT statement, using a single Manifold SQL function for tiles, TileMax.
CASTV(TileMax([Tile], 0) AS INT16)
The TileMax function takes two values and returns a pixel value that is the larger, that is, the maximum, of the two. The expression says to take whatever is in the pixel value for the tile, compare it to 0 and use whichever is bigger. For all negative pixel values obviously 0 will be the greater of the two. For all pixel values over land which have an elevation value greater than zero, the value of whatever is already in the tile will be the larger, since any positive number is greater than 0, so all positive pixel values will be left unchanged.
Land below sea level? - We are cheating slightly in this example, as the data set includes land regions that are below sea level, which the thematic format in use ends up coloring blue, as if they had water.
Transform - Tiles
Example: Rearrange Channels using an Expression - We use a simple expression in the Transform pane to rearrange the order of channels within the data.
Example: Parallel Speed Increase in an Image Transform - A short example illustrating how using all CPU cores (on by default) increases speed by a factor of four in a simple use of the Transform pane to modify an image.