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;
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.
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,
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?
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?