00001 /*!@file Image/ResizeSpec.C Represents multiple ways of transforming image dimensions */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the 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: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/ResizeSpec.C $ 00035 // $Id: ResizeSpec.C 8828 2007-10-12 21:20:18Z rjpeters $ 00036 // 00037 00038 #ifndef IMAGE_RESIZESPEC_C_DEFINED 00039 #define IMAGE_RESIZESPEC_C_DEFINED 00040 00041 #include "Image/ResizeSpec.H" 00042 00043 #include "Util/Assert.H" 00044 #include "Util/StringConversions.H" 00045 #include "Util/StringUtil.H" 00046 #include "Util/log.H" 00047 #include "Util/sformat.H" 00048 00049 #include <iterator> 00050 #include <vector> 00051 00052 // ###################################################################### 00053 bool ResizeSpec::operator==(const ResizeSpec& that) const 00054 { 00055 if (this->itsMethod != that.itsMethod) 00056 return false; 00057 00058 // OK, now what if the methods are the same: 00059 00060 switch (this->itsMethod) 00061 { 00062 case NOOP: 00063 return true; 00064 break; 00065 00066 case FIXED: 00067 return this->itsNewDims == that.itsNewDims; 00068 break; 00069 00070 case SCALE_UP: // fall-through 00071 case SCALE_DOWN: 00072 return (this->itsFactorW == that.itsFactorW 00073 && this->itsFactorH == that.itsFactorH); 00074 break; 00075 } 00076 00077 ASSERT(0); /* can't happen */ return false; 00078 } 00079 00080 // ###################################################################### 00081 std::string ResizeSpec::toString() const 00082 { 00083 switch (itsMethod) 00084 { 00085 case NOOP: return "noop"; break; 00086 00087 case FIXED: return convertToString(itsNewDims); break; 00088 00089 case SCALE_UP: 00090 if (itsFactorW == itsFactorH) 00091 return sformat("*%g", itsFactorW); 00092 else 00093 return sformat("*%gx%g", itsFactorW, itsFactorH); 00094 break; 00095 00096 case SCALE_DOWN: 00097 if (itsFactorW == itsFactorH) 00098 return sformat("/%g", itsFactorW); 00099 else 00100 return sformat("/%gx%g", itsFactorW, itsFactorH); 00101 break; 00102 } 00103 00104 ASSERT(0); /* can't happen */ return std::string(); 00105 } 00106 00107 // ###################################################################### 00108 ResizeSpec ResizeSpec::fromString(const std::string& origstr) 00109 { 00110 const std::string str = toLowerCase(origstr); 00111 00112 if (str.length() == 0 00113 || str.compare("none") == 0 00114 || str.compare("noop") == 0) 00115 { 00116 return ResizeSpec(); // no-op ResizeSpec 00117 } 00118 else if (str[0] == '*' || str[0] == '/') 00119 { 00120 const Method m = (str[0] == '*' ? SCALE_UP : SCALE_DOWN); 00121 00122 std::vector<std::string> parts; 00123 split(str.substr(1), "x", std::back_inserter(parts)); 00124 00125 if (parts.size() == 1) 00126 { 00127 const double f = fromStr<double>(parts[0]); 00128 if (f < 0.0) 00129 LFATAL("while parsing '%s' as a ResizeSpec: expected " 00130 "a non-negative scale factor, but got %s", 00131 origstr.c_str(), parts[0].c_str()); 00132 00133 if (f == 0.0 || f == 1.0) 00134 return ResizeSpec(); // no-op ResizeSpec 00135 00136 return ResizeSpec(m, Dims(), f, f); 00137 } 00138 else if (parts.size() == 2) 00139 { 00140 const double fw = fromStr<double>(parts[0]); 00141 const double fh = fromStr<double>(parts[1]); 00142 00143 if (fw < 0.0) 00144 LFATAL("while parsing '%s' as a ResizeSpec: expected " 00145 "a non-negative scale factor, but got %s", 00146 origstr.c_str(), parts[0].c_str()); 00147 00148 if (fh < 0.0) 00149 LFATAL("while parsing '%s' as a ResizeSpec: expected " 00150 "a non-negative scale factor, but got %s", 00151 origstr.c_str(), parts[1].c_str()); 00152 00153 if ((fw == 0.0 || fw == 1.0) && (fh == 0.0 || fh == 1.0)) 00154 return ResizeSpec(); // no-op ResizeSpec 00155 00156 return ResizeSpec(m, Dims(), fw, fh); 00157 } 00158 else 00159 LFATAL("while parsing '%s' as a ResizeSpec: after '%c', " 00160 "expected either one floating-point value or " 00161 "two values separated by 'x', but got '%s'", 00162 origstr.c_str(), str[0], str.substr(1).c_str()); 00163 } 00164 else 00165 { 00166 const Dims d = fromStr<Dims>(str); 00167 if (d.isEmpty()) 00168 return ResizeSpec(); // no-op ResizeSpec 00169 return ResizeSpec(FIXED, d, 0.0, 0.0); 00170 } 00171 00172 conversion_error::raise<ResizeSpec>(origstr); 00173 ASSERT(0); /* can't happen */ return ResizeSpec(); 00174 } 00175 00176 // ###################################################################### 00177 Dims ResizeSpec::transformDims(const Dims& in) 00178 { 00179 switch (itsMethod) 00180 { 00181 case NOOP: 00182 return in; 00183 break; 00184 00185 case FIXED: 00186 return itsNewDims; 00187 break; 00188 00189 case SCALE_UP: 00190 // if a scale factor is 0, then that dimension just passes 00191 // through untouched 00192 return Dims(itsFactorW > 0.0 00193 ? int(0.5 + in.w() * itsFactorW) 00194 : in.w(), 00195 itsFactorH > 0.0 00196 ? int(0.5 + in.h() * itsFactorH) 00197 : in.h()); 00198 break; 00199 00200 case SCALE_DOWN: 00201 // if a scale factor is 0, then that dimension just passes 00202 // through untouched 00203 return Dims(itsFactorW > 0.0 00204 ? int(0.5 + in.w() / itsFactorW) 00205 : in.w(), 00206 itsFactorH > 0.0 00207 ? int(0.5 + in.h() / itsFactorH) 00208 : in.h()); 00209 break; 00210 } 00211 00212 // we should never get here, because even if the user gave bogus 00213 // input, we should have caught that in convertFromString() or 00214 // wherever, so that once we have a ResizeSpec object, it should be 00215 // guaranteed to have a valid itsMethod value: 00216 ASSERT(0); /* can't happen */ return Dims(); 00217 } 00218 00219 // ###################################################################### 00220 /* So things look consistent in everyone's emacs... */ 00221 /* Local Variables: */ 00222 /* mode: c++ */ 00223 /* indent-tabs-mode: nil */ 00224 /* End: */ 00225 00226 #endif // IMAGE_RESIZESPEC_C_DEFINED