00001 /*!@file Foveator/BlurFoveator.C Foveator class that performs progressive blurring */ 00002 00003 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Foveator/BlurFoveator.C $ 00004 // $Id: BlurFoveator.C 4663 2005-06-23 17:47:28Z rjpeters $ 00005 00006 #include "Foveator/BlurFoveator.H" 00007 00008 #include "Image/Pixels.H" 00009 00010 #include <algorithm> // for std::max() 00011 #include <cmath> 00012 00013 // ###################################################################### 00014 00015 // constructor with initialization of original image 00016 BlurFoveator::BlurFoveator( const Image< PixRGB< byte > >& img, 00017 int filterSize ) : Foveator( img ) 00018 { 00019 // find the greater of two dimensions 00020 int dMax = std::max( width, height ); 00021 00022 // generate blur filters 00023 matrices = (dMax+1) * dMax / 2 - 1; 00024 typedef GaussianBlurMatrix* GaussianBlurMatrixPtr; 00025 gbms = new GaussianBlurMatrixPtr[matrices]; 00026 int k = -1; 00027 for( int i = 0; i < dMax; i++ ) 00028 { 00029 for( int j = 0; j <= i; j++ ) 00030 { 00031 if( k > -1 ) 00032 { 00033 gbms[k] = new GaussianBlurMatrix( filterSize ); 00034 gbms[k]->setBlurRadius( radius( i, j, width * height ) ); 00035 } 00036 k++; 00037 } 00038 } 00039 } 00040 00041 // copy constructor 00042 BlurFoveator::BlurFoveator( const BlurFoveator& bf ) : 00043 Foveator( bf.original ) 00044 { 00045 matrices = bf.matrices; 00046 typedef GaussianBlurMatrix* GaussianBlurMatrixPtr; 00047 gbms = new GaussianBlurMatrixPtr[matrices]; 00048 for( int i = 0; i < matrices; i++ ) 00049 { 00050 gbms[i] = new GaussianBlurMatrix( *(bf.gbms[i]) ); 00051 } 00052 } 00053 00054 // assignment operator 00055 BlurFoveator& BlurFoveator::operator=( const BlurFoveator& bf ) 00056 { 00057 BlurFoveator *newbf = new BlurFoveator( bf ); 00058 return *newbf; 00059 } 00060 00061 // destructor 00062 BlurFoveator::~BlurFoveator() 00063 { 00064 delete [] gbms; 00065 } 00066 00067 // ###################################################################### 00068 00069 // constructor for GaussianBlurMatrix 00070 BlurFoveator::GaussianBlurMatrix::GaussianBlurMatrix( int filterSize ) 00071 { 00072 if( filterSize % 2 == 0) 00073 { 00074 LERROR( "Blur filter size should be positive odd integer!" ); 00075 LINFO( "Blur foveation will be unstable/unpredictable!" ); 00076 } 00077 halfFilter = filterSize/2 + 1; 00078 size = (halfFilter+1) * halfFilter / 2; 00079 weights = new float[size]; 00080 } 00081 00082 // copy constructor for GaussianBlurMatrix 00083 BlurFoveator::GaussianBlurMatrix:: 00084 GaussianBlurMatrix( const GaussianBlurMatrix& gbm ) 00085 { 00086 halfFilter = gbm.halfFilter; 00087 size = gbm.size; 00088 weights = new float[size]; 00089 for( int i = 0; i < size; i++ ) 00090 { 00091 weights[i] = gbm.weights[i]; 00092 } 00093 } 00094 00095 // assignment operator 00096 BlurFoveator::GaussianBlurMatrix& BlurFoveator::GaussianBlurMatrix:: 00097 operator=( const GaussianBlurMatrix& gbm ) 00098 { 00099 GaussianBlurMatrix *newgbm = new GaussianBlurMatrix( gbm ); 00100 return *newgbm; 00101 } 00102 00103 // destructor for GaussianBlurMatrix 00104 BlurFoveator::GaussianBlurMatrix::~GaussianBlurMatrix() 00105 { 00106 delete [] weights; 00107 } 00108 00109 // calculate a blurred pixel 00110 PixRGB<byte> BlurFoveator::GaussianBlurMatrix:: 00111 blurPixel( int x, int y, const Image< PixRGB<byte> >& img ) const 00112 { 00113 float newR = 0.0f; 00114 float newG = 0.0f; 00115 float newB = 0.0f; 00116 float denom = 0.0f; 00117 00118 int k = 0; 00119 for( int i = 0; i < halfFilter; i++ ) 00120 { 00121 for( int j = 0; j <= i; j++ ) 00122 { 00123 if( !k ) 00124 { 00125 PixRGB<byte> pix = img.getVal( x, y ); 00126 newR += pix.red(); 00127 newG += pix.green(); 00128 newB += pix.blue(); 00129 denom++; 00130 } 00131 else 00132 { 00133 if( img.coordsOk( x + i, y + j ) ) 00134 { 00135 PixRGB<byte> pix = img.getVal( x + i, y + j ); 00136 newR += weights[k] * pix.red(); 00137 newG += weights[k] * pix.green(); 00138 newB += weights[k] * pix.blue(); 00139 denom += weights[k]; 00140 } 00141 if( img.coordsOk( x + j, y + i ) ) 00142 { 00143 PixRGB<byte> pix = img.getVal( x + j, y + i ); 00144 newR += weights[k] * pix.red(); 00145 newG += weights[k] * pix.green(); 00146 newB += weights[k] * pix.blue(); 00147 denom += weights[k]; 00148 } 00149 if( img.coordsOk( x - i, y + j ) ) 00150 { 00151 PixRGB<byte> pix = img.getVal( x - i, y + j ); 00152 newR += weights[k] * pix.red(); 00153 newG += weights[k] * pix.green(); 00154 newB += weights[k] * pix.blue(); 00155 denom += weights[k]; 00156 } 00157 if( img.coordsOk( x - j, y + i ) ) 00158 { 00159 PixRGB<byte> pix = img.getVal( x - j, y + i ); 00160 newR += weights[k] * pix.red(); 00161 newG += weights[k] * pix.green(); 00162 newB += weights[k] * pix.blue(); 00163 denom += weights[k]; 00164 } 00165 if( img.coordsOk( x - i, y - j ) ) 00166 { 00167 PixRGB<byte> pix = img.getVal( x - i, y - j ); 00168 newR += weights[k] * pix.red(); 00169 newG += weights[k] * pix.green(); 00170 newB += weights[k] * pix.blue(); 00171 denom += weights[k]; 00172 } 00173 if( img.coordsOk( x - j, y - i ) ) 00174 { 00175 PixRGB<byte> pix = img.getVal( x - j, y - i ); 00176 newR += weights[k] * pix.red(); 00177 newG += weights[k] * pix.green(); 00178 newB += weights[k] * pix.blue(); 00179 denom += weights[k]; 00180 } 00181 if( img.coordsOk( x + i, y - j ) ) 00182 { 00183 PixRGB<byte> pix = img.getVal( x + i, y - j ); 00184 newR += weights[k] * pix.red(); 00185 newG += weights[k] * pix.green(); 00186 newB += weights[k] * pix.blue(); 00187 denom += weights[k]; 00188 } 00189 if( img.coordsOk( x + j, y - i ) ) 00190 { 00191 PixRGB<byte> pix = img.getVal( x + j, y - i ); 00192 newR += weights[k] * pix.red(); 00193 newG += weights[k] * pix.green(); 00194 newB += weights[k] * pix.blue(); 00195 denom += weights[k]; 00196 } 00197 } 00198 k++; 00199 } 00200 } 00201 00202 newR /= denom; 00203 newG /= denom; 00204 newB /= denom; 00205 PixRGB<byte> newPixel( newR, newG, newB ); 00206 return newPixel; 00207 } 00208 00209 // set Gaussian blur radius 00210 void BlurFoveator::GaussianBlurMatrix::setBlurRadius( const float& r ) 00211 { 00212 int k = 0; 00213 for( int i = 0; i < halfFilter; i++ ) 00214 { 00215 for( int j = 0; j <= i; j++ ) 00216 { 00217 weights[k] = (float)( exp( -( (i*i+j*j)/(2*r*r) ) ) ); 00218 k++; 00219 } 00220 } 00221 } 00222 00223 // ###################################################################### 00224 00225 // Radius calculation function based on distance between point and origin 00226 // Should be monotonic increasing 00227 float BlurFoveator::radius( int x, int y, int area ) 00228 { 00229 return( 10.0f * ( x*x + y*y ) / area + 0.5f ); 00230 } 00231 00232 // Blur-foveation method, returns foveated image 00233 Image< PixRGB<byte> > BlurFoveator::foveate( void ) 00234 { 00235 Image< PixRGB<byte> > fovImg( width, height, NO_INIT ); 00236 00237 // determine maximum distance to an edge 00238 int dMax = std::max( std::max( origin.i, width - origin.i ), 00239 std::max( origin.j, height - origin.j ) ); 00240 00241 int k = -1; 00242 for( int i = 0; i < dMax; i++ ) 00243 { 00244 for( int j = 0; j <= i; j++ ) 00245 { 00246 // check if we are operating on origin pixel 00247 if( k == -1 ) 00248 { 00249 fovImg.setVal( origin.i, origin.j, 00250 original.getVal( origin.i, origin.j ) ); 00251 } 00252 else 00253 { 00254 if( fovImg.coordsOk( origin.i + i, origin.j + j ) ) 00255 { 00256 fovImg.setVal( origin.i + i, origin.j + j, 00257 gbms[k]->blurPixel( origin.i + i, 00258 origin.j + j, 00259 original ) ); 00260 } 00261 if( fovImg.coordsOk( origin.i + j, origin.j + i ) ) 00262 { 00263 fovImg.setVal( origin.i + j, origin.j + i, 00264 gbms[k]->blurPixel( origin.i + j, 00265 origin.j + i, 00266 original ) ); 00267 } 00268 if( fovImg.coordsOk( origin.i - i, origin.j + j ) ) 00269 { 00270 fovImg.setVal( origin.i - i, origin.j + j, 00271 gbms[k]->blurPixel( origin.i - i, 00272 origin.j + j, 00273 original ) ); 00274 } 00275 if( fovImg.coordsOk( origin.i - j, origin.j + i ) ) 00276 { 00277 fovImg.setVal( origin.i - j, origin.j + i, 00278 gbms[k]->blurPixel( origin.i - j, 00279 origin.j + i, 00280 original ) ); 00281 } 00282 if( fovImg.coordsOk( origin.i - i, origin.j - j ) ) 00283 { 00284 fovImg.setVal( origin.i - i, origin.j - j, 00285 gbms[k]->blurPixel( origin.i - i, 00286 origin.j - j, 00287 original ) ); 00288 } 00289 if( fovImg.coordsOk( origin.i - j, origin.j - i ) ) 00290 { 00291 fovImg.setVal( origin.i - j, origin.j - i, 00292 gbms[k]->blurPixel( origin.i - j, 00293 origin.j - i, 00294 original ) ); 00295 } 00296 if( fovImg.coordsOk( origin.i + i, origin.j - j ) ) 00297 { 00298 fovImg.setVal( origin.i + i, origin.j - j, 00299 gbms[k]->blurPixel( origin.i + i, 00300 origin.j - j, 00301 original ) ); 00302 } 00303 if( fovImg.coordsOk( origin.i + j, origin.j - i ) ) 00304 { 00305 fovImg.setVal( origin.i + j, origin.j - i, 00306 gbms[k]->blurPixel( origin.i + j, 00307 origin.j - i, 00308 original ) ); 00309 } 00310 } 00311 k++; 00312 } 00313 } 00314 00315 return fovImg; 00316 } 00317 00318 // ###################################################################### 00319 00320 Image< PixRGB<byte> > BlurFoveator:: 00321 foveate( const Image< PixRGB<byte> >& img, int filterSize, int x, int y ) 00322 { 00323 // generate an image of same dimensions 00324 int width = img.getWidth(); 00325 int height = img.getHeight(); 00326 Image< PixRGB< byte > > fovImg( width, height, NO_INIT ); 00327 00328 // generate a Gaussian blur filter of the appropriate size 00329 GaussianBlurMatrix gbm( filterSize ); 00330 00331 // determine maximum distance to an edge 00332 int dMax = std::max( std::max( x, width - x ), 00333 std::max( y, height - y ) ); 00334 00335 for( int i = 0; i < dMax; i++ ) 00336 { 00337 for( int j = 0; j <= i; j++ ) 00338 { 00339 // check if we are operating on the origin pixel 00340 if( !i && !j ) 00341 { 00342 fovImg.setVal( x, y, img.getVal( x, y ) ); 00343 } 00344 else 00345 { 00346 gbm.setBlurRadius( radius( i, j, width * height ) ); 00347 if( fovImg.coordsOk( x + i, y + j ) ) 00348 { 00349 fovImg.setVal( x + i, y + j, 00350 gbm.blurPixel( x + i, y + j, img ) ); 00351 } 00352 if( fovImg.coordsOk( x + j, y + i ) ) 00353 { 00354 fovImg.setVal( x + j, y + i, 00355 gbm.blurPixel( x + j, y + i, img ) ); 00356 } 00357 if( fovImg.coordsOk( x - i, y + j ) ) 00358 { 00359 fovImg.setVal( x - i, y + j, 00360 gbm.blurPixel( x - i, y + j, img ) ); 00361 } 00362 if( fovImg.coordsOk( x - j, y + i ) ) 00363 { 00364 fovImg.setVal( x - j, y + i, 00365 gbm.blurPixel( x - j, y + i, img ) ); 00366 } 00367 if( fovImg.coordsOk( x - i, y - j ) ) 00368 { 00369 fovImg.setVal( x - i, y - j, 00370 gbm.blurPixel( x - i, y - j, img ) ); 00371 } 00372 if( fovImg.coordsOk( x - j, y - i ) ) 00373 { 00374 fovImg.setVal( x - j, y - i, 00375 gbm.blurPixel( x - j, y - i, img ) ); 00376 } 00377 if( fovImg.coordsOk( x + i, y - j ) ) 00378 { 00379 fovImg.setVal( x + i, y - j, 00380 gbm.blurPixel( x + i, y - j, img ) ); 00381 } 00382 if( fovImg.coordsOk( x + j, y - i ) ) 00383 { 00384 fovImg.setVal( x + j, y - i, 00385 gbm.blurPixel( x + j, y - i, img ) ); 00386 } 00387 } 00388 } 00389 } 00390 00391 return fovImg; 00392 } 00393 00394 // ###################################################################### 00395 /* So things look consistent in everyone's emacs... */ 00396 /* Local Variables: */ 00397 /* indent-tabs-mode: nil */ 00398 /* End: */