ProConcepts Raster - kataya/arcgis-pro-sdk GitHub Wiki
Raster related functionality in ArcGIS Pro can be found in two namespaces within two separate assemblies. The ArcGIS.Core.Data.Raster namespace within ArcGIS.Core.dll provides the raster classes and members to work with raster datasets, in memory rasters, pixel blocks and cursors. The ArcGIS.Desktop.Mapping namespace within ArcGIS.Desktop.Mapping.dll provides the classes and members to work with raster layers and colorizers.
Language: C#
Subject: Raster
Contributor: ArcGIS Pro SDK Team <[email protected]>
Organization: Esri, http://www.esri.com
Date: 11/24/2020
ArcGIS Pro: 2.7
Visual Studio: 2017, 2019
The RasterDataset
class represents a raster dataset stored in a storage media, file system or a geodatabase. A RasterDataset
is a file raster dataset if it is opened from a file system and it is a database raster dataset if it is opened from a file geodatabase or an enterprise geodatabase. A file raster dataset and a geodatabase raster dataset behave the same except for some minor differences.
A RasterDataset
has properties associated with it that can accessed using the RasterDefinition
class. The RasterDatasetDefinition
associated with a RasterDataset
can be obtained using the GetDefinition
method. A RasterDataset
is composed of one or more persistent raster bands. You can get a RasterBand
from a RasterDataset
by using the GetBand
and GetBandByName
methods. A RasterBand
has properties associated with it that can accessed using the RasterBandDefinition
class. The RasterBandDefinition
associated with a RasterBand
can be obtained using the GetDefinition
method.
// Get the RasterDatasetDefinition from the raster dataset.
RasterDatasetDefinition rasterDatasetDefinition = rasterDataset.GetDefinition();
// Get the number of bands from the raster band definition.
int bandCount = rasterDatasetDefinition.GetBandCount();
// Get a RasterBand from the raster dataset.
RasterBand rasterBand = rasterDataset.GetBand(0);
// Get the RasterBandDefinition from the raster band.
RasterBandDefinition rasterBandDefinition = rasterBand.GetDefinition();
// Get the name of the raster band from the raster band.
string bandName = rasterBandDefinition.GetName();
The RasterDataset
class can be used to create a Raster
using the CreateDefaultRaster
, CreateRaster
and CreateFullRaster
methods.
- The
CreateFullRaster
method creates a raster with all the properties from the raster dataset, such as number of bands and width and height of the raster dataset. - The
CreateDefaultRaster
method creates a raster that has a square cell size and contains only three raster bands even if the dataset has more than three bands. The three bands are the default bands used in the raster RGB colorizer. - The
CreateRaster
method creates a raster that has the same properties and the given list of bands from a raster dataset.
A RasterDataset
can be opened using the FileSystemDataStore
class for a file raster dataset or Geodatabase
class for a geodatabase raster dataset.
// Create a FileSystemConnectionPath using the folder path.
FileSystemConnectionPath connectionPath =
new FileSystemConnectionPath(new System.Uri(@"C:\Temp"), FileSystemDatastoreType.Raster);
// Create a new FileSystemDatastore using the FileSystemConnectionPath.
FileSystemDatastore dataStore = new FileSystemDatastore(connectionPath);
// Open the raster dataset.
RasterDataset fileRasterDataset = dataStore.OpenDataset<RasterDataset>("Sample.tif");
// Create a FileGeodatabaseConnectionPath using the path to the gdb. Note: This can be a path to a .sde file.
FileGeodatabaseConnectionPath geodatabaseConnectionPath =
new FileGeodatabaseConnectionPath(new Uri(@"C:\Temp\rasters.gdb"));
// Create a new Geodatabase object using the FileGeodatabaseConnectionPath.
Geodatabase geodatabase = new Geodatabase(geodatabaseConnectionPath);
// Open the raster dataset.
RasterDataset gdbRasterDataset = geodatabase.OpenDataset<RasterDataset>("sample");
In addition to being accessed through a workspace, the RasterDataset
can also be retrieved from a Raster
using the GetRasterDataset
method.
The MosaicDataset
class represents a mosaic dataset on disk or in a geodatabase. A flag indicating whether a MosaicDataset
is referenced can accessed using the MosaicDatasetDefinition
class. The MosaicDatasetDefinition
associated with a MosaicDataset
can be obtained using the GetDefinition
method.
A MosaicDataset
can be opened using the FileSystemDataStore
class for a file raster dataset or Geodatabase
class for a geodatabase raster dataset.
// Create a FileGeodatabaseConnectionPath using the path to the gdb.
FileGeodatabaseConnectionPath connectionPath = new FileGeodatabaseConnectionPath(new System.Uri(dataStorePath));
// Create a new Geodatabase object using the FileGeodatabaseConnectionPath.
Geodatabase gdb = new Geodatabase(connectionPath);
// Open the Mosaic dataset.
MosaicDataset mosaicDatasetToOpen = gdb.OpenDataset<MosaicDataset>(name);
// Create a FileSystemConnectionPath using the path to the folder.
FileSystemConnectionPath connectionPath =
new FileSystemConnectionPath(new System.Uri(@"c:\test"), FileSystemDatastoreType.Raster);
// Create a new FileSystemDatastore using the FileSystemConnectionPath.
FileSystemDatastore dataStore = new FileSystemDatastore(connectionPath);
// Open the Mosaic dataset.
MosaicDataset mosaicDatasetToOpen = dataStore.OpenDataset<MosaicDataset>("testmosaicdataset.amd");
The MosaicDataset
class has methods that allow you to access the tables associated with a mosaic dataset:
- GetCatalog: This method returns a feature class representing the catalog (attribute) table of the mosaic dataset.
- GetBoundary: This method returns a feature class representing the boundary table of the mosaic dataset.
- GetSeamline: This method returns a feature class representing the seamline table of the mosaic dataset if it exists.
- GetStereoTable: This method returns a feature class representing the stereo table of the mosaic dataset if it exists.
To access the image related properties of the mosaic dataset, cast the MosaicDataset
class to the Raster
class. This will allow you to access image related properties and pixels of the mosaiced image.
To access the raster dataset from the raster field of the mosac dataset catalog table, use the RasterValue
class.
// Get the catalog table from the mosaic dataset
FeatureClass mdCatalog = mosaicDataset.GetCatalog();
// Use the row cursor to get rows from the catalog.
RowCursor catalogCursor = mdCatalog.Search();
while (catalogCursor.MoveNext())
{
// Get the feature from the current row.
Feature currFeature = catalogCursor.Current as Feature;
// Get the value for the Raster field.
var rasterFieldVal = currFeature["RASTER"];
RasterValue rasterVal = rasterFieldVal as RasterValue;
// Use the RasterValue class to get the raster dataset.
RasterDataset rasterValrasterDataset = rasterVal.GetRasterDataset();
}
The Raster
class, in contrast to the static RasterDataset
and RasterBand
classes, is transient in nature and can be modified without affecting the source data. This allows the raster to represent what you want—for example, you can set a transformation on a raster, specify a projection or extent, and set other properties without changing the underlying raster dataset. If you want to persist the change, the modified raster can be saved to another raster dataset using the SaveAs
method. As such, a Raster
is most easily understood as a vehicle to provide re sampling, transformation, and data type conversion from one or more raster bands to a desired output coordinate system.
A Raster
can be used to get and set properties such as extent, width, height, spatial reference, pixel type, and NoData
value. Re-sampling occurs when the raster is changed geometrically, such as setting an extent, a spatial reference, or a geodata transformation. In this case, the SetResampleType
method can be used to specify the re-sampling method, and it will be applied during SaveAs
or during raster display.
You can get the cell size of a raster using the GetMeanCellSize
method. However, setting a cell size for a raster should be done by adjusting the width, height, and extent of the raster. If the height and/or width are changed, the cell size of the raster will be recalculated using the new height and width to divide the current raster extent. In this case, it will most likely result in a raster with non-square cell size.
The MapToPixel
and PixelToMap
methods are used to perform a transformation between pixel and map space. You can get the column and row in pixel space by passing x and y coordinates in map space and vice versa. The GetPixelValue
method can be used to identify a pixel value on a raster by specifying the column and row of the pixel.
A raster can be obtained from a RasterLayer, MosaicLayer or ImageServiceLayer using the GetRaster
method. The raster obtained in this way represents the raster that is rendered using the Colorizer associated with the layer. The raster dataset that the raster was created from can be obtained by using the GetRasterDataset
method.
The PixelBlock
class is a container for pixel arrays. It has the properties of width, height, pixel type, and number of planes. Each plane is a pixel array corresponding to one raster band. The PixelBlock
class can handle generic pixel arrays from any raster data source. To support different pixel types, PixelBlock
transports pixels in an Array, which can contain many different data types.
The PixelBlock
class is used to read, modify, and write pixel values or a portion of pixel values of the raster data. Create a pixel block from a raster using the CreatePixelBlock
method. This initializes the size and other properties of the pixel block. Use the Read
method to read the pixel values into the pixel block, then use the GetPixelData
method to get and/or modify the pixel values of the pixel block. The Write
and Erase
methods can be used to write and erase the pixel block to the raster dataset respectively.
// Create a full raster from the raster dataset.
ArcGIS.Core.Data.Raster.Raster raster = rasterDataset.CreateFullRaster();
// Calculate size of pixel block to create. Use 128 or height/width of the raster, whichever is smaller.
int pixelBlockHeight = raster.GetHeight() > 128 ? 128 : raster.GetHeight();
int pixelBlockWidth = raster.GetWidth() > 128 ? 128 : raster.GetWidth();
// Create a new (blank) pixel block.
PixelBlock currentPixelBlock = raster.CreatePixelBlock(pixelBlockWidth, pixelBlockHeight);
// Read pixel values from the raster dataset into the pixel block starting from the given top left corner.
raster.Read(0, 0, currentPixelBlock);
// Do something with the pixel block...
// Write the pixel block to the raster dataset starting from the given top left corner.
raster.Write(0, 0, currentPixelBlock);
await QueuedTask.Run(() =>
{
// Read pixel values from the raster dataset into the pixel block starting from the given top left corner.
raster.Read(0, 0, currentPixelBlock);
// For each plane (band) in the pixel block
for (int plane = 0; plane < currentPixelBlock.GetPlaneCount(); plane++)
{
// Get a copy of the array of pixels from the pixel block corresponding to the current plane.
Array sourcePixels = currentPixelBlock.GetPixelData(plane, true);
// Get the height and width of the pixel block.
int pBHeight = currentPixelBlock.GetHeight();
int pBWidth = currentPixelBlock.GetWidth();
// Iterate through the pixels in the array.
for (int i = 0; i < pBHeight; i++)
{
for (int j = 0; j < pBWidth; j++)
{
// Get the NoData mask value to see if the pixel is a valid pixel.
if (Convert.ToByte(currentPixelBlock.GetNoDataMaskValue(plane, j, i)) == 1)
{
// Get the pixel value from the array and process it (add 5 to the value).
// Note: This is assuming the pixel type is Unisigned 8bit.
int pixelValue = Convert.ToInt16(sourcePixels.GetValue(j, i)) + 5;
// Make sure the pixel value does not go above the range of the pixel type.
pixelValue = pixelValue > 254 ? 254 : pixelValue;
// Set the new pixel value to the array.
// Note: This is assuming the pixel type is Unisigned 8bit.
sourcePixels.SetValue(Convert.ToByte(pixelValue), j, i);
}
}
}
// Set the modified array of pixels back to the pixel block.
currentPixelBlock.SetPixelData(plane, sourcePixels);
}
// Write the pixel block to the raster dataset starting from the given top left corner.
raster.Write(0, 0, currentPixelBlock);
});
For a small raster dataset, the size of the pixel block can be the size of the entire dataset, which can usually be held in memory at one time. When working with a large amount of raster data, the best practice is to divide the raster into small pixel blocks and perform reading and writing pixels block by block using the RasterCursor
class.
The CreateCursor
method on the Raster
class provides a simple way to create a RasterCursor
with a user-specified pixel block size.
await QueuedTask.Run(() =>
{
// Create a full raster from the raster dataset.
ArcGIS.Core.Data.Raster.Raster raster = rasterDataset.CreateFullRaster();
// Calculate size of pixel blocks to process. Use 1000 or height/width of the raster, whichever is smaller.
int pixelBlockHeight = raster.GetHeight() > 1000 ? 1000 : raster.GetHeight();
int pixelBlockWidth = raster.GetWidth() > 1000 ? 1000 : raster.GetWidth();
// Create the raster cursor using the height and width calculated.
RasterCursor rasterCursor = raster.CreateCursor(pixelBlockWidth, pixelBlockHeight);
// Use a do while loop to iterate through the pixel blocks of the raster using the raster cursor.
do
{
// Get the current pixel block from the cursor.
PixelBlock currentPixelBlock = rasterCursor.Current;
// Do something with the pixel block...
// Once you are done, move to the next pixel block.
}
while (rasterCursor.MoveNext());
});
Pixels, or cells, in a raster dataset that are missing information are called NoData. For a file-based raster dataset, NoData is stored as a value in the raster dataset. The pixels that have the same value as the NoData value are NoData pixels. For a database raster dataset, NoData pixels are stored as a bit mask—a two-dimensional array of 0s and 1s, where 0 represents that the corresponding pixel is a NoData pixel.
The GetNoDataValue and
SetNoDataValue` methods can be used to get and set the NoData value on a raster. The NoData value is used in saving (SaveAs) to a new dataset.
The GetNoDataValue
can also be used to get the NoData value on a RasterBand
.
The NoData value is used in writing pixel blocks to the raster dataset. For mask-based NoData, the SetNoDataMask
method on the PixelBlock
class can be used to set NoData when writing pixel blocks.
Raster data can be visualized in ArcGIS Pro by adding it to a 2D or 3D map as a layer. The type of layer added to the map depends on the type of raster data.
An image or pixel data on disk or in a geodatabase is represented as a RasterLayer
. Learn more about raster layers.
A mosaic dataset is represented as a special type of group layer called a MosaicLayer
. Learn more about mosaic layers.
Raster data from an Image Service is represented as an ImageServiceLayer
. Learn more about image service layers.
The way in which raster data is visualized is controlled by a colorizer. All raster layers (raster, mosaic and image service layers) have a colorizer associated with them. Learn more about colorizers.