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 IIMAGE
.
There are two files for this demo program: mgitopadapthistequal__define.pro
(doc) to define the operation and mg_dataop_demo.pro
(doc) to setup using the operation. To run the demo, make sure both files are compiled or in your path and run MG_DATAOP_DEMO
.
You’ll probably want to look at the documentation for the parent classes of our class: IDLitComponent
, IDLitIMessaging
, IDLitOperation
, and 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.
The init
and cleanup
methods
The init
method has several jobs:
- call
IDLitDataOperation::init
with the proper keywords (TYPES
and_EXTRA
), - register properties, and
- initialize member variables (properties).
As usual for a subclass’ init
method, the first task is to call the parent’s init
method:
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 _EXTRA
. The TYPES
determines which itools data types the operation will act on. The REVERSIBLE_OPERATION
and 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::registerProperty
(IDLitComponent
is a parent class of IDLitDataOperation
). The positional parameter is the member variable name. The type is specified using the INTEGER
and 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 IDLitDataOperation::cleanup
.
The setProperty
and getProperty
methods
The setProperty
and getProperty
methods are fairly standard. They must provide access to all registered properties and must pass keywords on to IDLitDataOperation::setProperty
and IDLitDataOperation::getProperty
.
The doExecuteUI
, execute
, and undoExecute
methods
The 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.
The 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).
The undoExecute
method is not needed for this operation because REVERSIBLE_OPERATION
is not set.
Using the operation
MG_DATAOP_DEMO
puts MGitOpAdaptHistEqual
into 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)
Here, 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.
June 20th, 2006 at 5:01 pm
[…] For simple operations, subclassing IDLitDataOperation is an easy way to quickly add an operation to the iTools system. See previous post “Creating an iTool data operation” for more information about IDLitDataOperation. If you want to do anything more complicated than a numeric operation on the dependent variable of the currently selected visualization, then you want to subclass IDLitOperation. We will examine a fairly simple subclass of IDLitOperation, MGitOpDerivative, which calculates the derivative of data in a plot visualization. […]
July 17th, 2006 at 7:58 pm
[…] The iTools are easy to use interactively (O.K., easy once you learn some of the conventions and jargon). But they also have the ability to be extended and controlled programmatically. I have given a couple examples of extending an iTool with new operations (data operation, general operation). I’ll post more extending iTools visualizations, file readers/writers, manipulators, user interface services, and custom user interfaces in the weeks to follow. But programmatically controlling an iTool is both fairly easy and extremely useful, especially in situations where a visualization needs to be created which further needs to be explored interactively. […]