test-renderlib.C

00001 /*!@file AppMedia/stim-renderLib.C Psychophysics display for a search for a
00002   target that is presented in various repeated noise backgrounds */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-searchGabor.C $
00036 // $Id: psycho-searchGabor.C 10794 2009-02-08 06:21:09Z itti $
00037 //
00038 
00039 #include "Component/ModelManager.H"
00040 #include "Component/ModelOptionDef.H"
00041 #include "Image/ColorOps.H" // for makeRGB()
00042 #include "Image/CutPaste.H" // for inplacePaste()
00043 #include "Image/DrawOps.H" // for drawLine()
00044 #include "Image/Image.H"
00045 #include "Image/MathOps.H"  // for inplaceSpeckleNoise()
00046 #include "Image/LowPass.H" // for LowPass5x, LowPass5y
00047 #include "Image/ShapeOps.H" // for rescale()
00048 #include "Image/Transforms.H" // for mosaic()
00049 #include "Image/Layout.H"
00050 #include "Psycho/PsychoDisplay.H"
00051 #include "Psycho/EyeTrackerConfigurator.H"
00052 #include "Psycho/EyeTracker.H"
00053 #include "Psycho/PsychoOpts.H"
00054 #include "Image/geom.h"
00055 #include "Psycho/ClassicSearchItem.H"
00056 #include "Psycho/SearchArray.H"
00057 #include "Component/EventLog.H"
00058 #include "Component/ComponentOpts.H"
00059 #include "Raster/Raster.H"
00060 #include "rutz/shared_ptr.h"
00061 #include "Util/MathFunctions.H"
00062 #include "Util/StringUtil.H"
00063 #include "Util/StringConversions.H"
00064 #include "GUI/GUIOpts.H"
00065 
00066 #include <sstream>
00067 #include <ctime>
00068 #include <ctype.h>
00069 #include <vector>
00070 #include <string>
00071 #include <fstream>
00072 
00073 using namespace std;
00074 
00075 static const ModelOptionCateg MOC_RANDGENIMAGE = {
00076   MOC_SORTPRI_2, "Options for random image generation" };
00077 
00078 static const ModelOptionDef OPT_RandImageDims =
00079   { MODOPT_ARG(Dims), "GenImageDims", &MOC_RANDGENIMAGE, OPTEXP_CORE,
00080     "dimensions of the random image",
00081     "rand-image-dims", '\0', "<width>x<height>", "1280x720" };
00082 
00083 // Fill classes for different kinds of textures/colors/gradients
00084 class fillTool {
00085 public:
00086   fillTool() {}
00087   virtual Image<byte> fill(const Dims d) const {return Image<byte>(d,NO_INIT);}
00088   //  virtual void whoami() const {LINFO("I am a fillTool...");}
00089 protected:
00090 };
00091 
00092 // brodatz only for now
00093 class fillTexture : public fillTool {
00094 public:
00095   Image<byte> fill(const Dims d) const; 
00096 
00097   void setSeed(const uint c) {seed = c;}
00098   uint getSeed() const {return seed;} 
00099   //  void whoami() const {LINFO("I am a fillTexture...");}
00100 protected:
00101   // brodatz seed
00102   uint seed;
00103 };
00104 
00105 // single, grayscale 'color'
00106 class fillColor : public fillTool {
00107 public:
00108   Image<byte> fill(const Dims d) const;
00109 
00110   void setColor(const byte c) {bg = c;}
00111   byte getColor() const {return bg;}
00112   //  void whoami() const {LINFO("I am a fillColor...");}
00113 
00114 protected:
00115   byte bg;
00116 };
00117 
00118 // generic class of objects that can be drawn
00119 class renderObject {
00120 public:
00121   renderObject() {}
00122   virtual void drawOn(Image<byte> &im) const = 0;
00123   virtual bool inBounds(const Dims &d) const = 0;
00124   Point2D<int> getLocation() {return loc;} const
00125   void setLocation(const Point2D<int> &P) {loc = P;}
00126 
00127   int getSize() {return siz;} const
00128   void setSize(const int &s) {siz = s;}
00129 
00130   float getDirection() {return dir;} const
00131   void setDirection(const float &t) {dir = t;}
00132 
00133 protected:
00134   Point2D<int> loc; 
00135   float dir; //angle
00136   int siz;
00137 };
00138 
00139 class renderDot : public renderObject {
00140 public: 
00141   void drawOn(Image<byte> &im) const;
00142   bool inBounds(const Dims &d) const
00143   {return 0 <= loc.i - dir && 0 <= loc.j - dir && loc.i + dir < d.w() && loc.j + dir < d.h();}
00144 
00145   void setFill(rutz::shared_ptr<fillTool> f) {filler = f;}
00146   rutz::shared_ptr<fillTool> getFill() const {return filler;} 
00147 private:
00148   rutz::shared_ptr<fillTool> filler;
00149 };
00150 
00151 // Generate a random integer uniformly in (x,y)
00152 int randomInRange(const int x, const int y);
00153 
00154 // Generate a random point uniformly in d
00155 //geom::vec2d randomPtIn(const Dims d);
00156 Point2D<int> randomPointIn(const Dims d);
00157 //geom::vec2d randomPtIn(const Rectangle d);
00158 
00159 void drawRandomLine(Image<byte> & im, const byte val, const int thickness);
00160 void extrapolateLine(Dims d, Point2D<int> & X, Point2D<int> & Y);
00161 
00162 template <class T>
00163 Image<byte> makeNary(const Image<T>& src, const std::vector<T> thresholds,
00164                      const std::vector<byte> levels);
00165 
00166 
00167 Image<byte> texturizeImage(const Image<byte> im, const uint Nlevels);
00168 Image<byte> discretizeImage(const Image<byte> im, const int Nlevels);
00169 Image<byte> getBrodatzTexture(uint seed, const Dims dims);
00170 Image<byte> getStretchedTexture(const std::string filename, const Dims dims);
00171 Image<byte> getTiledTexture(const std::string filename, const Dims dims);
00172 
00173 // ######################################################################
00174 static int submain(const int argc, char** argv)
00175 {
00176   MYLOGVERB = LOG_INFO;  // suppress debug messages
00177 
00178   // Instantiate a ModelManager:
00179   ModelManager manager("AppMedia: Flyover stimulus");
00180 
00181   // get dimensions of window
00182   if (manager.parseCommandLine(argc, argv,"<out_stem>", 1, 1) == false)
00183     return(1);
00184 
00185   //  Image<float> myFloatImg(dims.w(), dims.h(), ZEROS);
00186   //Image<double> myDoubleImg(dims.w(), dims.h(), ZEROS);
00187   char filename[255], texfile[255], fillfile[255];
00188 
00189   OModelParam<Dims> dims(&OPT_RandImageDims, &manager);
00190 
00191   // get command line parameters for filename
00192   sprintf(filename, "%s.png",manager.getExtraArg(0).c_str());
00193   sprintf(texfile, "%s-tex.png",manager.getExtraArg(0).c_str());
00194   sprintf(fillfile, "%s-fill.png",manager.getExtraArg(0).c_str());
00195 
00196   // let's get all our ModelComponent instances started:
00197   manager.start();
00198 
00199   // **************** Experimental settings *************** //
00200 
00201   // number of available noise frames in the stimuli folder
00202   //  const uint Nnoises = 100;
00203 
00204   //tests
00205   Image<byte> myBkgd = Image<byte>(dims.getVal(),ZEROS)+128; //gray bkgd
00206   Image<byte> myMap = myBkgd;
00207   rutz::shared_ptr<fillTexture> style(new fillTexture);
00208   rutz::shared_ptr<fillColor> color(new fillColor);
00209 
00210   rutz::shared_ptr<renderDot> dot(new renderDot);  
00211   dot->setSize(50);
00212 
00213   int rseed, rcol;
00214   for(int i = 0; i < 50; i++) {
00215     rseed = randomUpToIncluding(255);
00216     rcol = randomUpToIncluding(1);
00217     if(rcol==0) {
00218       style->setSeed(rseed);
00219       dot->setFill(style);
00220     }
00221     else {
00222       color->setColor(rseed);
00223       dot->setFill(color);
00224     }
00225     dot->setLocation(randomPointIn(dims.getVal()));
00226     dot->drawOn(myMap);
00227   }
00228   // test texture
00229   LINFO("writing pattern image to %s", filename);
00230   Raster::WriteGray(myMap,filename);
00231 
00232   // stop all our ModelComponents
00233   manager.stop();
00234 
00235   // all done!
00236   return 0;
00237 }
00238 
00239 // ######################################################################
00240 
00241 extern "C" int main(const int argc, char** argv)
00242 {
00243   // simple wrapper around submain() to catch exceptions (because we
00244   // want to allow PsychoDisplay to shut down cleanly; otherwise if we
00245   // abort while SDL is in fullscreen mode, the X server won't return
00246   // to its original resolution)
00247   try
00248     {
00249       return submain(argc, argv);
00250     }
00251   catch (...)
00252     {
00253       REPORT_CURRENT_EXCEPTION;
00254     }
00255 
00256   return 1;
00257 }
00258 
00259 
00260 // ######################################################################
00261 Image<byte> fillTexture::fill(const Dims d) const {
00262     return getBrodatzTexture(seed, d);
00263 } 
00264 
00265 // ######################################################################
00266 Image<byte> fillColor::fill(const Dims d) const {
00267   return Image<byte>(d,ZEROS) + bg;
00268 } 
00269 
00270 // ######################################################################
00271 void renderDot::drawOn(Image<byte> & im) const
00272   {
00273     const byte mask_col = 255;
00274 
00275     Image<byte> mask(im.getDims(), ZEROS);
00276     drawDisk(mask, loc, siz, mask_col);
00277 
00278     Image<byte> myPrint = filler->fill(im.getDims());
00279     std::vector<Image<byte> > bgs;
00280     bgs.push_back(im); bgs.push_back(myPrint);
00281     byte bg_assigns[2] = {0, mask_col};
00282     im = mosaic(mask, &bgs[0], bg_assigns, 2);
00283   }
00284 
00285 // ######################################################################
00286 // Generate a random integer uniformly in (x,y) (open interval)
00287 int randomInRange(const int x, const int y)
00288 {
00289   return randomUpToNotIncluding(y-x-1)+(x+1);
00290 }
00291 
00292 // ######################################################################
00293 
00294 // draw a random line 
00295 void drawRandomLine(Image<byte> & im, const byte val, const int thickness)
00296 {
00297   Point2D<int> P = randomPointIn(im.getDims());
00298   Point2D<int> Q = randomPointIn(im.getDims());
00299 
00300   extrapolateLine(im.getDims(),P,Q);
00301   drawLine(im, P, Q, val, thickness);
00302 }
00303 
00304 // ######################################################################
00305 
00306 // extend a line segment to boundaries
00307 void extrapolateLine(Dims d, Point2D<int> & X, Point2D<int> & Y)
00308 {
00309   // check if X and Y are in d
00310   Image<byte> foo(d, NO_INIT);
00311   if(!(foo.coordsOk(X) && foo.coordsOk(Y)) || X == Y) return;
00312 
00313   if (X.i == Y.i) {X.j = 0; Y.j = d.h(); return;}
00314   else if(X.j == Y.j) {X.i = 0; Y.j = d.w(); return;}
00315   else {float y_0 = (X.j*Y.i-X.i*Y.j)/(Y.i-X.i);
00316     float x_0 = (X.i*Y.j-X.j*Y.i)/(Y.j-X.j);
00317     float slope = (Y.j-X.j)/(Y.i-X.i);
00318     
00319     std::vector<Point2D<int> > bounds; 
00320     bounds.push_back(Point2D<int>(0,y_0));
00321     bounds.push_back(Point2D<int>(x_0,0));
00322     bounds.push_back(Point2D<int>(d.w()-1,y_0+(d.w()-1)*slope));
00323     bounds.push_back(Point2D<int>(x_0+(d.h()-1)/slope,d.h()-1));
00324 
00325     bool Xdone = 0;
00326     for(int i = 0; i < 4; i++)
00327       if(foo.coordsOk(bounds[i])) { 
00328         if(!Xdone) {
00329           X = bounds[i]; 
00330           Xdone = true;
00331         }
00332         else {
00333             Y = bounds[i]; 
00334             break;
00335         }
00336       }
00337   }
00338 }
00339 
00340 // ######################################################################
00341 
00342 // Generate a random point uniformly in d
00343 Point2D<int> randomPointIn(const Dims d)
00344 {
00345   return Point2D<int>(randomInRange(0,d.w()),
00346                       randomInRange(0,d.h()));
00347 }
00348 
00349 // ######################################################################
00350 
00351 // inspired from makeBinary in Transforms.C
00352 template <class T>
00353 Image<byte> makeNary(const Image<T>& src, const std::vector<T> thresholds,
00354                   const std::vector<byte> levels)
00355 {
00356   ASSERT(thresholds.size() == levels.size() - 1);
00357   Image<byte> acc(src.getDims(),ZEROS);
00358   byte floor;
00359   for(uint i = 0; i < thresholds.size(); i++)
00360     {
00361       if(i == 0) 
00362         {
00363           floor = levels[0];
00364         }
00365     else 
00366       {
00367         floor = 0;
00368       }
00369     acc += makeBinary(src, thresholds[i],floor,levels[1]);
00370     }
00371 
00372   return acc;
00373 }
00374 
00375 // ######################################################################
00376 // maps discretized image to textured image
00377 Image<byte> texturizeImage(const Image<byte> im, const uint Nlevels)
00378 {
00379   uint i, seed;
00380   //  Image<byte> levelImage = discretizeImage(im, Nlevels);
00381   std::vector<Image<byte> > texBkgds;
00382   for(i = 0; i < Nlevels; i++)
00383     {
00384       seed = randomInRange(0,112); // num brodatz images
00385       texBkgds.push_back(getBrodatzTexture(seed, im.getDims()));
00386     }
00387 
00388   byte tiers[Nlevels];
00389   for(uint i = 0; i < Nlevels; i++) 
00390       tiers[i] = i*(255/(Nlevels-1));
00391 
00392   return mosaic(im, &texBkgds[0], tiers, Nlevels);
00393   //return mosaic(levelImage, &texBkgds[0], tiers, Nlevels);
00394 }
00395 
00396 // ######################################################################
00397 // discretizes image
00398 Image<byte> discretizeImage(const Image<byte> im, const int Nlevels)
00399 {
00400   byte imMin, imMax, i;
00401   getMinMax(im, imMin, imMax);
00402 
00403   const byte Ncuts = Nlevels - 1;
00404   
00405   // the ratios that partition the image
00406   float coeffs[Ncuts];
00407   for(i = 0; i < Ncuts; i++)
00408       coeffs[i] = (i+1.0)/(Ncuts+1.0);
00409 
00410   // the values in the noise image that partition the image
00411   std::vector<byte> cuts;
00412   for(i = 0; i < Ncuts; i++)
00413       cuts.push_back(imMax*coeffs[i]+imMin*(1-coeffs[i])); 
00414 
00415   // the mapped values of the outside image
00416   std::vector<byte> tiers;
00417   for(i = 0; i <= cuts.size(); i++) 
00418       tiers.push_back(i*(255/cuts.size()));
00419 
00420   // use makeNary to cut the image
00421   Image<byte> pattern = makeNary(im,cuts,tiers);
00422 
00423   // draw a random line cutting across the image
00424   drawRandomLine(pattern, tiers[2], 50);
00425 
00426   return pattern;
00427   
00428 } 
00429 
00430 // ######################################################################
00431 Image<byte> getBrodatzTexture(uint seed, const Dims dims)
00432 {
00433   char texPath[255];
00434   
00435   // there are only 111 images in the brodatz database
00436   const uint Nimages = 111;
00437   seed = seed % (Nimages - 1) + 1;
00438 
00439   sprintf(texPath, "/lab/jshen/projects/eye-cuing/stimuli/textures/brodatz/D%u.png",seed);
00440   return getStretchedTexture(texPath, dims);
00441 }
00442 
00443 // ######################################################################
00444 Image<byte> getStretchedTexture(const std::string filename, const Dims dims)
00445 {
00446   Image<byte> pat = Raster::ReadGray(filename,RASFMT_PNG);
00447   return rescale(pat, dims);
00448 }
00449 
00450 // ######################################################################
00451 Image<byte> getTiledTexture(const std::string filename, const Dims dims)
00452 {
00453   //filename refers to a simple texture, black and white, PNG
00454   Image<byte> pat = Raster::ReadGray(filename,RASFMT_PNG);
00455 
00456   const size_t nX = dims.w()/pat.getWidth()+1;
00457   const size_t nY = dims.h()/pat.getHeight()+1;
00458 
00459   std::vector<Image<byte> > tiles(nX,pat);
00460   Layout<byte> horiztile(&tiles[0],nX,Layout<byte>::H);
00461 
00462   std::vector<Layout<byte> > rows(nY,horiztile);
00463   Layout<byte> whole(&rows[0],nY,Layout<byte>::V);
00464 
00465   return crop(whole.render(),Point2D<int>(0,0),dims);
00466 }
00467 
00468 // ######################################################################
00469 /* So things look consistent in everyone's emacs... */
00470 /* Local Variables: */
00471 /* indent-tabs-mode: nil */
00472 /* End: */
Generated on Sun May 8 08:40:08 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3