00001 /*!@file Channels/StereoChannel.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: 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Channels/StereoChannel.C $ 00035 // $Id: StereoChannel.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #ifndef STEREOCHANNEL_C_DEFINED 00039 #define STEREOCHANNEL_C_DEFINED 00040 00041 #include "Channels/StereoChannel.H" 00042 00043 #include "Channels/ChannelOpts.H" 00044 #include "Channels/DisparityChannel.H" 00045 #include "Component/OptionManager.H" 00046 #include "Image/CutPaste.H" 00047 #include "Image/FilterOps.H" 00048 #include "Image/Kernels.H" 00049 #include "Image/Pixels.H" 00050 #include "Image/PyramidOps.H" 00051 00052 // ###################################################################### 00053 // StereoChannel member definitions: 00054 // ###################################################################### 00055 00056 // instantiations for our static members: 00057 const uint StereoChannel::nPhase; 00058 const uint StereoChannel::nTheta; 00059 const float StereoChannel::dPhase; 00060 const float StereoChannel::dTheta; 00061 const float StereoChannel::stddev; 00062 const float StereoChannel::period; 00063 00064 00065 // ###################################################################### 00066 StereoChannel::StereoChannel(OptionManager& mgr) : 00067 ComplexChannel(mgr, "Stereo", "stereo", STEREO), 00068 itsPyrType("StereoChannelPyramidType", this, Gaussian3), 00069 itsNumTheta(&OPT_NumTheta, this), 00070 itsNumPhase("NumPhase", this, nPhase/2 + 1) 00071 { 00072 fImgL = NULL; fImgR = NULL; 00073 00074 // let's create our subchannels (may be reconfigured later if our 00075 // number of orientations changes): 00076 buildSubChans(); 00077 } 00078 00079 // ###################################################################### 00080 StereoChannel::~StereoChannel() 00081 { } 00082 00083 // ###################################################################### 00084 void StereoChannel::start1() 00085 { 00086 00087 // get the depth of the feature maps 00088 itsDepth = dispChan(0,0).getLevelSpec().maxDepth(); 00089 00090 // create the phased gabor pyramids 00091 createPhasedGaborPyramids(); 00092 } 00093 00094 // ###################################################################### 00095 DisparityChannel& StereoChannel::dispChan(const uint idO, 00096 const uint idP) const 00097 { 00098 uint idx= idO * itsNumPhase.getVal() + idP; 00099 return *(dynCast<DisparityChannel>(this->subChan(idx))); 00100 } 00101 00102 // ###################################################################### 00103 void StereoChannel::buildSubChans() 00104 { 00105 // kill any subchans we may have had... 00106 this->removeAllSubChans(); 00107 00108 // let's instantiate our subchannels now that we know how many we 00109 // want. They will inherit the current values (typically 00110 // post-command-line parsing) of all their options as they are 00111 // constructed: 00112 LINFO("Using %d orientations spanning [0..180]deg and %d phase spanning [0..360]deg", 00113 itsNumTheta.getVal(), itsNumPhase.getVal()); 00114 00115 double theta; 00116 double phase; 00117 00118 for (uint i = 0; i < itsNumTheta.getVal(); i ++) 00119 for (uint j = 0; j < itsNumPhase.getVal(); j ++) 00120 { 00121 theta = 180.0 * double(i) / double(itsNumTheta.getVal()); 00122 // the phase range is -PI/2 to PI/2 but -PI/2 to 0 is normalized. 00123 // the number of thetas is always odd 00124 // first half is 0 to PI/2 00125 if(j <= itsNumPhase.getVal()/2) 00126 phase = 90.0 * double(j) / double(itsNumPhase.getVal()/2); 00127 // the second half is -PI/2 to 0 00128 else 00129 phase = 90.0 * double(j-1) / double(itsNumPhase.getVal()/2) + 00130 180.0; 00131 00132 addSubChan(makeSharedComp 00133 (new DisparityChannel(getManager(), 00134 i*itsNumPhase.getVal() 00135 +j,theta,phase ))); 00136 00137 dispChan(i,j).setNumTheta(nTheta); 00138 dispChan(i,j).setNumPhase(nPhase); 00139 00140 } 00141 00142 // Here, we just use our subchannels' default tag names 00143 00144 // if we have been requested to export some options, let's ask it 00145 // again on our newly built channels: 00146 ModelComponent::exportOptions(MC_RECURSE); 00147 } 00148 00149 // ###################################################################### 00150 void StereoChannel::createPhasedGaborPyramids() 00151 { 00152 // create the phased gabor pyramids 00153 if(fImgL != NULL || fImgR != NULL) 00154 { 00155 for(uint i = 0; i < itsDepth; i++) 00156 { 00157 for(uint j = 0; j < nTheta; j++) 00158 { 00159 delete(fImgL[i][j]); 00160 delete(fImgR[i][j]); 00161 } 00162 } 00163 00164 for(uint i = 0; i < itsDepth; i++) 00165 { 00166 delete(fImgL[i]); 00167 delete(fImgR[i]); 00168 } 00169 00170 delete(fImgL); 00171 delete(fImgR); 00172 } 00173 00174 fImgL = new Image<float>**[itsDepth]; 00175 fImgR = new Image<float>**[itsDepth]; 00176 00177 for(uint i = 0; i < itsDepth; i++) 00178 { 00179 fImgL[i] = new Image<float>*[nTheta]; 00180 fImgR[i] = new Image<float>*[nTheta]; 00181 } 00182 00183 for(uint i = 0; i < itsDepth; i++) 00184 { 00185 for(uint j = 0; j < nTheta; j++) 00186 { 00187 fImgL[i][j] = new Image<float>[nPhase]; 00188 fImgR[i][j] = new Image<float>[nPhase]; 00189 } 00190 } 00191 } 00192 00193 // ###################################################################### 00194 void StereoChannel::paramChanged(ModelParamBase* const param, 00195 const bool valueChanged, 00196 ParamClient::ChangeStatus* status) 00197 { 00198 ComplexChannel::paramChanged(param, valueChanged, status); 00199 00200 // if the param is our number of channel and it has 00201 // become different from our number of orientations * number of phase , 00202 // let's reconfigure: 00203 if (param == &itsNumTheta && 00204 // param == &itsNumPhase && 00205 numChans() != itsNumPhase.getVal() * itsNumTheta.getVal()) 00206 buildSubChans(); 00207 } 00208 00209 // ###################################################################### 00210 void StereoChannel::doInput(const InputFrame& inframe) 00211 { 00212 ASSERT(inframe.grayFloat().initialized()); 00213 00214 imgL = inframe.grayFloat(); 00215 // IMPORTANT 00216 // at this point the secondary view image should already 00217 // be set by Stereo Vision. 00218 00219 // create an image pyramid for both images 00220 pyrL = buildPyrGaussian(imgL, 0, itsDepth, 5); 00221 pyrR = buildPyrGaussian(imgR, 0, itsDepth, 5); 00222 00223 // apply the gabor filter at various angle and phase on both eyes 00224 applyGabor(); 00225 00226 // for normalization 00227 ImageSet<float> tDispMap(itsDepth); 00228 ImageSet<float> tempDM; 00229 00230 for(uint d = 0; d < itsDepth; d++) 00231 { 00232 tDispMap[d].resize(pyrL[d].getWidth(),pyrL[d].getHeight(),true); 00233 //ispMap[d] += 1.0F; 00234 } 00235 00236 // pass the response array to each subchannel 00237 // so they can calculate each disparity correspondence 00238 for (uint i = 0; i < itsNumTheta.getVal(); i ++) 00239 for (uint j = 0; j < itsNumPhase.getVal(); j ++) 00240 { 00241 dispChan(i,j).setRawFilteredImages(fImgL,fImgR); 00242 dispChan(i,j).doInput(inframe); 00243 00244 //dispChan(i,j).getDispMap(&tempDM); 00245 00246 // add the results for normalizing the output 00247 //for (uint d = 0; d< itsDepth; d++) 00248 // tDispMap[d] += tempDM[d]; 00249 00250 } 00251 00252 // normalize the values to [0, 1] - confidence level 00253 // and store the pyramid for the interaction 00254 /* for (uint i = 0; i < itsNumTheta.getVal(); i ++) 00255 for (uint j = 0; j < itsNumPhase.getVal(); j ++) 00256 { 00257 dispChan(i,j).normalizeDispMap(tDispMap, 00258 itsNumTheta.getVal()*itsNumPhase.getVal()); 00259 dispChan(i,j).storePyramid(t); 00260 } 00261 */ 00262 00263 00264 } 00265 00266 // ###################################################################### 00267 void StereoChannel::setSecondImage(const Image<float>* bwimg) 00268 { 00269 imgR = *bwimg; 00270 } 00271 00272 // ###################################################################### 00273 void StereoChannel::getRawFilteredImages(Image<float> ****fImgLE, 00274 Image<float> ****fImgRI) 00275 { 00276 *fImgLE = fImgL; 00277 *fImgRI = fImgR; 00278 } 00279 00280 // ###################################################################### 00281 void StereoChannel::applyGabor() 00282 { 00283 Image<float> gaborF;Image<float> gF; 00284 Point2D<int> a(3,3); Dims b(5,5); 00285 for(uint d = 0; d < itsDepth; d++) 00286 { 00287 for(uint t = 0; t < nTheta; t++) 00288 { 00289 for(uint p = 0; p < nPhase; p++) 00290 { 00291 gaborF = gaborFilter<float>(stddev,period,p*dPhase,t*dTheta); 00292 ASSERT(gaborF.getWidth() == 11 && gaborF.getHeight() == 11); 00293 gaborF = crop(gaborF,a,b,false); 00294 00295 fImgL[d][t][p] = convolve(pyrL[d],gaborF,CONV_BOUNDARY_ZERO); 00296 //fImgL[d][t][p].rectify(); 00297 fImgR[d][t][p] = convolve(pyrR[d],gaborF,CONV_BOUNDARY_ZERO); 00298 //fImgR[d][t][p].rectify(); 00299 } 00300 } 00301 } 00302 } 00303 00304 // ###################################################################### 00305 /* So things look consistent in everyone's emacs... */ 00306 /* Local Variables: */ 00307 /* indent-tabs-mode: nil */ 00308 /* End: */ 00309 00310 #endif // STEREOCHANNEL_C_DEFINED