roiFinder.cpp

00001 
00002 /* Copyright (c) 2009       Maxim Makhinya
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 //#define EQ_USE_ROI                // use ROI
00019 #define EQ_ROI_USE_TRACKER        // disable ROI in case it can't help
00020 //#define EQ_ROI_USE_DEPTH_TEXTURE  // use depth texture instead of color
00021 
00022 //#define EQ_ROI_TEST_SPEED         // measure and print ROI speed
00023 
00024 #include "roiFinder.h"
00025 
00026 #ifdef EQ_ROI_USE_DEPTH_TEXTURE
00027 #include "roiFragmentShader_glsl.h"
00028 #else 
00029 #include "roiFragmentShaderRGB_glsl.h"
00030 #endif
00031 
00032 #include "frameBufferObject.h"
00033 #include "log.h"
00034 
00035 #include <eq/base/base.h>
00036 
00037 
00038 namespace eq
00039 {
00040 
00041 // use to address one shader and program per shared context set
00042 static const char seeds = 42;
00043 static const char* shaderRBInfo = &seeds;
00044 
00045 #define GRID_SIZE 16 // will be replaced later by variable
00046 
00047 
00048 ROIFinder::ROIFinder()
00049     : _glObjects( 0 )
00050 {
00051     _tmpAreas[0].pvp       = PixelViewport( 0, 0, 0, 0 );
00052     _tmpAreas[0].hole      = PixelViewport( 0, 0, 0, 0 );
00053     _tmpAreas[0].emptySize = 0;
00054 }
00055 
00056 void ROIFinder::_dumpDebug( const uint32_t stage )
00057 {
00058     static uint32_t counter = 0;
00059     std::ostringstream ss;
00060     ss << "_img_" << ++counter << "_" << stage;
00061 
00062     _tmpImg.reset();
00063     _tmpImg.setPixelViewport( PixelViewport( 0, 0, _wb, _hb ));
00064 
00065     _tmpImg.setFormat( Frame::BUFFER_COLOR, GL_RGB  );
00066     _tmpImg.setType(   Frame::BUFFER_COLOR, GL_UNSIGNED_BYTE );
00067 
00068     _tmpImg.validatePixelData( Frame::BUFFER_COLOR );
00069 
00070     uint8_t* dst  = _tmpImg.getPixelPointer( Frame::BUFFER_COLOR );
00071     uint8_t* src1 = &_mask[0];
00072     uint8_t* src2 = &_tmpMask[0];
00073 
00074     memset( dst, 0, _wbhb*3 );
00075 
00076     for( int32_t y = 0; y < _hb; y++ )
00077         for( int32_t x = 0; x < _wb; x++ )
00078         {
00079             dst[0] = *src1++;
00080             dst[1] = *src2++;
00081             dst += 3;
00082         }
00083 
00084     EQWARN << "Dumping ROI image: " << ss.str( ) << std::endl;
00085     _tmpImg.writeImages( ss.str( ));
00086 }
00087 
00088 
00089 
00090 PixelViewport ROIFinder::_getObjectPVP( const PixelViewport& pvp,
00091                                         const uint8_t*       src )
00092 {
00093     EQASSERT( pvp.x >= 0 && pvp.x+pvp.w <= _wb &&
00094               pvp.y >= 0 && pvp.y+pvp.h <= _hb );
00095 
00096     // Calculate per-pixel histograms
00097     const uint8_t* s = src + pvp.y*_wb + pvp.x;
00098 
00099     memset( _histX, 0, pvp.w );
00100     memset( _histY, 0, pvp.h );
00101     for( int32_t y = 0; y < pvp.h; y++ )
00102     {
00103         for( int32_t x = 0; x < pvp.w; x++ )
00104         {
00105             const uint8_t val = s[ x ] & 1;
00106             _histX[ x ] += val;
00107             _histY[ y ] += val;
00108         }
00109         s += _wb;
00110     }
00111 
00112     // Find AABB based on X and Y axis historgams
00113     int32_t xMin = pvp.w;
00114     for( int32_t x = 0; x < pvp.w; x++ )
00115         if( _histX[x] != 0 )
00116         {
00117             xMin = x;
00118             break;
00119         }
00120 
00121     int32_t xMax = 0;
00122     for( int32_t x = pvp.w-1; x >= 0; x-- )
00123         if( _histX[x] != 0 )
00124         {
00125             xMax = x;
00126             break;
00127         }
00128 
00129     if( xMax < xMin )
00130         return PixelViewport( pvp.x, pvp.y, 0, 0 );
00131 
00132     int32_t yMin = pvp.h;
00133     for( int32_t y = 0; y < pvp.h; y++ )
00134         if( _histY[y] != 0 )
00135         {
00136             yMin = y;
00137             break;
00138         }
00139 
00140     int32_t yMax = 0;
00141     for( int32_t y = pvp.h-1; y >= 0; y-- )
00142         if( _histY[y] != 0 )
00143         {
00144             yMax = y;
00145             break;
00146         }
00147 
00148     if( yMax < yMin )
00149         return PixelViewport( pvp.x, pvp.y, 0, 0 );
00150 
00151     return PixelViewport( pvp.x+xMin, pvp.y+yMin, xMax-xMin+1, yMax-yMin+1 );
00152 }
00153 
00154 
00155 void ROIFinder::_resize( const PixelViewport& pvp )
00156 {
00157     _pvp = pvp;
00158 
00159     _w   = _pvp.w;
00160     _h   = _pvp.h;
00161     _wh  = _w * _h;
00162     _wb  = _w + 1; // borders are only on left and 
00163     _hb  = _h + 1; // top borders of the image
00164     _wbhb = _wb * _hb;
00165 
00166     if( static_cast<int32_t>(_mask.size()) < _wbhb )
00167     {
00168         _mask.resize( _wbhb );
00169         _tmpMask.resize( _wbhb );
00170 
00171         // w * h * sizeof( GL_FLOAT ) * RGBA
00172         _perBlockInfo.resize( _wh * 4 );
00173     }
00174 }
00175 
00176 
00177 void ROIFinder::_init( )
00178 {
00179     _areasToCheck.clear();
00180     memset( &_mask[0]   , 0, _mask.size( ));
00181     memset( &_tmpMask[0], 0, _tmpMask.size( ));
00182 
00183     EQASSERT( static_cast<int32_t>(_perBlockInfo.size()) >= _w*_h*4 );
00184     EQASSERT( static_cast<int32_t>(_mask.size())         >= _wb*_h  );
00185 
00186     const float*    src = &_perBlockInfo[0];
00187           uint8_t*  dst = &_mask[0];
00188 
00189     for( int32_t y = 0; y < _h; y++ )
00190     {
00191         for( int32_t x = 0; x < _w; x++ )
00192         {
00193             if( src[x*4] < 1.0 )
00194                 dst[x] = 255;
00195         }
00196         src += _w*4;
00197         dst += _wb;
00198     }
00199 }
00200 
00201 
00202 void ROIFinder::_fillWithColor( const PixelViewport& pvp,
00203                                       uint8_t* dst, const uint8_t val )
00204 {
00205     for( int32_t y = pvp.y; y < pvp.y + pvp.h; y++ )
00206         for( int32_t x = pvp.x; x < pvp.x + pvp.w; x++ )
00207             dst[ y * _wb + x ] = val; 
00208 }
00209 
00210 void ROIFinder::_invalidateAreas( Area* areas, uint8_t num )
00211 {
00212     for( uint8_t i = 0; i < num; i++ )
00213         areas[i].valid = false;
00214 }
00215 
00216 void ROIFinder::_updateSubArea( const uint8_t type )
00217 {
00218     EQASSERT( type <= 16 );
00219 
00220     if( type == 0 )
00221         return;
00222 
00223     PixelViewport pvp;
00224     switch( type )
00225     {
00226         case 1:  pvp = PixelViewport( _dim.x1,_dim.y2,_dim.w1,_dim.h2 ); break;
00227         case 2:  pvp = PixelViewport( _dim.x2,_dim.y3,_dim.w2,_dim.h3 ); break;
00228         case 3:  pvp = PixelViewport( _dim.x3,_dim.y2,_dim.w3,_dim.h2 ); break;
00229         case 4:  pvp = PixelViewport( _dim.x2,_dim.y1,_dim.w2,_dim.h1 ); break;
00230         case 5:  pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w1,_dim.h4 ); break;
00231         case 6:  pvp = PixelViewport( _dim.x1,_dim.y3,_dim.w4,_dim.h3 ); break;
00232         case 7:  pvp = PixelViewport( _dim.x3,_dim.y2,_dim.w3,_dim.h5 ); break;
00233         case 8:  pvp = PixelViewport( _dim.x2,_dim.y1,_dim.w5,_dim.h1 ); break;
00234         case 9:  pvp = PixelViewport( _dim.x1,_dim.y2,_dim.w1,_dim.h5 ); break;
00235         case 10: pvp = PixelViewport( _dim.x2,_dim.y3,_dim.w5,_dim.h3 ); break;
00236         case 11: pvp = PixelViewport( _dim.x3,_dim.y1,_dim.w3,_dim.h4 ); break;
00237         case 12: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w4,_dim.h1 ); break;
00238         case 13: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w1,_dim.h6 ); break;
00239         case 14: pvp = PixelViewport( _dim.x3,_dim.y1,_dim.w3,_dim.h6 ); break;
00240         case 15: pvp = PixelViewport( _dim.x1,_dim.y3,_dim.w6,_dim.h3 ); break;
00241         case 16: pvp = PixelViewport( _dim.x1,_dim.y1,_dim.w6,_dim.h1 ); break;
00242         default:
00243             EQUNIMPLEMENTED;
00244     }
00245 
00246     EQASSERT( pvp.hasArea( ));
00247     EQASSERT( pvp.x >=0 && pvp.y >=0 && pvp.x+pvp.w <=_w && pvp.y+pvp.h <=_h );
00248 
00249     Area& a = _tmpAreas[type];
00250 
00251     a.pvp = _getObjectPVP( pvp, &_mask[0] );
00252 
00253     a.hole = _emptyFinder.getLargestEmptyArea( a.pvp );
00254 
00255     a.emptySize = pvp.getArea() - a.pvp.getArea() + a.hole.getArea();
00256 
00257     EQASSERT( !a.valid );
00258 
00259 #ifndef NDEBUG
00260     a.valid = true;
00261 #endif
00262 }
00263 
00264 
00265 // positions of a hole:
00266 //
00267 //  1 7 5
00268 //  2 8 6
00269 //  0 4 3
00270 //
00271 // 0, 1, 3, 5 - corners
00272 // 2, 4, 6, 7 - sides
00273 // 8          - center
00274 //
00275 
00276 
00277 static const uint8_t _interests[10][8] =
00278 {
00279     { 2, 3, 7,10, 0, 0, 0, 0 }, // corner
00280     { 3, 4, 8,11, 0, 0, 0, 0 }, // corner
00281     { 2, 3, 4, 7, 8,10,11,14 }, // side
00282     { 1, 2, 6, 9, 0, 0, 0, 0 }, // corner
00283     { 1, 2, 3, 6, 7, 9,10,15 }, // side
00284     { 1, 4, 5,12, 0, 0, 0, 0 }, // corner
00285     { 1, 2, 4, 5, 6, 9,12,13 }, // side
00286     { 1, 3, 4, 5, 8,11,12,16 },  // side
00287     { 1, 3, 0, 0, 0, 0, 0, 0 }, // vertical
00288     { 2, 4, 0, 0, 0, 0, 0, 0 }, // horizontal
00289 };                              // center is 1..16
00290 
00291 static const uint8_t _compilNums[11][2] =
00292 {
00293     {2,2},{2,2},{4,3},{2,2},{4,3},{2,2},{4,3},{4,3},{1,2},{1,2},{18,4}
00294 };
00295 
00296 static const uint8_t _compilations[10][4][3] =
00297 {
00298     {{2, 7, 0},{3,10, 0},{0,0, 0},{0,0, 0}}, // corner
00299     {{3, 8, 0},{4,11, 0},{0,0, 0},{0,0, 0}}, // corner
00300     {{2, 4,14},{4,10,11},{3,8,10},{2,7, 8}}, // side
00301     {{1, 6, 0},{2, 9, 0},{0,0, 0},{0,0, 0}}, // corner
00302     {{1, 3,15},{3, 9,10},{2,7, 9},{1,6, 7}}, // side
00303     {{1,12, 0},{4, 5, 0},{0,0, 0},{0,0, 0}}, // corner
00304     {{2, 4,13},{4, 5, 6},{1,6,12},{2,9,12}}, // side
00305     {{1, 3,16},{1,11,12},{5,4,11},{3,5, 8}}, // side
00306     {{1, 3, 0},{0, 0, 0},{0,0, 0},{0,0, 0}}, // vertical
00307     {{2, 4, 0},{0, 0, 0},{0,0, 0},{0,0, 0}}, // horizontal
00308 };
00309 
00310 
00311 static const uint8_t _compilations16[18][4] =// center
00312 {
00313     {13,2, 4,14},{13,4,10,11},{13,3,8,10},{13,2,7, 8},
00314     {16,1, 3,15},{16,3, 9,10},{16,2,7, 9},{16,1,6, 7},
00315     {14,2, 4,13},{14,4, 5, 6},{14,1,6,12},{14,2,9,12},
00316     {15,1, 3,16},{15,1,11,12},{15,5,4,11},{15,3,5, 8},
00317     {5 ,6, 7, 8},{9,10,11,12}
00318 };
00319 
00320 
00321 uint8_t ROIFinder::_splitArea( Area& a )
00322 {
00323     EQASSERT( a.hole.getArea() > 0 );
00324 #ifndef NDEBUG
00325     _invalidateAreas( _tmpAreas, 17 );
00326 #endif
00327 
00328     _dim.x1 = a.pvp.x;
00329     _dim.x2 = a.hole.x;
00330     _dim.x3 = a.hole.x + a.hole.w;
00331 
00332     _dim.w1 = _dim.x2 - _dim.x1;
00333     _dim.w2 = a.hole.w;
00334     _dim.w3 = a.pvp.x + a.pvp.w - _dim.x3;
00335     _dim.w4 = _dim.w1 + _dim.w2;
00336     _dim.w5 = _dim.w2 + _dim.w3;
00337     _dim.w6 = _dim.w4 + _dim.w3;
00338 
00339     _dim.y1 = a.pvp.y;
00340     _dim.y2 = a.hole.y;
00341     _dim.y3 = a.hole.y + a.hole.h;
00342 
00343     _dim.h1 = _dim.y2 - _dim.y1;
00344     _dim.h2 = a.hole.h;
00345     _dim.h3 = a.pvp.y + a.pvp.h - _dim.y3;
00346     _dim.h4 = _dim.h1 + _dim.h2;
00347     _dim.h5 = _dim.h2 + _dim.h3;
00348     _dim.h6 = _dim.h4 + _dim.h3;
00349 
00350     // other cases
00351     uint8_t type;
00352     if( a.pvp.h == a.hole.h ) // hole through the whole block
00353     {
00354         EQASSERT( a.pvp.w != a.hole.w );
00355         type = 8;
00356     }else
00357     if( a.pvp.w == a.hole.w ) // hole through the whole block
00358     {
00359         type = 9;
00360     }else
00361     if( a.pvp.x == a.hole.x ) // left side
00362     {
00363         if( a.pvp.y == a.hole.y )
00364         {// in the lower left corner
00365             type = 0;
00366         }else
00367         if( a.pvp.y + a.pvp.h == a.hole.y + a.hole.h )
00368         {// in the upper left corner
00369             type = 1;
00370         }else
00371         {// in the left middle
00372             type = 2;
00373         }
00374     }else
00375     if( a.pvp.y == a.hole.y ) // bottom side
00376     {
00377         if( a.pvp.x + a.pvp.w == a.hole.x + a.hole.w )
00378         {// in the bottom right corner
00379             type = 3;
00380         }else
00381         {// in the bottom middle
00382             type = 4;
00383         }
00384     }else
00385     if( a.pvp.x + a.pvp.w == a.hole.x + a.hole.w ) // right side
00386     {
00387         if( a.pvp.y + a.pvp.h == a.hole.y + a.hole.h )
00388         {// in the upper right corner
00389             type = 5;
00390         }else
00391         {// in the right middle
00392             type = 6;
00393         }
00394     }else
00395     if( a.pvp.y + a.pvp.h == a.hole.y + a.hole.h ) // top side
00396     {// in the upper middle corner
00397             type = 7;
00398     }else
00399     {// must be in the center
00400             type = 10;
00401     }
00402 
00403     // Calculate areas of interest
00404     if( type == 10 ) // center hole position
00405     {
00406         for( uint8_t i = 1; i <= 16; i++ )
00407             _updateSubArea( i );
00408     }else
00409     {
00410         for( uint8_t i = 0; i < 8; i++ )
00411             _updateSubArea( _interests[ type ][ i ] );
00412     }
00413 
00414     // find best combinations of areas of interest
00415     const uint8_t varaintsNum     = _compilNums[type][0];
00416     const uint8_t areasPerVariant = _compilNums[type][1];
00417 
00418     int32_t maxSum  = 0;
00419     int32_t variant = 0;
00420     if( type == 10 ) // center hole
00421     {
00422         for( uint8_t i = 0; i < varaintsNum; i++ )
00423         {
00424             int32_t sum = 0;
00425             for( uint8_t j = 0; j < areasPerVariant; j++ )
00426             {
00427                 EQASSERT( _tmpAreas[_compilations16[i][j]].valid );
00428                 sum += _tmpAreas[_compilations16[i][j]].emptySize;
00429             }
00430 
00431             if( sum > maxSum )
00432             {
00433                 maxSum  = sum;
00434                 variant = i;
00435             }
00436         }
00437 
00438         for( uint8_t j = 0; j < areasPerVariant; j++ )
00439         {
00440             EQASSERT( _tmpAreas[_compilations16[variant][j]].valid );
00441             _finalAreas[j] = &_tmpAreas[_compilations16[variant][j]];
00442         }
00443 
00444         return areasPerVariant;
00445     }
00446     // else any other hole
00447 
00448     for( uint8_t i = 0; i < varaintsNum; i++ )
00449     {
00450         int32_t sum = 0;
00451         for( uint8_t j = 0; j < areasPerVariant; j++ )
00452         {
00453             EQASSERT( _tmpAreas[_compilations[type][i][j]].valid );
00454             sum += _tmpAreas[_compilations[type][i][j]].emptySize;
00455         }
00456 
00457         if( sum > maxSum )
00458         {
00459             maxSum  = sum;
00460             variant = i;
00461         }
00462     }
00463 
00464     for( uint8_t j = 0; j < areasPerVariant; j++ )
00465     {
00466         EQASSERT( _tmpAreas[_compilations[type][variant][j]].valid );
00467         _finalAreas[j] = &_tmpAreas[_compilations[type][variant][j]];
00468     }
00469 
00470     return areasPerVariant;
00471 }
00472 
00473 
00474 void ROIFinder::_findAreas( PixelViewportVector& resultPVPs )
00475 {
00476     EQASSERT( _areasToCheck.size() == 0 );
00477 
00478     Area area( PixelViewport( 0, 0, _w, _h ));
00479     area.pvp  = _getObjectPVP( area.pvp, &_mask[0] );
00480 
00481     if( area.pvp.w <= 0 || area.pvp.h <= 0 )
00482         return;
00483 
00484     area.hole = _emptyFinder.getLargestEmptyArea( area.pvp );
00485 
00486     if( area.hole.getArea() == 0 )
00487         resultPVPs.push_back( area.pvp );
00488     else
00489         _areasToCheck.push_back( area );
00490 
00491     // try to split areas
00492     while( _areasToCheck.size() > 0 )
00493     {
00494         Area curArea = _areasToCheck.back();
00495         _areasToCheck.pop_back();
00496 
00497         uint8_t n = _splitArea( curArea );
00498         EQASSERT( n >= 2 && n <= 4 );
00499 
00500         for( uint8_t i = 0; i < n; i++ )
00501         {
00502             EQASSERT( _finalAreas[i]->valid );
00503             EQASSERT( _finalAreas[i]->pvp.hasArea( ));
00504             
00505             if( _finalAreas[i]->hole.getArea() == 0 )
00506                 resultPVPs.push_back( _finalAreas[i]->pvp );
00507             else
00508                 _areasToCheck.push_back( *_finalAreas[i] );
00509         }
00510     }
00511 
00512     // correct position and sizes
00513     for( uint32_t i = 0; i < resultPVPs.size(); i++ )
00514     {
00515 #ifndef NDEBUG
00516         // fill temporary array with found regions to 
00517         // dump it later in _dumpDebug
00518         _fillWithColor( resultPVPs[i], &_tmpMask[0],
00519                         255 - i*200/resultPVPs.size( ));
00520 #endif
00521 
00522         PixelViewport& pvp = resultPVPs[i];
00523         pvp.x += _pvp.x;
00524         pvp.y += _pvp.y;
00525 
00526         pvp.apply( Zoom( GRID_SIZE, GRID_SIZE ));
00527     }
00528 
00529 }
00530 
00531 const void* ROIFinder::_getInfoKey( ) const
00532 {
00533     return ( reinterpret_cast< const char* >( this ) + 3 );
00534 }
00535 
00536 
00537 void ROIFinder::_readbackInfo( )
00538 {
00539     EQASSERT( _glObjects );
00540     EQASSERT( _glObjects->supportsEqTexture( ));
00541     EQASSERT( _glObjects->supportsEqFrameBufferObject( ));
00542 
00543     PixelViewport pvp = _pvp;
00544     pvp.apply( Zoom( GRID_SIZE, GRID_SIZE ));
00545     pvp.w = EQ_MIN( pvp.w+pvp.x, _pvpOriginal.w+_pvpOriginal.x ) - pvp.x;
00546     pvp.h = EQ_MIN( pvp.h+pvp.y, _pvpOriginal.h+_pvpOriginal.y ) - pvp.y;
00547 
00548     EQASSERT( pvp.isValid());
00549 
00550     // copy frame buffer to texture
00551     const void* bufferKey = _getInfoKey( );
00552     Texture*    texture   = _glObjects->obtainEqTexture( bufferKey );
00553 
00554 #ifdef EQ_ROI_USE_DEPTH_TEXTURE
00555     texture->setFormat( GL_DEPTH_COMPONENT );
00556 #else
00557     texture->setFormat( GL_RGBA );
00558 #endif
00559 
00560     texture->copyFromFrameBuffer( pvp );
00561 
00562     // draw zoomed quad into FBO
00563     const void*     fboKey = _getInfoKey( );
00564     FrameBufferObject* fbo = _glObjects->getEqFrameBufferObject( fboKey );
00565 
00566     if( fbo )
00567     {
00568         EQCHECK( fbo->resize( _pvp.w, _pvp.h ));
00569     }
00570     else
00571     {
00572         fbo = _glObjects->newEqFrameBufferObject( fboKey );
00573         fbo->setColorFormat( GL_RGBA32F );
00574         EQCHECK( fbo->init( _pvp.w, _pvp.h, 0, 0 ));
00575     }
00576     fbo->bind();
00577 
00578     texture->bind();
00579 
00580     // Enable & download depth texture
00581     glEnable( GL_TEXTURE_RECTANGLE_ARB );
00582 
00583     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR );
00584     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR );
00585     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S,
00586                                                             GL_CLAMP_TO_EDGE );
00587     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T,
00588                                                             GL_CLAMP_TO_EDGE );
00589 
00590     // Enable shaders
00591     //
00592     GLuint program = _glObjects->getProgram( shaderRBInfo );
00593 
00594     if( program == Window::ObjectManager::INVALID )
00595     {
00596         // Create fragment shader which reads depth values from 
00597         // rectangular textures
00598         const GLuint shader = _glObjects->newShader( shaderRBInfo,
00599                                                         GL_FRAGMENT_SHADER );
00600         EQASSERT( shader != Window::ObjectManager::INVALID );
00601 
00602 #ifdef EQ_ROI_USE_DEPTH_TEXTURE
00603         const GLchar* fShaderPtr = roiFragmentShader_glsl.c_str();
00604 #else
00605         const GLchar* fShaderPtr = roiFragmentShaderRGB_glsl.c_str();
00606 #endif
00607         EQ_GL_CALL( glShaderSource( shader, 1, &fShaderPtr, 0 ));
00608         EQ_GL_CALL( glCompileShader( shader ));
00609 
00610         GLint status;
00611         glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
00612         if( !status )
00613             EQERROR << "Failed to compile fragment shader for ROI finder"
00614                     << std::endl;
00615 
00616         program = _glObjects->newProgram( shaderRBInfo );
00617 
00618         EQ_GL_CALL( glAttachShader( program, shader ));
00619         EQ_GL_CALL( glLinkProgram( program ));
00620 
00621         glGetProgramiv( program, GL_LINK_STATUS, &status );
00622         if( !status )
00623         {
00624             EQWARN << "Failed to link shader program for ROI finder"
00625                    << std::endl;
00626             return;
00627         }
00628 
00629         // use fragment shader and setup uniforms
00630         EQ_GL_CALL( glUseProgram( program ));
00631 
00632         GLint param = glGetUniformLocation( program, "texture" );
00633         glUniform1i( param, 0 );
00634     }
00635     else
00636     {
00637         // use fragment shader
00638         EQ_GL_CALL( glUseProgram( program ));
00639     }
00640 
00641     // Draw Quad
00642     glDisable( GL_LIGHTING );
00643     glColor3f( 1.0f, 1.0f, 1.0f );
00644 
00645     glBegin( GL_QUADS );
00646         glVertex3i(      0,      0, 0 );
00647         glVertex3i( _pvp.w,      0, 0 );
00648         glVertex3i( _pvp.w, _pvp.h, 0 );
00649         glVertex3i(      0, _pvp.h, 0 );
00650     glEnd();
00651 
00652     // restore state
00653     glDisable( GL_TEXTURE_RECTANGLE_ARB );
00654     EQ_GL_CALL( glUseProgram( 0 ));
00655 
00656     fbo->unbind();
00657 
00658     // finish readback of info
00659     EQASSERT( static_cast<int32_t>(_perBlockInfo.size()) >= _pvp.w*_pvp.h*4 );
00660 
00661     texture = fbo->getColorTextures()[0];
00662     texture->download( &_perBlockInfo[0], GL_RGBA, GL_FLOAT );
00663 }
00664 
00665 
00666 static PixelViewport _getBoundingPVP( const PixelViewport& pvp )
00667 {
00668     PixelViewport pvp_;
00669 
00670     pvp_.x = ( pvp.x / GRID_SIZE );
00671     pvp_.y = ( pvp.y / GRID_SIZE );
00672 
00673     pvp_.w = (( pvp.x + pvp.w + GRID_SIZE-1 )/GRID_SIZE ) - pvp_.x;
00674     pvp_.h = (( pvp.y + pvp.h + GRID_SIZE-1 )/GRID_SIZE ) - pvp_.y;
00675 
00676     return pvp_;
00677 }
00678 
00679 
00680 PixelViewportVector ROIFinder::findRegions( const uint32_t         buffers,
00681                                             const PixelViewport&   pvp,
00682                                             const Zoom&            zoom,
00683                                             const uint32_t         stage,
00684                                             const uint32_t         frameID,
00685                                             Window::ObjectManager* glObjects )
00686 {
00687     PixelViewportVector result;
00688     result.push_back( pvp );
00689 
00690 #ifndef EQ_USE_ROI
00691     return result; // disable read back info usage
00692 #endif
00693 
00694 #ifdef EQ_ROI_TEST_SPEED
00695     eq::base::Clock clock; 
00696     clock.reset();
00697 for( int i = 0; i < 100; i++ ) {
00698 #endif
00699 
00700     EQASSERT( glObjects );
00701     EQASSERTINFO( !_glObjects, "Another readback in progress?" );
00702     EQLOG( LOG_ASSEMBLY )   << "ROIFinder::getObjects " << pvp
00703                             << ", buffers " << buffers
00704                             << std::endl;
00705 
00706     if( zoom != Zoom::NONE )
00707     {
00708         EQWARN << "R-B optimization impossible when zoom is used"
00709                << std::endl;
00710         return result;
00711     }
00712 
00713 #ifdef EQ_ROI_USE_TRACKER
00714 //    EQWARN << "frID: " << frameID << " stage: " << stage << std::endl;
00715     uint8_t* ticket;
00716     if( !_roiTracker.useROIFinder( pvp, stage, frameID, ticket ))
00717         return result;
00718 #endif
00719 
00720     _pvpOriginal = pvp;
00721     _resize( _getBoundingPVP( pvp ));
00722 
00723     // go through depth buffer and check min/max/BG values
00724     // render to and read-back usefull info from FBO
00725     _glObjects = glObjects;
00726     _readbackInfo();
00727     _glObjects = 0;
00728 
00729     // Analyze readed back data and find regions of interest
00730     _init( );
00731 //    _dumpDebug( 0 );
00732 
00733     _emptyFinder.update( &_mask[0], _wb, _hb );
00734     _emptyFinder.setLimits( 200, 0.002f );
00735     
00736     result.clear();
00737     _findAreas( result );
00738 //    _dumpDebug( 1 );
00739 
00740 #ifdef EQ_ROI_USE_TRACKER
00741     _roiTracker.updateDelay( result, ticket );
00742 #endif
00743 
00744 #ifdef EQ_ROI_TEST_SPEED
00745 }
00746     const float time = clock.getTimef() / 100;
00747     const float fps  = 1000.f / time;
00748 
00749     static float minFPS = 10000;    minFPS = EQ_MIN( fps, minFPS );
00750     static float maxFPS = 0;        maxFPS = EQ_MAX( fps, maxFPS );
00751     static float sumFPS = 0;        sumFPS += fps;
00752     static float frames = 0;        frames++;
00753 
00754     const float avgFPS = sumFPS / frames;
00755     EQWARN << "=============================================" << std::endl;
00756     EQWARN << "ROI min fps: " << minFPS << " (" << 1000.f/minFPS
00757           << " ms) max fps: " << maxFPS << " (" << 1000.f/maxFPS
00758           << " ms) avg fps: " << avgFPS << " (" << 1000.f/avgFPS
00759           << " ms) cur fps: " << fps    << " (" << 1000.f/fps
00760           << " ms) areas found: " << result.size() << std::endl;
00761 
00762     if( frames < 5 ) { minFPS = 10000; maxFPS = 0; }
00763 #endif //EQ_ROI_TEST_SPEED
00764 
00765 //    EQWARN << "Areas found: " << result.size() << std::endl;
00766     return result;
00767 }
00768 
00769 }
00770 
Generated on Mon Aug 10 18:58:41 2009 for Equalizer 0.9 by  doxygen 1.5.8