0

I am at beginner level in image processing with python.

I have classified satellite image with python in 10 classes. I am able to write the image in geotiff format. However, I do not know how extract the attribute table of the classified raster from Python.

For now I am using ArcGIS by adding the classified raster which I have saved from Python processing and again reclassifying the raster and then only I got to export the attribute table which is easy but time consuming.

But I want to do this Python environment. Should I create Geopandas dataframe?

  • 1
    You can read the attribute table using da.SearchCursor, see example here. Or try RasterToNumpyArray. What output do you want? – BERA Jan 14 at 10:00
0

An attribute table is basically a table that has a value - (pixel) count relation for all your classes. I'll assume you have the raster data as a numpy array before writing it as a GeoTIFF. Look at the following example and imagine that arr is the numpy array with the raster data.

import numpy as np

np.random.seed(99)

arr = np.random.randint(1, 11, size=(400, 300))
values, counts = np.unique(arr, return_counts=True)

If you take a look at values and counts you will see they both are 1D numpy arrays containing all unique values of your array and their frequency, respectively.

>>> values
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])
>>> counts
array([12078, 11871, 11998, 12004, 12077, 11918, 11951, 12102, 11829,
       12172], dtype=int64

Now you can use pandas in order to create a DataFrame and then export it as a CSV file.

import pandas as pd

df = pd.DataFrame({'VALUE': values, 'COUNT': counts})

The DataFrame looks like this:

>>>df
   VALUE  COUNT
0      1  12078
1      2  11871
2      3  11998
3      4  12004
4      5  12077
5      6  11918
6      7  11951
7      8  12102
8      9  11829
9     10  12172

Note that you can also add additional fields to your attribute table. For exmaple, suppose you want to store also the name of each class and not just their codes (integers). You could create a dict with the name of each class and then map it to a new column of your DataFrame named class.

class_map = {
    1: 'Evergreen Needleleaf Forests',
    2: 'Evergreen Broadleaf Forests',
    3: 'Deciduous Needleleaf Forests',
    4: 'Deciduous Broadleaf Forests',
    5: 'Mixed Forests',
    6: 'Closed Shrublands',
    7: 'Open Shrublands',
    8: 'Woody Savannas',
    9: 'Savannas',
    10: 'Grasslands'
}
df['CLASS'] = df['VALUE'].map(class_map)

Now the DataFrame looks like this:

>>>df
   VALUE  COUNT                         CLASS
0      1  12078  Evergreen Needleleaf Forests
1      2  11871   Evergreen Broadleaf Forests
2      3  11998  Deciduous Needleleaf Forests
3      4  12004   Deciduous Broadleaf Forests
4      5  12077                 Mixed Forests
5      6  11918             Closed Shrublands
6      7  11951               Open Shrublands
7      8  12102                Woody Savannas
8      9  11829                      Savannas
9     10  12172                    Grasslands

Finally, you just have to export the DataFrame to a CSV (or other format you consider more appropiate) file. Note that you can just ignore the index by passing index=False as an argument. Here I just give the index a new label, just like ArcGIS does.

df.to_csv('raster_attribute_table.csv', index_label='OID')


If you are using gdal to write the GeoTIFF, the process could be as simple as:

# create an empty Raster Attribute Table and populate it using the values, their frequency and their class
rat = gdal.RasterAttributeTable()
rat.CreateColumn('VALUE', gdal.GFT_Integer, gdal.GFU_Generic)
rat.CreateColumn('COUNT', gdal.GFT_Integer, gdal.GFU_Generic)
rat.CreateColumn('CLASS', gdal.GFT_String, gdal.GFU_Generic)
for value, count in zip(values, counts):
    rat.SetValueAsInt(i, 0, value)
    rat.SetValueAsInt(i, 1, count)
    rat.SetValueAsInt(i, 2, class_map[value])

# save the raster atttribute table to the band (assume ds is the gdal DataSet)
band = ds.GetRasterBand(1)
band.SetDefaultRAT(rat)
band.FlushCache()

del ds, band
  • I have some quarries regarding>>> np.random.seed(99) arr = np.random.randint(1, 11, size=(400, 300)) The classified raster has minimum value of 0 and maximum value of 210. It has 0, 10, 20.......... to 100 as serial class but after 100values it only has 2 class assigned before during the process as 205 as cloud and 210 as water bodies . – Tua Jan 14 at 14:09
  • 1
    @Tua I just put it as an example. You won't be using the array I created but the one that contains your original data. It does not matter what data you have because np.unique() will extract all unique values and their frequencies. If you provide the relevant portion of the code you are using in your question, I could try to edit my answer so you get a better understanding. – Marcelo Villa Jan 14 at 15:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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