PDA

View Full Version : can't reuse a pure c++ .h file's methods and classes


sincnarf
23rd July 2007, 06:38
hello I have this .h file and I want to use the RGBImage class defined in it: It's called image.h. I can use it under a cygwin cygnus compiler.



#ifndef IMAGE_H
#define IMAGE_H

#include <iostream.h>

template <class T> // an image of type T
// use only simple types like int, unsigned char
// double or float, etc.
class Image {

private:
T* pixel;
int mHeight;
int mWidth;

public:
Image() { pixel = new T[1]; mHeight = mWidth = 0; }
Image(const Image<T> & img );
Image(int w, int h);

Image<T> & operator=(const Image<T> & img); // copy constructor

// OLD element access operator
inline T & operator () (int x, int y) const {
#ifdef IMAGE_RANGE_CHECK
// cout << "Test range check..." << endl;
if (y >= mHeight || x >= mWidth || y < 0 || x < 0) {
cout << "Cannot access pixel (" << x << "," << y <<
") of Image[" << mWidth << " x " << mHeight << "]!" << endl;
exit(1);
}
#endif
return pixel[y * mWidth + x];
}

// one-dimensional element access operator;
inline T & operator [] (int i) const {
#ifdef IMAGE_RANGE_CHECK
if (i >= mWidth * mHeight || i < 0) {
cout << "Cannot access pixel [" << i <<
"] of Image[" << mWidth * mHeight << "]!" << endl;
exit(1);
}
#endif
return pixel[i];
}

// destructor
~Image(){ delete [] pixel; }

void resize(int w, int h);
void setAll( T x ); // set the values

inline int height() const { return mHeight; }
inline int width() const { return mWidth; }
T max();
T min();
};


// --------------------------------------------------------------------

template <class T>
Image<T>::Image( const Image<T> & img ) { // important for functions returning Image
int h = img.height(), w = img.width(), i;
pixel = new T[1];
resize( w,h );
for (i = 0; i < w*h; i++) pixel[i] = img[i];
// for a faster alternative, replace previous line with the one below ;
// and... you must #include <string.h>
// memcpy( pixel, & img[0], sizeof(T) * w * h );
}


// set the image size only
template <class T>
Image<T>::Image( int w, int h ) {
pixel = new T[1];
resize( w,h );
}


// ---------------- Copy constructor -----------------------------------
template <class T>
Image<T> & Image<T>::operator=(const Image<T> & img) {
int w,h,i;
if ( this != &img ) { // don't copy to yourself
resize( w = img.width(), h = img.height() );
for (i = 0; i < w*h; i++) pixel[i] = img[i];
// for a faster alternative, replace previous line with the one below ;
// and... you must #include <string.h>
// memcpy( pixel, & Img[0] , sizeof(T) * ht * wd );
}
return *this;
}


//----------- Allocates memory for an image, no initialization -----------
template <class T>
void Image<T>::resize(int w, int h) {
int i;
delete [] pixel;

if (w * h == 0) {
cout << "CreateImage: invalid dimensions (" << w << " x " <<
h << ")..." << endl;
exit(1);
}

pixel = new T[w*h];
mWidth = w; mHeight = h;
}


// set the values of an image
template <class T>
void Image<T>::setAll( T x ) {
int n = width() * height();
for (int i = 0; i < n; i++) pixel[i] = x;
}

// return the maximum value of the image
template <class T>
T Image<T>::max() {
int i,imax,n = height()*width();
for (i=imax=0; i < n; i++)
if (pixel[i] > pixel[imax])
imax = i;
return pixel[imax];
}

// return the minimum value of the image
template <class T>
T Image<T>::min() {
int i,imin,n = height()*width();
for (i=imin=0; i < n; i++)
if (pixel[i] < pixel[imin])
imin = i;
return pixel[imin];
}



#define RED(pixel) ((pixel) & 0xff)
#define GREEN(pixel) (((pixel)>>8) & 0xff)
#define BLUE(pixel) (((pixel)>>16) & 0xff)
#define COLOR_RGB(r,g,b) (((b)<<16)+((g)<<8)+(r))



class RGBImage : public Image<int> {

public:
RGBImage() { };
~RGBImage() { };
inline void setPix( int x, int y, unsigned char r, unsigned char g, unsigned char b) {
(*this)(x,y) = COLOR_RGB(r,g,b);
}
inline void setPix( int i, unsigned char r, unsigned char g, unsigned char b) {
(*this)[i] = COLOR_RGB(r,g,b);
}
};




#endif




Anybody can teach me specific steps to follow in order for me to use a fully-c++ .h file?

marcel
23rd July 2007, 07:04
Well, what you have there is a template image class and a particular Image<int>.
I really haven't seen RGB components represented on 32 bits, so I recommend using 8 bit components.

The class seems to have simple methods to get/set pixel data in an image, also to query image properties.

What you have to do is to include this header in a source file( wherever you need it ) and instantiate the Image<int> class.
Then you can fill this with image data.

Basically, this is it.

Regards

sincnarf
30th July 2007, 22:45
Continued: Problems on image's colors after using qRed qBlue qGreen qRgb.

Anyone here encountered loading an image (either of the three: JPEG PNG BMP) and all you see are shades of blue and black?

Thanks by the way, but I have another problem. eventhough I can now compile my project without errors (eventhough I am able to use the functions COLOR_RGB(), RED(x,y),

GREEN(x,y) and BLUE(x,y)), there seems to be something wrong with the qRgb, qRed, qGreen and qBlue functions of Qt. Or is it just that I am using the wrong

image conversion type? - (QImage::Format_RGB32)

I am trying to copy a QImage's RGB values to my Image<t,t> but wrong colors or RGB components are set regardless of the image type (JPG PNG BMP) using my function.


void MainWindow::doF1()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::currentPath());
if (!fileName.isEmpty()) {
QImage tempImage(fileName);
if (tempImage.isNull()) {
QMessageBox::information(this, tr("Load Warning"), tr("Cannot load %1.").arg(fileName));
return;
}


QImage image = tempImage.convertToFormat(QImage::Format_RGB32);
imagelabImage.resize(image.width(), image.height());
int pixel = 0;
int x = 0;
int y = 0;

for (x= 0; x < image.width(); x++){
for (y = 0; y < image.height(); y++){
pixel = image.pixel(x, y);

// The following line I think is where something weird happens to the
// red and green components of a non-black pixel.

imagelabImage(x, y) = qRgb(qRed(pixel), qGreen(pixel) , qBlue(pixel));

// for Non-black colors (not (0, 0, 0)), the red and green components become 0 after applying qRgb().

// I used this to print each pixel
// QString rgb = QString::number(qRed(pixel), 10) + QString::number(qGreen(pixel), 10) + QString::number(qBlue(pixel), 10);
// QMessageBox::information(this, tr("rgb = "), rgb);

// and I observed that the color white becomes (0, 0, 255) which is not //correct, because white is supposed
// to be (255, 255, 255) but I got (0, 0, 255) which is blue.

pixel = imagelabImage(x, y);
image.setPixel(x, y, pixel);
}
}

QGraphicsScene *scene = new QGraphicsScene;
QGraphicsPixmapItem *item = scene->addPixmap(QPixmap::fromImage(image));
item->setShapeMode(QGraphicsPixmapItem::BoundingRectShap e);
item->setFlag(QGraphicsItem::ItemIsMovable);
graphicsViewVis->setScene(scene);
graphicsViewVis->show();
}
}


The doF1 function stated above just copies a qt image with type QImage::Format_RGB32 into the RGBImage/Image<t,t> I originally included before. Then from that RGBImage / Image<t,t>, I copy it again to a QImage so that it can be displayed.

See the screen shot below attached herewith. the left QGraphicsView is the original image, the right QGraphicsView contains the supposed to be copied image. but observe that the image is not copied correctly because you'll only see an image with shades of black and blue.

http://www.qtcentre.org/forum/attachment.php?attachmentid=1435&d=1185826530

Here is another image that when applied with my function doF1 becomes an image with only shades of blue and black.

http://www.qtcentre.org/forum/attachment.php?attachmentid=1436&d=1185827544

So my main problem now is I do not know what's wrong with my doF1 function, if it's the qRgb, qRed, qGreen, qBlue that have bugs or if I am using the wrong image conversion type (QImage::Format_RGB32).

marcel
30th July 2007, 22:59
It seems to me that the RGBImage class stores RGB components as (unsigned char), while QImage gives them as int.

So you have a type incompatibility there.

What type is imagelabimage?

Regards

marcel
30th July 2007, 23:11
Yes, I think that is it.

#define COLOR_RGB(r,g,b) (((b)<<16)+((g)<<8)+(r))



class RGBImage : public Image<int> {

public:
RGBImage() { };
~RGBImage() { };
inline void setPix( int x, int y, unsigned char r, unsigned char g, unsigned char b) {
(*this)(x,y) = COLOR_RGB(r,g,b);
}
inline void setPix( int i, unsigned char r, unsigned char g, unsigned char b) {
(*this)[i] = COLOR_RGB(r,g,b);
}
};
If you look at that code, you can see that the pixel depth in that image is 24 bits, while a qRgb component is actually 32 bits and I don't really know if it works to assign a qRgb to a Image pixel.

You could try something like this:

unsigned char rcomp = (unsigned char)(qRed(pixel)>>24);
unsigned char gcomp = (unsigned char)(qGreen(pixel)>>24);
unsigned char bcomp = (unsigned char)(qBlue(pixel)>>24);
imagelabImage->setPix(x, y, rcomp, gcomp, bcomp);
To retrieve the current pixel just ask getPix from imagelabImage.

If shifting doesn't work, you can just try the explicit cast.
I cannot test and I am not sure which one will work.

You can take a look at what qRed,... return and if they are between 0..255 then only a cast is needed.
I think this is the case so you can lose the shifting.

Regards

sincnarf
1st August 2007, 21:31
Thanks marchel, i did what was suggested but the images now do not look like shades of blue and black, instead, all the pixels were set to black!! (0, 0, 0). what exactly does >>24, >>8 or >>16 do?

marcel
1st August 2007, 21:37
OK. I thought that would happen.
">>" is the C++ shift right operator.
>> 24 means shift right with 24 bits aka divide by 2^24.

But it is OK.
You can just lose the shifting and it will work:

unsigned char rcomp = (unsigned char)(qRed(pixel));
unsigned char gcomp = (unsigned char)(qGreen(pixel));
unsigned char bcomp = (unsigned char)(qBlue(pixel));
imagelabImage->setPix(x, y, rcomp, gcomp, bcomp);
The shifting is not necessary anymore since qRed, qBlue and qGreen expand 8 bit values to 32 bit.
So you basically get a 32 bit value with the most 24 significant bits always 0.

Regards

sincnarf
2nd August 2007, 03:03
Still no luck removing the >>24 does not set the right colors, it returned to having shades of blue and black only.

marcel
2nd August 2007, 09:47
I don't know. Can you post the updated code?
It wouldn't hurt if you did some debugging, to see what values you actually put/take out from that image.


Still no luck removing the >>24 does not set the right colors, it returned to having shades of blue and black only.
Well, things like this (meaning image handling) can't be done by guessing to add or remove something in the code. What you do has to be logic.

So I would start with debugging, see what are the pixels taken from the QImage and what are the pixels taken from the Image.

If possible, post those debug values.

Regards

sincnarf
2nd August 2007, 13:11
Thanks again Marcel. Here's my current function and I can already load an image, though there's a problem with the colors (see attached image). The colors are somewhat "adjusted" using Format_RGB32. The original objective is just to create an exact copy from the left graphicsView to the rightgraphics view.


void MainWindow::doF1()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Image"), QDir::currentPath());
if (!fileName.isEmpty()) {
QImage tempImage(fileName);

if (tempImage.isNull()) {
QMessageBox::information(this, tr("Load Warning"),
tr("Cannot load %1.").arg(fileName));
return;
}
QImage image = tempImage.convertToFormat(QImage::Format_RGB32);
RGBImage rgbImage;
rgbImage.resize(image.width(), image.height());

int pixel = 0;
int x = 0;
int y = 0;

for (x= 0; x < image.width(); x++){
for (y = 0; y < image.height(); y++){
pixel = image.pixel(x, y);

unsigned char rcomp = (unsigned char)(qRed(pixel));
unsigned char gcomp = (unsigned char)(qGreen(pixel));
unsigned char bcomp = (unsigned char)(qBlue(pixel));

rgbImage.setPix(x, y, rcomp, gcomp, bcomp);

pixel = rgbImage(x,y);
image.setPixel(x, y, pixel);

}
}

QGraphicsScene *scene = new QGraphicsScene;
QGraphicsPixmapItem *item = scene->addPixmap(QPixmap::fromImage(image));
item->setShapeMode(QGraphicsPixmapItem::BoundingRectShap e);
item->setFlag(QGraphicsItem::ItemIsMovable);
graphicsViewVis->setScene(scene);
graphicsViewVis->show();
}
}


Observe the colors that were set in the right image (attached Format_RGB32.jpg), http://www.qtcentre.org/forum/attachment.php?attachmentid=1443&d=1186052918I tried to print the values of the rgbImage and they're exactly the same as the original/left Image, I think that there's something wrong with using QImage::Format_RGB32.

So I tried to use QImage::Indexed8 and the colors were correct http://www.qtcentre.org/forum/attachment.php?attachmentid=1444&d=1186052918, but the main problem in using QImage::Indexed8 is that the right image has white spots and the loading of the image takes too long (about 15 seconds, I thought the program hung but it didnt).

Which makes me decide to use QImage::Format_RGB32 and possibly create a way to recompute/correct the rgb values. This is my current problem.

marcel
2nd August 2007, 13:23
You should stick to RGB32.
The problem is in line 31 of the code you posted:

pixel = rgbImage(x,y);
As before, you can't assign that directly.
First convert it to qRgb, using qRed, etc...
It is the reverse transformation of what you did before.

EDIT: Actually, I think it is better to use the macros from your header to extract the components and build a qRgb:

#define RED(pixel) ((pixel) & 0xff)
#define GREEN(pixel) (((pixel)>>8) & 0xff)
#define BLUE(pixel) (((pixel)>>16) & 0xff)


Regards

sincnarf
3rd August 2007, 04:39
EDIT: Actually, I think it is better to use the macros from your header to extract the components and build a qRgb:


At last! Solved the problem. Thanks !!! Thank you Marcel, expect your name in my acknowledgements page. Hehe