Hi All,
I am using a labelled volume (the interpolation type of the volume property is nearest) on which each object is given to a unique color but I noticed some closer objects did not give the expected color and I know understand why.
Do you guys have an explanation about this?
Thanks
Hello,
Can you, please, share an image of the unexpected result?
best,
PC
Hi,
thanks for your response.
Well the image1 is displayed by default, in the seconde one, all objects have the same color (red) and the last image shows that when the label 16 has changed it’s color (green), the color of the label 17 is affected instead of staying unchanged (red).
The volume data is in 16bit with 292 different objects (0 to 291).
This is how I set the color transfer :
colorTransferFunction->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
for (T lbl : labels)
{
if (lbl == 0) continue;
auto clr = generateRandRGB(lbl);
colorTransferFunction->AddRGBPoint(lbl, double(clr.r) / 255, double(clr.g) / 255, double(clr.b) / 255);
opacityTransferFunction->AddPoint(lbl, 1.0);
}
Hi,
Judging from the code, you’re generating colors at random (is that what generateRandRGB
does?). Hence, I don’t think that result is unexpected.
hi,
yes generateRandRGB generates colors but not random colors, it generates unique color depending on the given seed (and in this example 16 and 17 are different ); the color of object 17 should be red like other objects.
The problem is still not clear. In your picture, object 17 is red like the other objects (expected) and object 16 is green (expected).
if you look closer, it’s slightly different from the others
Sorry, I’m still not convinced. I believe sharing the code of generateRandRGB()
can help tackling the issue in an objective way than subtle color differences which can be due to image compression, lighting, etc.
This is what the function does:
RGB_V generateRandRGB(uint32_t seed)
{
uint32_t rnd = rand_kiss(seed);
float H = float(rnd & 0x0000000FF) / 255.f;
float S = float((rnd & 0x0000FF00)) / (65280 * 255.f);
float V = float((rnd & 0x00FF0000)) / (16711680 * 255.f);
// set correct ranges
H *= 360.f; // 360 degrees
V *= 100.f; // percent
S *= 100.f; // percent
// limit saturation range
S = S * 40 + 40; // range:[40%,80%]
V = V * 60 + 40; // range:[40%,100%]
if (H > 360 || H < 0 || S>100 || S < 0 || V>100 || V < 0)
{
std::cout << "The givem HSV values are not in valid range. H,S,V:" << H << "," << S << "," << V << std::endl;
}
float s = S / 100;
float v = V / 100;
float C = s * v;
float X = C * (1 - std::abs(std::fmod(H / 60.0, 2) - 1));
float m = v - C;
float r, g, b;
if (H >= 0 && H < 60)
r = C, g = X, b = 0;
else if (H >= 60 && H < 120)
r = X, g = C, b = 0;
else if (H >= 120 && H < 180)
r = 0, g = C, b = X;
else if (H >= 180 && H < 240)
r = 0, g = X, b = C;
else if (H >= 240 && H < 300)
r = X, g = 0, b = C;
else
r = C, g = 0, b = X;
RGB_V color;
color.r = (r + m) * 255;
color.g = (g + m) * 255;
color.b = (b + m) * 255;
return color;
}
uint32_t rand_kiss(uint32_t seed)
{
uint32_t x = seed | 1;
uint32_t y = seed | 2;
uint32_t z = seed | 4;
uint32_t w = seed | 8;
x = x * 69069 + 1;
y ^= y << 13;
y ^= y >> 17;
y ^= y << 5;
w = w + w + z;
seed = x + y + w;
x = seed | 1;
y = seed | 2;
z = seed | 4;
w = seed | 8;
x = x * 69069 + 1;
y ^= y << 13;
y ^= y >> 17;
y ^= y << 5;
w = w + w + z;
return x + y + w;
}
It’s 99.9% chance for the unexpected result being caused by all those bitshift and bitwise operations and not a VTK problem. Those need a thorough examination and testing since that code is obfuscated (it’s poorly documented, the variable names are meaningless and full of magic numbers). A better, less error-prone idea would be a nested loop over H,S and V values to initialize a table of contrasting colors (with 20, 200, 2k colors…). Then, compute a hash from the object number and use the hash as index to your color palette. And a small piece of advice: don’t try to reinvent the wheel. C++'s standard library and Boost for example already have APIs to do that kind of stuff. Those libraries have been peer reviewed and tested thoroughly.
Here, c# - Generate distinctly different RGB colors in graphs - Stack Overflow, you can try some of the contrasting color generation algorithms proposed there. They’re in C#, but it’s not difficult to translate them to C++. Here’s another source (in Java, also easily translatable): java - How to automatically generate N "distinct" colors? - Stack Overflow, again no dangerous bitshift/bitwise ops. A ready C++ implementation: GitHub - xuboying/randomcolor-cpp :
Thank you for your feedback;
I will take more time to enhance my code and take into account to your suggestions.
Hello,
I come back to my issue and I think the reason why there is this weird behavior with the colors is that there are more than 256 objects in my volume which need more than 256 colors I have tested other volumes with less objects and it works fine.
Is vtkColorTransferFunction limited to 256?
Is there in VTK some options to allow large number of colors?
Thanks
I wonder why do even need 256 classes. I my line of work, a typical example is to color cells by rock type. More than 20 rock types becomes confusing for the geologist. If you have so many classes, then you actually have a continuous variable. In this case, you have the entire color space available (for 24-bit RGB, you have 2^24 colors, ranging in the millions).