ENVI API Frequently Asked Questions
This topic provides a list of common questions and answers related to programming in ENVI.
Data Management
- How do I view the properties of a data file?
- How do I open and process multiple files in a loop?
- How do I set a data value to ignore?
- How do I convert the pixel values of a raster to a different data type?
- What are Hydrate and Dehydrate routines used for?
Analytics
- How do I find a list of task names?
- Some data-processing operations are available as a virtual raster and an ENVITask. Which one should I use?
- How do I save the results of an ENVITask to a file on disk?
- How do I perform band math with rasters?
- How do I create and apply masks?
Regions of interest (ROIs)
Data Management
How do I view the properties of a data file?
Print the properties of a raster, vector, or region of interest (ROI) object, as the following example shows:
IDL> e = ENVI()
ENVI> File = FILEPATH('qb_boulder_msi', $
Subdir=['data'], Root_Dir=e.Root_Dir)
ENVI> Raster = e.OpenRaster(File)
ENVI> Print, Raster
IDL prints the basic properties of the input file such as the data type (unsigned integer), number of bands (4), number of columns (1024), and number of rows (1024). See the Properties section of the ENVIRaster, ENVIVector, ENVIPointCloud, or ENVIROI help topics for descriptions of each property.
To determine the spatial reference of a raster object, issue a PRINT statement on the SPATIALREF property, as follows:
ENVI> Print, Raster.SPATIALREF
IDL prints details of the spatial reference such as the coordinate system, pixel size, rotation angle, tie point map coordinates, and the pixel location of the tie point coordinates.
Note: Vectors do not have spatial references, but they have coordinate systems. See Map Information for details.
Rasters also have metadata. Issue a print statement on the METADATA property to see the available metadata fields:
ENVI> Print, Raster.METADATA
To get the details of a particular metadata field, use brackets and single quotes as follows:
ENVI> Print, Raster.METADATA['wavelength']
How do I open and process multiple files in a loop?
Use the following code as a template. It opens multiple image files from disk, including all subdirectories underneath the indicated directory. It uses a FOR loop to process the data.
- Be sure to include PRO and END statements, along with the COMPILE_OPT IDL2 statement.
- The HEADLESS keyword to the ENVI function will process the data in batch mode without displaying the user interface. To display the user interface in your script, remove this keyword.
- Replace
C:\MyData\
with a valid path to your own data files, and change the.tif
file type to that of your own data files.
PRO ProcessMultipleFilesExample
COMPILE_OPT IDL2
; Start the application
e = ENVI(/HEADLESS)
; Select input files
Files = File_Search('C:\MyData\', '*.tif')
FOR i=0, N_Elements(Files)-1 DO BEGIN
Raster = e.OpenRaster(Files[i])
; data processing here
ENDFOR
END
How do I set a data value to ignore?
To permanently set a data value to ignore on one or more rasters, use the ENVIRasterMetadata::UpdateItem or ENVIRasterMetadata::AddItem method, depending on whether or not a 'data ignore value' header field exists. Then write the resulting metadata to an ENVI header file. For example, suppose that a data vendor distributes imagery with ocean pixels set to a fill value of -9999. Set a data ignore value as follows:
PRO SetDataIgnoreValue
COMPILE_OPT IDL2
; Start the application
e = ENVI()
; Open the raster
file = 'C:\Data\Myfile.dat'
raster = e.OpenRaster(file)
; Set a data ignore value
metadata = raster.METADATA
IF (metadata.HasTag ('data ignore value')) THEN BEGIN
metadata.UpdateItem, 'data ignore value', -9999.0
ENDIF ELSE BEGIN
metadata.AddItem, 'data ignore value', -9999.0
ENDELSE
; Save the raster to ENVI format so that the
; header file will update
outFile = e.GetTemporaryFilename()
raster.Export, outFile, 'ENVI'
END
To temporarily set a data value to ignore when displaying a raster, set the DATA_IGNORE_VALUE keyword of the ENVI::OpenRaster method. This overrides any data ignore values already set in the header file, but it does not update the header file. For example:
file = 'C:\Data\Myfile.dat'
raster = e.OpenRaster(file, DATA_IGNORE_VALUE=-9999.0)
You can also set a unique data value for pixels that have a non-zero pixel state (NoData, Mask, Outside of ROI) when exporting a raster to disk. Here is an example that masks any pixels that are outside of a selected ROI. If you were to display the masked raster immediately after creating it, you would not see the masked pixels. In this case, you must export the masked raster and set the DATA_IGNORE_VALUE keyword to 0. When you reopen and display the masked raster, you will see the masked pixels.
; Start the application
e = ENVI()
; Open an input file
file = FILEPATH('qb_boulder_msi', ROOT_DIR=e.ROOT_DIR, $
SUBDIRECTORY = ['data'])
raster = e.OpenRaster(file)
; Open a multi-part ROI
fileName = Filepath('qb_boulder_roi.xml', SUBDIR=['data'], $
ROOT_DIR=e.Root_Dir)
rois = e.OpenRoi(fileName)
; Create a masked raster based on the water ROI.
; Pixels outside of the ROI are masked.
mask = ENVIRoiMaskRaster(raster, rois[2])
; Save the masked raster to disk
outFile = e.GetTemporaryFilename()
mask.Export, outFile, 'ENVI', DATA_IGNORE_VALUE=0
See Masks for more information about creating and applying raster masks in ENVI.
How do I convert the pixel values of a raster to a different data type?
The process of converting data types (for example, integer to floating-point) is called casting or type-casting. Use ENVICastRaster or the CastRaster task for this purpose.
What are Hydrate and Dehydrate routines used for?
When using the ENVI API, you may have come across routines that are named Hydrate and Dehydrate. These pertain to a concept in computer science called serialization, where data objects are reduced into a simple format so they can be stored and transferred to different environments. The objects can be reconstructed back to their original form later. In the case of ENVI, objects such as ENVIRaster or ENVICoordSys can be dehydrated into text format so that they can be used in cloud-computing environments. Then they can be hydrated in order to restore them to their full state.
See the Dehydrate and Hydrate topics for ENVI API routines (for example, ENVIRaster::Dehydrate and ENVIRaster::Hydrate) for details on usage.
Analytics
Where can I find a list of task names?
See the ENVITask help topic for a list of available data-processing tasks. To print task names and the details of individual tasks, use these options:
Task_Names Property
This is the most common method for printing a list of task names. Type the following at the IDL command line:
IDL> e = ENVI()
ENVI> Print, e.Task_Names
Use a string from the resulting list to create an instance of a task, for example:
ENVI> Task = ENVITask('ISODATAClassification')
Print the task variable to learn what that task does:
ENVI> Print, Task
QueryTaskCatalog
You can access the catalog of ENVITasks anytime within a script by using the QueryTaskCatalog task:
Task = ENVITask('QueryTaskCatalog')
Task.Execute
taskNames = Task.TASKS
Use the QueryTask task to access details of a selected task within the catalog:
Task = ENVITask('QueryTask')
Task.Task_Name = 'ISODATA Classification'
Task.Execute
taskDefinition = Task.DEFINITION
Some data-processing operations are available as a virtual raster and an ENVITask. Which one should I use?
See the Virtual Rasters topic for more information about virtual rasters and how they differ from ENVITasks.
How do I save the result of an ENVITask to a file on disk?
Set the OUTPUT_RASTER_URI property to a valid path and filename for the raster. The result will be in ENVI raster format. Here is an example of saving a median filter image to disk:
; Start the application
e = ENVI()
; Open an input file
File = Filepath('qb_boulder_msi', Subdir=['data'], $
Root_Dir=e.Root_Dir)
Raster = e.OpenRaster(File)
; Run the Median Filter task
Task = ENVITask('MedianFilter')
Task.INPUT_RASTER = Raster
Task.WINDOW_SIZE = 5
Task.OUTPUT_RASTER_URI = 'C:\MyData\MedianRaster.dat'
Task.Execute
ENVITasks that create vector output (for example, the ClassificationToShapefile task) behave similarly. In these cases, set the OUTPUT_VECTOR_URI property and provide a .shp
file extension.
You can also have ENVI automatically create a filename and save the result to your system's temporary directory. Use the ENVI::GetTemporaryFilename method in conjunction with the OUTPUT_RASTER_URI property.
Task.OUTPUT_RASTER_URI = e.GetTemporaryFilename()
The resulting file remains in your system's temporary directory when you close the ENVI session; you must delete it manually if you no longer need it.
You can also save a raster to PNG, NITF 2.0, NITF 2.1, NSIF 1.0, and TIFF formats. Use the following tasks:
When creating a custom task that creates raster output, set the direction
key to output
for the OUTPUT_RASTER parameter in the task template. For example:
"name": "OUTPUT_RASTER",
"keyword": "OUT_FILENAME",
"display_name": "Output Raster",
"type": "ENVIRASTER",
"direction": "output",
"required": true,
"description": "This is a reference to the output raster of filetype ENVI."
By doing this, ENVI will automatically create an OUTPUT_RASTER_URI input property.
How do I perform band math with rasters?
Use ENVIPixelwiseBandMathRaster to apply a mathematical expression to a raster on a pixel-by-pixel basis. You must name the band variables as bx, where x is the order of the band (not the band number). For example, b1 is the first band in the raster, b2 is the second band, and so forth. Here is an example:
; Start the application
e = ENVI()
; Open an input file
file = FILEPATH('qb_boulder_msi', ROOT_DIR=e.ROOT_DIR, $
SUBDIRECTORY = ['data'])
raster = e.OpenRaster(file)
; Calculate enhanced NDVI
expression = '((b4 + b2) - 2*b1) / ((b4 + b2) + 2*b1)'
bandMathRaster = ENVIPixelwiseBandMathRaster(raster, expression)
; Display the result
View = e.GetView()
Layer = View.CreateLayer(bandMathRaster)
If you are writing a script that uses ENVITasks, use the PixelwiseBandMathRaster task.
How do I create and apply masks?
Please refer to the Masks topic, which describes working with masks in the ENVI user interface and API.
Regions of Interest (ROIs)
How do I process the pixels within an ROI?
You can do some simple tasks with ROIs using the ENVI API:
- Get the pixel addresses
- Count the number of pixels within the ROI
- Create masks using ROI thresholds
- Create a classification image
However, you may want process the pixels within an ROI, for example calculating statistics or analyzing the pixel data. Set the ROI keyword in the ENVIRaster::GetData method to retrieve the pixel data within an ROI. The following example shows how to calculate the mean value of the pixels in a multi-part ROI:
PRO GetROIExample
COMPILE_OPT IDL2
; Start the application
e = ENVI(/HEADLESS)
; Open an input raster
file = FILEPATH('qb_boulder_msi', ROOT_DIR=e.ROOT_DIR, $
SUBDIRECTORY = ['data'])
raster = e.OpenRaster(file)
; Open an ROI file
file = FILEPATH('qb_boulder_roi.xml', ROOT_DIR=e.ROOT_DIR, $
SUBDIRECTORY = ['data'])
rois = e.OpenRoi(file)
FOREACH roi, rois DO BEGIN
pixelData = raster.GetData(ROI=roi)
mean = Total(pixelData,1, /DOUBLE) / roi.PixelCount(raster)
Print,'Roi: ' + roi.Name
Print,'Mean = ', mean
ENDFOREACH
END
Big ROIs will return a large amount of data. To avoid returning too much data, use a combination of ENVIROIMaskRaster and ENVIRaster::GetData as follows:
- Use the ENVIRaster::GetData method while setting the PIXEL_STATE keyword, to retreive the pixel data within the ROI.
- Get the locations (indices) of the "good" pixels in the masked raster, i.e., non-masked pixels. See Raster Pixel State for details.
- Do some processing on the ROI data.
Example:
; Launch the application
e = ENVI()
; Open and display an ENVIRaster
file = FILEPATH('qb_boulder_msi', ROOT_DIR=e.ROOT_DIR, $
SUBDIR = ['data'])
raster = e.OpenRaster(file)
View = e.GetView()
Layer = View.CreateLayer(raster)
; Open a multi-part ROI
ROIFile = FILEPATH('qb_boulder_roi.xml', $
ROOT_DIR=e.ROOT_DIR, SUBDIR = ['data'])
rois = e.OpenROI(ROIFile)
; Display the water ROI only
waterROILayer = Layer.AddROI(rois[2])
; Print the number of pixels in this ROI
Print, 'Number of pixels in this ROI layer: ',rois[2].PixelCount(raster)
; Create a masked raster using the water ROI
maskedRaster = ENVIROIMaskRaster(raster, rois[2])
; Get the data values
data = maskedRaster.GetData(PIXEL_STATE=pixelState)
; Exclude pixels that have no data
goodIndices = where(pixelState eq 0)
; Process the good pixels
goodData = data[goodIndices]
; processing here
If you issue a Help command on the goodData
variable, you will see that it is an unsigned integer array with 14,716 elements. This ROI has 3,679 pixels with four bands of data (3679 * 4 = 14716).