PDA

View Full Version : Tiff in unsigned short



spawnwj
20th July 2006, 11:15
Hi,

I got a tiff image already converted to unsigned short*.
How can I display the image from the unsigned short* in QT?
I am using QT4.1.

Thank you....

wysota
20th July 2006, 11:23
Hi,

I got a tiff image already converted to unsigned short*.
Why not unsigned char*?


How can I display the image from the unsigned short* in QT?
What does the bitmap contain? Only the pixell data? If so, then you can use QImage::bits() to access QImage pixell storage and copy the data there.

spawnwj
20th July 2006, 11:37
Why not unsigned char*?


What does the bitmap contain? Only the pixell data? If so, then you can use QImage::bits() to access QImage pixell storage and copy the data there.

The image comes in unsigned short*. I can't do anything about that.
I think if it is in unsigned char* we can load it directly into QPixel or QImage right?


Hm... I have to check if the bitmap only contain pixel data.
Any hints on how to do this?

I am new to image processing so I do not really know how to proceed from here.

Thanks

wysota
20th July 2006, 11:39
Where did you get those ushort* from? Ask the author what they contain :) But it should still be uchar*, because ushort can be 16 bits long and uchar is always 8bits.

spawnwj
22nd July 2006, 08:35
Where did you get those ushort* from? Ask the author what they contain :) But it should still be uchar*, because ushort can be 16 bits long and uchar is always 8bits.

Hi....

The images I am getting is 16 bit greyscale image converted from tiff. It is more for image processing. But I just need to display it in QT. Can anyone tell me how I can go about doing it?
The images comes in ushort*. Therefore I do not know how I can display it.

Thanks

Mad Max
22nd July 2006, 09:41
You should convert a 16bit raster to the 8bit raster. After that you will be able to show this image through Qt's classes.
Here is a simple function for converting 16 to 8 bit.


// data - the souce 16bit raster
// dest - the destination 8bit raster
// len - raster length (width * height)
template<typename T>
bool conv16to8bit(const T * const data, unsigned char * const dest, unsigned len)
{
if ( !data || !dest || !len ) return false;

size_t type_size = sizeof(T);
if ( type_size != 2 ) return false;

bool isSigned = ( typeid(T) == typeid(signed short) );

T minValue = ( isSigned ?
static_cast<T>(::pow(2, type_size * 8 - 1)/2)-1 :
static_cast<T>(::pow(2, type_size * 8 - 1)) );
T maxValue = ( isSigned ? static_cast<T>(::pow(2, type_size * 8 - 1)/2) * (-1) : 0 );

for (const T * pix = data; pix < data+len; pix++)
{
if ( *pix < minValue ) minValue = *pix;
if ( *pix > maxValue ) maxValue = *pix;
}

const char VBLACK = 16;
float K = (4096.f * ( 256 - VBLACK )) / ( maxValue - minValue );
float B = minValue * K / 4096.f - VBLACK;

unsigned char * dst = dest;
for (const T * pix = data; pix < data+len; pix++)
{
int c = static_cast<int>( 0.5f + (::abs(*pix) * K / 4096 - B));
if ( c < 0 ) c = 0;
if ( c > 255 ) c = 255;
*dst++ = static_cast<unsigned char>(c);
}

return true;
};

spawnwj
24th July 2006, 05:31
void CMMMGui::setImageInGUI(ushort* image, int page)
{

uchar* finalImage = new uchar[300 * 300];
_conv16to8bit(image, finalImage, 90000);

QImage img = QImage(finalImage,300,300,QImage::Format_ARGB32);

QPixmap pix = QPixmap(300,300);
ui.label_Photo->setPixmap( QPixmap::fromImage( img ) );
}

Thanks for the code.
I have tried to call your function to convert it to 8bit. The image is looking slightly better. But still not the same image yet :(
Anything I do wrong here?

I think there is something wrong with the format define in the QImage. I cant seem to get a right one for it.
QImage img = QImage(finalImage,300,300,QImage::Format_ARGB32);

Thanks




You should convert a 16bit raster to the 8bit raster. After that you will be able to show this image through Qt's classes.
Here is a simple function for converting 16 to 8 bit.


// data - the souce 16bit raster
// dest - the destination 8bit raster
// len - raster length (width * height)
template<typename T>
bool conv16to8bit(const T * const data, unsigned char * const dest, unsigned len)
{
if ( !data || !dest || !len ) return false;

size_t type_size = sizeof(T);
if ( type_size != 2 ) return false;

bool isSigned = ( typeid(T) == typeid(signed short) );

T minValue = ( isSigned ?
static_cast<T>(::pow(2, type_size * 8 - 1)/2)-1 :
static_cast<T>(::pow(2, type_size * 8 - 1)) );
T maxValue = ( isSigned ? static_cast<T>(::pow(2, type_size * 8 - 1)/2) * (-1) : 0 );

for (const T * pix = data; pix < data+len; pix++)
{
if ( *pix < minValue ) minValue = *pix;
if ( *pix > maxValue ) maxValue = *pix;
}

const char VBLACK = 16;
float K = (4096.f * ( 256 - VBLACK )) / ( maxValue - minValue );
float B = minValue * K / 4096.f - VBLACK;

unsigned char * dst = dest;
for (const T * pix = data; pix < data+len; pix++)
{
int c = static_cast<int>( 0.5f + (::abs(*pix) * K / 4096 - B));
if ( c < 0 ) c = 0;
if ( c > 255 ) c = 255;
*dst++ = static_cast<unsigned char>(c);
}

return true;
};

Mad Max
24th July 2006, 06:41
Try to set to zero a value of the variable VBLACK.

spawnwj
24th July 2006, 07:04
I have updated the code as shown below...
I can see the full image now but it is rotated anticlockwise 90 degree....
Any idea why?

Thanks


uchar* finalImage = new uchar[300*300];
_conv16to8bit(image, finalImage, 90000);

QImage img(300, 300,QImage::Format_Indexed8);
img.setNumColors(256);
for(int i = 0; i <= 255; i++)
{
int myColor = qRgb(i, i, i);
img.setColor(i, myColor);
}

for(int i = 0; i<300; i++)
for(int j = 0; j<300; ++j)
img.setPixel(i, j, finalImage[(i*300)+j]);

ui.label_Photo->setPixmap( QPixmap::fromImage( img ) );

spawnwj
24th July 2006, 07:26
for(int i = 0; i<300; i++)
for(int j = 0; j<300; ++j)
img.setPixel(i, j, finalImage[(i*300)+j]);


Hi the image looks fine now. I just swap i and j at setPixel.
So far so good.
Thanks for all the help

Mad Max
24th July 2006, 07:35
I have updated the code as shown below...
I can see the full image now but it is rotated anticlockwise 90 degree....
Any idea why?
:( I'm surprised with this behaviour. Do you sure that it happened because of the function of convert?

I want to explain a bit. This function was made only for display of images, not for processing. This algorithm does scale 16bit values to the 8bit range and considers min and max values of pixels at the same time. If you will processing 8bit image and you need to keep the source image as far as possible you should change the algorithm of convert. It should be such as:


template<typename T>
bool conv16to8bit(const T * const data, unsigned char * const dest, unsigned len)
{
if ( !data || !dest || !len ) return false;

size_t type_size = sizeof(T);
if ( type_size != 2 ) return false;

bool isSigned = ( typeid(T) == typeid(signed short) );

T maxValue = ( isSigned ?
static_cast<T>(::pow(2, type_size * 8 - 1)/2)-1 :
static_cast<T>(::pow(2, type_size * 8 - 1)) );

unsigned char * dst = dest;
for (const T * pix = data; pix < data+len; pix++)
{
int c = static_cast<int>( 0.5f + (::abs(*pix) / maxValue * 255));
if ( c < 0 ) c = 0;
if ( c > 255 ) c = 255;
*dst++ = static_cast<unsigned char>(c);
}

return true;
};


I didn't check this code. May be it has a couple errors. ;)

spawnwj
24th July 2006, 10:40
I have further reduce the code to the one below.
It looks ok without the rotation issue.

However I got one question...
If the source is 16 bit, I got a full image with the right size.
If the source is 8bit, I got a image that is 1/4 of the size and repeat 2 times.
For example... The actual full image size is defined below.
1 2
3 4
It will have 2 repeating image on 1 and 2 while 3 and 4 is empty.
Is this normal?




uchar* finalImage = new uchar[imageSize.width()*imageSize.height()];
_conv16to8bit(imageData, finalImage, imageSize.width()*imageSize.height());

QImage img(finalImage, imageSize.width(), imageSize.height(),QImage::Format_Indexed8);
img.setNumColors(256);
for(int i = 0; i <= 255; i++)
{
int myColor = qRgb(i, i, i);
img.setColor(i, myColor);
}


:( I'm surprised with this behaviour. Do you sure that it happened because of the function of convert?

I want to explain a bit. This function was made only for display of images, not for processing. This algorithm does scale 16bit values to the 8bit range and considers min and max values of pixels at the same time. If you will processing 8bit image and you need to keep the source image as far as possible you should change the algorithm of convert. It should be such as:


template<typename T>
bool conv16to8bit(const T * const data, unsigned char * const dest, unsigned len)
{
if ( !data || !dest || !len ) return false;

size_t type_size = sizeof(T);
if ( type_size != 2 ) return false;

bool isSigned = ( typeid(T) == typeid(signed short) );

T maxValue = ( isSigned ?
static_cast<T>(::pow(2, type_size * 8 - 1)/2)-1 :
static_cast<T>(::pow(2, type_size * 8 - 1)) );

unsigned char * dst = dest;
for (const T * pix = data; pix < data+len; pix++)
{
int c = static_cast<int>( 0.5f + (::abs(*pix) / maxValue * 255));
if ( c < 0 ) c = 0;
if ( c > 255 ) c = 255;
*dst++ = static_cast<unsigned char>(c);
}

return true;
};


I didn't check this code. May be it has a couple errors. ;)

Mad Max
24th July 2006, 11:04
Is this normal?

Yes, I think this is normal behaviour for this function. I never used it in such way. :D It seems you've too much oversimplified my function. In original it checks the dimension of source type. Just don't use this function for 8bit images.

jrideout
25th July 2006, 08:25
you might want to check out TiffIO (http://artis.imag.fr/Software/TiffIO/) as well.

spawnwj
26th July 2006, 08:41
you might want to check out TiffIO (http://artis.imag.fr/Software/TiffIO/) as well.

Thanks... I got that in my system.
But my source is already converted to ushort*. I can only start working for there.