Creating a custom iImage tool which accepts BYTESCALE_RANGE as a keyword.
Topic:
This help article provides an example of a custom iTool that will accept BYTESCALE_RANGE as a keyword. This keyword is used to set the minimum and maximum values used for byte-scaling.Discussion:
Creating this custom iTool involves two steps:
1. Create a launch routine (See MyImage.pro below) that will essentially be a wrapper around the iImage tool. It will accept a DATA argument (which should be an image), all keywords accepted by iImage, and the BYTESCALE_RANGE keyword (which will be used to determine the minimum and maximum values used for byte-scaling the displayed image). When the BYTESCALE_RANGE keyword is set, a new ParameterSet object must be created. The IMAGE_DIMENSIONS, IMAGE_LOCATION and RGB_TABLE keywords are not passed using _EXTRA. These keywords are used to add all of the necessary information to the ParameterSet object passed to the visualization class. See the comments in the code for details.
2. Since we are now accepting a new keyword, we must also define/register a new visualization class (See BSRangeVisImage__Define.pro below), which will be prepared to handle this additional information. Since the majority of the functionality needed is already in the IDLitVisImage object class, the new class will inherit the IDLitVisImage visual class. All methods, with the exception of the OnDataChangeUpdate method, will be used directly from the inherited visual class. Since the OnDataChangeUpdate method handles the appearance of the image, this method must be modified to handle the new keyword (BYTESCALE_RANGE) when necessary. See the comments in the code for details.
Here is an example using this tool:
Create some fake data
IDL> data = dist(100)
To fully see the affect of the BYTESCALE_RANGE keyword, we will get the data's range
IDL> print, min(data, max = mx), mx
0.000000 70.7107
Set the minimum byte scale value to be 20 and the maximum byte scale value to be 50.
IDL> myimage, data, bytescale_range = [20, 50]
The resulting image will have all pixels where the data is less than 20 set to 0, and all pixels where the data is greater than 50 set to 255.Solution:
;*********************** MyImage.pro ************************
pro myimage, data, $
bytescale_range = bytescale_range, $
image_location = imagelocation, $
image_dimensions = imagedimensions, $
rgb_table = rgbtable, $
_extra = _extra
; Register the BSRangeVisImage visualization.
itregister, 'my image tool', 'bsrangevisimage', $
/visualization
case (size(data))[0] of
0: $ ; No data has been passed
iimage, visualization_type = 'my image tool', $
_extra = _extra
2: begin ; Single plane image.
if keyword_set(bytescale_range) then begin
; Initialize an IDLitParameterSet object for
; passing information to BSRangeVisImage.
oparmset = obj_new('idlitparameterset')
; Add the image data to the IDLitParameterSet object.
oparmset -> add, obj_new('idlitdataidlimagepixels', $
data, $
name = 'Image Plane', $
identifier='imagepixels', $
_extra = _extra), $
parameter_name='imagepixels'
if ((n_elements(imagelocation) eq 2) or $
(n_elements(imagedimensions) eq 2)) then begin
; IMAGE_LOCATION or/and IMAGE_DIMENSIONS is/are set.
; Get the dimensions of the input data
imgdims = size(data, /dimensions)
if (n_elements(imagelocation) eq 2) then begin
; IMAGE_LOCATION keyword set.
; Set XMIN and XMAX according to IMAGELOCATION.
xmin = imagelocation[0]
ymin = imagelocation[1]
endif else begin
; Otherwise set XMIN and XMAX to 0.
xmin = 0
ymin = 0
endelse
if (n_elements(imagedimensions) eq 2) then begin
; IMAGE_DIMENSIONS keyword set.
; Set XMAX, YMAX and DELTA according to
; IMAGEDIMENSIONS.
xmax = xmin + imagedimensions[0]
ymax = ymin + imagedimensions[1]
delta = double(imagedimensions) / double(imgdims)
endif else begin
; Otherwise, use the data's dimensions to set
; XMAX and YMAX.
xmax = xmin + imgdims[0]
ymax = ymin + imgdims[1]
delta = [1.0,1.0]
endelse
; Create X and Y vectors/coordinates for the data.
x = dindgen(imgdims[0])*delta[0] + xmin
y = dindgen(imgdims[1])*delta[1] + ymin
; Add the X vector information to the
; IDLitParameterSet object.
if (obj_valid(oparmset) ne 0) then begin
oparmset->add, obj_new('idlitdataidlvector', $
x, name='x'), parameter_name='x'
; Add the Y vector information to the
; IDLitParameterSet object.
oparmset->add, obj_new('idlitdataidlvector', $
y, name='y'), parameter_name='y'
endif
endif
; Add the BYTESCALE_RANGE information to the
; IDLitParameterSet object.
oparmset -> add, obj_new('idlitdataidlvector', $
bytescale_range, $
identifier = 'bytescale_range', _extra = _extra)
if (n_elements(rgbtable) ne 0) then begin
; RGB_TABLE keyword is set.
; Copile iImage so the _SetPalette routine can
; be used to add the palette information to the
; IDLitParameterSet object.
resolve_routine, 'iimage', /compile_full_file, $
/no_recompile
_setpalette, oparmset, rgbtable
endif
; Pass the IDLitParameterSet object to iImage setting
; the VISUALIZATION_TYPE to "My IMage".
iimage, initial_data = oparmset, $
visualization_type = 'my image tool', $
_extra = _extra
endif else $
iimage, data, visualization_type = 'my image tool', $
_extra = _extra
end
else: $
; Pass DATA to iImage. BYTESCALE_RANGE will be ignored
; in all cases other than a single plane image.
iimage, data, visualization_type = 'my image tool', $
_extra = _extra
endcase
end
;************************************************************
;**************** BSRangeVisImage__Define.pro ****************
;***** Initialization *****
function bsrangevisimage::init, _ref_extra = _extra
; Initialize the inherited IDLitVisImage superclass.
if (self -> idlitvisimage::init() ne 1) then $
return, 0
if(n_elements(_extra) gt 0)then $
self->IDLitVisImage::SetProperty, _extra=_extra
return, 1 ; Success.
end
;***** OnDataChangeUpdate method *****
; This method will override the OnDataChangeUpdate method
; of the inherited object class. Unless a parameter with
; identifier BYTESCALE_RANGE is encountered, the methods
; from the super class will be called.
pro bsrangevisimage::ondatachangeupdate, osubject, parmname, $
no_subrect_update=nosubrectupdate
; Input parameters.
if strlowcase(parmname) eq '' then begin
; Get the number of parameters and their names.
oparams = osubject->get(/all, count = nparam, $
name = paramnames)
; Cycle through the input parameters.
for i = 0, nparam-1 do begin
; Get the identifier for the parameter.
oparams[i] -> getproperty, identifier = temp
if strlowcase(temp) eq 'bytescale_range' then begin
; BYTESCALE_RANGE parameter encountered.
; Get the byte-scale range.
r = oparams[i] -> getdata(data)
; Set the BYTESCALE_MIN and BYTESCALE_MAX
; properties.
self -> setproperty, $
bytescale_min = data[0], $
bytescale_max = data[1]
endif else $
; If not the RANGE parameter, call the
; OnDataChangeUpdate method of the
; IDLitVisImage superclass.
self -> idlitvisimage::ondatachangeupdate, $
osubject, parmname, $
no_subrect_update = nosubrectupdate
endfor ; i = 0, nparams-1
endif else $
; Pass all other parameters to the OnDataChangeUpdate
; method of the IDLitVisImage superclass.
self -> idlitvisimage::ondatachangeupdate, $
osubject, parmname, $
no_subrect_update = nosubrectupdate
end
;***** Class Definition *****
pro bsrangevisimage__define
; Define the BSRangeVisImage class structure which
; inherits the IDLitVisImage class.
struct = {bsrangevisimage, $
inherits idlitvisimage}
end
;************************************************************