00001 /*!@file Image/fancynorm.C Intrafeature competition with maxNormalize(). */ 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/fancynorm.C $ 00035 // $Id: fancynorm.C 9993 2008-07-29 00:04:18Z lior $ 00036 // 00037 00038 #include "Image/fancynorm.H" 00039 00040 #include "Util/Assert.H" 00041 #include "Image/Image.H" 00042 #include "Image/ImageSet.H" 00043 #include "Image/FilterOps.H" 00044 #include "Image/Kernels.H" 00045 #include "Image/MathOps.H" 00046 #include "Image/ShapeOps.H" 00047 #include "Image/Transforms.H" 00048 #include "Image/PyramidOps.H" 00049 #include "Util/StringConversions.H" 00050 #include "Util/log.H" 00051 #include "rutz/compat_cmath.h" 00052 #include "rutz/trace.h" 00053 00054 #include <algorithm> 00055 #include <cmath> 00056 00057 // uncomment this define to get some info on how maxNormalize works with your 00058 // images. Intended for debugging purposes. 00059 //#define SHOW_MAXNORM_INFO 00060 00061 // ###################################################################### 00062 template <class T> 00063 Image<T> maxNormalize(const Image<T>& src, 00064 const T mi, const T ma, const MaxNormType normtyp, 00065 int nbiter, const Image<float> *lrexcit) 00066 { 00067 GVX_TRACE(__PRETTY_FUNCTION__); 00068 #ifdef SHOW_MAXNORM_INFO 00069 T mm, mmm; getMinMax(src, mm, mmm); 00070 LDEBUG("mini = %f, maxi= %f", float(mm), float(mmm)); 00071 #endif 00072 00073 Image<T> result; 00074 00075 // do normalization depending on desired type: 00076 switch(normtyp) 00077 { 00078 case VCXNORM_NONE: 00079 result = maxNormalizeNone(src, mi, ma); 00080 break; 00081 case VCXNORM_MAXNORM: 00082 result = maxNormalizeStd(src, mi, ma); 00083 break; 00084 case VCXNORM_FANCYFAST: 00085 result = maxNormalizeFancyFast(src, mi, ma, nbiter); 00086 break; 00087 case VCXNORM_FANCYONE: 00088 nbiter = 1; 00089 case VCXNORM_FANCY: 00090 result = maxNormalizeFancy(src, mi, ma, nbiter, 1.0, lrexcit); 00091 break; 00092 case VCXNORM_FANCYLANDMARK: 00093 result = maxNormalizeFancyLandmark(src, mi, ma, nbiter); 00094 break; 00095 case VCXNORM_LANDMARK: 00096 result = maxNormalizeLandmark(src, mi, ma); 00097 break; 00098 case VCXNORM_FANCYWEAK: 00099 result = maxNormalizeFancy(src, mi, ma, nbiter, 0.5); 00100 break; 00101 case VCXNORM_FANCYVWEAK: 00102 result = maxNormalizeFancy(src, mi, ma, nbiter, 0.1); 00103 break; 00104 case VCXNORM_IGNORE: 00105 result = src; 00106 break; 00107 case VCXNORM_SURPRISE: 00108 result = src; 00109 break; 00110 case VCXNORM_STDEV: 00111 result = maxNormalizeStdev(src); 00112 break; 00113 case VCXNORM_STDEV0: 00114 result = maxNormalizeStdev0(src); 00115 break; 00116 default: 00117 LFATAL("Unknown normalization type: %d", int(normtyp)); 00118 } 00119 00120 #ifdef SHOW_MAXNORM_INFO 00121 getMinMax(result, mm, mmm); 00122 LDEBUG("newmin = %f, newmax = %f", float(mm), float(mmm)); 00123 #endif 00124 00125 return result; 00126 } 00127 00128 // ###################################################################### 00129 template <class T> 00130 Image<T> maxNormalizeNone(const Image<T>& src, const T mi, const T ma) 00131 { 00132 GVX_TRACE(__PRETTY_FUNCTION__); 00133 Image<T> result = src; 00134 00135 // first clamp negative values to zero 00136 inplaceRectify(result); 00137 00138 // then, normalize between mi and ma if not zero 00139 if (mi != T() || ma != T()) inplaceNormalize(result, mi, ma); 00140 00141 return result; 00142 } 00143 00144 // ###################################################################### 00145 // ##### maxNorm from Itti et al, IEEE-PAMI, 1998: 00146 template <class T> 00147 Image<T> maxNormalizeStd(const Image<T>& src, const T mi, const T ma) 00148 { 00149 GVX_TRACE(__PRETTY_FUNCTION__); 00150 ASSERT(src.initialized()); 00151 T zero = T(); 00152 00153 Image<T> result = src; 00154 00155 // first clamp negative values to zero 00156 inplaceRectify(result); 00157 00158 // then, normalize between mi and ma if not zero 00159 if (mi != zero || ma != zero) inplaceNormalize(result, mi, ma); 00160 00161 const int w = result.getWidth(); 00162 const int h = result.getHeight(); 00163 00164 // normalize between mi and ma and multiply by (max - mean)^2 00165 00166 // we want to detect quickly local maxes, but avoid getting local mins 00167 T thresh = T(mi + (ma - mi) / 10.0); 00168 00169 // then get the mean value of the local maxima: 00170 double lm_sum = 0.0; 00171 int lm_nb = 0; 00172 for (int j = 1; j < h - 1; j ++) 00173 for (int i = 1; i < w - 1; i ++) 00174 { 00175 int index = i + w * j; 00176 T val = result.getVal(index); 00177 if (val >= thresh && 00178 val >= result.getVal(index - w) && 00179 val >= result.getVal(index + w) && 00180 val >= result.getVal(index - 1) && 00181 val >= result.getVal(index + 1)) // local max 00182 { 00183 lm_sum += double(val); 00184 lm_nb ++; 00185 } 00186 } 00187 // scale factor is (max - mean_local_max)^2: 00188 if (lm_nb > 1) 00189 { 00190 double factor = ma - (T)(lm_sum / double(lm_nb)); 00191 result *= T(factor * factor); 00192 } 00193 else if (lm_nb == 1) // a single narrow peak 00194 result *= (ma * ma); 00195 else 00196 { 00197 /* LERROR("No local maxes found !!"); */ 00198 } 00199 00200 return result; 00201 } 00202 00203 // ###################################################################### 00204 // ##### fancyNorm from Itti et al, JEI, 2001 -- FAST implementation: 00205 template <class T> 00206 Image<T> maxNormalizeFancyFast(const Image<T>& src, const T mi, const T ma, 00207 const int nbiter) 00208 { 00209 GVX_TRACE(__PRETTY_FUNCTION__); 00210 ASSERT(src.initialized()); 00211 T zero = T(); 00212 00213 Image<T> result = src; 00214 00215 // first clamp negative values to zero 00216 inplaceRectify(result); 00217 00218 // then, normalize between mi and ma if not zero 00219 if (mi != zero || ma != zero) inplaceNormalize(result, mi, ma); 00220 00221 const int w = result.getWidth(); 00222 const int h = result.getHeight(); 00223 00224 int wh = std::max(w, h); 00225 // we want an inhibitory 1D sigma of at least FANCYISIG % of wh 00226 // we know that 1D sigma of the lowpass9 filter is 1.5 pixel 00227 // each level down a pyramid, 1D sigma increases by sqrt(5) 00228 int ilev = 1+(int)(log(float(wh) / 1.5 * FANCYISIG / 100.0) / 00229 log(sqrt(5))); 00230 00231 // This is needed for log() <= -2*log(sqrt(5)), i.e. wh <= 1.2 = 6 / 5 00232 if (ilev < 0) ilev = 0; 00233 00234 int elev = (int)(log(float(wh) / 1.5 * FANCYESIG / 100.0) / 00235 log(sqrt(5))); 00236 00237 // This is needed for log() <= -log(sqrt(5)), i.e. wh <= 33.5 = 75 / sqrt(5) 00238 if (elev < 0) elev = 0; 00239 00240 for (int i = 0; i < nbiter; ++i) 00241 { 00242 ImageSet<T> inhibPyr = buildPyrGaussian(result, 0, ilev+1, 9); 00243 Image<T> excit = inhibPyr[elev]; // excitatory center 00244 Image<T> inhib = inhibPyr[ilev]; // inhibitory surround 00245 excit *= T(FANCYCOEX); inhib *= T(FANCYCOIN); 00246 excit = rescale(excit, w, h); 00247 inplaceAttenuateBorders(excit, wh/16); 00248 inhib = rescale(inhib, w, h); 00249 excit -= inhib; 00250 00251 T globinhi, minim, maxim; getMinMax(result, minim, maxim); 00252 globinhi = (T)(0.01 * FANCYINHI * maxim); 00253 00254 result += excit; // we get broad inhibition from everywhere 00255 result += -globinhi; // we get fixed global inhibition 00256 inplaceRectify(result); 00257 } 00258 00259 return result; 00260 } 00261 00262 // ###################################################################### 00263 // ##### fancyNorm from Itti et al, JEI, 2001 -- FULL implementation: 00264 template <class T> 00265 Image<T> maxNormalizeFancy(const Image<T>& src, const T mi, const T ma, 00266 const int nbiter, const double weakness, 00267 const Image<float>* lrexcit) 00268 { 00269 GVX_TRACE(__PRETTY_FUNCTION__); 00270 // Normalize using fancy normalization: multiple iterations of 00271 // filtering by a DoG 00272 00273 ASSERT(src.initialized()); 00274 T zero = T(); 00275 00276 Image<T> result = src; 00277 00278 // first clamp negative values to zero 00279 inplaceRectify(result); 00280 00281 // then, normalize between mi and ma if not zero 00282 if (mi != zero || ma != zero) inplaceNormalize(result, mi, ma); 00283 00284 const int w = result.getWidth(); 00285 const int h = result.getHeight(); 00286 00287 int siz = std::max(w, h); 00288 int maxhw = std::max(0, std::min(w, h) / 2 - 1); 00289 // build separable Gaussians for DoG computation: 00290 float esig = (float(siz) * FANCYESIG) * 0.01F; 00291 float isig = (float(siz) * FANCYISIG) * 0.01F; 00292 Image<float> gExc = 00293 gaussian<float>(FANCYCOEX/(esig*sqrt(2.0*M_PI)) * weakness, esig, maxhw); 00294 Image<float> gInh = 00295 gaussian<float>(FANCYCOIN/(isig*sqrt(2.0*M_PI)) * weakness, isig, maxhw); 00296 00297 for (int i = 0; i < nbiter; ++i) 00298 { 00299 if (lrexcit) // tuned long-range excitation 00300 { 00301 Image<T> tmp(result); 00302 tmp = downSize(tmp, w / (1<<LRLEVEL), h / (1<<LRLEVEL)); 00303 tmp = convolve(tmp, *lrexcit, CONV_BOUNDARY_ZERO); // full influence 00304 tmp += T(1.0); // will be used as multiplicative excitation 00305 inplaceClamp(tmp, T(1.0), T(1.25)); // avoid crazyness 00306 tmp = rescale(tmp, w, h); 00307 T tmi, tma; getMinMax(tmp, tmi,tma); 00308 LDEBUG("lrexcit(%d): [%f..%f]", i, double(tmi), double(tma)); 00309 result *= tmp; 00310 } 00311 00312 Image<T> excit = sepFilter(result, gExc, gExc, CONV_BOUNDARY_CLEAN); // excitatory part 00313 Image<T> inhib = sepFilter(result, gInh, gInh, CONV_BOUNDARY_CLEAN); // inhibitory part 00314 excit -= inhib; 00315 T minim, maxim; getMinMax(result, minim, maxim); 00316 T globinhi = (T)(0.01 * FANCYINHI * maxim); 00317 00318 result += excit; // we get broad inhibition from everywhere 00319 result += -globinhi; // we get fixed global inhibition 00320 inplaceRectify(result); 00321 // sigmoid(FANCYG, FANCYH, FANCYS); 00322 } 00323 00324 return result; 00325 } 00326 00327 // ###################################################################### 00328 // ##### fancyNorm from Itti et al, JEI, 2001 -- FULL implementation: 00329 // adapted to find landmarks 00330 template <class T> 00331 Image<T> maxNormalizeFancyLandmark(const Image<T>& src, const T mi, const T ma, 00332 const int nbiter) 00333 { 00334 GVX_TRACE(__PRETTY_FUNCTION__); 00335 // Normalize using fancy normalization: multiple iterations of 00336 // filtering by a DoG 00337 00338 ASSERT(src.initialized()); 00339 T zero = T(); 00340 00341 Image<T> result = src; 00342 00343 // first clamp negative values to zero 00344 inplaceRectify(result); 00345 00346 // then, normalize between mi and ma if not zero 00347 if (mi != zero || ma != zero) inplaceNormalize(result, mi, ma); 00348 00349 const int w = result.getWidth(); 00350 const int h = result.getHeight(); 00351 00352 int siz = std::max(w, h); 00353 int maxhw = std::max(0, std::min(w, h) / 2 - 1); 00354 // build separable Gaussians for DoG computation: 00355 float esig = (float(siz)*2)*0.01; 00356 float isig = (float(siz)*3)*0.01; 00357 Image<float> gExc = gaussian<float>(FANCYCOEX/(esig*sqrt(2.0*M_PI)), 00358 esig, maxhw); 00359 Image<float> gInh = gaussian<float>(FANCYCOIN/(isig*sqrt(2.0*M_PI)), 00360 isig, maxhw); 00361 00362 for (int i = 0; i < nbiter; ++i) 00363 { 00364 Image<T> excit = sepFilter(result, gExc, gExc, CONV_BOUNDARY_CLEAN); // excitatory part 00365 Image<T> inhib = sepFilter(result, gInh, gInh, CONV_BOUNDARY_CLEAN); // inhibitory part 00366 excit -= inhib; 00367 T minim, maxim; getMinMax(result, minim, maxim); 00368 T globinhi = (T)(0.01 * FANCYINHI * maxim); 00369 00370 result += excit; // we get broad inhibition from everywhere 00371 result += -globinhi; // we get fixed global inhibition 00372 inplaceRectify(result); 00373 // sigmoid(FANCYG, FANCYH, FANCYS); 00374 } 00375 00376 return result; 00377 } 00378 00379 // ###################################################################### 00380 00381 template <class T> 00382 Image<T> maxNormalizeLandmark(const Image<T>& src, const T mi, const T ma) 00383 { 00384 GVX_TRACE(__PRETTY_FUNCTION__); 00385 ASSERT(src.initialized()); 00386 Image<T> result = src; 00387 inplaceNormalize(result, (T)MAXNORMMIN, (T)MAXNORMLANDMARK); 00388 00389 // AIM: to find goodness of map 00390 // compare maps b4 and after maxnormalization fancy 00391 // comp_next = # components after maxnormalisation of map 00392 // area_prev = area of component b4 maxnorm 00393 // area_next = " " after " 00394 // activity_prev = activity of component b4 maxnorm 00395 00396 Image<byte> target; 00397 Image<T> comp_map; 00398 T max, thresh; 00399 float area_prev = 0.0f; 00400 int comp_next = 0; 00401 double activity_prev = 0.0, real_activity = 0.0, standout = 0.0; 00402 double sum_prev = 0.0, sum_next = 0.0; 00403 float goodness_map = 0.0f; // is this a good map for landmarks? 00404 float landmarkness = 0.0f; // is this a good landmark? 00405 00406 thresh = (T) MAXNORMMIN; 00407 Point2D<int> max_locn; 00408 findMax(result, max_locn, max); 00409 00410 // find values b4 maxnorm 00411 while(max > thresh) 00412 { 00413 area_prev = 0.0f; 00414 activity_prev = 0.0; 00415 int val = segmentLandmark(result, max_locn, target, activity_prev, 00416 standout, area_prev); 00417 00418 if (val != -1) 00419 { 00420 result = result - result * (Image<T>)target; 00421 real_activity = (double)src.getVal(max_locn); 00422 findMax(result, max_locn, max); 00423 00424 if(area_prev > 0.125) 00425 { 00426 sum_prev += (double)area_prev * activity_prev; 00427 00428 // find peaks within this component 00429 int peaks = findPeaks((Image<T>)target,(T) MAXNORMMIN, 00430 (T) MAXNORMLANDMARK, 00431 sum_next); 00432 if(peaks == 0) 00433 { 00434 peaks = 10; // very irregular, hence cancelled 00435 } 00436 00437 // compute landmarkness value 00438 LINFO("area_prev = %f, peaks = %d", 00439 area_prev, peaks); 00440 LINFO("real_activity = %f, activity_prev = %f, standout = %f", 00441 real_activity, activity_prev, standout); 00442 landmarkness = (float) (real_activity * standout); 00443 //landmarkness = (float)real_activity / 00444 // (area_prev * peaks * peaks); 00445 //landmarkness *= 10.0f; 00446 LINFO("-----landmarkness = %f", landmarkness); 00447 00448 if (!comp_map.initialized()) 00449 comp_map = (Image<T>)target / 255.0f * (T)landmarkness ; 00450 else comp_map += (Image<T>)target / 255.0f * (T)landmarkness; 00451 } 00452 } 00453 else break; 00454 } 00455 00456 // find peaks in this image 00457 result = src; 00458 comp_next = findPeaks(result,(T) MAXNORMMIN, (T) MAXNORMLANDMARK, 00459 sum_next); 00460 00461 // compute goodness 00462 if(comp_next == 0) 00463 { 00464 comp_next = 10; // very irregular, hence cancelled 00465 } 00466 if (sum_prev != 0.0) 00467 goodness_map = (float)(sum_next / (sum_prev * comp_next * comp_next)) ; 00468 00469 goodness_map = pow(goodness_map, 0.5); 00470 LINFO("# of comps = %d", comp_next); 00471 00472 LINFO("goodness_map = %f", goodness_map); 00473 00474 // all components found 00475 if (comp_map.initialized()) 00476 comp_map *= (T)(goodness_map); 00477 00478 else comp_map.resize(src.getDims(), true); 00479 return comp_map; 00480 } 00481 00482 // ###################################################################### 00483 template <class T> 00484 int findPeaks(const Image<T>& src, const T mi, const T ma, 00485 double& sum_activity) 00486 { 00487 GVX_TRACE(__PRETTY_FUNCTION__); 00488 Image<T> result = src; 00489 result = maxNormalize(result, mi, ma, VCXNORM_FANCY); 00490 T max, thresh; Point2D<int> max_locn; double standout = 0.0; 00491 int peaks = 0; 00492 thresh = (T)((ma - mi)/10 + mi); 00493 sum_activity = 0.0; 00494 00495 findMax(result, max_locn, max); 00496 while(max > thresh) 00497 { 00498 float area = 0.0f; double activity = 0.0; Image<byte> target; 00499 int val = segmentLandmark(result, max_locn, target, 00500 activity, standout, area); 00501 if(val != -1) 00502 { 00503 if(area > 0.0675) 00504 { 00505 peaks++; 00506 sum_activity += (double)area * activity; 00507 } 00508 result = result - result * (Image<T>)target; 00509 findMax(result, max_locn, max); 00510 } 00511 else break; 00512 } 00513 return peaks; 00514 } 00515 00516 //****************************************************************** 00517 template <class T> 00518 float goodness_map(const Image<T>& src) 00519 { 00520 GVX_TRACE(__PRETTY_FUNCTION__); 00521 ASSERT(src.initialized()); 00522 00523 Image<T> result = src; 00524 inplaceNormalize(result, (T)MAXNORMMIN, (T)MAXNORMLANDMARK); 00525 00526 // AIM: to find goodness of map 00527 // compare maps b4 and after maxnormalization fancy 00528 // comp_next = # components after maxnormalisation of map 00529 // area_prev = area of component b4 maxnorm 00530 // area_next = " " after " 00531 // activity_prev = activity of component b4 maxnorm 00532 00533 Image<byte> target; 00534 Image<T> comp_map; 00535 T max, thresh; 00536 float area_prev = 0.0f; 00537 int comp_next = 0; 00538 double standout = 0.0, activity_prev = 0.0; 00539 double sum_prev = 0.0, sum_next = 0.0; 00540 float goodness_map = 0.0f; // is this a good map for landmarks? 00541 00542 00543 thresh = (T) MAXNORMMIN; 00544 Point2D<int> max_locn; 00545 findMax(result, max_locn, max); 00546 00547 // find values b4 maxnorm 00548 while(max > thresh) 00549 { 00550 area_prev = 0.0f; 00551 activity_prev = 0.0, standout = 0.0 ; 00552 int val = segmentLandmark(result, max_locn, target, activity_prev, 00553 standout, area_prev); 00554 00555 if (val != -1) 00556 { 00557 result = result - result * (Image<T>)target; 00558 findMax(result, max_locn, max); 00559 00560 if(area_prev > 0.125) 00561 { 00562 sum_prev += (double)area_prev * activity_prev; 00563 } 00564 } 00565 else break; 00566 } 00567 result = src; 00568 comp_next = findPeaks(result,(T) MAXNORMMIN, (T) MAXNORMLANDMARK, 00569 sum_next); 00570 00571 // compute goodness 00572 if(comp_next == 0) 00573 { 00574 comp_next = 10; // very irregular, hence cancelled 00575 } 00576 if (sum_prev != 0.0) 00577 goodness_map = (float)(sum_next / (sum_prev * comp_next * comp_next)) ; 00578 LINFO("# of comps = %d", comp_next); 00579 LINFO("goodness_map = %f", goodness_map); 00580 00581 return goodness_map; 00582 } 00583 00584 // ###################################################################### 00585 template <class T> 00586 Image<T> maxNormalizeStdev(const Image<T>& src) 00587 { 00588 // renormalize the image to have stdev=1 and minval=0 00589 00590 const float s = float(stdev(src)); 00591 00592 if (s == 0.0f) 00593 return Image<T>(src.getDims(), ZEROS); 00594 00595 typedef typename promote_trait<T, float>::TP TF; 00596 00597 Image<TF> result(src); 00598 result /= s; 00599 00600 TF mini, maxi; getMinMax(result, mini, maxi); 00601 result -= mini; 00602 00603 return Image<T>(result); 00604 } 00605 00606 // ###################################################################### 00607 template <class T> 00608 Image<T> maxNormalizeStdev0(const Image<T>& src) 00609 { 00610 // renormalize the image to have mean=0 and stdev=1 00611 00612 const float s = float(stdev(src)); 00613 const float u = float(mean(src)); 00614 00615 if (s == 0.0f) 00616 return Image<T>(src.getDims(), ZEROS); 00617 00618 typedef typename promote_trait<T, float>::TP TF; 00619 00620 Image<TF> result(src); 00621 result -= u; // mean -> 0 00622 result /= s; // stdev -> 1 00623 00624 return Image<T>(result); 00625 } 00626 00627 00628 // ###################################################################### 00629 // converters for MaxNormType 00630 // ###################################################################### 00631 00632 std::string convertToString(const MaxNormType val) 00633 { 00634 GVX_TRACE(__PRETTY_FUNCTION__); 00635 return maxNormTypeName(val); 00636 } 00637 00638 void convertFromString(const std::string& str, MaxNormType& val) 00639 { 00640 GVX_TRACE(__PRETTY_FUNCTION__); 00641 // CAUTION: assumes types are numbered and ordered! 00642 for (int i = 0; i < NBMAXNORMTYPES; i ++) 00643 if (str.compare(maxNormTypeName(MaxNormType(i))) == 0) 00644 { val = MaxNormType(i); return; } 00645 00646 conversion_error::raise<MaxNormType>(str); 00647 } 00648 00649 00650 00651 // ###################################################################### 00652 #include "inst/Image/fancynorm.I" 00653 00654 // ###################################################################### 00655 /* So things look consistent in everyone's emacs... */ 00656 /* Local Variables: */ 00657 /* indent-tabs-mode: nil */ 00658 /* End: */