00001 /*!@file Transport/GameOfLifeInput.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/Transport/GameOfLifeInput.C $ 00035 // $Id: GameOfLifeInput.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #ifndef TRANSPORT_GAMEOFLIFEINPUT_C_DEFINED 00039 #define TRANSPORT_GAMEOFLIFEINPUT_C_DEFINED 00040 00041 #include "Transport/GameOfLifeInput.H" 00042 00043 #include "Component/ModelOptionDef.H" 00044 #include "Image/CutPaste.H" 00045 #include "Image/ShapeOps.H" 00046 #include "Raster/GenericFrame.H" 00047 #include "Transport/TransportOpts.H" 00048 00049 namespace 00050 { 00051 Image<byte> gameOfLifeUpdate(const Image<byte>& in, 00052 int* nlive) 00053 { 00054 Image<byte> out(in.getDims(), ZEROS); 00055 00056 Image<byte>::const_iterator sptr = in.begin(); 00057 Image<byte>::iterator dptr = out.beginw(); 00058 00059 const int w = in.getWidth(); 00060 const int h = in.getHeight(); 00061 00062 *nlive = 0; 00063 00064 for (int y = 0; y < h; ++y) 00065 for (int x = 0; x < w; ++x) 00066 { 00067 int nn = 0; // number of live neighbors 00068 00069 if (y > 1) 00070 { 00071 if (x > 1 && sptr[-1-w] > 0) ++nn; 00072 if ( sptr[ 0-w] > 0) ++nn; 00073 if (x < w-1 && sptr[ 1-w] > 0) ++nn; 00074 } 00075 00076 if (x > 1 && sptr[-1] > 0) ++nn; 00077 if (x < w-1 && sptr[ 1] > 0) ++nn; 00078 00079 if (y < h-1) 00080 { 00081 if (x > 1 && sptr[-1+w] > 0) ++nn; 00082 if ( sptr[ 0+w] > 0) ++nn; 00083 if (x < w-1 && sptr[ 1+w] > 0) ++nn; 00084 } 00085 00086 if (*sptr > 0) // cell is currently live 00087 { 00088 *dptr = 00089 (nn == 2 || nn == 3) 00090 ? 255 // stay alive 00091 : 0; // die 00092 } 00093 else // cell is currently dead 00094 { 00095 *dptr = 00096 (nn == 3) 00097 ? 255 // come alive 00098 : 0; // stay dead 00099 } 00100 00101 if (*dptr > 0) 00102 ++*nlive; 00103 00104 ++sptr; 00105 ++dptr; 00106 } 00107 00108 return out; 00109 } 00110 } 00111 00112 // Used by: GameOfLifeInput 00113 const ModelOptionDef OPT_GameOfLifeFillFraction = 00114 { MODOPT_ARG(double), "GameOfLifeFillFraction", &MOC_INPUT, OPTEXP_CORE, 00115 "In the \"Game of Life\" (with --in=life), this is the fraction " 00116 "of cells to be filled as \"live\" when creating the initial " 00117 "random game board, and when re-seeding the board after it becomes " 00118 "stuck.", 00119 "life-fill-fraction", '\0', "float", "0.4" }; 00120 00121 // Used by: GameOfLifeInput 00122 const ModelOptionDef OPT_GameOfLifeCellSize = 00123 { MODOPT_ARG(uint), "GameOfLifeCellSize", &MOC_INPUT, OPTEXP_CORE, 00124 "In the \"Game of Life\" (with --in=life), this is the size, in " 00125 "pixels, of each cell.", 00126 "life-cell-size", '\0', "uint", "4" }; 00127 00128 // ###################################################################### 00129 GameOfLifeInput::GameOfLifeInput(OptionManager& mgr) 00130 : 00131 FrameIstream(mgr, "Random Input", "GameOfLifeInput"), 00132 itsFillFraction(&OPT_GameOfLifeFillFraction, this), 00133 itsCellSize(&OPT_GameOfLifeCellSize, this), 00134 itsDims(320,240), // if you change this default value, also update 00135 // the documentation of OPT_InputFrameSource in 00136 // Media/MediaOpts.C 00137 itsGenerator(0), 00138 itsBoard(), 00139 itsStarted(false) 00140 { 00141 itsGenerator.seed(time(NULL)); 00142 } 00143 00144 // ###################################################################### 00145 GameOfLifeInput::~GameOfLifeInput() 00146 {} 00147 00148 // ###################################################################### 00149 void GameOfLifeInput::setConfigInfo(const std::string& dimsstring) 00150 { 00151 // NOTE: if you modify any behavior here, then please update the 00152 // corresponding documentation for the global "--in" option inside 00153 // the OPT_InputFrameSource definition in Media/MediaOpts.C 00154 00155 if (dimsstring.size() == 0) 00156 return; 00157 00158 Dims d; convertFromString(dimsstring, d); 00159 this->setDims(d); 00160 } 00161 00162 // ###################################################################### 00163 GenericFrameSpec GameOfLifeInput::peekFrameSpec() 00164 { 00165 GenericFrameSpec result; 00166 00167 result.nativeType = GenericFrame::RGB_U8; 00168 result.videoFormat = VIDFMT_AUTO; 00169 result.videoByteSwap = false; 00170 result.dims = itsDims; 00171 result.floatFlags = 0; 00172 00173 return result; 00174 } 00175 00176 // ###################################################################### 00177 GenericFrame GameOfLifeInput::readFrame() 00178 { 00179 if (!itsStarted) 00180 { 00181 00182 #if 0 00183 00184 #define i 0 00185 #define Q 255 00186 const byte gosper_glider_gun[] = 00187 { 00188 // 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5 00189 /*0*/ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,Q,i,i,i,i,i,i,i,i,i,i,i, 00190 /*1*/ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,Q,i,Q,i,i,i,i,i,i,i,i,i,i,i, 00191 /*2*/ i,i,i,i,i,i,i,i,i,i,i,i,Q,Q,i,i,i,i,i,i,Q,Q,i,i,i,i,i,i,i,i,i,i,i,i,Q,Q, 00192 /*3*/ i,i,i,i,i,i,i,i,i,i,i,Q,i,i,i,Q,i,i,i,i,Q,Q,i,i,i,i,i,i,i,i,i,i,i,i,Q,Q, 00193 /*4*/ Q,Q,i,i,i,i,i,i,i,i,Q,i,i,i,i,i,Q,i,i,i,Q,Q,i,i,i,i,i,i,i,i,i,i,i,i,i,i, 00194 /*5*/ Q,Q,i,i,i,i,i,i,i,i,Q,i,i,i,Q,i,Q,Q,i,i,i,i,Q,i,Q,i,i,i,i,i,i,i,i,i,i,i, 00195 /*6*/ i,i,i,i,i,i,i,i,i,i,Q,i,i,i,i,i,Q,i,i,i,i,i,i,i,Q,i,i,i,i,i,i,i,i,i,i,i, 00196 /*7*/ i,i,i,i,i,i,i,i,i,i,i,Q,i,i,i,Q,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i, 00197 /*8*/ i,i,i,i,i,i,i,i,i,i,i,i,Q,Q,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i 00198 }; 00199 00200 const byte block_engine_1[] = 00201 { 00202 // 0,1,2,3,4,5,6,7, 00203 /*0*/ i,i,i,i,i,Q,i,Q, 00204 /*1*/ i,i,i,i,i,Q,i,i, 00205 /*2*/ i,i,i,Q,i,i,i,i, 00206 /*3*/ i,Q,i,Q,i,i,i,i, 00207 /*4*/ Q,Q,i,Q,i,i,i,i, 00208 /*5*/ i,Q,i,i,i,i,i,i, 00209 }; 00210 00211 const byte block_engine_2[] = 00212 { 00213 // 0,1,2,3,4, 00214 /*0*/ Q,i,Q,i,Q, 00215 /*1*/ Q,i,Q,Q,i, 00216 /*2*/ Q,Q,i,i,i, 00217 /*3*/ i,i,i,i,Q, 00218 /*4*/ Q,i,Q,Q,Q, 00219 }; 00220 00221 const byte block_engine_3[] = 00222 { 00223 // 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8 00224 /*0*/ Q,Q,Q,Q,Q,Q,Q,Q,i,Q,Q,Q,Q,Q,i,i,i,Q,Q,Q,i,i,i,i,i,i,Q,Q,Q,Q,Q,Q,Q,i,Q,Q,Q,Q,Q 00225 }; 00226 00227 #undef i 00228 #undef Q 00229 00230 #endif 00231 00232 itsBoardHist.resize(0); 00233 itsBoard = Image<byte>(itsDims.w() / itsCellSize.getVal(), 00234 itsDims.h() / itsCellSize.getVal(), 00235 ZEROS); 00236 00237 #if 0 00238 if (0) 00239 const Image<byte> pattern(&gosper_glider_gun[0], 36, 9); 00240 if (0) 00241 const Image<byte> pattern(&block_engine_1[0], 8, 6); 00242 if (0) 00243 const Image<byte> pattern(&block_engine_2[0], 5, 5); 00244 if (0) 00245 const Image<byte> pattern(&block_engine_3[0], 39, 1); 00246 00247 inplacePaste(itsBoard, pattern, Point2D<int>(60,60)); 00248 #endif 00249 00250 const double t = itsFillFraction.getVal(); 00251 00252 for (Image<byte>::iterator 00253 p = itsBoard.beginw(), stop = itsBoard.endw(); 00254 p != stop; ++p) 00255 *p = 00256 (itsGenerator.fdraw() < t) 00257 ? 255 00258 : 0; 00259 00260 itsStarted = true; 00261 } 00262 else 00263 { 00264 int nlive = 0; 00265 itsBoard = gameOfLifeUpdate(itsBoard, &nlive); 00266 if (nlive == 0) 00267 // oops, everybody died, so let's restart on the next frame: 00268 itsStarted = false; 00269 } 00270 00271 for (size_t i = 0; i < itsBoardHist.size(); ++i) 00272 if (itsBoard == itsBoardHist[i]) 00273 { 00274 // we've started cycling, so let's break the cycle and start 00275 // fresh on the next frame: 00276 LINFO("cycle detected with period %"ZU, 00277 itsBoardHist.size() - i); 00278 itsStarted = false; 00279 break; 00280 } 00281 00282 itsBoardHist.push_back(itsBoard); 00283 00284 while (itsBoardHist.size() >= 8) 00285 itsBoardHist.pop_front(); 00286 00287 const Image<byte> result = 00288 rescale(itsBoard, itsDims, RESCALE_SIMPLE_NOINTERP); 00289 00290 return GenericFrame(result); 00291 } 00292 00293 // ###################################################################### 00294 void GameOfLifeInput::setDims(const Dims& s) 00295 { 00296 itsDims = s; 00297 } 00298 00299 // ###################################################################### 00300 /* So things look consistent in everyone's emacs... */ 00301 /* Local Variables: */ 00302 /* mode: c++ */ 00303 /* indent-tabs-mode: nil */ 00304 /* End: */ 00305 00306 #endif // TRANSPORT_GAMEOFLIFEINPUT_C_DEFINED