roiEmptySpaceFinder.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 #include "roiEmptySpaceFinder.h"
00019 
00020 
00021 namespace eq
00022 {
00023 
00024 void ROIEmptySpaceFinder::_resize( const int32_t w, const int32_t h )
00025 {
00026     _w = w;
00027     _h = h;
00028 
00029     _mask = 0;
00030 
00031     if( static_cast<int32_t>(_data.size()) < w * h )
00032         _data.resize( w * h );
00033 
00034     setLimits( (w-1)*(h-1), 1.0 );
00035 }
00036 
00037 
00038 void ROIEmptySpaceFinder::update( const uint8_t* mask,
00039                                  const int32_t  w,
00040                                  const int32_t  h  )
00041 {
00042     _resize( w, h );
00043 
00044     _mask = mask;
00045     const uint8_t*  s = mask + _w*(_h-1);
00046           uint16_t* d = &_data[_w*(_h-1)];
00047 
00048     // First element
00049     d[_w-1] = s[_w-1] > 0 ? 1 : 0;
00050 
00051     // First raw
00052     for( int32_t x = _w-2; x >= 0; x-- )
00053         d[x] = d[x+1] + ( s[x] > 0 ? 1 : 0 );
00054 
00055     // All other raws
00056     for( int32_t y = 1; y < _h; y++ )
00057     {
00058         const uint16_t* dp = d; // previous calculated raw
00059         s -= _w;
00060         d -= _w;
00061         uint16_t rawSum = 0;
00062         for( int32_t x = _w-1; x >= 0; x-- )
00063         {
00064             rawSum += s[x] > 0 ? 1 : 0;
00065             d[x] = dp[x] + rawSum;
00066         }
00067     }
00068 }
00069 
00070 
00071 inline uint16_t ROIEmptySpaceFinder::getArea(
00072                                     const int32_t x, const int32_t y,
00073                                     const int32_t w, const int32_t h ) const
00074 {
00075     return  getArea( x, y, w, h, &_data[0] + y * _w + x );
00076 }
00077 
00078 inline uint16_t ROIEmptySpaceFinder::getArea(
00079                                     const int32_t x, const int32_t y,
00080                                     const int32_t w, const int32_t h,
00081                                     const uint16_t* data ) const
00082 {
00083     EQASSERT( x >= 0 && w > 0 && x+w < _w );
00084     EQASSERT( y >= 0 && h > 0 && y+h < _h );
00085 
00086     const uint16_t* data_ = data + h*_w;
00087     return  *data - data[ w ] - *data_ + data_[ w ];
00088 }
00089 
00090 
00091 bool ROIEmptySpaceFinder::_updateMaximalEmptyRegion(
00092                                     const int32_t x, const int32_t y,
00093                                     const int32_t w, const int32_t h,
00094                                     PixelViewport& pvp,
00095                                     const uint16_t* data ) const
00096 {
00097     uint16_t maxArea = pvp.w * pvp.h;
00098     bool updated = false;
00099     int32_t maxW = 0;
00100     int32_t maxH = 0;
00101 
00102     // find biggest diagonal
00103     int32_t cwh = 2;
00104     while( cwh <= w && cwh <= h && getArea( x, y, cwh, cwh, data ) == 0 )
00105         cwh++;
00106 
00107     cwh--;
00108 
00109     if( cwh*cwh > maxArea )
00110     {
00111         maxArea = cwh*cwh;
00112         maxW = cwh;
00113         maxH = cwh;
00114         updated = true;
00115     }
00116 
00117     // check parallelepipids
00118     if( cwh * w > maxArea )
00119     {
00120         int32_t ch = cwh;
00121         for( int32_t cw = cwh+1; cw <= w; cw++ )
00122         {
00123             while( getArea( x, y, cw, ch, data ) != 0 )
00124             {
00125                 ch--;
00126                 if( ch == 0 )
00127                 {
00128                     cw = w + 1;
00129                     break;
00130                 }
00131             }
00132             if( cw*ch > maxArea )
00133             {
00134                 maxArea = cw*ch;
00135                 maxW = cw;
00136                 maxH = ch;
00137                 updated = true;
00138             }
00139         }
00140     }
00141 
00142     if( cwh * h > maxArea )
00143     {
00144         int32_t cw = cwh;
00145         for( int32_t ch = cwh+1; ch <= h; ch++ )
00146         {
00147             while( getArea( x, y, cw, ch, data ) != 0 )
00148             {
00149                 cw--;
00150                 if( cw == 0 )
00151                 {
00152                     ch = h + 1;
00153                     break;
00154                 }
00155             }
00156             if( cw*ch > maxArea )
00157             {
00158                 maxArea = cw*ch;
00159                 maxW = cw;
00160                 maxH = ch;
00161                 updated = true;
00162             }
00163         }
00164     }
00165 
00166     if( updated )
00167         pvp = PixelViewport( x, y, maxW, maxH );
00168 
00169     return updated;
00170 }
00171 
00172 PixelViewport ROIEmptySpaceFinder::getLargestEmptyArea(const PixelViewport& pvp )
00173 const
00174 {
00175     EQASSERT(   pvp.x >= 0    && pvp.w > 0 &&
00176                 pvp.y >= 0    && pvp.h > 0 &&
00177                 pvp.x + pvp.w < _w && 
00178                 pvp.y + pvp.h < _h );
00179 
00180     EQASSERT( _mask );
00181 
00182     PixelViewport res( pvp.x, pvp.y, 0, 0 );
00183 
00184           uint16_t maxArea = getArea( pvp.x, pvp.y, pvp.w, pvp.h );
00185     const uint16_t minRel  = static_cast<uint16_t>( pvp.w * pvp.h * _limRel );
00186 
00187     // totally empty
00188     if( maxArea == 0 )
00189         return pvp;
00190 
00191     // totally full
00192     if( maxArea == pvp.w*pvp.h )
00193         return res;
00194 
00195     // over limit
00196     if( maxArea < _limAbs || maxArea < minRel )
00197         return res;
00198 
00199     // search for biggest empty pvp
00200     const uint16_t* data    = &_data[0] + pvp.y * _w;
00201     const uint8_t*  m       = _mask     + pvp.y * _w;
00202 
00203     maxArea = 0;
00204 
00205     for( int y=pvp.y, h=pvp.h; h > 0; y++, h-- )
00206     {
00207         // skeep if found area bigger than the rest of image
00208         if( h * pvp.w - getArea( pvp.x, y, pvp.w, h ) <= maxArea )
00209             break;
00210 
00211         for( int x=pvp.x, w=pvp.w; w > 0; x++, w-- )
00212         {
00213             // skeep non empty blocks
00214             if( m[x] != 0 )
00215                 continue;
00216 
00217             // skeep if found area bigger than the rest of image
00218             if( w*h - getArea( x, y, w, h, data + x ) <= maxArea )
00219             {
00220                 w = 0;
00221                 continue;
00222             }
00223 
00224             if( _updateMaximalEmptyRegion( x, y, w, h, res, data + x ))
00225                 maxArea = res.w * res.h;
00226         }
00227         m    += _w;
00228         data += _w;
00229     }
00230 
00231     const uint16_t curArea = res.w * res.h;
00232     if( curArea < _limAbs || curArea < minRel )
00233         return PixelViewport( pvp.x, pvp.y, 0, 0 );
00234 
00235     return res;
00236 }
00237 
00238 
00239 }
Generated on Mon Aug 10 18:58:41 2009 for Equalizer 0.9 by  doxygen 1.5.8