The ability to extend the itools is one of their main strengths. This can be adding a button for an operation (like our example here), the capability to read/write new file types, new visualizations, or new ways to manipulate visualizations. Plus, the user interface can be customized to various levels. Toolbars and panels can be added to the standard configuration, but a totally custom interface can be created also. Capabilities can also be removed to provide a simpler interface for a specific task.
This example adds an adaptive histogram equalization operation to
There are two files for this demo program:
doc) to define the operation and
doc) to setup using the operation. To run the demo, make sure both files are compiled or in your path and run
You’ll probably want to look at the documentation for the parent classes of our class:
IDLitDataOperation during the course of this tutorial.
Define the member variables
The member variables will include all the properties of the operation, plus whatever else is needed to be stored during the life of the operation. The properties will be registered in the
init method using the names defined here.
init method has several jobs:
IDLitDataOperation::initwith the proper keywords (
- register properties, and
- initialize member variables (properties).
As usual for a subclass’
init method, the first task is to call the parent’s
if (~self->idlitdataoperation::init(types=['IDLARRAY2D'], $ name='Adapt Hist Eq', $ icon='image', $ reversible_operation=0B, $ expensive_operation=0B, $ _extra=e)) then return, 0L
Note that it is important that it get passed
TYPES determines which itools data types the operation will act on. The
EXPENSIVE_OPERATION keywords relate to the undo/redo system.
REVERSIBLE_OPERATION determines what happens when the user undo’s the operation. If
REVERSIBLE_OPERATION is set, then the
undoExecute method is called. If
REVERSIBLE_OPERATION is not set, then the itools will cache data before the operation is executed so that it can be restored when it is undone.
EXPENSIVE_OPERATION determines the behavoir after the operation is undone. If
EXPENSIVE_OPERATION is set, then the result of the operation is cached so it can be redone without having to calculate it again. If not set it must be calculated again via the
execute method if it is redone.
self->registerProperty, 'clip', /float, $ description='Slope limit of histogram', $ name='Clip', $ sensitive=1
Register properties of the operation via
IDLitComponent is a parent class of
IDLitDataOperation). The positional parameter is the member variable name. The type is specified using the
FLOAT keywords (others are available, though not corresponding to all the IDL types), but could be specifed via a code as the second positional parameter.
The cleanup method simply calls
getProperty methods are fairly standard. They must provide access to all registered properties and must pass keywords on to
doExecuteUI method is called to present a GUI for the user to modify properties, see a preview, etc. before the operation is executed. It gets the tool object reference, does a quick sanity check, and does a UI service:
otool = self->getTool() if (~otool) then return, 0L return, otool->doUIService('OperationPreview', self)
Documented predefined choices for services are: ‘PropertySheet’ or ‘OperationPreview’. You can also write your own UI service. Note that this method will not be called if the
SHOW_EXECUTION_UI property of the operation is not set.
execute method actually does the calculations of the operation. The function accepts a single positional parameter which is an input for the original data and an output for the operated upon data. This is the statement that actually does the adaptive histogram equalization:
data = adapt_hist_equal(bytscl(data), $ clip=self.clip, $ nregions=self.nregions, $ top=self.top)
The status of the execution is returned (1 for success, 0 for failure).
undoExecute method is not needed for this operation because
REVERSIBLE_OPERATION is not set.
Using the operation
IIMAGE and loads some default data. The itool is created with a data set in the standard way:
f = filepath('endocell.jpg', subdir=['examples', 'data']) endo = read_image(f) iimage, endo id = itGetCurrent(tool=otool)
ITGETCURRENT gets the itool identifier and object reference. We only need the object reference, but are required to get the identifier. Be sure to use
ITGETCURRENT right after creating the itool, because if another itool is created or even becames the current window in the OS, it will be the current itool.
otool->registerOperation, 'AdaptHistEqual', $ 'MGitOpAdaptHistEqual', $ identifier='Operations/AdaptHistEqual', $ icon='image'
This registers the operation on our itool. The positional parameters give a name for our operation and the classname that defines the operation. The
IDENTIFIER keyword locates the operation in the menu system. For instance, the identifier ‘File/AdaptHistEqual’ would put this in the File menu of the itool. More usefully, ‘Operations/My Operations/AdaptHistEqual’ would create a new submenu in the Operations menu and put this operation in it. The
ICON keyword specifies an icon for the operation in the operation browser. In this case,
icon='image' is equivalent to
icon = filepath('image.bmp', subdir=['examples', 'data'])
Hopefully, this will provide a template for further operations. I hope to provide more demos/templates/tutorials for other methods of extending the itools including file readers, file writers, general operations, manipulators, visualizations, UI services, user interface panels, and full-blown user interfaces.