PDA

View Full Version : QImage and "raw" grey scale



high_flyer
9th December 2008, 10:44
Hi,

with Qt3 I have done this a lot, and now I need to convert and display 16bit gray scale.
But what ever I tried so far either gives me a uniform gray image (even if the buffer is empty) or no image at all.
I am a bit lost, maybe one of you can see what it is I am missing?
Efficiency is not an issue.
I just want to see the image.
The buffer is checked, and is valid, with a valid image (saved to file through grabbing lib). plus, I see in the debugger the contents.
I never get a black image even if the buffer is all full with '0'.
After setting the data in to the image, my QImage object returns false on isNull().
So I am quite sure my problem is format issue, not data issue.

Here is my code :

QImage convert16to8mono(unsigned short *inBuff, int sizeBytes, unsigned char *outBuff)
{
//convert 16 to 8 bit
for(int i=0; i<sizeBytes/2; i++)
outBuff[i] = (((double)inBuff[i]) / 0xFFFF) * 255;

QImage qimage(1280,960,QImage::Format_Indexed8);
qimage.setNumColors(256);
for(int i=0; i<256; i++)
qimage.setColor(i,qRgb(i,i,i));

//trail 1
//qimage.loadFromData(outBuff,sizeBytes/2,0/*BMP*/); //this is raw data, so there are no format specific headers etc.
//trail 2
memcpy(qimage.bits(),outBuff,sizeBytes/2);

//trail 3 :
// for(int y=0,i=0;y<960; y++)
// for(int x=0; x<1280; x++,i++)
// qimage.setPixel(x,y,outBuff[i]);

return qimage;
}

P.S
the contents of outBuff is also checked, and it has plausible values.

wysota
9th December 2008, 10:56
What is the structure of data in outBuf? Values 0-255 representing pixel colours? Could you check the exact values there? Are they different than 0?

high_flyer
9th December 2008, 11:03
Hi Witek,

yes, outBuff are values 0-255.
And as I said, I checked them, and they are not 0 (well some are, but its not a null buffer).

However, I tried this with out a camera, then the original buffer and outBuff contain only 0 and I expected a black image.
Depending on which variation I am using in the code above, I either get a uniform gray image (even with a buffer full with zeros) or nothing.

patrik08
9th December 2008, 12:04
If the image comming from a camera device create raw data image:

1- bool RawImage::create( int width, int height, int channels )
2- write your buffer RawImage::QByteArray data....
3- at end QImage convertToQImage(bool cmyk = false , bool raw = false);

( idea from www.scribus.net code )



///// header
#ifndef RAWIMAGE_H
#define RAWIMAGE_H

#include <QtGui>

class RawImage : public QByteArray
{
public:
RawImage();
RawImage( int width, int height, int channels);
~RawImage();
bool create( int width, int height, int channels);
int width() const {
return m_width;
};
int height() const {
return m_height;
};
int channels() const {
return m_channels;
};
uchar *bits() {
return (uchar*)data();
};
uchar *scanLine(int row);
void setAlpha(int x, int y, int alpha);
QImage convertToQImage(bool cmyk = false , bool raw = false);
private:
int m_width;
int m_height;
int m_channels;
};


#endif
///// source

#include "rawimage.h"


RawImage::RawImage()
{
m_width = 0;
m_height = 0;
m_channels = 0;
resize(0);
}

RawImage::RawImage( int width, int height, int channels )
{
create(width, height, channels);
}

RawImage::~RawImage()
{
resize(0);
}

bool RawImage::create( int width, int height, int channels )
{
m_width = width;
m_height = height;
m_channels = channels;
int finalSize=width * height * channels;
resize(finalSize);
return (size()==finalSize);
}

uchar *RawImage::scanLine(int row)
{
if (row < m_height)
return (uchar*)(data() + (row * m_channels * m_width));
else
return (uchar*)data();
}

void RawImage::setAlpha(int x, int y, int alpha)
{
uchar *d;
if ((y < m_height) && (x < m_width))
{
d = (uchar*)(data() + (y * m_channels * m_width) + (x * m_channels));
d[m_channels-1] = alpha;
}
}


QImage RawImage::convertToQImage(bool cmyk, bool raw)
{
int chans = channels();
QImage img = QImage(width(), height(), QImage::Format_ARGB32);
QRgb *ptr;
uchar *src;
uchar cr, cg, cb, ck, ca;
// img.create(width(), height(), 32);
if (raw)
{
for (int i = 0; i < height(); i++)
{
ptr = (QRgb *)img.scanLine(i);
src = scanLine(i);
for (int j = 0; j < width(); j++)
{
*ptr++ = qRgba(src[0],src[1],src[2],src[3]);
src += chans;
}
qDebug() << "## raw line -> " << i;
}
}
else
{
// img.setAlphaBuffer( true );
for (int i = 0; i < height(); i++)
{
ptr = (QRgb *)img.scanLine(i);
src = scanLine(i);
for (int j = 0; j < width(); j++)
{
if (chans > 1)
{
if (cmyk)
{
ck = src[3];
cr = 255 - qMin(255, src[0] + ck);
cg = 255 - qMin(255, src[1] + ck);
cb = 255 - qMin(255, src[2] + ck);
if (chans > 4)
{
ca = src[4];
*ptr++ = qRgba(cr,cg,cb,ca);
}
else
*ptr++ = qRgba(cr,cg,cb,255);
}
else
{
if (chans > 3)
*ptr++ = qRgba(src[0],src[1],src[2],src[3]);
else
*ptr++ = qRgba(src[0],src[1],src[2],255);
}
}
else
*ptr++ = qRgba(src[0],src[0],src[0],255);
src += chans;
}

//////qDebug() << "## n line -> " << i;

}
}
return img;
}



wath is your source data tiff?

wysota
9th December 2008, 12:22
The code looks fine... What happens if you use setPixel() to set data not from your buffer but some arbitrary one? Try drawing a red line or something across the image. My impression is that you can be having two copies of the image and you change not the one you are supposed to but the code you pasted doesn't prove that.

Is the size of the destination image correct? Could you check after memcpy() if pixel() returns expected values?

high_flyer
9th December 2008, 14:26
Hi Witek,

I think you are on the correct path.
I tried the following:
Instead of allocating the QImage in my function above, I allocate it there where I use it, and give it as a parameter to the conversion function.
In addition, I use the setPixel() loop to fill it with white (index 255).
(so not even using my buffer)

Still same results - meaning - a uniform gray image. (even if I use (only) red in the color table.)

Do you see something wrong in my use of QImage:


QPixmap pixmap(1280,960);
QImage qimage(1280,960,QImage::Format_Indexed8);
convert16to8mono(qimage,buff,size*2,buff8);
if(!qimage.isNull())
pixmap.fromImage(qimage);

high_flyer
9th December 2008, 15:40
@patrik08:
Thanks for the suggestion.
But I am just interested to know why my code doesn't work.

high_flyer
9th December 2008, 16:50
So, after simplifying even more this is my code:


void convert16to8mono(QImage &qimage,unsigned short *inBuff, int sizeBytes, unsigned char *outBuff)
{
qimage.setNumColors(1);
qimage.setColor(0,qRgb(255,0,0));

for(int y=0,i=0;y<960; y++)
for(int x=0; x<1280; x++,i++)
{
qimage.setPixel(x,y,0);
}
}


and I use it like that:


QPixmap pixmap(1280,960);
QImage qimage(1280,960,QImage::Format_Indexed8);
convert16to8mono(qimage,buff,size*2,buff8);
if(!qimage.isNull())
pixmap.fromImage(qimage);

ui.lblImage->setPixmap(pixmap);


result is a uniform gray image, instead of a red image....

I am at a loss to what I still might be doing wrong...

EDIT:
I solved it.
As always the problem ist between the chair and keyboard.
I forgot that fromImage returns the new pixmap, and not changing the calling object.

Thanks for helping.

wysota
9th December 2008, 16:56
Hi Dani,

Ah... I think I see the problem. QPixmap::fromImage() is a static method returning a pixmap, thus it should be:

QPixmap px = QPixmap::fromImage(qimage);

So the problem is not with the image, but with the pixmap you try to convert it to.

high_flyer
9th December 2008, 17:01
hehe - I just saw it by my self as you where posting your answer

Thanks!