00001 /*!@file SceneUnderstanding/CornersFeatures.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: Lior Elazary <elazary@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/plugins/SceneUnderstanding/CornersFeatures.C $ 00035 // $Id: CornersFeatures.C 13765 2010-08-06 18:56:17Z lior $ 00036 // 00037 00038 #ifndef CornersFeatures_C_DEFINED 00039 #define CornersFeatures_C_DEFINED 00040 00041 #include "plugins/SceneUnderstanding/CornersFeatures.H" 00042 00043 #include "Image/DrawOps.H" 00044 #include "Image/MathOps.H" 00045 //#include "Image/OpenCVUtil.H" 00046 #include "Image/Kernels.H" 00047 #include "Image/FilterOps.H" 00048 #include "Image/Transforms.H" 00049 #include "Image/fancynorm.H" 00050 #include "Image/Convolutions.H" 00051 #include "Image/MatrixOps.H" 00052 #include "Simulation/SimEventQueue.H" 00053 #include "GUI/DebugWin.H" 00054 #include <math.h> 00055 #include <fcntl.h> 00056 #include <limits> 00057 #include <string> 00058 00059 const ModelOptionCateg MOC_CornersFeatures = { 00060 MOC_SORTPRI_3, "CornersFeatures-Related Options" }; 00061 00062 // Used by: SimulationViewerEyeMvt 00063 const ModelOptionDef OPT_CornersFeaturesShowDebug = 00064 { MODOPT_ARG(bool), "CornersFeaturesShowDebug", &MOC_CornersFeatures, OPTEXP_CORE, 00065 "Show debug img", 00066 "corners-debug", '\0', "<true|false>", "false" }; 00067 00068 00069 //Define the inst function name 00070 SIMMODULEINSTFUNC(CornersFeatures); 00071 00072 // ###################################################################### 00073 CornersFeatures::CornersFeatures(OptionManager& mgr, const std::string& descrName, 00074 const std::string& tagName) : 00075 SimModule(mgr, descrName, tagName), 00076 SIMCALLBACK_INIT(SimEventV2Output), 00077 SIMCALLBACK_INIT(SimEventSaveOutput), 00078 SIMCALLBACK_INIT(SimEventUserInput), 00079 itsShowDebug(&OPT_CornersFeaturesShowDebug, this), 00080 itsPatchSize(20,20) 00081 { 00082 00083 initRandomNumbers(); 00084 00085 itsSOFM = new SOFM("Corners", itsPatchSize.sz(), 50,50 ); 00086 //itsSOFM->RandomWeights(); 00087 itsSOFM->ReadNet("SOFM.net"); 00088 00089 } 00090 00091 00092 // ###################################################################### 00093 CornersFeatures::~CornersFeatures() 00094 { 00095 } 00096 00097 00098 // ###################################################################### 00099 void CornersFeatures::onSimEventV2Output(SimEventQueue& q, 00100 rutz::shared_ptr<SimEventV2Output>& e) 00101 { 00102 itsLines = e->getLines(); 00103 //itsCornersProposals = e->getCornersProposals(); 00104 evolve(q); 00105 00106 q.post(rutz::make_shared(new SimEventCornersOutput(this, itsCorners))); 00107 } 00108 00109 // ###################################################################### 00110 void CornersFeatures::onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e) 00111 { 00112 if (itsShowDebug.getVal()) 00113 { 00114 // get the OFS to save to, assuming sinfo is of type 00115 // SimModuleSaveInfo (will throw a fatal exception otherwise): 00116 nub::ref<FrameOstream> ofs = 00117 dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs; 00118 Layout<PixRGB<byte> > disp = getDebugImage(q); 00119 ofs->writeRgbLayout(disp, "CornersFeatures", FrameInfo("CornersFeatures", SRC_POS)); 00120 } 00121 } 00122 00123 // ###################################################################### 00124 void CornersFeatures::onSimEventUserInput(SimEventQueue& q, rutz::shared_ptr<SimEventUserInput>& e) 00125 { 00126 00127 LINFO("Got event %s %ix%i key=%i", 00128 e->getWinName(), 00129 e->getMouseClick().i, 00130 e->getMouseClick().j, 00131 e->getKey()); 00132 00133 if (e->getMouseClick().isValid()) 00134 { 00135 } 00136 00137 //evolve(q); 00138 00139 } 00140 00141 std::vector<CornersFeatures::CornerState> CornersFeatures::getCorners(std::vector<V2::LineSegment>& lines) 00142 { 00143 std::vector<CornersFeatures::CornerState> corners; 00144 float minDist = 5; 00145 float minDistSq = minDist*minDist; 00146 00147 //Image<float> edges(320, 240, ZEROS); 00148 //for(uint i=0; i<lines.size(); i++) 00149 //{ 00150 // V2::LineSegment& ls1 = itsLines[i]; 00151 // drawLine(edges, Point2D<int>(ls1.p1), Point2D<int>(ls1.p2), 255.0F); 00152 //} 00153 00154 00155 for(uint i=0; i<lines.size(); i++) 00156 { 00157 V2::LineSegment& ls1 = itsLines[i]; 00158 00159 //Image<PixRGB<byte> > tmp(320,240,ZEROS); // = edges; 00160 //drawLine(tmp, Point2D<int>(ls1.p1), Point2D<int>(ls1.p2), PixRGB<byte>(255,0,0)); 00161 00162 std::vector<float> angles1; //The angles from p1 prospective 00163 std::vector<float> angles2; //the angles from p2 prospective 00164 double dx = ls1.p2.i - ls1.p1.i; 00165 double dy = ls1.p2.j - ls1.p1.j; 00166 double ang = atan2(dx, dy) + M_PI/2; 00167 angles1.push_back(ang); 00168 angles2.push_back(ang+M_PI); 00169 00170 for(uint j=i+1; j<lines.size(); j++) 00171 { 00172 if (i == j) 00173 continue; 00174 V2::LineSegment& ls2 = itsLines[j]; 00175 00176 //Find if line segment i p1 intesect line segment j, and find the angle betwwen this 00177 //point and the reset of the ends 00178 if (ls1.p1.distanceToSegment(ls2.p1, ls2.p2) < minDist) 00179 { 00180 double dx1 = ls2.p1.i - ls1.p1.i; 00181 double dy1 = ls2.p1.j - ls1.p1.j; 00182 00183 double dx2 = ls2.p2.i - ls1.p1.i; 00184 double dy2 = ls2.p2.j - ls1.p1.j; 00185 00186 //If we intresected on a line then add both ends 00187 if ( (dx1*dx1 + dy1*dy1) > minDistSq) //p1 is further 00188 angles1.push_back(atan2(dx1, dy1) + M_PI/2); 00189 00190 if ( (dx2*dx2 + dy2*dy2) > minDistSq) //p2 is further 00191 angles1.push_back(atan2(dx2, dy2) + M_PI/2); 00192 } 00193 00194 00195 //Do the same for p2 in line segment i 00196 if (ls1.p2.distanceToSegment(ls2.p1, ls2.p2) < minDist) 00197 { 00198 double dx1 = ls2.p1.i - ls1.p2.i; 00199 double dy1 = ls2.p1.j - ls1.p2.j; 00200 00201 double dx2 = ls2.p2.i - ls1.p2.i; 00202 double dy2 = ls2.p2.j - ls1.p2.j; 00203 00204 //If we intresected on a line then add both ends 00205 if ( (dx1*dx1 + dy1*dy1) > minDistSq) //p1 is further 00206 angles2.push_back(atan2(dx1, dy1) + M_PI/2); 00207 00208 if ( (dx2*dx2 + dy2*dy2) > minDistSq) //p2 is further 00209 angles2.push_back(atan2(dx2, dy2) + M_PI/2); 00210 00211 } 00212 } 00213 00214 //Add the two corners 00215 00216 CornerState c1; 00217 c1.center = ls1.p1; 00218 c1.angles = angles1; 00219 corners.push_back(c1); 00220 00221 CornerState c2; 00222 c2.center = ls1.p2; 00223 c2.angles = angles2; 00224 corners.push_back(c2); 00225 00226 00227 00228 } 00229 00230 00231 return corners; 00232 00233 } 00234 00235 // ###################################################################### 00236 void CornersFeatures::evolve(SimEventQueue& q) 00237 { 00238 00239 //Find corners from lines end points; 00240 00241 00242 std::vector<CornerState> corners = getCorners(itsLines); 00243 00244 itsCorners = corners; 00245 00246 //Add to corners db 00247 //////////////////////////////////////// 00248 00249 //for(uint i=0; i<corners.size(); i++) 00250 //{ 00251 // CornerState& cs = corners[i]; 00252 // //Find the nearest corner in the db 00253 // // and update the prob 00254 // // 00255 // std::vector<GaussianDef> gmmF; 00256 // double weight = 1.0/double(cs.angles.size()); //equal weight 00257 // for(uint i=0; i<cs.angles.size(); i++) 00258 // gmmF.push_back(GaussianDef(weight, cs.angles[i], 1*M_PI/180)); //1 deg variance 00259 00260 // bool found = false; 00261 // for(uint j=0; j<itsCornersDB.size(); j++) 00262 // { 00263 // CornerState& dbcs = itsCornersDB[j]; 00264 00265 // std::vector<GaussianDef> gmmG; 00266 // double weight = 1.0/double(dbcs.angles.size()); //equal weight 00267 // for(uint i=0; i<dbcs.angles.size(); i++) 00268 // gmmG.push_back(GaussianDef(weight, dbcs.angles[i], 1*M_PI/180)); //1 deg variance 00269 00270 // double dist = L2GMM(gmmF, gmmG); 00271 00272 // if (dist < 2) 00273 // { 00274 // //Found it 00275 // dbcs.prob++; 00276 // found = true; 00277 // break; 00278 // } 00279 00280 // } 00281 00282 // if (!found) 00283 // itsCornersDB.push_back(cs); //add it to the db 00284 //} 00285 00286 00287 ////Write out the corners db 00288 //FILE *fp = fopen("corners.dat", "w"); 00289 00290 //for(uint i=0; i<itsCornersDB.size(); i++) 00291 //{ 00292 // CornerState& dbcs = itsCornersDB[i]; 00293 // for(uint j=0; j<dbcs.angles.size(); j++) 00294 // fprintf(fp," %f", dbcs.angles[j]); 00295 // fprintf(fp," %f\n", dbcs.prob); 00296 //} 00297 //fclose(fp); 00298 00299 00300 00301 00302 //////////////////////////////////////// 00303 00304 //Sample from the cor 00305 //Image<float> tmp=itsCornersProposals; 00306 //inplaceNormalize(itsCornersProposals, 0.0F, 100.0F); 00307 00308 //inplaceNormalize(itsEdges, 0.0F, 255.0F); 00309 00310 //itsCorners.clear(); 00311 00312 //int radius = 10; 00313 //for(int i=0; i<20; i++) 00314 //{ 00315 // Point2D<int> maxLoc; float maxVal; 00316 // findMax(tmp, maxLoc, maxVal); 00317 00318 // Point2D<int> tl(maxLoc.i-(itsPatchSize.w()/2), maxLoc.j-(itsPatchSize.h()/2)); 00319 00320 // if (itsEdges.coordsOk(tl) && 00321 // itsEdges.coordsOk(tl.i+itsPatchSize.w(), tl.j+itsPatchSize.h())) 00322 // { 00323 // Image<float> patch = crop(itsEdges, tl, itsPatchSize); 00324 00325 // itsSOFM->setInput(patch); 00326 // itsSOFM->Propagate(); 00327 00328 // double winnerVal; 00329 // Point2D<int> winnerId = itsSOFM->getWinner(winnerVal); 00330 // //LINFO("WinnerVal %e\n", winnerVal); 00331 00332 00333 // Image<float> learnedPatch(patch.getDims(), NO_INIT); 00334 // std::vector<float> weights = itsSOFM->getWeights(winnerId); 00335 // for(uint i=0; i<weights.size(); i++) 00336 // learnedPatch[i] = weights[i]; 00337 00338 // //Only organize if we have not learned this patch 00339 // //if (winnerVal > 1) 00340 // // itsSOFM->organize(patch); 00341 00342 // CornerState cs; 00343 // cs.id = winnerId; 00344 // cs.patch = patch; 00345 // cs.learnedPatch = learnedPatch; 00346 // cs.loc = maxLoc; 00347 // cs.prob = 0; 00348 // itsCorners.push_back(cs); 00349 // } 00350 // //Apply IOR 00351 // drawDisk(tmp, maxLoc, radius, 0.0f); 00352 //} 00353 00354 //itsSOFMMap = itsSOFM->getWeightsImage(); 00355 00356 //itsSOFM->WriteNet("SOFM.net"); 00357 00358 } 00359 00360 00361 Layout<PixRGB<byte> > CornersFeatures::getDebugImage(SimEventQueue& q) 00362 { 00363 Layout<PixRGB<byte> > outDisp; 00364 00365 Image<PixRGB<byte> > cornersImg(320, 240, ZEROS); 00366 for(uint i=0; i<itsCorners.size(); i++) 00367 { 00368 for(uint ai=0; ai<itsCorners[i].angles.size(); ai++) 00369 { 00370 int x1 = int(cos(itsCorners[i].angles[ai])*30.0/2.0); 00371 int y1 = int(sin(itsCorners[i].angles[ai])*30.0/2.0); 00372 Point2D<float> p1(itsCorners[i].center.i-x1, itsCorners[i].center.j+y1); 00373 00374 drawLine(cornersImg, Point2D<int>(itsCorners[i].center), Point2D<int>(p1), PixRGB<byte>(0,255,0)); 00375 } 00376 } 00377 00378 outDisp = cornersImg; 00379 00380 return outDisp; 00381 00382 } 00383 00384 // ###################################################################### 00385 /* So things look consistent in everyone's emacs... */ 00386 /* Local Variables: */ 00387 /* indent-tabs-mode: nil */ 00388 /* End: */ 00389 00390 #endif 00391