00001 /*!@file Foveator/LPTFoveator.C Foveator class that performs log polar transform */ 00002 00003 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Foveator/LPTFoveator.C $ 00004 // $Id: LPTFoveator.C 9412 2008-03-10 23:10:15Z farhan $ 00005 00006 #include "Foveator/LPTFoveator.H" 00007 00008 #include "Image/Pixels.H" 00009 00010 #include <algorithm> // for std::max() 00011 00012 // ###################################################################### 00013 00014 // constructor with initialization of original image 00015 00016 LPTFoveator::LPTFoveator( const Image< PixRGB<byte> >& img, 00017 int lptW, int lptH) : Foveator( img ), 00018 lptWidth( lptW ), 00019 lptHeight( lptH ) 00020 { 00021 if( lptW <= 0 || lptH <= 0 ) 00022 LERROR( "LPTFoveator map image must have positive dimensions." ); 00023 setOrigin( width / 2, height / 2 ); 00024 } 00025 00026 // destructor 00027 00028 LPTFoveator::~LPTFoveator() 00029 { 00030 lptMap.clear(); 00031 } 00032 00033 // ###################################################################### 00034 00035 // set origin and recalculate the LPT mapping 00036 00037 bool LPTFoveator::setOrigin( Point2D<int> pt ) 00038 { 00039 if( Foveator::setOrigin( pt ) ) 00040 { 00041 // find log multiplier 00042 int maxX = std::max( origin.i, width - origin.i ); 00043 int maxY = std::max( origin.j, height - origin.j ); 00044 logMultiplier = ( lptWidth - 1 ) / log( maxX*maxX + maxY*maxY + 1.0 ); 00045 00046 // calculate LPT pixel mapping 00047 lptMap.clear(); 00048 Point2D<int> mapPt; 00049 Point2D<int> originalPt; 00050 for( int x = 0; x < width; x++ ) 00051 { 00052 for( int y = 0; y < height; y++ ) 00053 { 00054 originalPt.i = x; 00055 originalPt.j = y; 00056 mapPt.i = (int)radius( x - origin.i, y - origin.j ); 00057 mapPt.j = (int)angle( x - origin.i, y - origin.j ); 00058 lptMap.insert( std::pair< Point2D<int>, Point2D<int> > 00059 ( mapPt, originalPt ) ); 00060 } 00061 } 00062 00063 // send positive feedback 00064 return true; 00065 } 00066 else 00067 return false; 00068 } 00069 00070 bool LPTFoveator::setOrigin( int x, int y ) 00071 { 00072 Point2D<int> pt( x, y ); 00073 return setOrigin( pt ); 00074 } 00075 00076 // ###################################################################### 00077 00078 Image< PixRGB<byte> > LPTFoveator::foveate( void ) 00079 { 00080 Image< PixRGB<byte> > fovImg = invLPT( getLPT() ); 00081 return fovImg; 00082 } 00083 00084 // ###################################################################### 00085 00086 Image< PixRGB<byte> > LPTFoveator::getLPT( void ) 00087 { 00088 Image< PixRGB<byte> > lptImg( lptWidth, lptHeight, NO_INIT ); 00089 for( int x = 0; x < lptWidth; x++ ) 00090 { 00091 for( int y = 0; y < lptHeight; y++ ) 00092 { 00093 Point2D<int> pt( x, y ); 00094 Point2DMapPtr pmp = lptMap.lower_bound( pt ); 00095 int count = 0; 00096 int rAcc = 0; 00097 int gAcc = 0; 00098 int bAcc = 0; 00099 while( pmp != lptMap.upper_bound( pt ) ) 00100 { 00101 // accumulation of RGB values 00102 rAcc += original.getVal( (*pmp).second ).red(); 00103 gAcc += original.getVal( (*pmp).second ).green(); 00104 bAcc += original.getVal( (*pmp).second ).blue(); 00105 count++; 00106 pmp++; 00107 } 00108 if( count > 1 ) 00109 { 00110 rAcc /= count; 00111 gAcc /= count; 00112 bAcc /= count; 00113 } 00114 PixRGB<byte> pix( rAcc, gAcc, bAcc ); 00115 lptImg.setVal( pt, pix ); 00116 } 00117 } 00118 return lptImg; 00119 } 00120 00121 // ###################################################################### 00122 00123 Image< PixRGB<byte> > LPTFoveator::invLPT( const Image< PixRGB<byte> >& img ) 00124 { 00125 Image< PixRGB<byte> > invImg( width, height, NO_INIT ); 00126 for( Point2DMapPtr pmp = lptMap.begin(); pmp != lptMap.end(); pmp++ ) 00127 { 00128 invImg.setVal( (*pmp).second, img.getVal( (*pmp).first ) ); 00129 } 00130 return invImg; 00131 } 00132 00133 // ###################################################################### 00134 00135 Image< PixRGB<byte> > LPTFoveator::foveate( const Image< PixRGB<byte> >& img, 00136 int lptW, int lptH, int x, int y, 00137 bool getMap ) 00138 { 00139 // find log multiplier 00140 int maxX = std::max( x, img.getWidth() - x ); 00141 int maxY = std::max( y, img.getHeight() - y ); 00142 double logMult = ( lptW - 1 ) / log( maxX * maxX + maxY * maxY + 1.0 ); 00143 00144 // declare and allocate accumulators and counter 00145 int **R_acc; 00146 int **G_acc; 00147 int **B_acc; 00148 int **counter; 00149 00150 typedef int* intptr; 00151 R_acc = new intptr[lptW]; 00152 G_acc = new intptr[lptW]; 00153 B_acc = new intptr[lptW]; 00154 counter = new intptr[lptW]; 00155 for( int i = 0; i < lptW; i++ ) 00156 { 00157 R_acc[i] = new int[lptH]; 00158 G_acc[i] = new int[lptH]; 00159 B_acc[i] = new int[lptH]; 00160 counter[i] = new int[lptH]; 00161 } 00162 00163 // initialize accumulators and counter to all zeros 00164 for( int i = 0; i < lptW; i++ ) 00165 { 00166 for( int j = 0; j < lptH; j++ ) 00167 { 00168 R_acc[i][j] = 0; 00169 G_acc[i][j] = 0; 00170 B_acc[i][j] = 0; 00171 counter[i][j] = 0; 00172 } 00173 } 00174 00175 // accumulate and count LPT pixels 00176 for( int i = 0; i < img.getWidth(); i++ ) 00177 { 00178 for( int j = 0; j < img.getHeight(); j++ ) 00179 { 00180 // make coordinates relative to origin 00181 int xx = i - x; 00182 int yy = j - y; 00183 00184 // determine r 00185 int r = int( logMult * log( xx * xx + yy * yy + 1.0 ) + 0.5 ); 00186 // determine theta 00187 int theta; 00188 if( yy == 0 ) 00189 { 00190 theta = (int)( ( xx >= 0 ) ? 00191 0.0 : 0.5 * ( lptH - 1 ) ); 00192 } 00193 else if( xx == 0 ) 00194 { 00195 theta = (int)( ( yy > 0 ) ? 00196 0.25 * ( lptH - 1 ) : 0.75 * ( lptH - 1 ) ); 00197 } 00198 else 00199 { 00200 theta = (int)( ( M_PI + atan2( -1.0 * yy, -1.0 * xx ) ) / 00201 ( 2 * M_PI ) * ( lptH - 1 ) + 0.5 ); 00202 } 00203 00204 // add pixel values 00205 R_acc[r][theta] += ( img.getVal( i, j ) ).red(); 00206 G_acc[r][theta] += ( img.getVal( i, j ) ).green(); 00207 B_acc[r][theta] += ( img.getVal( i, j ) ).blue(); 00208 counter[r][theta]++; 00209 } 00210 } 00211 00212 // write pixels to image 00213 Image< PixRGB<byte> > mapImage( lptW, lptH, NO_INIT ); 00214 for( int r = 0; r < lptW; r++ ) 00215 { 00216 for( int theta = 0; theta < lptH; theta++ ) 00217 { 00218 if( counter[r][theta] > 1 ) 00219 { 00220 // divide accumulators by counter matrix 00221 R_acc[r][theta] /= counter[r][theta]; 00222 G_acc[r][theta] /= counter[r][theta]; 00223 B_acc[r][theta] /= counter[r][theta]; 00224 } 00225 PixRGB<byte> pix( R_acc[r][theta], G_acc[r][theta], B_acc[r][theta] ); 00226 mapImage.setVal( r, theta, pix ); 00227 } 00228 } 00229 00230 // free memory 00231 delete [] R_acc; 00232 delete [] G_acc; 00233 delete [] B_acc; 00234 delete [] counter; 00235 00236 if( getMap ) 00237 return mapImage; 00238 else 00239 return ( invLPT( mapImage, img.getWidth(), img.getHeight(), x, y ) ); 00240 } 00241 00242 // ###################################################################### 00243 00244 Image< PixRGB<byte> > LPTFoveator::invLPT( const Image< PixRGB<byte> >& img, 00245 int w, int h, int x, int y ) 00246 { 00247 // find log multiplier 00248 int maxX = std::max( x, w - x ); 00249 int maxY = std::max( y, h - y ); 00250 double logMult = ( img.getWidth() - 1 ) / 00251 log( maxX * maxX + maxY * maxY + 1.0 ); 00252 00253 Image< PixRGB<byte> > invImage( w, h, NO_INIT ); 00254 00255 // write to image 00256 for( int i = 0; i < w; i++ ) 00257 { 00258 for( int j = 0; j < h; j++ ) 00259 { 00260 // make coordinates relative to origin 00261 int xx = i - x; 00262 int yy = j - y; 00263 00264 // determine r 00265 int r = int( logMult * log( xx * xx + yy * yy + 1.0 ) + 0.5 ); 00266 // determine theta 00267 int theta; 00268 if( yy == 0 ) 00269 { 00270 theta = (int)( ( xx >= 0 ) ? 00271 0.0 : 0.5 * ( img.getHeight() - 1 ) ); 00272 } 00273 else if( xx == 0 ) 00274 { 00275 theta = (int)( ( yy > 0 ) ? 00276 0.25 * ( img.getHeight() - 1 ) : 00277 0.75 * ( img.getHeight() - 1 ) ); 00278 } 00279 else 00280 { 00281 theta = (int)( ( M_PI + atan2( -1.0 * yy, -1.0 * xx ) ) / 00282 ( 2 * M_PI ) * ( img.getHeight() - 1 ) + 0.5 ); 00283 } 00284 00285 invImage.setVal( i, j, img.getVal( r, theta ) ); 00286 } 00287 } 00288 return invImage; 00289 } 00290 00291 // ###################################################################### 00292 /* So things look consistent in everyone's emacs... */ 00293 /* Local Variables: */ 00294 /* indent-tabs-mode: nil */ 00295 /* End: */