00001 /*! \file Neuro/GistEstimatorContextBased.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: Manu Viswanathan <mviswana at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/GistEstimatorContextBased.C $ 00035 // $Id: GistEstimatorContextBased.C 13065 2010-03-28 00:01:00Z itti $ 00036 // 00037 00038 //------------------------------ HEADERS -------------------------------- 00039 00040 // Gist specific headers 00041 #include "Neuro/GistEstimatorContextBased.H" 00042 00043 // Other INVT headers 00044 #include "Neuro/VisualCortex.H" 00045 #include "Neuro/NeuroSimEvents.H" 00046 00047 #include "Simulation/SimEventQueue.H" 00048 00049 #include "Channels/GaborChannel.H" 00050 #include "Channels/OrientationChannel.H" 00051 #include "Channels/RawVisualCortex.H" 00052 00053 #include "Image/CutPaste.H" 00054 #include "Image/MathOps.H" 00055 #include "Image/Point2D.H" 00056 #include "Image/Dims.H" 00057 00058 #include "nub/ref.h" 00059 #include "rutz/shared_ptr.h" 00060 00061 // Standard C++ headers 00062 #include <vector> 00063 #include <algorithm> 00064 #include <cmath> 00065 #include <ctime> 00066 00067 //-------------------------- INITIALIZATION ----------------------------- 00068 00069 GistEstimatorContextBased:: 00070 GistEstimatorContextBased(OptionManager& mgr, 00071 const std::string& descrName, 00072 const std::string& tagName) 00073 : GistEstimatorAdapter(mgr, descrName, tagName), 00074 SIMCALLBACK_INIT(SimEventVisualCortexOutput), 00075 itsGistVector(GRID_SIZE * GRID_SIZE * NUM_FILTERS, 1, ZEROS) 00076 {} 00077 00078 //----------------------------- CLEAN-UP -------------------------------- 00079 00080 GistEstimatorContextBased::~GistEstimatorContextBased() 00081 {} 00082 00083 //------------------ GIST FEATURE VECTOR COMPUTATION -------------------- 00084 00085 namespace { // prevent global namespace pollution and possible linker errors 00086 00087 // Some useful shortcuts 00088 typedef GistEstimatorContextBased::PixelType PixelType ; 00089 typedef GistEstimatorContextBased::ImageType ImageType ; 00090 00091 // As per the Torralba paper, their wavelet image decompositions are 00092 // equivalent to Gabor filters applied at different orientations and 00093 // scales. Thus, the following function simply retrieves the Gabor 00094 // channel for the specified orientation and scale. 00095 ImageType 00096 apply_gabor_filter(const RawVisualCortex* vc, uint orientation, uint scale) 00097 { 00098 nub::soft_ref<OrientationChannel> oc ; 00099 dynCastWeakToFrom(oc, vc->subChan("orientation")) ; 00100 GaborChannel& gc = oc->gabor(orientation) ; 00101 return gc.getImage(scale) ; 00102 } 00103 00104 // The following function divides the supplied filtered image into the 00105 // specified grid sizes and returns the average pixel values for each of 00106 // these subimages. 00107 std::vector<double> grid_averages(const ImageType& I, const Dims& grid_size) 00108 { 00109 const int M = GistEstimatorContextBased::GRID_SIZE ; 00110 std::vector<double> averages(M*M) ; 00111 00112 int A = 0 ; 00113 for (int y = 0, Y = 0; y < M; ++y, Y += grid_size.h()) 00114 for (int x = 0, X = 0; x < M; ++x, X += grid_size.w()) 00115 { 00116 ImageType sub = crop(I, Point2D<int>(X, Y), grid_size, true) ; 00117 averages[A++] = mean(sub) ; 00118 } 00119 00120 return averages ; 00121 } 00122 00123 } // end of local namespace encapsulating above helpers 00124 00125 // The evolve method filters the "current" image passed in by the INVT 00126 // simulation framework and computes this image's gist vector. To compute 00127 // this vector, it first applies Gabor filters to the input image at 00128 // different orientations and scales. Then, it subdivides each of the 00129 // filteration results into smaller "chunks" and populates the gist 00130 // vector with the average pixel values in these coarse chunks. 00131 void GistEstimatorContextBased:: 00132 onSimEventVisualCortexOutput(SimEventQueue& q, rutz::shared_ptr<SimEventVisualCortexOutput>& e) 00133 { 00134 ///////////// VisualCortex* vc = dynamic_cast<VisualCortex*>(e->source()) ; 00135 00136 const double G = GRID_SIZE ; 00137 const int N = GRID_SIZE * GRID_SIZE ; 00138 Image<double>::iterator gist_vector = itsGistVector.beginw() ; 00139 00140 clock_t start_time = clock() ; 00141 for (uint orientation = 0; orientation < NUM_ORIENTATIONS; ++orientation) 00142 for (uint scale = 0; scale < NUM_SCALES; ++scale, gist_vector += N) 00143 { 00144 00145 LFATAL("Please talk to Laurent to fix this"); 00146 00147 ImageType I; /////// = apply_gabor_filter(vc, orientation, scale) ; 00148 //LINFO("Gabor filter [O:%u, S:%u] returned %dx%d image", 00149 //orientation, scale, I.getWidth(), I.getHeight()) ; 00150 00151 Dims grid_size(static_cast<int>(std::ceil(I.getWidth()/G)), 00152 static_cast<int>(std::ceil(I.getHeight()/G))) ; 00153 //LINFO("computing averages for %dx%d subimages of filtered image", 00154 //grid_size.w(), grid_size.h()) ; 00155 std::vector<double> averages = grid_averages(I, grid_size) ; 00156 00157 //LINFO("copying %d averages to gist vector at offset %d", 00158 //int(averages.size()), 00159 //int(gist_vector - itsGistVector.beginw())) ; 00160 std::copy(averages.begin(), averages.end(), gist_vector) ; 00161 } 00162 LINFO("%g seconds to compute %dx%d gist vector", 00163 static_cast<double>(clock() - start_time)/CLOCKS_PER_SEC, 00164 itsGistVector.getHeight(), itsGistVector.getWidth()) ; 00165 00166 rutz::shared_ptr<SimEventGistOutput> 00167 gist_event(new SimEventGistOutput(this, itsGistVector)) ; 00168 q.post(gist_event) ; 00169 } 00170 00171 //----------------------------------------------------------------------- 00172 00173 /* So things look consistent in everyone's emacs... */ 00174 /* Local Variables: */ 00175 /* indent-tabs-mode: nil */ 00176 /* End: */