00001 /*!@file Psycho/ClassicSearchItem.C */ 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/Psycho/ClassicSearchItem.C $ 00035 // $Id: ClassicSearchItem.C 9079 2007-12-12 00:54:09Z rjpeters $ 00036 // 00037 00038 #ifndef PSYCHO_CLASSICSEARCHITEM_C_DEFINED 00039 #define PSYCHO_CLASSICSEARCHITEM_C_DEFINED 00040 00041 #include "Psycho/ClassicSearchItem.H" 00042 00043 #include "Image/Image.H" 00044 #include "Image/ShapeOps.H" 00045 00046 #include <cmath> 00047 00048 namespace 00049 { 00050 Image<double> makeC(int sz, const double angle) 00051 { 00052 Image<double> result(sz, sz, NO_INIT); 00053 00054 Image<double>::iterator ptr = result.beginw(); 00055 00056 const double ro2 = (0.25 * sz) * (0.25 * sz); 00057 const double ri2 = (0.2 * sz) * (0.2 * sz); 00058 const double xc = 0.5 * sz - 0.5; 00059 const double yc = 0.5 * sz - 0.5; 00060 00061 for (int y = 0; y < sz; ++y) 00062 { 00063 const double y2 = (y-yc)*(y-yc); 00064 00065 for (int x = 0; x < sz; ++x) 00066 { 00067 const double r2 = (x-xc)*(x-xc) + y2; 00068 00069 const double theta = atan2(yc-y, x-xc); 00070 00071 const double diff = geom::rad_npi_pi(geom::rad_npi_pi(angle) - theta); 00072 00073 if (fabs(diff) > M_PI/8.0 && 00074 r2 > ri2 && r2 <= ro2) 00075 *ptr++ = -1.0; 00076 else 00077 *ptr++ = 0.0; 00078 } 00079 } 00080 00081 return result; 00082 } 00083 00084 Image<double> makeO(int sz) 00085 { 00086 Image<double> result(sz, sz, NO_INIT); 00087 00088 Image<double>::iterator ptr = result.beginw(); 00089 00090 const double ro2 = (0.25 * sz) * (0.25 * sz); 00091 const double ri2 = (0.2 * sz) * (0.2 * sz); 00092 const double xc = 0.5 * sz - 0.5; 00093 const double yc = 0.5 * sz - 0.5; 00094 00095 for (int y = 0; y < sz; ++y) 00096 { 00097 const double y2 = (y-yc)*(y-yc); 00098 00099 for (int x = 0; x < sz; ++x) 00100 { 00101 const double r2 = (x-xc)*(x-xc) + y2; 00102 00103 if (r2 > ri2 && r2 <= ro2) 00104 *ptr++ = -1.0; 00105 else 00106 *ptr++ = 0.0; 00107 } 00108 } 00109 00110 return result; 00111 } 00112 00113 Image<double> makeQ(int sz, const double angle) 00114 { 00115 Image<double> result(sz, sz, NO_INIT); 00116 00117 Image<double>::iterator ptr = result.beginw(); 00118 00119 const double cosa = cos(-angle); 00120 const double sina = sin(-angle); 00121 const double ro2 = (0.25 * sz) * (0.25 * sz); 00122 const double ri2 = (0.2 * sz) * (0.2 * sz); 00123 const double xc = 0.5 * sz - 0.5; 00124 const double yc = 0.5 * sz - 0.5; 00125 00126 const double dh = 0.025 * sz; 00127 00128 for (int y = 0; y < sz; ++y) 00129 { 00130 const double y2 = (y-yc)*(y-yc); 00131 00132 for (int x = 0; x < sz; ++x) 00133 { 00134 const double r2 = (x-xc)*(x-xc) + y2; 00135 00136 const double u = (x-xc) * cosa - (yc-y) * sina; 00137 const double v = (x-xc) * sina + (yc-y) * cosa; 00138 00139 if ((r2 > ri2 && r2 <= ro2) 00140 || 00141 (fabs(v) <= dh && fabs(u-0.225*sz) < 0.1*sz)) 00142 *ptr++ = -1.0; 00143 else 00144 *ptr++ = 0.0; 00145 } 00146 } 00147 00148 return result; 00149 } 00150 00151 Image<double> makePlus(int sz, const double angle) 00152 { 00153 Image<double> result(sz, sz, NO_INIT); 00154 00155 Image<double>::iterator ptr = result.beginw(); 00156 00157 const double cosa = cos(-angle); 00158 const double sina = sin(-angle); 00159 const double xc = 0.5 * sz - 0.5; 00160 const double yc = 0.5 * sz - 0.5; 00161 00162 const double dh = 0.025 * sz; 00163 const double dw = 0.25 * sz; 00164 00165 for (int y = 0; y < sz; ++y) 00166 for (int x = 0; x < sz; ++x) 00167 { 00168 const double u = (x-xc) * cosa - (yc-y) * sina; 00169 const double v = (x-xc) * sina + (yc-y) * cosa; 00170 00171 if ((fabs(u) <= dw && fabs(v) <= dh) 00172 || 00173 (fabs(v) <= dw && fabs(u) <= dh)) 00174 *ptr++ = -1.0; 00175 else 00176 *ptr++ = 0.0; 00177 } 00178 00179 return result; 00180 } 00181 00182 Image<double> makeL(int sz, const double angle) 00183 { 00184 Image<double> result(sz, sz, NO_INIT); 00185 00186 Image<double>::iterator ptr = result.beginw(); 00187 00188 const double cosa = cos(-angle); 00189 const double sina = sin(-angle); 00190 const double xc = 0.5 * sz - 0.5; 00191 const double yc = 0.5 * sz - 0.5; 00192 00193 const double dh = 0.025 * sz; 00194 const double dw = 0.25 * sz; 00195 00196 for (int y = 0; y < sz; ++y) 00197 for (int x = 0; x < sz; ++x) 00198 { 00199 const double u = (x-xc) * cosa - (yc-y) * sina; 00200 const double v = (x-xc) * sina + (yc-y) * cosa; 00201 00202 if ((fabs(u+0.225*sz) <= dh && fabs(v) <= dw) 00203 || 00204 (fabs(v+0.225*sz) <= dh && fabs(u) <= dw)) 00205 *ptr++ = -1.0; 00206 else 00207 *ptr++ = 0.0; 00208 } 00209 00210 return result; 00211 } 00212 00213 Image<double> makeT(int sz, const double angle) 00214 { 00215 Image<double> result(sz, sz, NO_INIT); 00216 00217 Image<double>::iterator ptr = result.beginw(); 00218 00219 const double cosa = cos(-angle); 00220 const double sina = sin(-angle); 00221 const double xc = 0.5 * sz - 0.5; 00222 const double yc = 0.5 * sz - 0.5; 00223 00224 const double dh = 0.025 * sz; 00225 const double dw = 0.25 * sz; 00226 00227 for (int y = 0; y < sz; ++y) 00228 for (int x = 0; x < sz; ++x) 00229 { 00230 const double u = (x-xc) * cosa - (yc-y) * sina; 00231 const double v = (x-xc) * sina + (yc-y) * cosa; 00232 00233 if ((fabs(u) <= dh && fabs(v) <= dw) 00234 || 00235 (fabs(v-0.225*sz) <= dh && fabs(u) <= dw)) 00236 *ptr++ = -1.0; 00237 else 00238 *ptr++ = 0.0; 00239 } 00240 00241 return result; 00242 } 00243 00244 Image<double> makeDash(int sz, const double angle) 00245 { 00246 Image<double> result(sz, sz, NO_INIT); 00247 00248 Image<double>::iterator ptr = result.beginw(); 00249 00250 const double cosa = cos(-angle); 00251 const double sina = sin(-angle); 00252 const double xc = 0.5 * sz - 0.5; 00253 const double yc = 0.5 * sz - 0.5; 00254 00255 const double dh = 0.025 * sz; 00256 const double dw = 0.25 * sz; 00257 00258 for (int y = 0; y < sz; ++y) 00259 for (int x = 0; x < sz; ++x) 00260 { 00261 const double u = (x-xc) * cosa - (yc-y) * sina; 00262 const double v = (x-xc) * sina + (yc-y) * cosa; 00263 00264 if (fabs(u) <= dw && fabs(v) <= dh) 00265 *ptr++ = -1.0; 00266 else 00267 *ptr++ = 0.0; 00268 } 00269 00270 return result; 00271 } 00272 00273 Image<double> shrink(const Image<double>& img, int noctaves) 00274 { 00275 Image<double> result = img; 00276 for (int i = 0; i < noctaves; ++i) 00277 result = quickLocalAvg2x2(result); 00278 return result; 00279 } 00280 } 00281 00282 // ###################################################################### 00283 ClassicSearchItem::ClassicSearchItem(Type t, int sz, double angle, 00284 int antialiasOctaves) 00285 : 00286 itsType(t), 00287 itsSize(sz), 00288 itsAngle(angle), 00289 itsAntialiasOctaves(antialiasOctaves) 00290 {} 00291 00292 // ###################################################################### 00293 ClassicSearchItem::~ClassicSearchItem() 00294 {} 00295 00296 // ###################################################################### 00297 Image<double> ClassicSearchItem::getPatch() const 00298 { 00299 const int zoom = (1 << itsAntialiasOctaves); 00300 00301 switch (itsType) 00302 { 00303 case ITEM_C: return shrink(makeC(itsSize*zoom, itsAngle), itsAntialiasOctaves); 00304 case ITEM_O: return shrink(makeO(itsSize*zoom), itsAntialiasOctaves); 00305 case ITEM_Q: return shrink(makeQ(itsSize*zoom, itsAngle), itsAntialiasOctaves); 00306 case ITEM_PLUS: return shrink(makePlus(itsSize*zoom, itsAngle), itsAntialiasOctaves); 00307 case ITEM_L: return shrink(makeL(itsSize*zoom, itsAngle), itsAntialiasOctaves); 00308 case ITEM_T: return shrink(makeT(itsSize*zoom, itsAngle), itsAntialiasOctaves); 00309 case ITEM_DASH: return shrink(makeDash(itsSize*zoom, itsAngle), itsAntialiasOctaves); 00310 default: 00311 break; 00312 } 00313 00314 LFATAL("unsupported item type"); 00315 /* can't happen */ return Image<double>(); 00316 } 00317 00318 // ###################################################################### 00319 ClassicSearchItem::Type ClassicSearchItem::typeFromChar(char c) 00320 { 00321 switch (toupper(c)) 00322 { 00323 case 'C': return ITEM_C; 00324 case 'O': return ITEM_O; 00325 case 'Q': return ITEM_Q; 00326 case '+': return ITEM_PLUS; 00327 case 'L': return ITEM_L; 00328 case 'T': return ITEM_T; 00329 case '-': return ITEM_DASH; 00330 } 00331 00332 LFATAL("invalid search item type '%c'", c); 00333 /* can't happen */ return Type(-1); 00334 } 00335 00336 // ###################################################################### 00337 ClassicSearchItemFactory::ClassicSearchItemFactory(SearchItem::Type c, 00338 const std::string& types, 00339 int sz, 00340 const Range<double>& angleRange, 00341 int antialiasOctaves, 00342 int angleSeed, 00343 int typeSeed) 00344 : 00345 itsLayer(c), 00346 itsTypeList(types), 00347 itsSize(sz), 00348 itsAngleRange(angleRange), 00349 itsAntialiasOctaves(antialiasOctaves), 00350 itsAngles(angleSeed), 00351 itsTypes(typeSeed) 00352 { 00353 if (itsTypeList.size() == 0) 00354 LFATAL("search item typelist must include at least one type"); 00355 } 00356 00357 // ###################################################################### 00358 ClassicSearchItemFactory::~ClassicSearchItemFactory() 00359 {} 00360 00361 // ###################################################################### 00362 rutz::shared_ptr<SearchItem> ClassicSearchItemFactory::make(const geom::vec2d& pos) 00363 { 00364 ClassicSearchItem::Type t = 00365 ClassicSearchItem::typeFromChar(itsTypeList[itsTypes.idraw(itsTypeList.size())]); 00366 00367 rutz::shared_ptr<ClassicSearchItem> el 00368 (new ClassicSearchItem(t, itsSize, 00369 itsAngles.fdraw_range(itsAngleRange.min(), itsAngleRange.max()), 00370 itsAntialiasOctaves)); 00371 00372 el->type = itsLayer; 00373 el->pos = pos; 00374 00375 return el; 00376 } 00377 00378 // ###################################################################### 00379 /* So things look consistent in everyone's emacs... */ 00380 /* Local Variables: */ 00381 /* mode: c++ */ 00382 /* indent-tabs-mode: nil */ 00383 /* End: */ 00384 00385 #endif // PSYCHO_CLASSICSEARCHITEM_C_DEFINED