Joe Natal
Joe Natal

Reputation: 69

How can I colorize my grayscale 16 bit image using Qt?

I have a 16 bit grayscale QImage::Format_Grayscale16 of unsigned short values contiguous in memory. It displays properly on a QLabel after converting it to a pixmap. I now need to colorize it with a given colortable that maps intensities to a particular RGB value:

QVector<QRgb> table_16;
for (double i = 0; i < 4096; ++i) {

    table_16.append(qRgb(
        (int)std::round(std::clamp( -4 * std::abs(i - 4095.0 * 3 / 4) + 4095.0 * 3 / 2, 0.0, 4095.0)),
        (int)std::round(std::clamp(-4 * std::abs(i - 4095.0 * 2 / 4) + 4095.0 * 3 / 2, 0.0, 4095.0)),
        (int)std::round(std::clamp( -4 * std::abs(i - 4095.0 * 1 / 4) + 4095.0 * 3 / 2, 0.0, 4095.0))));

}

table_16[0] = qRgb(4095, 4095, 4095);

Note: The images are actually 12 bit, but are stored the same as a 16 bit image. Hence the 4096 limit for the RGB mapping.

Unfortunately I am having trouble. Firstly, is conversion to the RGB16 format correct? I have posted another question very similar, but for 8 bit grayscale. The Qt doc for setColorTable() states:

Only monochrome and 8-bit formats.

so I'm assuming I can't use this for my 16 bit image. Is the best course of action maybe to scale down and convert to an 8 bit? Any performance optimaztions would be great as well because the images are supposed to stream in real-time.

Upvotes: 1

Views: 1430

Answers (2)

Linville
Linville

Reputation: 3803

qRgb(int,int,int) creates an QRgb which stores 8-bits per channel (while the arguments are ints, they are masked against 0xff). qRgb64(..) will accept (and use) 16-bit values to create a QRgb64 which has the necessary precision.

Unfortunately, there isn't a QImage::Format_Indexed16 yet (see QTBUG-75536) contributing to why Qt doesn't support color tables directly with 16-bit grayscales. If you don't need the contrast data in the lower 8-bits (or just 4-bits in your case since only the 12 upper bits have real data) and the color table is always the same, converting to Format_Indexed8 and using a color table will be the most straightforward method.

If you do need the contrast data in the lower bits, you'll need to manually scale those 12-bits across the 8-bit per channel RGB. Create a new QImage with the same width/height and loop through the original data pixel-by-pixel. Gray16Lib is a Qt library with examples of various algorithms that attempt to preserve contrast (disclaimer, I wrote it).

Upvotes: 2

Joe Natal
Joe Natal

Reputation: 69

One somwhat expensive solution is as follows:

Create a new 8 bit image using convertToFormat(QImage::Format_Grayscale8)

Colorize by creating a QImage of format Indexed8, setting its colortable, and copying the 8 bit QImage data to this new Indexed8 format image. See my other question for more details.

This works, but if anyone knows a faster method, feel free to respond. There seems to be a lot of copying with this. I already have to traverse the image once to map the 12 bit to the 16 bit range.

Upvotes: 0

Related Questions