00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00049 d[_w-1] = s[_w-1] > 0 ? 1 : 0;
00050
00051
00052 for( int32_t x = _w-2; x >= 0; x-- )
00053 d[x] = d[x+1] + ( s[x] > 0 ? 1 : 0 );
00054
00055
00056 for( int32_t y = 1; y < _h; y++ )
00057 {
00058 const uint16_t* dp = d;
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
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
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
00188 if( maxArea == 0 )
00189 return pvp;
00190
00191
00192 if( maxArea == pvp.w*pvp.h )
00193 return res;
00194
00195
00196 if( maxArea < _limAbs || maxArea < minRel )
00197 return res;
00198
00199
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
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
00214 if( m[x] != 0 )
00215 continue;
00216
00217
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 }