0

I have a lot of output land cover raster files in .tif and want to only select the .tif files and change color map of all of them by taking a script that has attributes for Red, Green, Blue and LC Type. I have a list of raster values for colors and the associated land cover type; however, I know I am supposed to take the proportion of each RGB value out of 255 to properly assign the new color. I want to loop through each .tif file create the fields (Red, Green, Blue, and LC Type) and assign the appropriate value using a dictionary in ArcPy.

filepath = 'C:/directory'
env.workspace =filepath
for filename in os.listdir(filepath):
  if filename.endswith('.tif')


dictionary = {
    1: [255,0,0 'water'],
    2: [209, 255, 115 'Evergreen Needleleaf Forest'],
    3: [85,255,0 'Evergreen Broadleaf Forest'],
    4: [112,168,0 'Deciduous Needleleaf Forest'],
    5: [190,255,232 'Deciduous Broadleaf Forest'],
    6: [255,211,127 'Mixed Forest'],
    7: [0,255,0'Woodland'],
    8: [0,99,0 'Wooded Grassland'],
    9: [214,157,188 'Closed Shrubland'],
    10: [197, 0, 255'Open Shrubland'],
    11: [0,77,168 'Grassland'],
    12: [0,132,168 'Cropland'],
    13: [190,210,255 'Bare Ground'],
    14: [255,170,0 'Urban and Built-up'],
    17: [255,170,0 'Urban and Built-up']}
#create the four attributes, R,G,B, and LC
#create an update cursor
#loop through each .tif file create fields and assign values to records
2

1 Answer 1

1

I really think a colour table is what you're after, it's just a text file with the same base name as the TIFF image with '.clr' as the extension, when loaded into ArcMap the symbology is automatically imported from the colour file.. From your existing code I have extended to create a color file, build the raster attribute table and then apply the dictionary values to the RAT.

import os, sys, arcpy
filepath            = 'C:/directory'
arcpy.env.workspace = filepath

# note that you need more commas in your dictionary def
# to separate LC code from the blue value
dictionary = {
    1: [255,0,0,'water'],
    2: [209, 255, 115,'Evergreen Needleleaf Forest'],
    3: [85,255,0,'Evergreen Broadleaf Forest'],
    4: [112,168,0,'Deciduous Needleleaf Forest'],
    5: [190,255,232,'Deciduous Broadleaf Forest'],
    6: [255,211,127,'Mixed Forest'],
    7: [0,255,0,'Woodland'],
    8: [0,99,0,'Wooded Grassland'],
    9: [214,157,188,'Closed Shrubland'],
    10: [197, 0, 255,'Open Shrubland'],
    11: [0,77,168,'Grassland'],
    12: [0,132,168,'Cropland'],
    13: [190,210,255,'Bare Ground'],
    14: [255,170,0,'Urban and Built-up'],
    17: [255,170,0,'Urban and Built-up']}

for filename in os.listdir(filepath):
    fN,fE = os.path.splitext(filename)                       # break the name and extension
    if fE.lower == '.tif':                                   # more reliable than endswith
        if arcpy.Describe(filename).isInteger:               # can't build RAT on non-integer rasters
            arcpy.AddMessage('Bulding for {}'.format(filename))

            # add a new RAT and required attributes
            arcpy.BuildRasterAttributeTable_management(filename,'OVERWRITE') 
            arcpy.AddField_management(filename,'R','SHORT')      # add the R,G and B fields
            arcpy.AddField_management(filename,'G','SHORT')      # as data type 'short' which
            arcpy.AddField_management(filename,'B','SHORT')      # is the smallest int type
            arcpy.AddField_management(filename,'LC_Type','TEXT') # Land cover type as text, field names can't have spaces


            # build a colour file to symbolize
            CLRfilename = os.path.join(filepath,fN + '.clr')
            with open (CLRfilename, 'w') as CLR:
                for Detail in dictionary.iterkeys():
                    R,G,B,LC = dictionary[Detail] #unpack this element in the dictionary
                    CLR.write('{} {} {} {}\n'.format(Detail,R,G,B))
            arcpy.AddMessage('Created or overwritten colour file')

            # Iterate the rows in the raster attribute table
            with arcpy.da.UpdateCursor(filename,['value','R','G','B','LC_Type']) as UCur:
                for URow in UCur:
                    ThisIndex = URow[0]                    # the value for this pixel
                    if ThisIndex in dictionary:            # only use values that exist in the dictionary
                        R,G,B,LC = dictionary[ThisIndex]   # unpack this element in the dictionary
                        URow[1]   = R 
                        URow[2]   = G 
                        URow[3]   = B 
                        URow[4]   = LC
                        UCur.updateRow(URow)
        else:
            arcpy.AddWarning("Cannot do {}, it's not an integer type".format(filename))

Then if you need to export any changes to your R,G,B values in your raster dataset you can reexport the colour table like this:

desc  = arcpy.Describe(yourRaster)
cPath = desc.catalogPath # the full path your your raster dataset
CLRfilename = fN + '.clr'# fN already contains the path

with (CLRfilename, 'w') as CLR:
    with arcpy.da.SearchCursor(InRas,['value','R','G','B']) as SCur:
        for SRow in SCur:
            CLR.write('{} {} {} {}\n'.format(SRow[0],SRow[1],SRow[2],SRow[3]))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.