X

Help Articles are product support tips and information straight from the NV5 Geospatial Technical Support team developed to help you use our products to their fullest potential.



7732 Rate this article:
2.8

A program to convert a palettized TIFF to an ENVI classification image

Single band TIFF files with a color palette are converted to 3-band True Color RGB when imported into ENVI. This Help Article provides example code for a user-defined function that can import these palettized TIFF images as ENVI classification images.

Currently, ENVI will open a TIFF file with a palette as a true color RGB image. There are cases when the desired image type is a classification image. The file type can be changed in ENVI by editing the header and changing the file type to 'ENVI Classification'. This requires that the user interactively sets the number of classes and assigns the class colors manually. The below code will reclassify the RGB values into unique classes based on the unique RGB triplets in the dataset and output an ENVI classification image with the same visual effect as the palettized TIFF.

------------------------------------------------
; Take the histogram of a 2D palettized color image with a disorderly,
; possibly redundant and possibly partially unused color table, plus
; the R, G and B color intensity vectors of that table and return three
; things:
; - through parameter 'paletteIntsIn' return the True Color values of
; the original color table
; - through parameter 'collapsedPaletteInts' return the True Color values
; of an orderly, non-redundant color table
; - through the function's return value return a 3 x 256 color table
; which can be used as an ENVI classification image "lookup table"
Function collapse_colors, hist, r, g, b, paletteIntsIn, collapsedPaletteInts

; Pack RGB triplets into True Color int values
paletteIntsIn = ishft(long(b), 16) + ishft(long(g), 8) + r

; Get rid of color table values that are not used in 'data'.
irrelevantColors = where(hist eq 0, nIrrelevantColors)
if nIrrelevantColors gt 0 then paletteIntsIn[irrelevantColors] = 0

; Remap the colors in use into the beginning indexes of a new
; palette. Sorting is required to get rid of redundant color indexes.
SortedPal = sort(paletteIntsIn)
collapsedPaletteInts = paletteIntsIn[sortedPal[uniq(paletteIntsIn[sortedPal])]]
nClasses = n_elements(collapsedPaletteInts)

; Unpack the True Color values into RGB triplet values
enviLookup = bytarr(3, nClasses)
enviLookup[0,*] = collapsedPaletteInts and '0000FF'x
enviLookup[1,*] = ishft(collapsedPaletteInts, -8) and '0000FF'x
enviLookup[2,*] = ishft(collapsedPaletteInts, -16)

return, enviLookup

end
;++++++++++++++++++++++++++++++++++++++++++++++++

; Convert a 2D palettized color classification image stored as
; TIFF to ENVI classification image format
pro palettized_tiff_to_envi_class
compile_opt idl2

file = envi_pickfile(filter='*.tif;*.tiff', $
 title='Select RGB TIFF to convert to ENVI classification')
 if (file eq '') then return
envi_open_file, file, /no_realize, r_fid=fid

; Get important header info
envi_file_query, fid, ns=ns, nl=nl, dims=dims
inherit = envi_set_inheritance(fid, dims, /spatial)

;prompt for output file name
base = widget_auto_base(title='Select output Classification file name')
wo = widget_outf(base, uvalue='outf', /auto)
result = auto_wid_mng(base)
 if (result.accept eq 0) then return
fname=result.outf

; Tile for the benefit of very large TIFF's. Tiles will be full width of the image ("ns")
; by the max number of scanlines ("nLinesPerTile") that can be stored in 4 MB
; or less
maxTileSize = 2L ^ 22   ; 4 Mb
nLinesPerTile = maxTileSize / ns
nTiles = ceil(float(nl) / nLinesPerTile)
envi_report_init, ['Input File: ' + file_basename(file)], BASE=wStatus, $
 TITLE='Making histogram of ' + strtrim(ns * nl / (2L ^ 20), 2) + ' Mb Image'
envi_report_inc, wStatus, nTiles
hist = lonarr(256)   ; initialize
currentLine = 0
for tileIndex = 0, nTiles-1 do begin
    nextLine = (currentLine + nLinesPerTile) < nl
    currentTile = read_tiff(file, sub_rect=[0, currentLine, ns, (nextLine-currentLine)-1])
    hist += histogram(currentTile)
    currentTile = 0
    currentLine = nextLine
    envi_report_stat, wStatus, tileIndex+1, nTiles
endfor
envi_report_init, BASE=wStatus, /FINISH

; Do one small read to get color table info
void = read_tiff(file, rIn, gIn, bIn, sub_rect=[0,0,1,1])

; Collapse the disorderly, possibly partially unused and possibly
; redundant color table into a minimum-sized orderly, non-redundant
; color table
enviLookup = collapse_colors(hist, rIn, gIn, bIn, paletteIntsIn, $
 collapsedPaletteInts)
nClasses = n_elements(collapsedPaletteInts)

; Read in TIFF data (in horizontal tiles, if necessary), remap the
; data to the new color table indexes that are used by 'enviLookup'
; and output to a flat binary ENVI '.img' file
openw, unit, fname, /get_lun
envi_report_init, ['Input File: ' + file_basename(file), $
 'Output file: ' + fname], BASE=wStatus, $
 TITLE='Converting ' + strtrim(ns * nl, 2) + ' Pixels'
envi_report_inc, wStatus, nTiles
currentLine = 0
for tileIndex = 0, nTiles-1 do begin
    nextLine = (currentLine + nLinesPerTile) < nl
    currentTile = read_tiff(file, sub_rect=[0, currentLine, ns, nextLine-currentLine])
    h = histogram(currentTile, REVERSE_INDICES=r)
    ; Remap the current color indexes into their newly-mapped values in
    ; the 'enviLookup' output color table
    ; Don't handle first original color index unless it is ***not*** black.
    ; This routine forces the first color table index to be black!!!
    startingIndex =  paletteIntsIn[0] eq 0 ? 1L : 0L
    for i = startingIndex, nClasses-1 do begin
        currentClassSubscripts = $
            where(paletteIntsIn eq collapsedPaletteInts[i], nColorIndexes)
        for j = 0, nColorIndexes-1 do begin
            c = currentClassSubscripts[j]    ; Get the color index to match
            if r[c] ne r[c+1] then currentTile[r[r[c]:r[c+1]-1]] = i
        endfor
    endfor
    writeu, unit, currentTile
    r = 0    ; Free memory
    currentTile = 0
    currentLine = nextLine
    envi_report_stat, wStatus, tileIndex+1, nTiles
 endfor
 free_lun, unit
 envi_report_init, BASE=wStatus, /FINISH

; Set up the class information for the header
classes = 'Class '+ strtrim(bindgen(nClasses-1)+1, 2)
class_names = ['Unclassified', classes]

; Generate the ENVI header with the new information
file_type = envi_file_type('ENVI Classification')
envi_setup_head, fname=fname, ns=ns, nl=nl, nb=1, interleave=0, $
	data_type=1, file_type=file_type, class_names=class_names, $
	lookup=ENVIlookup, num_classes=nClasses, inherit=inherit, /write, /open

envi_file_mng, id=fid, /remove

END
Review on 12/31/2013 MM

Please login or register to post comments.
Featured

End-of-Life Policy Enforcement for ENVI 5.3 / IDL 8.5 and Earlier Versions

5/6/2024

April 1, 2024 Dear ENVI/IDL Customer,  We are reaching out to notify you of our supported... more »

How to Upgrade licenses to ENVI 6.x / IDL 9.x

12/5/2023

What is the new Upgrade function? Starting with ENVI 6.0 and IDL 9.0, we have implemented an... more »

What to do if the 'License Administrator - License Server' for the Next-Generation License Server does not start?

6/13/2023

Background: With the release of ENVI 5.7 & IDL 8.9 and the corresponding Next-Generation licensing... more »

Next-Generation Licensing FAQ

4/28/2023

  NV5 Geospatial has adopted a new licensing technology for all future releases of our ENVI, IDL... more »

The IDL Virtual Machine

6/6/2013

What is the IDL Virtual Machine? An IDL Virtual Machine is a runtime version of IDL that can... more »