00001 /*!@file Image/PyrBuilder.C Classes for building dyadic pyramids */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/PyrBuilder.C $ 00035 // $Id: PyrBuilder.C 14473 2011-02-03 20:36:39Z dberg $ 00036 // 00037 00038 #include "Image/PyrBuilder.H" 00039 00040 #include "Image/Image.H" 00041 #include "Image/ImageSet.H" 00042 #include "Image/ColorOps.H" 00043 #include "Image/CutPaste.H" 00044 #include "Image/FilterOps.H" 00045 #include "Image/MathOps.H" 00046 #include "Image/ShapeOps.H" 00047 #include "Image/Pixels.H" 00048 #include "Image/PyramidCache.H" 00049 #include "Image/PyramidOps.H" 00050 #include "rutz/trace.h" 00051 00052 // ###################################################################### 00053 // ##### PyrBuilder functions: 00054 // ###################################################################### 00055 00056 // ###################################################################### 00057 template <class T> 00058 PyrBuilder<T>::PyrBuilder() 00059 { 00060 GVX_TRACE(__PRETTY_FUNCTION__); 00061 } 00062 00063 // ###################################################################### 00064 template <class T> 00065 PyrBuilder<T>::~PyrBuilder() 00066 { 00067 GVX_TRACE(__PRETTY_FUNCTION__); 00068 } 00069 00070 // ###################################################################### 00071 template <class T> 00072 void PyrBuilder<T>::reset() 00073 { 00074 GVX_TRACE(__PRETTY_FUNCTION__); 00075 } 00076 00077 // ###################################################################### 00078 // ##### GaussianPyrBuilder Functions: 00079 // ###################################################################### 00080 00081 template <class T> 00082 GaussianPyrBuilder<T>::GaussianPyrBuilder(int filter_size) : 00083 PyrBuilder<T>(), itsFiltSize(filter_size) 00084 { 00085 GVX_TRACE(__PRETTY_FUNCTION__); 00086 } 00087 00088 template <class T> 00089 ImageSet<T> GaussianPyrBuilder<T>::build(const Image<T>& img, 00090 const int firstlevel, 00091 const int depth, 00092 PyramidCache<T>* cache) 00093 { 00094 GVX_TRACE(__PRETTY_FUNCTION__); 00095 00096 const ImageSet<T>* const cached = 00097 (cache != 0 && itsFiltSize == 5) 00098 ? cache->gaussian5.get(img) // may be null if there is no cached pyramid 00099 : 0; 00100 00101 return (cached != 0) 00102 ? *cached 00103 : buildPyrGaussian(img, firstlevel, depth, itsFiltSize); 00104 } 00105 00106 template <class T> inline 00107 GaussianPyrBuilder<T>* GaussianPyrBuilder<T>::clone() const 00108 { 00109 GVX_TRACE(__PRETTY_FUNCTION__); 00110 return new GaussianPyrBuilder<T>(*this); 00111 } 00112 00113 // ###################################################################### 00114 // ##### GaussianRadialPyrBuilder Functions: 00115 // ###################################################################### 00116 00117 template <class T> 00118 GaussianRadialPyrBuilder<T>::GaussianRadialPyrBuilder() : 00119 PyrBuilder<T>() 00120 { 00121 GVX_TRACE(__PRETTY_FUNCTION__); 00122 } 00123 00124 template <class T> 00125 ImageSet<T> GaussianRadialPyrBuilder<T>::build(const Image<T>& img, 00126 const int firstlevel, 00127 const int depth, 00128 PyramidCache<T>* cache) 00129 { 00130 GVX_TRACE(__PRETTY_FUNCTION__); 00131 00132 const ImageSet<T>* const cached = (cache != 0) 00133 ? cache->gaussian5.get(img) // may be null if there is no cached pyramid 00134 : 0; 00135 00136 return (cached != 0) 00137 ? *cached 00138 : buildRadialPyrGaussian(img, firstlevel, depth); 00139 } 00140 00141 template <class T> inline 00142 GaussianRadialPyrBuilder<T>* GaussianRadialPyrBuilder<T>::clone() const 00143 { 00144 GVX_TRACE(__PRETTY_FUNCTION__); 00145 return new GaussianRadialPyrBuilder<T>(*this); 00146 } 00147 00148 // ###################################################################### 00149 // ##### ConvolvePyrBuilder Functions: 00150 // ###################################################################### 00151 00152 template <class T> 00153 ConvolvePyrBuilder<T>:: 00154 ConvolvePyrBuilder(const Image<float>& filt, 00155 ConvolutionBoundaryStrategy boundary) : 00156 PyrBuilder<T>(), itsFilt(filt), itsBoundary(boundary) 00157 { 00158 GVX_TRACE(__PRETTY_FUNCTION__); 00159 } 00160 00161 template <class T> 00162 ImageSet<T> ConvolvePyrBuilder<T>::build(const Image<T>& img, 00163 const int firstlevel, 00164 const int depth, 00165 PyramidCache<T>* cache) 00166 { 00167 GVX_TRACE(__PRETTY_FUNCTION__); 00168 return buildPyrConvolve(img, firstlevel, depth, itsFilt, itsBoundary); 00169 } 00170 00171 template <class T> 00172 ConvolvePyrBuilder<T>* ConvolvePyrBuilder<T>::clone() const 00173 { 00174 GVX_TRACE(__PRETTY_FUNCTION__); 00175 return new ConvolvePyrBuilder<T>(*this); 00176 } 00177 00178 // ###################################################################### 00179 // ##### RGBConvolvePyrBuilder Functions: 00180 // ###################################################################### 00181 00182 template <class T> 00183 RGBConvolvePyrBuilder<T>:: 00184 RGBConvolvePyrBuilder(const Image<float>& rfilt, 00185 const Image<float>& gfilt, 00186 const Image<float>& bfilt, 00187 ConvolutionBoundaryStrategy boundary) : 00188 PyrBuilder<T>(), itsRFilt(rfilt), itsGFilt(rfilt), itsBFilt(rfilt), 00189 itsBoundary(boundary) 00190 { 00191 GVX_TRACE(__PRETTY_FUNCTION__); 00192 } 00193 00194 template <class T> 00195 ImageSet<T> RGBConvolvePyrBuilder<T>:: 00196 build(const Image< PixRGB<T> >& img, 00197 const int firstlevel, 00198 const int depth, 00199 PyramidCache<T>* cache) 00200 { 00201 GVX_TRACE(__PRETTY_FUNCTION__); 00202 Image<T> r, g, b; getComponents(img, r, g, b); 00203 ImageSet<T> rset = buildPyrConvolve(r, firstlevel, depth, itsRFilt, itsBoundary); 00204 ImageSet<T> gset = buildPyrConvolve(g, firstlevel, depth, itsGFilt, itsBoundary); 00205 ImageSet<T> bset = buildPyrConvolve(b, firstlevel, depth, itsBFilt, itsBoundary); 00206 ImageSet<T> result(depth); 00207 00208 for (int lev = firstlevel; lev < depth; ++lev) 00209 result[lev] = (rset[lev] + gset[lev] + bset[lev]) / 3; 00210 00211 return result; 00212 } 00213 00214 template <class T> 00215 ImageSet<T> RGBConvolvePyrBuilder<T>:: 00216 build(const Image<T>& img, 00217 const int firstlevel, 00218 const int depth, 00219 PyramidCache<T>* cache) 00220 { 00221 GVX_TRACE(__PRETTY_FUNCTION__); 00222 LFATAL("Cannot process greyscale images"); 00223 return ImageSet<T>(); 00224 } 00225 00226 template <class T> 00227 ImageSet< PixRGB<T> > RGBConvolvePyrBuilder<T>:: 00228 build2(const Image< PixRGB<T> >& img, 00229 const int firstlevel, 00230 const int depth, 00231 PyramidCache<T>* cache) 00232 { 00233 GVX_TRACE(__PRETTY_FUNCTION__); 00234 Image<T> r, g, b; getComponents(img, r, g, b); 00235 ImageSet<T> rset = buildPyrConvolve(r, firstlevel, depth, itsRFilt, itsBoundary); 00236 ImageSet<T> gset = buildPyrConvolve(g, firstlevel, depth, itsGFilt, itsBoundary); 00237 ImageSet<T> bset = buildPyrConvolve(b, firstlevel, depth, itsBFilt, itsBoundary); 00238 ImageSet< PixRGB<T> > result(depth); 00239 00240 for (int lev = firstlevel; lev < depth; ++lev) 00241 result[lev] = makeRGB (rset[lev], gset[lev], bset[lev]); 00242 00243 return result; 00244 } 00245 00246 template <class T> 00247 RGBConvolvePyrBuilder<T>* RGBConvolvePyrBuilder<T>::clone() const 00248 { 00249 GVX_TRACE(__PRETTY_FUNCTION__); 00250 return new RGBConvolvePyrBuilder<T>(*this); 00251 } 00252 00253 // ###################################################################### 00254 // ##### LaplacianPyrBuilder Functions: 00255 // ###################################################################### 00256 00257 template <class T> 00258 LaplacianPyrBuilder<T>::LaplacianPyrBuilder(const int filter_size) : 00259 PyrBuilder<T>(), itsFiltSize(filter_size) 00260 { 00261 GVX_TRACE(__PRETTY_FUNCTION__); 00262 } 00263 00264 template <class T> 00265 ImageSet<T> LaplacianPyrBuilder<T>::build(const Image<T>& img, 00266 const int firstlevel, 00267 const int depth, 00268 PyramidCache<T>* cache) 00269 { 00270 GVX_TRACE(__PRETTY_FUNCTION__); 00271 return buildPyrLaplacian(img, firstlevel, depth, itsFiltSize); 00272 } 00273 00274 template <class T> inline 00275 LaplacianPyrBuilder<T>* LaplacianPyrBuilder<T>::clone() const 00276 { 00277 GVX_TRACE(__PRETTY_FUNCTION__); 00278 return new LaplacianPyrBuilder<T>(*this); 00279 } 00280 00281 // ###################################################################### 00282 // ##### OrientedPyrBuilder Functions: 00283 // ###################################################################### 00284 00285 template <class T> 00286 OrientedPyrBuilder<T>::OrientedPyrBuilder(const int filter_size, 00287 const float theta, 00288 const float intens, 00289 const bool usetab) : 00290 PyrBuilder<T>(), itsFiltSize(filter_size), itsAngle(theta), 00291 itsGaborIntens(intens), itsUseTab(usetab) 00292 { 00293 GVX_TRACE(__PRETTY_FUNCTION__); 00294 } 00295 00296 template <class T> 00297 ImageSet<T> OrientedPyrBuilder<T>::build(const Image<T>& img, 00298 const int firstlevel, 00299 const int depth, 00300 PyramidCache<T>* cache) 00301 { 00302 GVX_TRACE(__PRETTY_FUNCTION__); 00303 00304 const ImageSet<T>* const lplc = 00305 (cache != 0 && itsFiltSize == 9) 00306 ? cache->laplacian9.get(img) // may be null if there is no cached pyramid 00307 : 0; 00308 00309 return lplc != 0 00310 ? buildPyrOrientedFromLaplacian<T>(*lplc, 00311 itsFiltSize, itsAngle, itsGaborIntens, 00312 itsUseTab) 00313 : buildPyrOriented(img, firstlevel, depth, 00314 itsFiltSize, itsAngle, itsGaborIntens, itsUseTab); 00315 } 00316 00317 template <class T> 00318 OrientedPyrBuilder<T>* OrientedPyrBuilder<T>::clone() const 00319 { 00320 GVX_TRACE(__PRETTY_FUNCTION__); 00321 return new OrientedPyrBuilder<T>(*this); 00322 } 00323 00324 00325 // ###################################################################### 00326 // ##### GenericPyrBuilder Functions: 00327 // ###################################################################### 00328 00329 template <class T> 00330 GenericPyrBuilder<T>::GenericPyrBuilder(const PyramidType typ, 00331 const float gabor_theta, 00332 const float intens) : 00333 PyrBuilder<T>(), itsPtype(typ), itsGaborAngle(gabor_theta), 00334 itsGaborIntens(intens) 00335 { 00336 GVX_TRACE(__PRETTY_FUNCTION__); 00337 } 00338 00339 template <class T> 00340 ImageSet<T> GenericPyrBuilder<T>::build(const Image<T>& image, 00341 const int firstlevel, 00342 const int depth, 00343 PyramidCache<T>* cache) 00344 { 00345 GVX_TRACE(__PRETTY_FUNCTION__); 00346 return buildPyrGeneric(image, firstlevel, depth, itsPtype, 00347 itsGaborAngle, itsGaborIntens); 00348 } 00349 00350 template <class T> 00351 GenericPyrBuilder<T>* GenericPyrBuilder<T>::clone() const 00352 { 00353 GVX_TRACE(__PRETTY_FUNCTION__); 00354 return new GenericPyrBuilder<T>(*this); 00355 } 00356 00357 // ###################################################################### 00358 // ##### ReichardtPyrBuilder Functions: 00359 // ###################################################################### 00360 template <class T> 00361 ReichardtPyrBuilder<T>::ReichardtPyrBuilder(const float dx, 00362 const float dy, 00363 const PyramidType typ, 00364 const float gabor_theta, 00365 const float intens) : 00366 PyrBuilder<T>(), itsDX(dx), itsDY(dy), itsPtype(typ), 00367 itsGaborAngle(gabor_theta), itsGaborIntens(intens) 00368 { 00369 GVX_TRACE(__PRETTY_FUNCTION__); 00370 } 00371 00372 template <class T> 00373 ImageSet<T> ReichardtPyrBuilder<T>::build(const Image<T>& image, 00374 const int firstlevel, 00375 const int depth, 00376 PyramidCache<T>* cache) 00377 { 00378 GVX_TRACE(__PRETTY_FUNCTION__); 00379 const ImageSet<T>* const cached = 00380 (cache != 0 && itsPtype == Gaussian5) 00381 ? cache->gaussian5.get(image) // may be null if there is no cached pyramid 00382 : 0; 00383 00384 // create a pyramid with the input image 00385 ImageSet<T> upyr = 00386 cached != 0 00387 ? *cached 00388 : buildPyrGeneric(image, firstlevel, depth, itsPtype, 00389 itsGaborAngle, itsGaborIntens); 00390 // create an empty pyramid 00391 ImageSet<T> spyr(depth); 00392 00393 // fill the empty pyramid with the shifted version 00394 for (int i = firstlevel; i < depth; ++i) 00395 spyr[i] = shiftImage(upyr[i], itsDX, itsDY); 00396 00397 // store both pyramids in the deques 00398 unshifted.push_back(upyr); 00399 shifted.push_back(spyr); 00400 00401 ImageSet<T> result(depth); 00402 00403 // so, it's our first time? Pretend the pyramid before this was 00404 // the same as the current one ... 00405 if (unshifted.size() == 1) 00406 { 00407 unshifted.push_back(upyr); 00408 shifted.push_back(spyr); 00409 } 00410 00411 // need to pop off old pyramid? 00412 if (unshifted.size() == 3) 00413 { 00414 unshifted.pop_front(); 00415 shifted.pop_front(); 00416 } 00417 00418 // compute the Reichardt maps 00419 for (int i = firstlevel; i < depth; ++i) 00420 { 00421 result[i] = 00422 (unshifted.back()[i] * shifted.front()[i]) - 00423 (unshifted.front()[i] * shifted.back()[i]); 00424 } 00425 00426 return result; 00427 } 00428 00429 // ###################################################################### 00430 template <class T> 00431 ReichardtPyrBuilder<T>* ReichardtPyrBuilder<T>::clone() const 00432 { 00433 GVX_TRACE(__PRETTY_FUNCTION__); 00434 return new ReichardtPyrBuilder<T>(*this); 00435 } 00436 00437 // ###################################################################### 00438 template <class T> 00439 void ReichardtPyrBuilder<T>::reset() 00440 { 00441 GVX_TRACE(__PRETTY_FUNCTION__); 00442 shifted.clear(); 00443 unshifted.clear(); 00444 } 00445 00446 // ###################################################################### 00447 // ##### TemplateMatchPyrBuilder Functions: 00448 // ###################################################################### 00449 TemplateMatchPyrBuilder::TemplateMatchPyrBuilder(const Image<float>& templ) : 00450 PyrBuilder<float>(), itsFilt(templ) 00451 { 00452 GVX_TRACE(__PRETTY_FUNCTION__); 00453 } 00454 00455 // ###################################################################### 00456 TemplateMatchPyrBuilder* TemplateMatchPyrBuilder::clone() const 00457 { 00458 GVX_TRACE(__PRETTY_FUNCTION__); 00459 return new TemplateMatchPyrBuilder(*this); 00460 } 00461 00462 // ###################################################################### 00463 ImageSet<float> TemplateMatchPyrBuilder::build(const Image<float>& image, 00464 const int firstlevel, 00465 const int depth, 00466 PyramidCache<float>* cache) 00467 { 00468 GVX_TRACE(__PRETTY_FUNCTION__); 00469 ImageSet<float> result(depth); 00470 if (0 >= firstlevel) 00471 result[0] = templateMatch(image); 00472 Image<float> prev_scale = image; 00473 00474 for (int lev = 1; lev < depth; ++lev) 00475 { 00476 Image<float> cur_scale = prev_scale; 00477 00478 cur_scale = decX(lowPass5x(cur_scale)); 00479 cur_scale = decY(lowPass5y(cur_scale)); 00480 00481 // Save the unconvolved image at this scale to be used as the 00482 // starting point for the next scale 00483 prev_scale = cur_scale; 00484 00485 if (lev >= firstlevel) 00486 result[lev] = templateMatch(cur_scale); 00487 } 00488 00489 return result; 00490 } 00491 00492 // ###################################################################### 00493 Image<float> TemplateMatchPyrBuilder::templateMatch(const Image<float>& img) 00494 { 00495 GVX_TRACE(__PRETTY_FUNCTION__); 00496 Image<float> conv = convolve(img, itsFilt, 00497 CONV_BOUNDARY_ZERO); 00498 Image<float> conv2 = convolve(binaryReverse(img, 255.0f), itsFilt, 00499 CONV_BOUNDARY_ZERO); 00500 return takeMax(conv, conv2); 00501 } 00502 00503 // ###################################################################### 00504 // ##### GaborPyrBuilder Functions: 00505 // ###################################################################### 00506 template <class T> 00507 GaborPyrBuilder<T>::GaborPyrBuilder(double angle, 00508 double filter_period, 00509 double elongation, 00510 int size, 00511 int buildFlags) : 00512 PyrBuilder<T>(), 00513 itsAngle(angle), 00514 itsPeriod(filter_period), 00515 itsElongation(elongation), 00516 itsSize(size), 00517 itsBuildFlags(buildFlags) 00518 { 00519 GVX_TRACE(__PRETTY_FUNCTION__); 00520 } 00521 00522 // ###################################################################### 00523 template <class T> 00524 GaborPyrBuilder<T>* GaborPyrBuilder<T>::clone() const 00525 { 00526 GVX_TRACE(__PRETTY_FUNCTION__); 00527 return new GaborPyrBuilder<T>(*this); 00528 } 00529 00530 // ###################################################################### 00531 template <class T> 00532 ImageSet<T> GaborPyrBuilder<T>::build(const Image<T>& img, 00533 const int firstlevel, 00534 const int depth, 00535 PyramidCache<T>* cache) 00536 { 00537 GVX_TRACE(__PRETTY_FUNCTION__); 00538 return buildPyrGabor(img, firstlevel, depth, 00539 itsAngle, itsPeriod, itsElongation, 00540 itsSize, itsBuildFlags); 00541 } 00542 00543 // ###################################################################### 00544 template <class T> 00545 ImageSet<T> GaborPyrBuilder<T>::input(const ImageSet<T>& pyr) 00546 { 00547 GVX_TRACE(__PRETTY_FUNCTION__); 00548 return buildPyrGabor(pyr, itsAngle, itsPeriod, itsElongation, 00549 itsSize, itsBuildFlags); 00550 } 00551 00552 // ###################################################################### 00553 // ##### Instantiations 00554 // ###################################################################### 00555 template class GaborPyrBuilder<float>; 00556 template class RGBConvolvePyrBuilder<float>; 00557 00558 #define INSTANTIATE(T) \ 00559 template class PyrBuilder< T >; \ 00560 template class GenericPyrBuilder< T >; \ 00561 template class GaussianPyrBuilder< T >; \ 00562 template class GaussianRadialPyrBuilder< T >; \ 00563 template class ConvolvePyrBuilder< T >; \ 00564 template class LaplacianPyrBuilder< T >; \ 00565 template class OrientedPyrBuilder< T >; \ 00566 template class ReichardtPyrBuilder< T >; \ 00567 00568 template class PyrBuilder<int>; 00569 00570 #ifdef INVT_INST_BYTE 00571 INSTANTIATE(byte); 00572 INSTANTIATE(PixRGB<byte>); 00573 #endif 00574 #ifdef INVT_INST_INT16 00575 INSTANTIATE(int16); 00576 INSTANTIATE(PixRGB<int16>); 00577 #endif 00578 #ifdef INVT_INST_INT32 00579 INSTANTIATE(int32); 00580 INSTANTIATE(PixRGB<int32>); 00581 #endif 00582 #ifdef INVT_INST_FLOAT 00583 INSTANTIATE(float); 00584 INSTANTIATE(PixRGB<float>); 00585 #endif 00586 00587 /* So things look consistent in everyone's emacs... */ 00588 /* Local Variables: */ 00589 /* indent-tabs-mode: nil */ 00590 /* End: */