00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <iostream>
00031 #include <math.h>
00032 #include <highgui.h>
00033
00034 using namespace std;
00035
00036 #include <qpixmap.h>
00037 #if QT_VERSION >= 0x040000
00038 #include <QMouseEvent>
00039 #endif
00040 #include "glbox.h"
00041 #include <stdlib.h>
00042
00043 #if defined(Q_CC_MSVC)
00044 #pragma warning(disable:4305) // init: truncation from const double to float
00045 #endif
00046
00051 GLBox::GLBox(QWidget* parent, const char* , const QGLWidget* shareWidget)
00052 : QGLWidget( parent, shareWidget )
00053 {
00054 init();
00055 }
00056
00057 GLBox::GLBox(const QGLFormat &format, QWidget *parent, const char *, const QGLWidget* shareWidget)
00058 : QGLWidget( format, parent, shareWidget )
00059 {
00060 init();
00061 }
00062
00063 void GLBox::init()
00064 {
00065 textureWidth = 0;
00066 textureHeight = 0;
00067 image=0;
00068 dx=dy=0;
00069 sx=sy=1;
00070 reloadImage = true;
00071 allowCache = false;
00072 yAxisUp = false;
00073 smooth=false;
00074 setupTransform();
00075 }
00076
00081 GLBox::~GLBox()
00082 {
00083 makeCurrent();
00084 if (texture!=0)
00085 glDeleteTextures( 1, &texture );
00086 }
00087
00088
00094 void GLBox::paintGL()
00095 {
00096
00097 glClearColor(0,0,0,0);
00098 glClear( GL_COLOR_BUFFER_BIT );
00099
00100 if (image ==0) return;
00101
00102
00103 float w = float(image->width);
00104 float h = float(image->height);
00105 float u = w/float(textureWidth);
00106 float v = h/float(textureHeight);
00107 float vUp = 0;
00108
00109 if (image->origin) {
00110
00111 vUp = v;
00112 v = 0;
00113 }
00114
00115 float imUp = 0;
00116
00117 if (yAxisUp) {
00118 imUp = h;
00119 h = 0;
00120 }
00121
00122 setImageSpace();
00123
00124 glDisable(GL_BLEND);
00125 loadTexture();
00126 glEnable(GL_TEXTURE_2D);
00127 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (smooth ? GL_LINEAR : GL_NEAREST));
00129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00130
00131 glBegin(GL_QUADS);
00132
00133 glTexCoord2f(u,v);
00134 glVertex2f(w,h);
00135
00136
00137 glTexCoord2f(u,vUp);
00138 glVertex2f(w,imUp);
00139
00140
00141 glTexCoord2f(0,vUp);
00142 glVertex2f(0,imUp);
00143
00144
00145 glTexCoord2f(0,v);
00146 glVertex2f(0,h);
00147
00148 glEnd();
00149
00150 glDisable(GL_TEXTURE_2D);
00151
00152 }
00153
00154
00159 void GLBox::initializeGL()
00160 {
00161 reloadImage = true;
00162
00163 glClearColor( 1,1,1,1 );
00164
00165
00166 }
00167
00168 GLuint GLBox::genGlTexture(int texWidth, int texHeight, bool smooth) {
00169 GLuint tex;
00170
00171
00172 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00173
00174 glGenTextures(1,&tex);
00175 glBindTexture(GL_TEXTURE_2D, tex);
00176
00177 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00178 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (smooth ? GL_LINEAR : GL_NEAREST));
00180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (smooth ? GL_LINEAR : GL_NEAREST));
00181
00182 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth,texHeight, 0, GL_RGBA,
00183 GL_UNSIGNED_BYTE, 0);
00184
00185 return tex;
00186 }
00187
00192 void GLBox::resizeGL( int w, int h )
00193 {
00194 glViewport( 0, 0, (GLint)w, (GLint)h );
00195 glMatrixMode( GL_PROJECTION );
00196 glLoadIdentity();
00197 glMatrixMode( GL_MODELVIEW );
00198 }
00199
00200 void GLBox::setImage( IplImage *image ) {
00201
00202 this->image = image;
00203 reloadImage = true;
00204 }
00205
00206 void GLBox::screenToImageCoord(int x, int y, float *imx, float *imy) const
00207 {
00208 float w = (float)width();
00209 float h = (float)height();
00210
00211 if (imx) *imx=0;
00212 if (imy) *imy=0;
00213 if (!image) return;
00214
00215 float fx = (float(x)*(float)image->width)/w;
00216 float fy = (float(y)*(float)image->height)/h;
00217
00218 if (imx) *imx = invAffineTransf[0][0]*fx + invAffineTransf[0][1]*fy + invAffineTransf[0][2];
00219 if (imy) *imy = invAffineTransf[1][0]*fx + invAffineTransf[1][1]*fy + invAffineTransf[1][2];
00220 }
00221
00222 #ifdef WIN32
00223 int lrint(float f) {
00224 return (int) floor(f+0.5);
00225 }
00226 #endif
00227
00228 void GLBox::imageToScreenCoord(float x, float y, int *scrx, int *scry) const
00229 {
00230
00231 float w = (float)width();
00232 float h = (float)height();
00233
00234 float imw=640;
00235 float imh=480;
00236
00237 if (image) {
00238 imw = image->width;
00239 imh = image->height;
00240 }
00241
00242 if (scrx) *scrx = lrint((affineTransf[0][0]*x + affineTransf[0][1]*y + affineTransf[0][2])*w/imw);
00243 if (scry) *scry = lrint((affineTransf[1][0]*x + affineTransf[1][1]*y + affineTransf[1][2])*h/imh);
00244 }
00245
00246 void GLBox::setupTransform() {
00247
00248 float h,f;
00249
00250 if (image) {
00251 h = (float)image->height;
00252 f = yAxisUp ? -1 : 1;
00253 } else {
00254 h = 0;
00255 f = 1;
00256 }
00257
00258 affineTransf[0][0] = sx;
00259 affineTransf[1][0] = 0;
00260
00261
00262 affineTransf[0][1] = 0;
00263 affineTransf[1][1] = sy*f;
00264
00265
00266 affineTransf[0][2] = dx*affineTransf[0][0];
00267 affineTransf[1][2] = dy*affineTransf[1][1] + (sy*(1-f)*h)/2;
00268
00269
00270 invertAffine();
00271 }
00272
00273
00274 #ifdef WITH_LIBVISION
00275
00276 void iplShareRaster(VL::RasterImage *ri, IplImage *ipl)
00277 {
00278 memset(ipl, 0, sizeof(IplImage));
00279 switch (ri->bytes) {
00280 case 1: ipl->depth = IPL_DEPTH_8U;
00281 ipl->nChannels = 1;
00282 memcpy(ipl->colorModel, "GRAY", 4);
00283 memcpy(ipl->channelSeq, "GRAY", 4);
00284 break;
00285 case 3: ipl->depth = IPL_DEPTH_8U;
00286 ipl->nChannels = 3;
00287 strcpy(ipl->colorModel, "RGB");
00288 strcpy(ipl->channelSeq, "RGB");
00289 break;
00290 case 4: ipl->depth = IPL_DEPTH_32F;
00291 ipl->nChannels = 1;
00292 break;
00293 default:
00294 std::cerr << "iplShareRaster(): unknown format !\n";
00295 abort();
00296 }
00297 ipl->width = ri->xdim;
00298 ipl->height = ri->ydim;
00299 ipl->imageData = (char *)ri->array;
00300 ipl->nSize = sizeof(IplImage);
00301 ipl->widthStep = ipl->width * ri->bytes;
00302 ipl->imageSize = ipl->widthStep * ipl->height;
00303 ipl->align = 1;
00304 }
00305
00306 void GLBox::setImage(VL::RasterImage *im)
00307 {
00308 iplShareRaster(im, &iplIm);
00309 setImage(&iplIm);
00310 }
00311
00312 #endif
00313
00314 void GLBox::setImageSpace()
00315 {
00316 GLfloat m[16];
00317 double w=640,h=480;
00318
00319 if (image) {
00320 w = image->width;
00321 h = image->height;
00322 }
00323
00324 glMatrixMode(GL_PROJECTION);
00325 glLoadIdentity();
00326 glOrtho(0, w, h, 0, -10, 10);
00327
00328 m[0] = affineTransf[0][0];
00329 m[1] = affineTransf[1][0];
00330 m[2] = 0;
00331 m[3] = 0;
00332
00333 m[4] = affineTransf[0][1];
00334 m[5] = affineTransf[1][1];
00335 m[6] = 0;
00336 m[7] = 0;
00337
00338 m[8] = 0;
00339 m[9] = 0;
00340 m[10] = 1;
00341 m[11] = 0;
00342
00343 m[12] = affineTransf[0][2] ;
00344 m[13] = affineTransf[1][2] ;
00345 m[14] = 0;
00346 m[15] = 1;
00347
00348 glMultMatrixf(m);
00349
00350 glMatrixMode(GL_MODELVIEW);
00351 glLoadIdentity();
00352 }
00353
00354 void GLBox::saveContext() {
00355 savedTexture = texture;
00356 }
00357
00358 void GLBox::restoreContext() {
00359 texture = savedTexture;
00360 }
00361
00362 bool GLBox::renderAndSave(const char *filename, int , int )
00363 {
00364 show();
00365 raise();
00366
00367
00368 makeCurrent();
00369 paintGL();
00370
00371 IplImage *buffer = cvCreateImage(cvSize(width(), height()), IPL_DEPTH_8U, 3);
00372 glReadPixels(0, 0, width(), height(), GL_BGR_EXT, GL_UNSIGNED_BYTE, buffer->imageData);
00373
00374 buffer->origin = 1;
00375 cvSaveImage(filename, buffer);
00376 cvReleaseImage(&buffer);
00377 return true;
00378
00379 }
00380
00381 void GLBox::loadTexture()
00382 {
00383 glBindTexture(GL_TEXTURE_2D, texture);
00384 if (reloadImage) {
00385 loadGlTexture(image);
00386 if (allowCache) reloadImage = false;
00387 }
00388 }
00389
00390 void GLBox::loadGlTexture(IplImage *im) {
00391
00392 if (!im) return;
00393
00394 if (texture && (textureWidth < im->width || textureHeight < im->height)) {
00395 glDeleteTextures( 1, &texture );
00396 texture = 0;
00397 }
00398 if (texture==0) {
00399 texture = genGlTexture(im->width, im->height, smooth);
00400 textureWidth = im->width;
00401 textureHeight = im->height;
00402 }
00403
00404 glBindTexture(GL_TEXTURE_2D, texture);
00405
00406 GLenum format;
00407 GLenum type;
00408 switch (im->depth) {
00409 case IPL_DEPTH_8U: type = GL_UNSIGNED_BYTE; break;
00410 case IPL_DEPTH_8S: type = GL_BYTE; break;
00411 case IPL_DEPTH_16S: type = GL_SHORT; break;
00412 case IPL_DEPTH_32F: type = GL_FLOAT; break;
00413 default:
00414 cerr << "GLBox::paintGL(): unsupported pixel type.\n";
00415 return;
00416 }
00417 switch (im->nChannels) {
00418 case 1: format = GL_LUMINANCE; break;
00419 case 3: format = (im->channelSeq[0] == 'B') ? GL_BGR_EXT : GL_RGB; break;
00420 case 4: format = GL_RGBA; break;
00421 default:
00422 cerr << "GLBox::paintGL(): unsupported number of channels.\n";
00423 return;
00424 }
00425
00426
00427 glPixelStorei(GL_UNPACK_ALIGNMENT, im->align);
00428
00429 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, im->width, im->height,
00430 format, type, im->imageData);
00431 }
00432
00433 void GLBox::mousePressEvent(QMouseEvent *e)
00434 {
00435 if (e->button() == Qt::LeftButton) {
00436 lastMousePos = e->pos();
00437 }
00438 }
00439
00440 void GLBox::mouseMoveEvent ( QMouseEvent * e )
00441 {
00442 float x1, y1, x2, y2;
00443 screenToImageCoord(lastMousePos.x(), lastMousePos.y(), &x1, &y1);
00444 screenToImageCoord(e->pos().x(), e->pos().y(), &x2, &y2);
00445
00446 lastMousePos = e->pos();
00447 dx += (x2 - x1);
00448 dy += (y2 - y1);
00449
00450 setupTransform();
00451 update();
00452 }
00453
00454 void GLBox::wheelEvent( QWheelEvent *e )
00455 {
00456 e->accept();
00457
00458 int delta = e->delta();
00459 float s= delta / 110.0f;
00460
00461 if (delta < 0)
00462 s = 1/(-s);
00463
00464 sx *= s;
00465 sy *= s;
00466 setupTransform();
00467 update();
00468 }
00469
00470 void GLBox::invertAffine() {
00471 float t4 = 1/(-affineTransf[1][0]*affineTransf[0][1]+affineTransf[0][0]*affineTransf[1][1]);
00472 invAffineTransf[0][0] = affineTransf[1][1]*t4;
00473 invAffineTransf[0][1] = -affineTransf[0][1]*t4;
00474 invAffineTransf[0][2] = (affineTransf[0][1]*affineTransf[1][2]-affineTransf[0][2]*affineTransf[1][1])*t4;
00475 invAffineTransf[1][0] = -affineTransf[1][0]*t4;
00476 invAffineTransf[1][1] = affineTransf[0][0]*t4;
00477 invAffineTransf[1][2] = -(affineTransf[0][0]*affineTransf[1][2]-affineTransf[0][2]*affineTransf[1][0])*t4;
00478 }
00479