PDA

View Full Version : OpenGL image viewer, need some help on implementation



Randulf
9th May 2007, 16:38
Hi i'm currently working on an application for showing HDR-images and need some tips on how to implement zooming in the application.
I have made a multi document interface with QtOpenGL widgets for displaying the images. in this widget I make a texture on a polygon the same size as the image.
Question is when zooming is it best to scale the polygon or change the viewport or gluOrtho2D? Or am I doing this all wrong?
I want the application to behave like for example photosshop so when I resize the window displaying the image the scale stays the same and in the middle of the window. Later on I also have to get the image coordinates from the mouseMove function so that I can display the raw color values of the image.

Right now it looks like this:


void GLWidget::resizeGL(int width, int height) {

glViewport( width / 2 - imageWith / 2,
height / 2 - imageHeight / 2,
imageWith,
imageHeight );
}



void GLWidget::paintGL()
{
...........

glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0, imageWith, 0, imageHeight);
.................
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
.................
glBegin( GL_QUADS );
glTexCoord2f( 0.0f, 0.0f );
glVertex2f( offsetValues[0], offsetValues[1] );

glTexCoord2f( 1.0f, 0.0f );
glVertex2f( (float)imageWith + offsetValues[0], offsetValues[1] );

glTexCoord2f( 1.0f, 1.0f );
glVertex2f( (float)imageWith + offsetValues[0], (float)imageHeight + offsetValues[1] );

glTexCoord2f( 0.0f, 1.0f );
glVertex2f( offsetValues[0], (float)imageHeight + offsetValues[1] );

glEnd();

}


Is there a simple way to do this? How would you do it?
I'm quite new to qt and still have a lot to learn in the noble art of programming.
Some help would be much appriciated.
Thanks in advance.
/Nils

minimoog
10th May 2007, 01:35
First thing.

ResizeGL method looks suspicouis, viewport depends of the image width and height, and doesn't make sense. Just use:


void GLWidget::resizeGL(int width, int height) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glViewport(0, 0, width, height);
};

This way you get texture to pixel exact mapping. So if vertex coordinate is x, y it's (x, y) coordinate on the window (be careful y axis is inverted).

For zooming you can scale, or change vertex coordinates (it's the same).

But I will think about the part scaling staying the same and in the middle.

What do you mean with "get the image coordinates from the mouseMove function so that I can display the raw color values of the image"?

BTW, this is mostly OpenGL related.

minimoog
10th May 2007, 02:13
Try this


void GLWidget::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, width, 0.0, height);
}



void GLWidget::paintGL()
{
................
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(width() / 2.0f, height() / 2.0f, 0.0f);
glScalef(scaleFactor, scaleFactor, 0.0f);
glTranslatef(-imageWidth / 2.0f, -imageHeight / 2.0f, 0.0f);

glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex2f(imageWidth, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex2f(imageWidth, imageHeight);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, imageHeight);
glEnd();
}

You must know the basics of matrix and coordinate transformations if you want to understand above code.

Randulf
10th May 2007, 08:10
Ah, yes!!
This is working perfectly. Thanks a lot!!!


What do you mean with "get the image coordinates from the mouseMove function so that I can display the raw color values of the image"?
Im going to have a widget with information about wich pixel the mouse pointer is over and what color values it has. Since I only get the window coordinates I have to translate them to image space. What I ment with raw valus is that I have two arrays with pixel valus, one with 32 bit HDR data and another with clamped values. Anyway that getting the valus from the array wont be a problem it just the translation that i'm unshure of.

Thanks again for the help.

Randulf
10th May 2007, 14:27
Hi!
Now I got everything working except from the translation from window coordinates to image.
This is how i do it now:


glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef(this->size().width() / 2.0f, this->size().height() / 2.0f, 0.0f);
glTranslatef(imageOffset.x(), -imageOffset.y(), 0.0f);
glScalef(zoomFactor, zoomFactor, 0.0f);
glTranslatef(-imageWidth / 2.0f, -imageHeight / 2.0f, 0.0f);

Then in the mouse move method:


void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
QPoint pos = event->pos();
QMatrix q,t1,t2,s,t3;
t1.translate(this->size().width() / 2, this->size().height() / 2);
t2.translate(imageOffset.x(), imageOffset.y());
s.scale(zoomFactor, zoomFactor);
t3.translate(- imageWidth / 2, - imageHeight / 2);
q = t1*t2*s*t3;
QMatrix qinv = q.inverted();
QPoint im = qinv.map(pos);
qDebug() << im;
}

This works fine when as long as I dont scale the image. I can move around the image in the window and it translates the coordinates.
This is is supposed to be simple.

Randulf
10th May 2007, 14:45
Seems like I multiplied the matrices in the wrong order.
Doing it the opposite way solved the problem.
q = t3*s*t2*t1;

minimoog
11th May 2007, 02:03
Well you have something like this transformations:

M = T1 * T2 * S * T3

You transform vertex with above transformations. Because projection is simple, with given window coordinate you want to know that position in object (untransformed) space, you need to untransform window coordinate to object space...

Vwindow = M * V

V = inverse(M) * Vwindow

inverse(T1 * T2 * S * T3) = inverse(T3) * inverse(T2) * inverse(S) * inverse(T1)

Because inverse of translation is just changing the sign, and inverse of scale is reciprocal

inverse(M) = (-T3) * (-T2) * (1 / S) * (-T1)

With this matrix you can transform window coordinate to object space (the image).

It's easy to build this matrix by yourself.

wysota
11th May 2007, 09:19
Is there a specific reason why you're doing it with OpenGL?

Randulf
11th May 2007, 11:07
Is there a specific reason why you're doing it with OpenGL?

Not really. Main reason is that I have used OpenGL before but for 3D.
Is QPainter easier to use?

wysota
11th May 2007, 11:21
I think you'd have fewer problems with a painter approach. All the rendering problems (transformations, etc.) would vanish and getting cursor coordinates would be as easy as reading a variable from the mouse event.

The most basic way to implement the viewer would be to use a QLabel with a pixmap. You can also embed it into a scroll area if you want scroll bars. Of course you can draw the image yourself using QPainter if you want more control over it (like easy scaling, etc.).

minimoog
11th May 2007, 14:12
We talk about HDR images, which pixel is represented with 16 bit float, 32 bit float or 32 bit integer. QPixmap doesn't support this kind of format. OpenGL support textures in 32 bit float format (GF 6 up, Radeon 9800 up) or 16 bit float (GF2 up). Also, he can use shaders for image processing.

wysota
11th May 2007, 14:58
We talk about HDR images, which pixel is represented with 16 bit float, 32 bit float or 32 bit integer. QPixmap doesn't support this kind of format.
Does your screen support it? Because if not, there is no point in doing something which you'll never see.


Also, he can use shaders for image processing.

And probe texels for colours when he wants to check the pixel value?

Using shaders would make sense if he had 100 images per second to process, but not with an image viewer. At least that's my point of view.