GLImageWidget.cpp
Go to the documentation of this file.
00001 /*******************************************************************************
00002  *  MapGLWidget.cpp
00003  *
00004  *  (C) 2006 AG Aktives Sehen <agas@uni-koblenz.de>
00005  *           Universitaet Koblenz-Landau
00006  ******************************************************************************/
00007 
00008 
00009 #include "GLImageWidget.h"
00010 
00011 //#include "Architecture/Config/Config.h" // TODO
00012 #include "../../Workers/Puma2/ThermalToColorOperator.h"
00013 #include "../../Workers/Puma2/Y8UV8ToRGB8Operator.h"
00014 // #include "../../Workers/Puma2/ImageWriter.h"
00015 
00016 #include <sstream>
00017 #include <QMouseEvent>
00018 
00019 using namespace puma2;
00020 
00021 #define THIS GLImageWidget
00022 
00023 const float ZOOM_STEP = sqrt(sqrt(2));
00024 
00025 THIS::THIS(QGLWidget *parent) : QGLWidget(parent) {
00026 
00027   setCursor(Qt::SizeAllCursor);
00028 
00029   m_Zoom=1.0;
00030   m_PosX=0.0;
00031   m_PosY=0.0;
00032 
00033   m_ImageWidth=1;
00034   m_ImageHeight=1;
00035   m_ViewportWidth=1;
00036   m_ViewportHeight=1;
00037 
00038   setPixelAspectRatio(1.0);
00039 
00040   m_TextureId=-1;
00041   m_TextureData=0;
00042   m_TextureResolution=0;
00043   m_TextureFormat=ImageGrabber::GRAY8;
00044   m_TextureByteSize=0;
00045 
00046   setMinimumSize(40,40);
00047 
00048 }
00049 
00050 THIS::~THIS() {
00051   if( m_TextureData ) {
00052     //TRACE_SYSTEMINFO( "Deleting texture memory" ) // TODO use ros
00053     delete[] m_TextureData;
00054   }
00055   if ( int(m_TextureId) != -1 ) {
00056     // TRACE_SYSTEMINFO( "Deleting OpenGL texture" ) // TODO use ros
00057     glDeleteTextures(1,&m_TextureId);
00058   }
00059 }
00060 
00061 void THIS::initializeGL() {
00062 
00063   glClearColor(1.0, 1.0, 1.0, 0.0);
00064 
00065   QSize s = size();
00066   int w = s.width();
00067   int h = s.height();
00068   m_ViewportWidth=w;
00069   m_ViewportHeight=h;
00070   glViewport(0, 0, m_ViewportWidth, m_ViewportHeight);
00071   glDisable( GL_DEPTH_TEST );
00072 }
00073 
00074 void THIS::resizeGL(int w, int h)
00075 {
00076   m_ViewportWidth=w;
00077   m_ViewportHeight=h;
00078   glViewport(0, 0, m_ViewportWidth, m_ViewportHeight);
00079   updateGL();
00080 }
00081 
00082 void THIS::paintGL() {
00083 
00084   //only update if visible on screen
00085   if (isVisible())
00086   {
00087     glClear( GL_COLOR_BUFFER_BIT );
00088     glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00089 
00090     glMatrixMode(GL_PROJECTION);
00091     glLoadIdentity();
00092     //the Y axis points downwards, center of view in (0,0,0):
00093   //  glOrtho(-0.5, 0.5, 0.5, -0.5, -1.0, 1.0);
00094     glOrtho( -0.5, 0.5, 0.5, -0.5, -1.0, 1.0);
00095     glMatrixMode(GL_MODELVIEW);
00096     glLoadIdentity();
00097 
00098     //correct aspect
00099     float viewPortAspect=float(m_ViewportWidth) / float(m_ViewportHeight);
00100     float imageAspect=float(m_ImageWidth) / float(m_ImageHeight) * m_PixelAspectRatio;
00101     float scaleX,scaleY;
00102 
00103     if (viewPortAspect > imageAspect) {
00104       scaleX=imageAspect/viewPortAspect;
00105       scaleY=1.0;
00106     } else {
00107       scaleX=1.0;
00108       scaleY=viewPortAspect/imageAspect;
00109     }
00110 
00111     //e.g. 1.0 means the image is as large as the viewport, 2.0 that it is two times larger
00112     float relativeImageWidth=scaleX*m_Zoom;
00113     float relativeImageHeight=scaleY*m_Zoom;
00114     float maxX;
00115     float maxY;
00116 
00117     if ( relativeImageWidth < 1.0 ) {
00118       maxX=(0.5/relativeImageWidth)-0.5;
00119     } else {
00120       maxX=(0.5*relativeImageWidth)-0.5;
00121     }
00122     if ( relativeImageHeight < 1.0 ) {
00123       maxY=(0.5/relativeImageHeight)-0.5;
00124     } else {
00125       maxY=(0.5*relativeImageHeight)-0.5;
00126     }
00127 
00128     if ( m_PosY >  maxY ) { m_PosY= maxY; }
00129     if ( m_PosY < -maxY ) { m_PosY=-maxY; }
00130     if ( m_PosX >  maxX ) { m_PosX= maxX; }
00131     if ( m_PosX < -maxX ) { m_PosX=-maxX; }
00132 
00133     glTranslatef(m_PosX,m_PosY,0.0);
00134     glScalef(m_Zoom,m_Zoom,0.0);
00135     glScalef( scaleX, scaleY, 1.0 );
00136 
00137     if (m_TextureData)
00138     {
00139       paintImage();
00140       paintVectorObjects();
00141     }
00142   }
00143 }
00144 
00145 void THIS::paintImage(){
00146 
00147   glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00148   glColor3f(1.0, 1.0, 1.0);
00149 
00150   if (m_TextureData) {
00151 
00152     if ( int ( m_TextureId ) == -1 )
00153     {
00154       glGenTextures ( 1, &m_TextureId );
00155       std::ostringstream stream;
00156       stream << "Using OpenGL texture # " << m_TextureId;
00157       // TRACE_INFO ( stream.str() ); // TODO use ros
00158     }
00159     else
00160     {
00161 //      glDeleteTextures ( 1, &m_TextureId );
00162 //      glGenTextures ( 1, &m_TextureId );
00163     }
00164 
00165     std::ostringstream stream;
00166     stream << "Loading texture data to texture ID " << m_TextureId;
00167     // TRACE_SYSTEMINFO( stream.str() ) // TODO use ros
00168 
00169     glEnable(GL_TEXTURE_2D);
00170     glBindTexture(GL_TEXTURE_2D, m_TextureId);
00171 
00172     if (m_TextureFormat==ImageGrabber::RGB8) {
00173       glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, m_TextureResolution, m_TextureResolution, 0, GL_RGB, GL_UNSIGNED_BYTE, m_TextureData );
00174     } else {
00175       glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, m_TextureResolution, m_TextureResolution, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_TextureData );
00176     }
00177   }
00178 
00179   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00180   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
00181   glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
00182 
00183   float usedTextureY=float(m_ImageHeight) / float(m_TextureResolution);
00184   float usedTextureX=float(m_ImageWidth) / float(m_TextureResolution);
00185 
00186   //draw
00187   glColor3f(0.0, 1.0, 0.0);
00188   glBegin(GL_POLYGON);
00189     glTexCoord2f(  0.0,  0.0 );
00190     glVertex3f( -0.5, -0.5, 0.0 );
00191     glTexCoord2f(  0.0,  usedTextureY );
00192     glVertex3f( -0.5, 0.5, 0.0 );
00193     glTexCoord2f(  usedTextureX, usedTextureY  );
00194     glVertex3f( 0.5, 0.5, 0.0 );
00195     glTexCoord2f(  usedTextureX,  0.0 );
00196     glVertex3f( 0.5, -0.5, 0.0 );
00197   glEnd();
00198 
00199   glDisable(GL_TEXTURE_2D);
00200 }
00201 
00202 
00203 void THIS::paintVectorObjects()
00204 {
00205   glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
00206   glColor3f(1.0, 1.0, 1.0);
00207   glPushMatrix();
00208   //scale to fit [-0.5..0.5]
00209   glTranslatef( -0.5, -0.5, 0.0 );
00210   //scale to fit [0..1]
00211   glScalef( 1.0/m_ImageWidth, 1.0/m_ImageHeight, 1.0 );
00212   //translate vertex coordinates to pixel centers (instead of top-left pixel corner)
00213   glTranslatef( 0.5, 0.5, 0.0 );
00214 
00215   std::list< VectorObject2D >::iterator vectorObjectIt;
00216   vectorObjectIt = m_VectorObjects.begin();
00217   while( vectorObjectIt != m_VectorObjects.end() )
00218   {
00219     vectorObjectIt->paintGl();
00220     vectorObjectIt++;
00221   }
00222 
00223   glPopMatrix();
00224 }
00225 
00226 void THIS::setColorImage(const unsigned char *image, unsigned width, unsigned height, float aspect)
00227 {
00228     if (!image) {
00229       //ROS_ERROR_STREAM("Received 0-pointer!");
00230       return;
00231     }
00232     setPixelAspectRatio( aspect );
00233 
00234 //    unsigned char convertedImage[image->size()];
00235 //    for(unsigned i = 0; i < image->size(); i++)
00236 //    {
00237 //        convertedImage[i] = image->at(i);
00238 //    }
00239     updateTexture( (unsigned char*)(const_cast<unsigned char*>(image)), width, height, ImageGrabber::RGB8 );
00240 }
00241 
00242 void THIS::setColorImage(const ColorImageRGB8* image, float aspect )
00243 {
00244   if (!image) {
00245     // TRACE_ERROR("Received 0-pointer!"); // TODO use ros
00246     return;
00247   }
00248   setPixelAspectRatio( aspect );
00249   updateTexture( (unsigned char*)(const_cast<ColorImageRGB8*>(image)->unsafeRowPointerArray()[0][0]), image->getWidth(), image->getHeight(), ImageGrabber::RGB8 );
00250 }
00251 
00252 void THIS::setColorImage(const GrayLevelImage8* imageY, const ColorImageUV8* imageUV, float aspect )
00253 {
00254   if ((!imageY) || (!imageUV)) {
00255     //TRACE_ERROR("Received 0-pointer!"); // TODO use ros
00256     return;
00257   }
00258 
00259   ColorImageRGB8 imageRGB;
00260   Y8UV8ToRGB8Operator o( *imageY, *imageUV, imageRGB );
00261   setPixelAspectRatio( aspect );
00262   updateTexture( (unsigned char*)( imageRGB.unsafeRowPointerArray()[0][0]), imageRGB.getWidth(), imageRGB.getHeight(), ImageGrabber::RGB8 );
00263 }
00264 
00265 void THIS::setGrayLevelImage(const puma2::GrayLevelImage8* image, float aspect )
00266 {
00267   if (!image) {
00268     // TRACE_ERROR("Received 0-pointer!"); // TODO use ros
00269     return;
00270   }
00271 
00272   setPixelAspectRatio( aspect );
00273   updateTexture( (unsigned char*)(const_cast<GrayLevelImage8*>(image)->unsafeRowPointerArray()[0]), image->getWidth(), image->getHeight(), ImageGrabber::GRAY8 );
00274 }
00275 
00276 void THIS::setThermalImage(const puma2::GrayLevelImage8* image, float roomTemp )
00277 {
00278   if (!image) {
00279     //TRACE_ERROR("Received 0-pointer!"); // TODO use ros
00280     return;
00281   }
00282   // TRACE_INFO("Received a new ThermalImage");// TODO use ros
00283 
00284   ColorImageRGB8 coloredThermalImage;
00285   ThermalToColorOperator( *image, coloredThermalImage, roomTemp-20, roomTemp+100 );
00286 
00287   //by default, stretch to display as 4:3 image
00288   float width=image->getWidth();
00289   float height=image->getHeight();
00290   float correctAspect= 4.0 / 3.0;
00291   float imageAspect=float(width) / float(height);
00292   setColorImage( &coloredThermalImage, correctAspect / imageAspect );
00293 }
00294 
00295 void THIS::setAnaglyphImage( const puma2::GrayLevelImage8* leftYImage, const puma2::GrayLevelImage8* rightYImage, float aspect )
00296 {
00297   if ( !leftYImage || !rightYImage ) {
00298     // TRACE_ERROR("Received 0-pointer!"); // TODO use ros
00299     return;
00300   }
00301 
00302   int w=leftYImage->getWidth();
00303   int h=leftYImage->getHeight();
00304 
00305   setPixelAspectRatio( aspect );
00306 
00307   unsigned char* tempImage=new unsigned char[w*h*3];
00308   unsigned char* left=(unsigned char*)(const_cast<GrayLevelImage8*>(leftYImage)->unsafeRowPointerArray()[0]);
00309   unsigned char* right=(unsigned char*)(const_cast<GrayLevelImage8*>(rightYImage)->unsafeRowPointerArray()[0]);
00310 
00311 
00312   int anaglyphOffset=1; // TODO add config Config::getInt( "Gui.iAnaglyphOffset" );
00313 
00314   //Move left image <anaglyphOffset> pixels to the left and put into R channel
00315   //Move right image <anaglyphOffset> pixels to the right and put into G+B channel
00316 
00317   for ( int y=0; y<h; y++ )
00318   {
00319     int i=y*w;
00320     int j=i*3;
00321     for ( int x=0; x<w-anaglyphOffset; x++ )
00322     {
00323       tempImage[j]=left[i+anaglyphOffset];
00324       i++;
00325       j+=3;
00326     }
00327     for ( int x=w-anaglyphOffset; x<w; x++ )
00328     {
00329       tempImage[j]=0;
00330       j+=3;
00331     }
00332   }
00333   for ( int y=0; y<h; y++ )
00334   {
00335     int i=y*w;
00336     int j=i*3;
00337     for ( int x=0; x<anaglyphOffset; x++ )
00338     {
00339       tempImage[j+1]=0;
00340       tempImage[j+2]=0;
00341       j+=3;
00342       i++;
00343     }
00344     for ( int x=anaglyphOffset; x<w; x++ )
00345     {
00346       tempImage[j+1]=right[i-anaglyphOffset];
00347       tempImage[j+2]=right[i-anaglyphOffset];
00348       j+=3;
00349       i++;
00350     }
00351   }
00352 
00353   updateTexture( tempImage, w, h, ImageGrabber::RGB8 );
00354 
00355   delete tempImage;
00356 }
00357 
00358 
00359 void THIS::addVectorObject( VectorObject2D vectorObject )
00360 {
00361   m_VectorObjects.push_back( vectorObject );
00362 }
00363 
00364 
00365 void THIS::clearForms()
00366 {
00367   m_VectorObjects.clear();
00368 }
00369 
00370 
00371 // INTERNAL FUNCTIONS/////////////////////////////////////////////////////////////////////////////////////
00372 
00373 void THIS::updateTexture( unsigned char* imageData, unsigned width, unsigned height, ImageGrabber::ColorFormat format )
00374 {
00375   unsigned char* texturePos;
00376   unsigned char* imagePos;
00377 
00378   // recreate texture if necessary
00379   unsigned newTextureResolution=calcTextureSize(width,height); // TODO
00380   if ( (m_TextureData==0) || (m_TextureResolution!=newTextureResolution) )
00381   {
00382     std::ostringstream stream;
00383     int newTextureRes= calcTextureSize(width,height); // TODO
00384     stream << "Resizing Texture to " << newTextureRes << "x" << newTextureRes;
00385     // TRACE_SYSTEMINFO(stream.str()); // TODO use ros
00386     initTexture( newTextureRes, width, height, format );
00387   }
00388   //clear texture if image size has changed but texture size doesn't have to change
00389   else if ( (m_ImageWidth != width) || (m_ImageHeight != height) ) {
00390     clearTexture();
00391   }
00392 
00393   std::ostringstream stream;
00394   stream << "Updating  texture";
00395   // TRACE_SYSTEMINFO( stream.str() ) // TODO use ros
00396 
00397   m_ImageWidth=width;
00398   m_ImageHeight=height;
00399   m_TextureFormat=format;
00400 
00401   unsigned bytesPerPixel=1;
00402   if (format==ImageGrabber::RGB8) { bytesPerPixel=3; }
00403 
00404   //draw in top-left corner of the texture
00405   texturePos=m_TextureData;
00406   imagePos=imageData;
00407 
00408   //draw new image in the center
00409   for( unsigned y = 0; y < height ; y++ ) {
00410     memcpy ( texturePos, imagePos, width*bytesPerPixel );
00411     //jump to next row in texture
00412     texturePos+=m_TextureResolution*bytesPerPixel;
00413     imagePos+=width*bytesPerPixel;
00414   }
00415 
00416   updateGL();
00417 }
00418 
00419 void THIS::clearTexture()
00420 {
00421   memset(m_TextureData, 128, m_TextureByteSize );
00422 }
00423 
00424 
00425 void THIS::initTexture( unsigned resolution, unsigned imageWidth, unsigned imageHeight, ImageGrabber::ColorFormat textureFormat )
00426 {
00427   m_ImageWidth=imageWidth;
00428   m_ImageHeight=imageHeight;
00429 
00430   unsigned bytesPerPixel=1;
00431   if (textureFormat==ImageGrabber::RGB8) { bytesPerPixel=3; }
00432 
00433   m_TextureResolution = resolution;
00434 
00435   if( m_TextureData ) { delete m_TextureData; }
00436   m_TextureByteSize=m_TextureResolution * m_TextureResolution * bytesPerPixel;
00437   m_TextureData = new unsigned char[ m_TextureByteSize ];
00438   clearTexture();
00439 }
00440 
00441 
00442 void THIS::saveImage( std::string filename )
00443 {
00444   if ( !m_TextureData )
00445   {
00446     //TRACE_ERROR("No image set!"); // TODO use ros
00447     return;
00448   }
00449   // TRACE_INFO("Saving texture image to "+filename); // TODO use ros
00450   switch( m_TextureFormat )
00451   {
00452     case ImageGrabber::RGB8:
00453     {
00454       ColorImageRGB8 image( m_ImageWidth, m_ImageHeight );
00455       //copy from top-left corner of the texture
00456       for( unsigned y = 0; y < m_ImageHeight ; y++ )
00457       {
00458         for( unsigned x = 0; x < m_ImageWidth; x++ )
00459         {
00460           image[y][x][0]=m_TextureData[x*3+y*m_TextureResolution*3];
00461           image[y][x][1]=m_TextureData[x*3+y*m_TextureResolution*3+1];
00462           image[y][x][2]=m_TextureData[x*3+y*m_TextureResolution*3+2];
00463         }
00464       }
00465       // ImageWriter::writeImage( image, filename ); // TODO
00466       break;
00467     }
00468     case ImageGrabber::GRAY8:
00469     {
00470       GrayLevelImage8 image( m_ImageWidth, m_ImageHeight );
00471       //copy from top-left corner of the texture
00472       for( unsigned y = 0; y < m_ImageHeight ; y++ )
00473       {
00474         for( unsigned x = 0; x < m_ImageWidth; x++ )
00475         {
00476           image[y][x]=m_TextureData[x+y*m_TextureResolution];
00477         }
00478       }
00479       // ImageWriter::writeImage( image, filename ); // TODO
00480       break;
00481     }
00482     default:
00483       break;
00484      //  TRACE_ERROR("Cannot save image: Invalid format!"); // TODO use ros
00485   }
00486 }
00487 
00488 
00489 // USER INTERACTION //////////////////////////////////////////////////////////////////////////////////////////
00490 
00491 void THIS::mouseDoubleClickEvent( QMouseEvent* event = 0 )
00492 {
00493   //correct aspect
00494   float viewPortAspect=float(m_ViewportWidth) / float(m_ViewportHeight);
00495   float imageAspect=float(m_ImageWidth) / float(m_ImageHeight) * m_PixelAspectRatio;
00496 //  float scaleX,scaleY;
00497 
00498 //   if (viewPortAspect > imageAspect) {
00499 //     scaleX=imageAspect/viewPortAspect;
00500 //     scaleY=1.0;
00501 //   } else {
00502 //     scaleX=1.0;
00503 //     scaleY=viewPortAspect/imageAspect;
00504 //   }
00505 //
00506 
00507   if (viewPortAspect > imageAspect) {
00508     m_Zoom = float(m_ImageHeight) / float(m_ViewportHeight);
00509   } else {
00510     m_Zoom = float(m_ImageWidth) / float(m_ViewportWidth);
00511   }
00512 
00513   m_PosX=0.0;
00514   m_PosY=0.0;
00515   updateGL();
00516 }
00517 
00518 void THIS::zoom(float z)
00519 {
00520   m_Zoom = z;
00521   m_PosX=0.0;
00522   m_PosY=0.0;
00523   updateGL();
00524 }
00525 
00526 void THIS::mousePressEvent(QMouseEvent* event)
00527 {
00528   m_MousePosOld = event->pos();
00529 }
00530 
00531 void THIS::mouseMoveEvent(QMouseEvent* event)
00532 {
00533   float deltaX=float(-m_MousePosOld.x() + event->x());
00534   float deltaY=float(-m_MousePosOld.y() + event->y());
00535   if (event->buttons() & Qt::LeftButton) {
00536     m_PosX += deltaX / m_ViewportWidth;
00537     m_PosY += deltaY / m_ViewportHeight;
00538   } else if (event->buttons() & Qt::RightButton) {
00539     m_Zoom *= std::pow( float(1.1), float(deltaY/10.0) );
00540     if (m_Zoom < 1.0) { m_Zoom=1.0; }
00541     if (m_Zoom > 32.0) { m_Zoom=32.0; }
00542   }
00543   m_MousePosOld = event->pos();
00544   updateGL();
00545 }
00546 
00547 
00548 void THIS::wheelEvent(QWheelEvent *event) {
00549   if (event->delta() < 0 ) {
00550     m_Zoom*=ZOOM_STEP;
00551     //NOTE wrong calculation, to be replaced
00552     m_PosX+=( 0.5 - float(event->x())/float(m_ViewportWidth ) ) / m_Zoom;
00553     m_PosY+=( 0.5 - float(event->y())/float(m_ViewportHeight) ) / m_Zoom;
00554   }
00555   if (event->delta() > 0 ) {
00556     m_Zoom/=ZOOM_STEP;
00557   }
00558   //if (m_Zoom < 1.0) { m_Zoom=1.0; }
00559   if (m_Zoom > 32.0) { m_Zoom=32.0; }
00560   updateGL();
00561 }
00562 
00563 
00564 // TODO originally in RobbieWidget
00565 int THIS::calcTextureSize( int width, int height )
00566 {
00567     int sizeSqared = 2;
00568     //find the next potence of two into which the image fits
00569     while ( ( sizeSqared < width || sizeSqared < height ) && ( sizeSqared <= 256*256 ) )
00570     {
00571       sizeSqared = sizeSqared * 2;
00572     }
00573     return sizeSqared;
00574 }
00575 
00576 #undef THIS


obj_rec_gui
Author(s): AGAS/agas@uni-koblenz.de
autogenerated on Mon Oct 6 2014 02:53:43