00001 /*!@file Image/ImageSetOps.C Free functions operating on sets of images */ 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/ImageSetOps.C $ 00035 // $Id: ImageSetOps.C 14633 2011-03-23 22:55:54Z dberg $ 00036 // 00037 00038 #include "Image/ImageSetOps.H" 00039 00040 #include "Image/DrawOps.H" 00041 #include "Image/FilterOps.H" 00042 #include "Image/Image.H" 00043 #include "Image/ImageSet.H" 00044 #include "Image/MathOps.H" 00045 #include "Image/Range.H" 00046 #include "Image/ShapeOps.H" 00047 #include "Util/Assert.H" 00048 #include "rutz/compat_cmath.h" 00049 00050 // ###################################################################### 00051 // ###################################################################### 00052 // ##### ImageSet processing functions 00053 // ###################################################################### 00054 // ###################################################################### 00055 00056 // ###################################################################### 00057 template <class T> 00058 bool isHomogeneous(const ImageSet<T>& x) 00059 { 00060 if (x.size() == 0) return true; 00061 00062 const Dims d = x[0].getDims(); 00063 00064 for (uint i = 1; i < x.size(); ++i) 00065 if (d != x[i].getDims()) 00066 return false; 00067 00068 return true; 00069 } 00070 00071 // ###################################################################### 00072 template <class T> 00073 bool isDyadic(const ImageSet<T>& pyr) 00074 { 00075 if (pyr.size() == 0) return false; 00076 00077 for (uint i = 1; i < pyr.size(); ++i) 00078 { 00079 const Dims prevdims = pyr[i-1].getDims(); 00080 const Dims curdims = pyr[i].getDims(); 00081 00082 // make sure we don't go below 1 00083 const int pw2 = std::max(prevdims.w()/2,1); 00084 const int ph2 = std::max(prevdims.h()/2,1); 00085 00086 if (curdims.w() != pw2) return false; 00087 if (curdims.h() != ph2) return false; 00088 } 00089 00090 return true; 00091 } 00092 00093 // ###################################################################### 00094 template <class T> 00095 Image<T> sum(const ImageSet<T>& x) 00096 { 00097 ASSERT(isHomogeneous(x)); 00098 00099 Image<T> result(x[0].getDims(), ZEROS); 00100 00101 for (uint a = 0; a < x.size(); ++a) 00102 { 00103 result += x[a]; 00104 } 00105 00106 return result; 00107 } 00108 00109 // ###################################################################### 00110 template <class T> 00111 Image<T> mean(const ImageSet<T>& x) 00112 { 00113 Image<T> result = sum(x); 00114 result /= x.size(); 00115 return result; 00116 } 00117 00118 // ###################################################################### 00119 template <class T> 00120 Range<T> rangeOf(const ImageSet<T>& x) 00121 { 00122 Range<T> result; 00123 00124 for (uint i = 0; i < x.size(); ++i) 00125 { 00126 result.merge(rangeOf(x[i])); 00127 } 00128 00129 return result; 00130 } 00131 00132 // ###################################################################### 00133 template <class T> 00134 ImageSet<T> takeSlice(const ImageSet<T>* sets, uint nsets, uint level) 00135 { 00136 ImageSet<T> result(nsets); 00137 00138 for (uint i = 0; i < nsets; ++i) 00139 { 00140 result[i] = sets[i][level]; 00141 } 00142 00143 return result; 00144 } 00145 00146 // ###################################################################### 00147 template <class T> 00148 Image<T> makeImageArray(const ImageSet<T>& x, 00149 int Nx, int grid_width, T grid_color, 00150 int destX, int destY) 00151 { 00152 if (Nx < 0) 00153 { 00154 Nx = int(ceil(sqrt(x.size()))); 00155 } 00156 00157 Image<T> result; 00158 00159 // One way or the other, all images must be reshaped to the same size 00160 // for concatArray(). So, if the user didn't request any specific 00161 // shaping (by setting destX or destY to -1), then we specify to 00162 // reshape each image to the size of the largest level. 00163 if (destX <= 0 || destY <= 0) 00164 { 00165 destX = x[0].getWidth(); 00166 destY = x[0].getHeight(); 00167 } 00168 00169 if (isDyadic(x) && destX == x[0].getWidth() && destY == x[0].getHeight()) 00170 { 00171 // With a dyadic pyramid, we get more appropriate upscaling by just 00172 // duplicating pixels. 00173 ImageSet<T> y = x; 00174 for (unsigned int i = 1; i < y.size(); ++i) 00175 y[i] = zoomXY(y[i], 1<<i, 1<<i); 00176 00177 result = concatArray(&y[0], y.size(), Nx); 00178 } 00179 else 00180 { 00181 result = concatArray(&x[0], x.size(), Nx, destX, destY); 00182 } 00183 00184 if (grid_width > 0) 00185 drawGrid(result, destX, destY, grid_width, grid_width, grid_color); 00186 00187 return result; 00188 } 00189 00190 // ###################################################################### 00191 template <class T> 00192 ImageSet<T> reduce(const ImageSet<T>& x, int octaves) 00193 { 00194 ImageSet<T> result(x); 00195 00196 for (int n = 0; n < octaves; ++n) 00197 { 00198 for (uint i = 0; i < x.size(); ++i) 00199 { 00200 result[i] = lowPass3(result[i]); 00201 result[i] = decXY(result[i]); 00202 } 00203 } 00204 00205 return result; 00206 } 00207 00208 // ###################################################################### 00209 template <class T> 00210 ImageSet<T> rescale(const ImageSet<T>& x, const Dims& dims) 00211 { 00212 ImageSet<T> result(x.size()); 00213 00214 for (uint i = 0; i < x.size(); ++i) 00215 { 00216 result[i] = rescale(x[i], dims); 00217 } 00218 00219 return result; 00220 } 00221 00222 // ###################################################################### 00223 ImageSet<float> orientedFilterSet(const Image<float>& lowPassedInput, 00224 float period, 00225 const float* angles, const uint numAngles) 00226 { 00227 ImageSet<float> result(numAngles); 00228 00229 LINFO("oriented laplacian period is %f", period); 00230 00231 const float k = (2.0f * M_PI) / period; 00232 00233 for (uint i = 0; i < numAngles; ++i) 00234 result[i] = orientedFilter(lowPassedInput, k, angles[i]); 00235 00236 return result; 00237 } 00238 00239 // ###################################################################### 00240 void splitPosNeg(const ImageSet<float>& x, ImageSet<float>& pos, ImageSet<float>& neg) 00241 { 00242 pos = ImageSet<float>(x.size()); 00243 neg = ImageSet<float>(x.size()); 00244 for (uint i = 0; i < x.size(); ++i) 00245 splitPosNeg(x[i], pos[i], neg[i]); 00246 } 00247 00248 // ###################################################################### 00249 // ###################################################################### 00250 // ##### ImageSet mathematical operators 00251 // ###################################################################### 00252 // ###################################################################### 00253 00254 // ###################################################################### 00255 template <class T> 00256 ImageSet<T>& operator-=(ImageSet<T>& x, const Image<T>& y) 00257 { 00258 ASSERT(isHomogeneous(x)); 00259 00260 for (uint i = 0; i < x.size(); ++i) 00261 x[i] -= y; 00262 00263 return x; 00264 } 00265 00266 // ###################################################################### 00267 template <class T> 00268 ImageSet<T>& operator+=(ImageSet<T>& x, const Image<T>& y) 00269 { 00270 ASSERT(isHomogeneous(x)); 00271 00272 for (uint i = 0; i < x.size(); ++i) 00273 x[i] += y; 00274 00275 return x; 00276 } 00277 00278 // ###################################################################### 00279 template <class T> 00280 ImageSet<T>& operator*=(ImageSet<T>& x, const Image<T>& y) 00281 { 00282 ASSERT(isHomogeneous(x)); 00283 00284 for (uint i = 0; i < x.size(); ++i) 00285 x[i] *= y; 00286 00287 return x; 00288 } 00289 00290 // ###################################################################### 00291 template <class T> 00292 ImageSet<T>& operator/=(ImageSet<T>& x, const Image<T>& y) 00293 { 00294 ASSERT(isHomogeneous(x)); 00295 00296 for (uint i = 0; i < x.size(); ++i) 00297 x[i] /= y; 00298 00299 return x; 00300 } 00301 00302 // ###################################################################### 00303 template <class T> 00304 ImageSet<T>& operator-=(ImageSet<T>& x, const T& v) 00305 { 00306 for (uint i = 0; i < x.size(); ++i) 00307 x[i] -= v; 00308 00309 return x; 00310 } 00311 00312 // ###################################################################### 00313 template <class T> 00314 ImageSet<T>& operator+=(ImageSet<T>& x, const T& v) 00315 { 00316 for (uint i = 0; i < x.size(); ++i) 00317 x[i] += v; 00318 00319 return x; 00320 } 00321 00322 // ###################################################################### 00323 template <class T> 00324 ImageSet<T>& operator*=(ImageSet<T>& x, const T& v) 00325 { 00326 for (uint i = 0; i < x.size(); ++i) 00327 x[i] *= v; 00328 00329 return x; 00330 } 00331 00332 // ###################################################################### 00333 template <class T> 00334 ImageSet<T>& operator/=(ImageSet<T>& x, const T& v) 00335 { 00336 for (uint i = 0; i < x.size(); ++i) 00337 x[i] /= v; 00338 00339 return x; 00340 } 00341 00342 // ###################################################################### 00343 template <class T> 00344 ImageSet<T> operator-(ImageSet<T>& x, const T& v) 00345 { 00346 ImageSet<T> res = x; 00347 return (res -= v); 00348 } 00349 00350 // ###################################################################### 00351 template <class T> 00352 ImageSet<T> operator+(ImageSet<T>& x, const T& v) 00353 { 00354 ImageSet<T> res = x; 00355 return (res += v); 00356 } 00357 00358 // ###################################################################### 00359 template <class T> 00360 ImageSet<T> operator*(ImageSet<T>& x, const T& v) 00361 { 00362 ImageSet<T> res = x; 00363 return (res *= v); 00364 } 00365 00366 // ###################################################################### 00367 template <class T> 00368 ImageSet<T> operator/(ImageSet<T>& x, const T& v) 00369 { 00370 ImageSet<T> res = x; 00371 return (res /= v); 00372 } 00373 00374 // ###################################################################### 00375 template <class T> 00376 ImageSet<T>& operator-=(ImageSet<T>& x, const ImageSet<T>& y) 00377 { 00378 ASSERT(x.size() == y.size()); 00379 00380 for (uint i = 0; i < x.size(); ++i) 00381 x[i] -= y[i]; 00382 00383 return x; 00384 } 00385 00386 // ###################################################################### 00387 template <class T> 00388 ImageSet<T>& operator+=(ImageSet<T>& x, const ImageSet<T>& y) 00389 { 00390 ASSERT(x.size() == y.size()); 00391 00392 for (uint i = 0; i < x.size(); ++i) 00393 x[i] += y[i]; 00394 00395 return x; 00396 } 00397 00398 // ###################################################################### 00399 template <class T> 00400 ImageSet<T>& operator*=(ImageSet<T>& x, const ImageSet<T>& y) 00401 { 00402 ASSERT(x.size() == y.size()); 00403 00404 for (uint i = 0; i < x.size(); ++i) 00405 x[i] *= y[i]; 00406 00407 return x; 00408 } 00409 00410 // ###################################################################### 00411 template <class T> 00412 ImageSet<T>& operator/=(ImageSet<T>& x, const ImageSet<T>& y) 00413 { 00414 ASSERT(x.size() == y.size()); 00415 00416 for (uint i = 0; i < x.size(); ++i) 00417 x[i] /= y[i]; 00418 00419 return x; 00420 } 00421 00422 // ###################################################################### 00423 template <class T> 00424 ImageSet<T> clampedDiff(const ImageSet<T>& b, const ImageSet<T>& c) 00425 { 00426 ASSERT(b.size() == c.size()); 00427 00428 ImageSet<T> res(b.size()); 00429 for (uint i = 0; i < b.size(); ++i) 00430 res[i] = clampedDiff(b[i],c[i]); 00431 00432 return res; 00433 } 00434 00435 // ###################################################################### 00436 // ###################################################################### 00437 // ##### In-place ImageSet modification functions 00438 // ###################################################################### 00439 // ###################################################################### 00440 00441 // ###################################################################### 00442 template <class T> inline 00443 void doRectify(ImageSet<T>& x) 00444 { 00445 for (uint i = 0; i < x.size(); ++i) 00446 inplaceRectify(x[i]); 00447 } 00448 00449 // ###################################################################### 00450 template <class T> inline 00451 void doLowThresh(ImageSet<T>& x, const T threshold, const T newval) 00452 { 00453 for (uint i = 0; i < x.size(); ++i) 00454 inplaceLowThresh(x[i], threshold, newval); 00455 } 00456 00457 // ###################################################################### 00458 template <class T> inline 00459 void doLowThreshAbs(ImageSet<T>& x, const T threshold, const T newval) 00460 { 00461 for (uint i = 0; i < x.size(); ++i) 00462 inplaceLowThreshAbs(x[i], threshold, newval); 00463 } 00464 00465 // ###################################################################### 00466 template <class T> inline 00467 void doSqrt(ImageSet<T>& x) 00468 { 00469 for (uint i = 0; i < x.size(); ++i) 00470 x[i] = sqrt(x[i]); 00471 } 00472 00473 // ###################################################################### 00474 template <class T> inline 00475 void doSquared(ImageSet<T>& x) 00476 { 00477 for (uint i = 0; i < x.size(); ++i) 00478 x[i] = squared(x[i]); 00479 } 00480 00481 // ###################################################################### 00482 void doMeanNormalize(ImageSet<float>& x) 00483 { 00484 x -= mean(x); 00485 } 00486 00487 // ###################################################################### 00488 void doOneNormalize(ImageSet<float>& x) 00489 { 00490 const Range<float> r = rangeOf(x); 00491 00492 for (uint i = 0; i < x.size(); ++i) 00493 { 00494 x[i] /= r.max(); 00495 } 00496 } 00497 00498 // ###################################################################### 00499 void doEnergyNorm(ImageSet<float>& x) 00500 { 00501 for (uint i = 0; i < x.size(); ++i) 00502 { 00503 x[i] = energyNorm(x[i]); 00504 } 00505 } 00506 00507 // ###################################################################### 00508 void doApplyBiases(ImageSet<float>& x, const float* biases) 00509 { 00510 for (uint i = 0; i < x.size(); ++i) 00511 { 00512 x[i] *= biases[i]; 00513 } 00514 } 00515 00516 // ###################################################################### 00517 void doAddWeighted(ImageSet<float>& x, const ImageSet<float>& y, float multiple) 00518 { 00519 ASSERT(x.size() == y.size()); 00520 for (uint a = 0; a < x.size(); ++a) 00521 x[a] += y[a] * multiple; 00522 } 00523 00524 // ###################################################################### 00525 void doClear(ImageSet<float>& x, float v) 00526 { 00527 for (uint a = 0; a < x.size(); ++a) 00528 { 00529 x[a].clear(v); 00530 } 00531 } 00532 00533 00534 // Include the explicit instantiations 00535 #include "inst/Image/ImageSetOps.I" 00536 00537 template bool isDyadic(const ImageSet<int>& pyr); 00538 template ImageSet<double>& operator/=(ImageSet<double>& x, const double& v); 00539 00540 // ###################################################################### 00541 /* So things look consistent in everyone's emacs... */ 00542 /* Local Variables: */ 00543 /* indent-tabs-mode: nil */ 00544 /* End: */