How to setup an Indexed vtkLookupTable?

Hello everyone,

I was wondering if someone could point me in the right direction as to how to setup a vtkLooupTable that’s indexed.

My basic idea is

vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
lut->SetNumberOfTableValues(255);
lut->SetIndexedLookup(true);

// I have a buffer externally created, that holds all 255 [rgba] values.

// I have 255 (RGBA) colours that I iterate over
for(int idx = 0; idx < 255; idx++)
{
   double r = buffer[4 * idx + 0];
   double g = buffer[4 * idx + 1];
   double b = buffer[4 * idx + 2];
   double a = buffer[4 * idx + 3];  // safely assuming all alphas = 1.0
   lut->SetTableValue((vtkIdType)idx, r, g, b, a); 

   std::string annotatedName = "# " + std::to_string(idx);
   lut->SetAnnotation( vtkVariant(idx) , annotatedName );
}

// min, max are values passed to this function.
lut->SetTableRange(min, max);
lut->Build();

return lut;

Is this the proper way of creating an indexed lookupTable?

Hello,

I believe you stumbled upon VTK’s indexed LUT caveat: you can’t skip index numbers, otherwise it misbehaves. At least that is what I found when I tried to create a LUT for categorical variables. In my case, the user can assign random unordered integers to the rock types (e.g. 1 for sandstone; 5 for shale; 2 for basalt; 13 for silt; etc.). Here’s how I build LUTs for discrete, unordered variables:

    //determine the greatest categorical code
    //cd -> category definition table (user-defined rock type names, integer codes and RGB colors).
    int maxCatCode = 0;
    for( int i = 0; i < catCount; ++i )
        maxCatCode = std::max<int>( maxCatCode, cd->getCategoryCode(i) );

    //table color indexes must go from 0 to greatest facies code, without skipping values
    size_t tableSize = maxCatCode + 1;
    vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
    lut->SetNumberOfTableValues(tableSize);

    //but assign only the codes defined in the category definition
    //which may be less than the total number of entries in the color table
    //this is a requirement by the way VTK's LUT work for categorical color tables
    for(size_t i = 0; i < tableSize; ++i)
    {
        if( cd->codeExists( i ) ){ //category code exists
            double rgb[3];
            QColor color;
            int catIndex = cd->getCategoryIndex( i );
            color = cd->getCustomColor( catIndex );
            rgb[0] = color.redF();
            rgb[1] = color.greenF();
            rgb[2] = color.blueF();
            lut->SetTableValue(i, rgb[0], rgb[1], rgb[2], 1.0);
            lut->SetAnnotation(i, QString::number(i).toStdString() );
        } else { //category code is not defined
            lut->SetTableValue(i, 1.0, 0.0, 1.0, alphaForNotFound); //illegal color codes are rendered as pink transparent.
            lut->SetAnnotation(i, "UNKNOWN CATEGORY" );
        }
    }
    lut->SetNanColor( 1.0, 0.0, 1.0, alphaForNaN ); //unvalued locations are also rendered as pink transparent.
    lut->IndexedLookupOn();
    lut->Build();

    return lut;

I hope this helps,

PC

I use indexed LUTs to render categorical variables like rock type maps/surfaces:


Green = shale; brown = siltstone; yellow = sandstone.

Hello Paulo,
thanks for the detailed response. I’ll try to see if I can address my situation based on your example.
Indeed, VTK’s indexed LUT caveat seems to be my issue, I just couldn’t figure out why it was misbehaving. I’ll try it out again hopefully this time I get it to work. Thanks.

Hi Paulo,

I was able to setup an indexed lookup table following your example above, thanks.
However, I noticed that the generation of my table seems to be slow, do you know what may cause the process to be slow.

Hi,

How many classes (table size) does it have?

best,

PC

How much is slow? One second? One minute?

Anyway, if it is done once, it souldn’t be a nuisance.

cheers,

PC

Hi,
The table size is about 502. Basically I’m using a .label.txt file (purportedly derived from ITK SNAP) which really shouldn’t matter but I thought it be worth mentioning. There are 0-based indices all the way to 502 (some indices are missing). so In reality the total number of indices (call it points) is less than 502.

so just as you example suggested if I cycle through a total of 502 and `index 2 is missing then the the else branch is executed as in

lut->SetAnnotation(i, "UNKNOWN CATEGORY" );

it’s at least a minute sluggish if not more but I noticed that if I omit

//lut->IndexedLookupOn()

then it’s faster and also behaves as expected. Makes me think do I really even need to flag it as indexed. Uhm?

G’day,

Well, 502 classes is too much. From an application stand point that does not make any sense. In the Earth sciences, for example, typically we make subsurface models with ~20 classes (e.g. rock types) at maximum. If data from the field contains too many rock types, the geologists normally group them into so-called facies to facilitate numeric modeling. I can’t imagine a possible application for a categorical variable with 502 classes… Why don’t you use a normal LUT?

take care,

PC