BINARY_CLASS.PRO

BINARY_CLASS.PRO

posted 02-11-2001 06:41 PM
The IDL routine below, binary_class.pro, takes SPLUS splitting rules and classifies an ENVI image, writing the header file (.hdr) and a metadata file (.txt) It can handle subsetting on the fly, but maintaining projection info has been disabled as I work out a bug. It has been tested on integer data only (TM and PROBE-1). It may have problems with large files, it crashed on a 380 MB file, but classified a 25 MB image in 24.6 seconds. Give it a try and send feedback. – Kerry
*****************************************

; PRO BINARY_CLASS
;
; This IDL routine imports an Splus decision tree output file
; interprates the spliting rules, formating them into case and if/then statements
; then uses them to classify an ENVI image.
;
; It uses a modified IMPORT_ASCII.pro routine to import the ascii Splus file, as
; well as ENVI_SELECT, and DIALOG_PICKFILE to allow the user to select input/output
; files
;
; User should copy the binary decision tree summary from Splus and save it
; to a text file, adding a space followed by an asterisk to the end of the line that
; begins ‘1)’. The ascii import routine will prompt the user to select the text file.
; The user should set the delimiter to blank spaces and
; choose ‘data starts at line’ = 4 or whatever line contains rule 1).
; it is not necessary to name the fields or assign the field data types, but the number of
; lines needs to be set to the larger of the listed values.
; (Ex. if line number reads 12,11,11,12, set it to 12)
;
; written by Kerry Halligan, Feb 11, 2001.

pro binary_class

varname = strarr(1)
varname = call_function(‘IMPORT_ASCII_mod2′)

;use the envi_select widget to select the image that contains the data, fid will be file id of the open file, pos will be the number of bands
envi_select, title=’Input Filename of Image’, fid=fid, pos=pos, dims=dims, /NO_SPEC;, /NO_DIMS

;use envi_file_query to find out number of rows, samples, bands, byte order, and
;note interleave: 0= bsq, 1=bil, 2=bip
;note data type: 1=byt, 2=interger, 4=floating point (see progguid.pdf page 330 for more)
envi_file_query, fid, data_type=data_type, nb=nb, interleave=interleave, sname=imagename, fname=fullpath;, h_map=h_map
;handle_value, h_map, map_info

;calculate the number of lines and samples of the input image (this deals with subsetting)
ns = dims(2)-dims(1)+1
nl = dims(4)-dims(3)+1

;use pickfile to select the output image (starting path will be same as input ascii rulesfile)
outimage = dialog_pickfile(title=’Enter Filename of Output Classified Image’, get_path=gp, path=filename)

;set up and write the envi header for output image
bandname=strarr(1)
bandname[0]=’binary_class (‘+imagename+’)’
envi_setup_head, data_type=1, $
descrip=’Classified image from BINARY_CLASS.PRO using SPLUS binary decision tree splitting rules and ENVI ROIs’, $
file_type=0, fname=outimage+’.hdr’, interleave=0, nb=1, nl=nl, ns=ns, map_info=map_info, $
xstart=dims(1), ystart=dims(3), bnames=bandname, /WRITE

;open a metadata file that has the same name as the output image with a .meta at the end and start filling it
openw,u2,outimage+’.txt’, /GET_LUN
date_time = systime()
printf,u2,’Metadata file for BINARY_CLASS run ‘,date_time
printf,u2, ‘ ‘
printf,u2, ‘Input image : ‘,imagename
printf,u2, ‘Input image pathname: ‘,fullpath
printf,u2, ‘ ‘
printf,u2, ‘Output classified image : ‘,outimage
printf,u2, ‘Number of lines : ‘, nl
printf,u2, ‘Number of samples : ‘, ns
printf,u2, ‘Number of bands : ‘, 1
printf,u2, ‘Data type : byte’

;get total number of fields
ntags = N_TAGS(sname)
;reference fields using tag numbers (ex. sname.(4) is 5th field)

;get the number of rows in the structure by using n_elements on field01
nrows = n_elements(sname.(1))
print,’number of rows in rules file = ‘,nrows

;make a 6 1d arrays, nrows long, to store required elements of the structure
rowarray = fltarr(nrows)
vararray = fltarr(nrows)
oparray = strarr(nrows)
valarray = fltarr(nrows)
astarray = strarr(nrows)
classnamearray = strarr(nrows)

;strip the ‘)’ off of the string in the first field and convert to float and fill astarray
;with asterisks if present in last column of the ascii file
for i=0,nrows-1 do begin
length2 = strlen(sname.(0)[i])
rowarray[i] = float(strmid(sname.(0)[i],0,length2-1))
endfor

astarray = sname.(ntags-1)
classnamearray = sname.(4)

;find the number of classes in the splus rules file
uniq_classes = uniq(classnamearray, sort(classnamearray))
num_classes = n_elements(uniq_classes)
;create a list of the unique class names sorted alphabetically
uniq_class_list = make_array(num_classes, /string)

for i=0,num_classes-1 do begin
uniq_class_list(i) = classnamearray[uniq_classes[i]]
endfor

;create a class number matrix the number
c = bindgen(num_classes)
class_num = c+1
printf,u2, ‘Class name ‘, ‘Class number’
for i = 0,num_classes-1 do begin
printf,u2, uniq_class_list[i], ‘ ‘,class_num[i]
endfor

;write the contents of the string array to the 3 temp arrays
for i=1,nrows-1 do begin

;find position of the operator
;op_pos will be 2 for single digit variable numbers
;op_pos will be 3 for double digit variable numbers
test = strpos(sname.(1)[i],’>’)
if (test ne -1) then begin
op_pos = strpos(sname.(1)[i],’>’)
endif else begin
op_pos = strpos(sname.(1)[i],'<‘)
endelse

;find total string length using strlen
length = strlen(sname.(1)[i])

;extract the variable string and convert to byte format and put in vararray
if (op_pos eq 2) then begin
vararray[i] = float(strmid(sname.(1)[i],op_pos-1,1))
endif else begin
vararray[i] = float(strmid(sname.(1)[i],op_pos-2,2))
endelse
vararray=byte(vararray)
;extract the operator and put it into oparray
oparray[i] = strmid(sname.(1)[i],op_pos,1)

;find the length of the value substring by subtracting the operator postion plus 1 from the total length
vallength = length – op_pos + 1

;extract the value string and convert to byte and put in valarray
valarray[i] = float(strmid(sname.(1)[i],op_pos+1,vallength))
endfor

;make image of the same dimensions (x,y, where z = total number of unique variables) using filename from the pickfile
openw,u1,outimage, /GET_LUN

;find all uniq variables (bands) that are used in the tree, and count them
;example from uniq help file: b = array[UNIQ(array, SORT(array))]
varlisttemp = vararray[uniq(vararray, sort(vararray))]

;count all variables including the first which will always be zero
numvarstemp = n_elements(varlisttemp)
varlist = varlisttemp[1:numvarstemp-1]
numvars = n_elements(varlist)

;convert varlist to ENVI bandlist by subtracting 1 from each element
for i=0,numvars-1 do begin
idlvars = varlist – 2
envivars = varlist – 1
endfor

printf,u2, ‘ ‘
printf,u2, ‘ENVI Image bands used:
printf,u2, FORMAT='(I2)’, envivars
printf,u2, ‘ ‘

;make an array with the same dimensions as as
image = make_array(ns,nl,numvars)

;retrieve image data for only those bands used in the tree
;this reduces the data volume read into memory to the bands that will actually be used
for i=0,numvars-1 do begin

;****double check that this is getting the right bands****
image[*,*,i] = ENVI_GET_DATA(dims=dims,fid=fid,pos=idlvars[i])
print,’importing envi image band number: ‘,envivars[i]
endfor

;create an array to hold the classified image
newarray = make_array(ns,nl, /byte)

print,’all parameters set, beginning classification’

;get time that classification begins
starttime = systime(1)

;begin a loop that processes the ENVI image pixel by pixel
for i=0,nl-1 do begin

; show percent completed to screen
percent = float(float(i)/float(nl)*100)
print,FORMAT='($(1A))’,’percent completed: ‘
print,FORMAT='(1F4.0)’,percent

for j=0,ns-1 do begin

;set the starting line number to the second line
rown = 1
;set the stop variable ‘done’ to 0
done = 0

;start the loop, stoping it when the variable done = 1
while (done eq 0) do begin
; print,’rown’,rown
;find out if the row contains a < operator
case 1 of
;the row contains a < operator
oparray[rown] eq ‘<‘: begin

; print,’operator was < ‘
; for < operator evaluate whether the < statement is true and if * is presnet;
; the band calculation is needed because where returns a 0 element vector,
; not a simple variable, when attempted as one line got error ‘expression must be scalar’
band = where(idlvars eq (vararray[rown]-2))

case 1 of

; the < statement is true, no *, change the rown variable to the next line number
image[j,i,band(0)] le valarray[rown] and astarray[rown] ne ‘*’: begin rown = rown+1
; print,’the < statement was true, no *, setting rown to ‘,rown
end

; the < statement is false, change the rown variable to the rown with rule number + 1
image[j,i,band(0)] gt valarray[rown] : begin
linenumber = where(rowarray eq rowarray[rown]+1)
rown = linenumber[0]
; print,’the < statement was false, setting rown to ‘,rown
end

; the < statement is true, * present, set done variable to 1
image[j,i,band(0)] le valarray[rown] and astarray[rown] eq ‘*’: begin
; print,’the < statement was true, * present, setting done to 1′
done = 1
end

endcase
end

;the row contains a > operator
oparray[rown] eq ‘>’: begin
; print,’operator was > ‘
; for > operator evaluate whether the > statement is true and if * is present;
; the band calculation is needed because where returns a 0 element vector,
; not a simple variable, when attempted as one line got error ‘expression must be scalar’
band = where(idlvars eq (vararray[rown]-2))

case 1 of

; the > statement is true, no *, change the rown variable to the next line number
image[j,i,band(0)] ge valarray[rown] and astarray[rown] ne ‘*’: begin rown = rown+1
; print,’the > statement was true, no *, setting rown to ‘,rown
end

; the > statement is false, change the rown variable to the rown with rule number + 1
image[j,i,band(0)] lt valarray[rown] : begin
linenumber = where(rowarray eq rowarray[rown]+1)
rown = linenumber[0]
; print,’the > statement was false, setting rown to ‘,rown
end

; the > statement is true, * present, set done variable to 1
image[j,i,band(0)] ge valarray[rown] and astarray[rown] eq ‘*’: begin
; print,’the > statement was true, * present, setting done to 1′
done = 1
end

endcase
end

endcase

endwhile
; now a asterisk has been reached where the statement is true,
; set the value of classified image for that cell to the class number
; (note that class numbers go from 1 to n for for classes in alphabetical order
classnumber = where(uniq_class_list eq classnamearray[rown])
; print, ‘setting the image pixel ‘, i, j, ‘to ‘,classnamearray[rown], classnumber[0]+1
newarray(j,i) = classnumber+1
endfor
endfor

;write the array to the output image
print,’writing output file’
writeu,u1,newarray

;calculate time that classification took
endtime = systime(1)
time = endtime – starttime
minutes = time/60
printf,u2,’Total time for classification: ‘,minutes, ‘ minutes’
print,’done, total time for classification: ‘,minutes, ‘ minutes’

close,u2,u1
end

;*** function below is almost exact duplicate of IMPORT_ASCII.pro, the modifications are noted
; as comments. The function it is the widget routine
; that formats the input ascii file and returns the resulting structure as a variable called ‘sname’
; $Id: import_ascii.pro,v 1.8 2000/07/14 16:35:13 chris Exp $
; Copyright (c) 1999-2000, Research Systems, Inc. All rights reserved.
; Unauthorized reproduction prohibited.
; NAME: IMPORT_ASCII
; PURPOSE: This routine is a macro allowing the user to read in an ASCII
; file and have the contents placed in the current scope as a structure variable.
; CATEGORY: Input/Output CALLING SEQUENCE: IMPORT_ASCII
; OUTPUTS: This procedure creates a structure variable and places it in the current scope. The variable is named ‘filename_ascii’ where filename is the main part of the file’s name not using the extension.
; EXAMPLE: IMPORT_ASCII MODIFICATION HISTORY: Written by: Scott Lasica, July, 1999
; Modified: CT, RSI, July 2000: moved varName out to IMPORT_CREATE_VARNAME
function IMPORT_ASCII_mod2
COMPILE_OPT hidden, strictarr
catch,error_status
if (error_status ne 0) then begin
dummy = DIALOG_MESSAGE(!ERROR_STATE.msg, /ERROR, $
TITLE=’Import_Ascii Error’)
return, title
endif
filename=DIALOG_PICKFILE(TITLE=’Select ASCII Splus rules file to read.’,/READ,$
FILTER=’*.*’,/MUST_EXIST, GET_PATH=gp)
if (filename eq ”) then return, title
templ = ASCII_TEMPLATE(filename, CANCEL=cancel)
if (cancel) then return, title
tempStr = READ_ASCII(filename, TEMPLATE=templ)
; store the return variable into a var for the user
varName = IMPORT_CREATE_VARNAME(filename, gp, ‘_ascii’)
; original: void = ROUTINE_NAMES(varName, STORE=ROUTINE_NAMES(/LEVEL)-1, tempStr)
void = ROUTINE_NAMES(‘sname’, STORE=ROUTINE_NAMES(/LEVEL)-1, tempStr)
; line below added
return, filename
end

[This message has been edited by halligan (edited 02-11-2001).]

[This message has been edited by halligan (edited 02-11-2001).]

halligan
Geo Newbie

Leave a Reply