VisualEvent.C

Go to the documentation of this file.
00001 /*!@file MBARI/VisualEvent.C classes useful for event tracking */
00002 
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00004 // by the University of Southern California (USC) and the iLab at USC.  //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Dirk Walther <walther@caltech.edu>
00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/MBARI/VisualEvent.C $
00034 // $Id: VisualEvent.C 9412 2008-03-10 23:10:15Z farhan $
00035 //
00036 
00037 #include "MBARI/VisualEvent.H"
00038 
00039 #include "Image/DrawOps.H"
00040 #include "Image/Image.H"
00041 #include "Image/Pixels.H"
00042 #include "Image/Rectangle.H"
00043 #include "Image/ShapeOps.H"
00044 #include "Image/Transforms.H"
00045 #include "Image/colorDefs.H"
00046 #include "MBARI/Geometry2D.H"
00047 #include "MBARI/mbariFunctions.H"
00048 #include "Util/Assert.H"
00049 #include "Util/StringConversions.H"
00050 
00051 #include <algorithm>
00052 #include <istream>
00053 #include <ostream>
00054 
00055 // ######################################################################
00056 // ###### Token
00057 // ######################################################################
00058 Token::Token()
00059   : bitObject(),
00060     location(),
00061     prediction(),
00062     line(),
00063     angle(0.0F),
00064     frame_nr(0)
00065 {}
00066 
00067 // ######################################################################
00068 Token::Token (float x, float y, uint frame, BitObject bo)
00069   : bitObject(bo),
00070     location(x,y),
00071     prediction(),
00072     line(),
00073     angle(0.0F),
00074     frame_nr(frame)
00075 {}
00076 
00077 // ######################################################################
00078 Token::Token (BitObject bo, uint frame)
00079   : bitObject(bo),
00080     location(bo.getCentroidXY()),
00081     prediction(),
00082     line(),
00083     angle(0.0F),
00084     frame_nr(frame)
00085 {}
00086 
00087 // ######################################################################
00088 Token::Token (std::istream& is)
00089 {
00090   readFromStream(is);
00091 }
00092 
00093 // ######################################################################
00094 void Token::writeToStream(std::ostream& os) const
00095 {
00096   os << frame_nr << ' ';
00097   location.writeToStream(os);
00098   prediction.writeToStream(os);
00099   line.writeToStream(os);
00100   os << angle << '\n';
00101   bitObject.writeToStream(os);
00102   os << "\n";
00103 }
00104 
00105 // ######################################################################
00106 void Token::readFromStream(std::istream& is)
00107 {
00108   is >> frame_nr;
00109   location.readFromStream(is);
00110   prediction.readFromStream(is);
00111   line.readFromStream(is);
00112   is >> angle;
00113   bitObject = BitObject(is);
00114 }
00115 
00116 // ######################################################################
00117 void Token::writePosition(std::ostream& os) const
00118 {
00119   location.writeToStream(os);
00120 }
00121 
00122 
00123 // ######################################################################
00124 // ####### PropertyVectorSet
00125 // ######################################################################
00126 PropertyVectorSet::PropertyVectorSet()
00127 {}
00128 
00129 // ######################################################################
00130 PropertyVectorSet::PropertyVectorSet(std::istream& is)
00131 {
00132   readFromStream(is);
00133 }
00134 
00135 // ######################################################################
00136 void PropertyVectorSet::writeToStream(std::ostream& os) const
00137 {
00138   uint s2;
00139   if (itsVectors.empty()) s2 = 0;
00140   else s2 = itsVectors.front().size();
00141 
00142   os << itsVectors.size() << " " << s2 << "\n";
00143 
00144   for (uint i = 0; i < itsVectors.size(); ++i)
00145     {
00146       for (uint j = 0; j < s2; ++j)
00147         os << itsVectors[i][j] << " ";
00148 
00149       os << "\n";
00150     }
00151 }
00152 
00153 // ######################################################################
00154 void PropertyVectorSet::readFromStream(std::istream& is)
00155 {
00156   uint s1, s2;
00157   is >> s1; is >> s2;
00158   itsVectors = std::vector< std::vector<float> > (s1, std::vector<float>(s2));
00159 
00160   for (uint i = 0; i < s1; ++i)
00161     for (uint j = 0; j < s2; ++j)
00162       is >> itsVectors[i][j];
00163 }
00164 
00165 // ######################################################################
00166 std::vector<float> PropertyVectorSet::getPropertyVectorForEvent(const int num)
00167 {
00168   for (uint i = 0; i < itsVectors.size(); ++i)
00169     if ((int)(itsVectors[i][0]) == num) return itsVectors[i];
00170 
00171   LFATAL("property vector for event number %d not found!", num);
00172   return std::vector<float>();
00173 }
00174 
00175 // ######################################################################
00176 // ####### VisualEvent
00177 // ######################################################################
00178 VisualEvent::VisualEvent(Token tk, int maxDist)
00179   : startframe(tk.frame_nr),
00180     endframe(tk.frame_nr),
00181     max_size(tk.bitObject.getArea()),
00182     maxsize_framenr(tk.frame_nr),
00183     closed(false),
00184     itsMaxDist(maxDist),
00185     xTracker(tk.location.x(),0.1F,10.0F),
00186     yTracker(tk.location.y(),0.1F,10.0F)
00187 {
00188   LINFO("tk.location = (%g, %g); area: %i",tk.location.x(),tk.location.y(),
00189         tk.bitObject.getArea());
00190   tokens.push_back(tk);
00191   ++counter;
00192   myNum = counter;
00193 }
00194 // initialize static variable
00195 uint VisualEvent::counter = 0;
00196 
00197 // ######################################################################
00198 VisualEvent::VisualEvent(std::istream& is)
00199 {
00200   readFromStream(is);
00201 }
00202 
00203 // ######################################################################
00204 void VisualEvent::writeToStream(std::ostream& os) const
00205 {
00206   os << myNum << " " << startframe << " " << endframe << "\n";
00207   os << max_size << " " << maxsize_framenr << "\n";
00208 
00209   if (closed) os << "1\n";
00210   else os << "0\n";
00211 
00212   os << itsMaxDist << "\n";
00213 
00214   xTracker.writeToStream(os);
00215   yTracker.writeToStream(os);
00216 
00217   os << tokens.size() << "\n";
00218 
00219   for (uint i = 0; i < tokens.size(); ++i)
00220     tokens[i].writeToStream(os);
00221 
00222   os << "\n";
00223 }
00224 
00225 // ######################################################################
00226 void VisualEvent::readFromStream(std::istream& is)
00227 {
00228   is >> myNum;
00229   is >> startframe;
00230   is >> endframe;
00231   is >> max_size;
00232   is >> maxsize_framenr;
00233 
00234   int n; is >> n;
00235   closed = (n == 1);
00236 
00237   is >> itsMaxDist;
00238 
00239   xTracker.readFromStream(is);
00240   yTracker.readFromStream(is);
00241 
00242   int t;
00243   is >> t;
00244   tokens.clear();
00245   for (int i = 0; i < t; ++i)
00246     tokens.push_back(Token(is));
00247 }
00248 
00249 // ######################################################################
00250 void VisualEvent::writePositions(std::ostream& os) const
00251 {
00252   for (uint i = 0; i < tokens.size(); ++i)
00253     tokens[i].writePosition(os);
00254 
00255   os << "\n";
00256 }
00257 
00258 // ######################################################################
00259 Point2D<int> VisualEvent::predictedLocation() const
00260 {
00261   int x = int(xTracker.getEstimate() + 0.5F);
00262   int y = int(yTracker.getEstimate() + 0.5F);
00263   return Point2D<int>(x,y);
00264 }
00265 
00266 // ######################################################################
00267 bool VisualEvent::isTokenOk(const Token& tk) const
00268 {
00269   return ((tk.frame_nr - endframe) == 1) && !closed;
00270 }
00271 
00272 // ######################################################################
00273 float VisualEvent::getCost(const Token& tk) const
00274 {
00275   if (!isTokenOk(tk)) return -1.0F;
00276 
00277   float cost = (xTracker.getCost(tk.location.x()) +
00278                 yTracker.getCost(tk.location.y()));
00279 
00280   LINFO("Event no. %i; obj location: %g, %g; predicted location: %g, %g; cost: %g",
00281         myNum, tk.location.x(), tk.location.y(), xTracker.getEstimate(),
00282         yTracker.getEstimate(), cost);
00283   return cost;
00284 }
00285 
00286 // ######################################################################
00287 void VisualEvent::assign(const Token& tk, const Vector2D& foe)
00288 {
00289   ASSERT(isTokenOk(tk));
00290 
00291   tokens.push_back(tk);
00292 
00293   tokens.back().prediction = Vector2D(xTracker.getEstimate(),
00294                                       yTracker.getEstimate());
00295   tokens.back().location = Vector2D(xTracker.update(tk.location.x()),
00296                                     yTracker.update(tk.location.y()));
00297 
00298   // update the straight line
00299   //Vector2D dir(xTracker.getSpeed(), yTracker.getSpeed());
00300   Vector2D dir = tokens.front().location - tokens.back().location;
00301   tokens.back().line.reset(tokens.back().location, dir);
00302 
00303   if (foe.isValid())
00304     tokens.back().angle = dir.angle(tokens.back().location - foe);
00305   else
00306     tokens.back().angle = 0.0F;
00307 
00308   if (tk.bitObject.getArea() > max_size)
00309     {
00310       max_size = tk.bitObject.getArea();
00311       maxsize_framenr = tk.frame_nr;
00312     }
00313   endframe = tk.frame_nr;
00314 }
00315 
00316 // ######################################################################
00317 bool VisualEvent::doesIntersect(const BitObject& obj, int frameNum) const
00318 {
00319   if (!isFrameOk(frameNum)) return false;
00320   else return getToken(frameNum).bitObject.doesIntersect(obj);
00321 }
00322 
00323 
00324 // ######################################################################
00325 std::vector<float>  VisualEvent::getPropertyVector()
00326 {
00327   std::vector<float> vec;
00328   Token tk = getMaxSizeToken();
00329   BitObject bo = tk.bitObject;
00330 
00331   // 0 - event number
00332   vec.push_back(getEventNum());
00333 
00334   // 1 - interesting value
00335   vec.push_back(-1);
00336 
00337   // not valid?
00338   if (!bo.isValid())
00339     {
00340       // 2  - set area to -1
00341       vec.push_back(-1);
00342 
00343       // 3-12 set everyone to 0
00344       for (uint i = 3; i <= 12; ++i)
00345         vec.push_back(0);
00346 
00347       // done
00348       return vec;
00349     }
00350 
00351   // we're valid
00352 
00353   // 2 - area
00354   vec.push_back(bo.getArea());
00355 
00356   // 3, 4, 5 - uxx, uyy, uxy
00357   float uxx, uyy, uxy;
00358   bo.getSecondMoments(uxx, uyy, uxy);
00359   vec.push_back(uxx);
00360   vec.push_back(uyy);
00361   vec.push_back(uxy);
00362 
00363   // 6 - major axis
00364   vec.push_back(bo.getMajorAxis());
00365 
00366   // 7 - minor axis
00367   vec.push_back(bo.getMinorAxis());
00368 
00369   // 8 - elongation
00370   vec.push_back(bo.getElongation());
00371 
00372   // 9 - orientation angle
00373   vec.push_back(bo.getOriAngle());
00374 
00375   // 10, 11, 12 - max, min, avg intensity
00376   float maxIntens,minIntens,avgIntens;
00377   bo.getMaxMinAvgIntensity(maxIntens, minIntens, avgIntens);
00378   vec.push_back(maxIntens);
00379   vec.push_back(minIntens);
00380   vec.push_back(avgIntens);
00381 
00382   // 13 - angle with respect to expansion
00383   vec.push_back(tk.angle);
00384 
00385   // done -> return the vector
00386   return vec;
00387  }
00388 
00389 // ######################################################################
00390 Dims VisualEvent::getMaxObjectDims() const
00391 {
00392   int w = -1, h = -1;
00393   std::vector<Token>::const_iterator t;
00394   for (t = tokens.begin(); t != tokens.end(); ++t)
00395     {
00396       Dims d = t->bitObject.getObjectDims();
00397       w = std::max(w, d.w());
00398       h = std::max(h, d.h());
00399     }
00400   return Dims(w,h);
00401 }
00402 
00403 // ######################################################################
00404 // ###### VisualEventSet
00405 // ######################################################################
00406 VisualEventSet::VisualEventSet(const int maxDist,
00407                                const uint minFrameNum,
00408                                const int minSize,
00409                                const std::string& fileName)
00410   : itsMaxDist(maxDist),
00411     itsMinFrameNum(minFrameNum),
00412     itsMinSize(minSize),
00413     startframe(-1),
00414     endframe(-1),
00415     itsFileName(fileName)
00416 {
00417   float maxAreaDiff = maxDist * maxDist / 4.0F;
00418   itsMaxCost = maxDist * maxDist + maxAreaDiff * maxAreaDiff;
00419 }
00420 
00421 // ######################################################################
00422 VisualEventSet::VisualEventSet(std::istream& is)
00423 {
00424   readFromStream(is);
00425 }
00426 
00427 // ######################################################################
00428 void VisualEventSet::writeToStream(std::ostream& os) const
00429 {
00430   os << itsFileName << "\n";
00431   os << itsMaxDist << " "
00432      << itsMaxCost << " "
00433      << itsMinFrameNum << " "
00434      << itsMinSize << "\n";
00435   os << startframe << ' ' << endframe << '\n';
00436 
00437   os << itsEvents.size() << "\n";
00438   std::list<VisualEvent>::const_iterator currEvent;
00439   for (currEvent = itsEvents.begin(); currEvent != itsEvents.end(); ++currEvent)
00440     currEvent->writeToStream(os);
00441 
00442   os << itsFOE.size() << '\n';
00443   for (uint i = 0; i < itsFOE.size(); ++i)
00444     itsFOE[i].writeToStream(os);
00445 
00446   os << "\n";
00447 }
00448 
00449 // ######################################################################
00450 void VisualEventSet::readFromStream(std::istream& is)
00451 {
00452   is >> itsFileName; LINFO("filename: %s",itsFileName.c_str());
00453   is >> itsMaxDist;
00454   is >> itsMaxCost;
00455   is >> itsMinFrameNum;
00456   is >> itsMinSize;
00457   is >> startframe;
00458   is >> endframe;
00459 
00460   int n; is >> n;
00461   itsEvents.clear();
00462   for (int i = 0; i < n; ++i)
00463     itsEvents.push_back(VisualEvent(is));
00464 
00465   is >> n;
00466   itsFOE.clear();
00467   for (int i = 0; i < n; ++i)
00468     itsFOE.push_back(Vector2D(is));
00469 }
00470 
00471 // ######################################################################
00472 void VisualEventSet::writePositions(std::ostream& os) const
00473 {
00474   std::list<VisualEvent>::const_iterator currEvent;
00475   for (currEvent = itsEvents.begin(); currEvent != itsEvents.end(); ++currEvent)
00476     currEvent->writePositions(os);
00477 }
00478 
00479 // ######################################################################
00480 void VisualEventSet::updateEvents(const Image<byte>& binMap,
00481                                   const Vector2D& curFOE,
00482                                   int frameNum)
00483 {
00484   if (startframe == -1) {startframe = frameNum; endframe = frameNum;}
00485   ASSERT((frameNum == endframe) || (frameNum == endframe+1));
00486   if (frameNum > endframe) endframe = frameNum;
00487 
00488   itsFOE.push_back(curFOE);
00489 
00490   std::list<VisualEvent>::iterator currEvent;
00491   for (currEvent = itsEvents.begin(); currEvent != itsEvents.end(); ++currEvent)
00492     {
00493       if (currEvent->isClosed()) continue;
00494 
00495       // get the predicted location
00496       Point2D<int> pred = currEvent->predictedLocation();
00497 
00498       // is the prediction too far outside the image?
00499       //int gone = itsMaxDist / 2;
00500       int gone = 0;
00501       if ((pred.i < -gone) || (pred.i >= (binMap.getWidth() + gone)) ||
00502           (pred.j < -gone) || (pred.j >= (binMap.getHeight() + gone)))
00503         {
00504           currEvent->close();
00505           LINFO("Event %i out of bounds - closed",currEvent->getEventNum());
00506           continue;
00507         }
00508 
00509       // get the region used for searching for a match
00510       Rectangle region =
00511         Rectangle::tlbrI(pred.j - itsMaxDist, pred.i - itsMaxDist,
00512                         pred.j + itsMaxDist, pred.i + itsMaxDist);
00513       region = region.getOverlap(binMap.getBounds());
00514 
00515       // extract all the BitObjects from the region
00516       std::list<BitObject> objs = extractBitObjects(binMap, region, itsMinSize);
00517       //LINFO("pred. location: %s; region: %s; Number of extracted objects: %i",
00518       //    toStr(pred).c_str(),toStr(region).c_str(),objs.size());
00519 
00520       // now look which one fits best
00521       float lCost = -1.0F;
00522       std::list<BitObject>::iterator cObj, lObj = objs.end();
00523       for (cObj = objs.begin(); cObj != objs.end(); ++cObj)
00524         {
00525           if (doesIntersect(*cObj, frameNum)) continue;
00526 
00527           float cost = currEvent->getCost(Token(*cObj,frameNum));
00528 
00529           //LINFO("Event no. %i; cost: %g; lowest cost: %g",currEvent->getEventNum(),
00530           //    cost, lCost);
00531          if (cost < 0.0F) continue;
00532          if ((lCost == -1.0F) || (cost < lCost))
00533            {
00534              lCost = cost;
00535              lObj = cObj;
00536              //LINFO("best cost: %g",lCost);
00537            }
00538         }
00539 
00540       // cost too high no fitting object found? -> close event
00541       if ((lCost > itsMaxCost) || (lCost == -1.0))
00542         {
00543           currEvent->close();
00544           LINFO("Event %i - no token found, closing event",
00545                 currEvent->getEventNum());
00546         }
00547       else
00548         {
00549           // associate the best fitting guy
00550           Token tk(*lObj, frameNum);
00551           currEvent->assign(tk, curFOE);
00552 
00553           LINFO("Event %i - token found at %g, %g",currEvent->getEventNum(),
00554                 currEvent->getToken(frameNum).location.x(),
00555                 currEvent->getToken(frameNum).location.y());
00556         }
00557     }
00558 }
00559 
00560 // ######################################################################
00561 void VisualEventSet::initiateEvents(std::list<BitObject>& bos, int frameNum)
00562 {
00563   if (startframe == -1) {startframe = frameNum; endframe = frameNum;}
00564   ASSERT((frameNum == endframe) || (frameNum == endframe+1));
00565   if (frameNum > endframe) endframe = frameNum;
00566 
00567   std::list<BitObject>::iterator currObj;
00568 
00569   // loop over the BitObjects
00570   currObj = bos.begin();
00571   while(currObj != bos.end())
00572     {
00573       // is there an intersection with an event?
00574       if (doesIntersect(*currObj, frameNum))
00575         {
00576           //LINFO("Object at %g, %g intersects with event %i, erasing the object",
00577           //    currObj->getCentroidX(), currObj->getCentroidY(),
00578           //    currEvent->getEventNum());
00579           currObj = bos.erase(currObj);
00580         }
00581       else
00582         {
00583           //LINFO("Object at %g, %g does not intersect with event %i",
00584           //currObj->getCentroidX(), currObj->getCentroidY(),
00585           //currEvent->getEventNum());
00586           ++currObj;
00587         }
00588     }
00589 
00590   // now go through all the remaining BitObjects and create new events for them
00591   for (currObj = bos.begin(); currObj != bos.end(); ++currObj)
00592     {
00593       itsEvents.push_back(VisualEvent(Token(*currObj, frameNum), itsMaxDist));
00594       LINFO("assigning object of area: %i to new event %i",currObj->getArea(),
00595             itsEvents.back().getEventNum());
00596     }
00597 }
00598 
00599 // ######################################################################
00600 bool VisualEventSet::doesIntersect(const BitObject& obj, int frameNum) const
00601 {
00602   std::list<VisualEvent>::const_iterator cEv;
00603   for (cEv = itsEvents.begin(); cEv != itsEvents.end(); ++cEv)
00604     if (cEv->doesIntersect(obj,frameNum)) return true;
00605 
00606   return false;
00607 }
00608 
00609 /*
00610 // ######################################################################
00611 Vector2D VisualEventSet::updateFOE()
00612 {
00613   const uint minTrackFrames = 3;
00614   std::vector<StraightLine2D> lines;
00615   std::vector<std::list<VisualEvent>::iterator> events =
00616     getEventsForFrame(endframe);
00617 
00618   // go through all the events and extract the straight lines
00619   for (uint i = 0; i < events.size(); ++i)
00620     {
00621       // must have at least minTrackFrames points until here
00622       if ((endframe - events[i]->getStartFrame() + 1) >= minTrackFrames)
00623         {
00624           StraightLine2D l = events[i]->getToken(endframe).line;
00625           if (l.isValid()) lines.push_back(l);
00626         }
00627     }
00628 
00629   // get all the intersection points of the straight lines
00630   std::vector<float> xCoords, yCoords;
00631   for (uint i = 0; i < lines.size(); ++i)
00632     for (uint j = 0; j < lines.size(); ++j)
00633       {
00634         if (i == j) continue;
00635         float n,m;
00636         Vector2D inter = lines[i].intersect(lines[j],n,m);
00637         if (inter.isValid())
00638           {
00639             xCoords.push_back(inter.x());
00640             yCoords.push_back(inter.y());
00641           }
00642       }
00643 
00644   // update the FOE
00645   Vector2D currFOE;
00646 
00647   if (xCoords.empty())
00648     {
00649       //itsFOE.push_back(Vector2D());
00650     }
00651   else
00652     {
00653 
00654       // this is all for taking the median
00655       // sort xCoords and yCoords
00656       //std::sort(xCoords.begin(),xCoords.end());
00657       //std::sort(yCoords.begin(),yCoords.end());
00658 
00659       // take the median to be the FOE
00660       //currFOE = Vector2D(xCoords[int(xCoords.size()/2)],
00661       //           yCoords[int(yCoords.size()/2)]);
00662 
00663       // compute the mean of x and y
00664       float sumX = 0.0F, sumY = 0.0F;
00665       for (uint i = 0; i < xCoords.size(); ++i)
00666         { sumX += xCoords[i]; sumY += yCoords[i]; }
00667       currFOE = Vector2D(sumX/float(xCoords.size()),
00668                          sumY/float(yCoords.size()));
00669 
00670       //if (sumFOE.isValid()) sumFOE += currFOE;
00671       //else sumFOE = currFOE;
00672       //++numFOE;
00673     }
00674 
00675   if (xFOE.isInitialized())
00676     {
00677       // update KalmanFilters with currFOE
00678       if (currFOE.isValid())
00679         itsFOE.push_back(Vector2D(xFOE.update(currFOE.x()),
00680                                   yFOE.update(currFOE.y())));
00681       else
00682         itsFOE.push_back(Vector2D(xFOE.update(), yFOE.update()));
00683     }
00684   else
00685     {
00686       if (currFOE.isValid())
00687         {
00688           // initialize KalmanFilters
00689           xFOE.init(currFOE.x(), 0.0001F, 10000.0F);
00690           yFOE.init(currFOE.y(), 0.0001F, 10000.0F);
00691         }
00692 
00693       // store currFOE
00694       itsFOE.push_back(currFOE);
00695     }
00696 
00697   //if (sumFOE.isValid()) itsFOE.push_back(sumFOE/numFOE);
00698   //else itsFOE.push_back(Vector2D());
00699 
00700   return itsFOE.back();
00701 }
00702 */
00703 
00704 // ######################################################################
00705 Vector2D VisualEventSet::getFOE(int frameNum) const
00706 {
00707 
00708   int idx = frameNum - startframe;
00709   //LINFO("frameNum = %i, startframe = %i, idx = %i, itsFOE.size() = %i",
00710   //    frameNum, startframe, idx, itsFOE.size());
00711   ASSERT((idx >= 0)&& (idx < (int)itsFOE.size()));
00712 
00713   return itsFOE[idx];
00714 }
00715 
00716 // ######################################################################
00717 uint VisualEventSet::numEvents() const
00718 {
00719   return itsEvents.size();
00720 }
00721 
00722 // ######################################################################
00723 void VisualEventSet::reset()
00724 {
00725   itsEvents.clear();
00726 }
00727 
00728 // ######################################################################
00729 void VisualEventSet::cleanUp(uint currFrame, uint maxFrameSkip)
00730 {
00731   std::list<VisualEvent>::iterator currEvent = itsEvents.begin();
00732   while (currEvent != itsEvents.end())
00733     {
00734       if (currEvent->isClosed() &&
00735           (currEvent->getNumberOfFrames() < itsMinFrameNum))
00736         {
00737           LINFO("Erasing event %i, because it has only %i frames.",
00738                 currEvent->getEventNum(), currEvent->getNumberOfFrames());
00739           currEvent = itsEvents.erase(currEvent);
00740         }
00741       else ++currEvent;
00742 
00743     } // end while loop over events
00744 }
00745 
00746 // ######################################################################
00747 void VisualEventSet::closeAll()
00748 {
00749   std::list<VisualEvent>::iterator cEvent;
00750   for (cEvent = itsEvents.begin(); cEvent != itsEvents.end(); ++cEvent)
00751     cEvent->close();
00752 }
00753 
00754 // ######################################################################
00755 std::vector<Token> VisualEventSet::getTokens(uint frameNum)
00756 {
00757   std::vector<Token> tokens;
00758   std::list<VisualEvent>::iterator currEvent;
00759   for (currEvent = itsEvents.begin(); currEvent != itsEvents.end(); ++currEvent)
00760     {
00761       // does this guy participate in frameNum?
00762       if (!currEvent->isFrameOk(frameNum)) continue;
00763 
00764       tokens.push_back(currEvent->getToken(frameNum));
00765     } // end loop over events
00766 
00767   return tokens;
00768 }
00769 
00770 // ######################################################################
00771 void VisualEventSet::drawTokens(Image< PixRGB<byte> >& img,
00772                                 uint frameNum,
00773                                 PropertyVectorSet& pvs,
00774                                 int circleRadius,
00775                                 BitObjectDrawMode mode,
00776                                 float opacity,
00777                                 PixRGB<byte> colorInteresting,
00778                                 PixRGB<byte> colorCandidate,
00779                                 PixRGB<byte> colorPred,
00780                                 PixRGB<byte> colorFOE,
00781                                 bool showEventLabels)
00782 {
00783   // dimensions of the number text and location to put it at
00784   const int numW = 10;
00785   const int numH = 21;
00786 
00787   std::list<VisualEvent>::iterator currEvent;
00788   for (currEvent = itsEvents.begin(); currEvent != itsEvents.end(); ++currEvent)
00789     {
00790       // does this guy participate in frameNum?
00791       if (!currEvent->isFrameOk(frameNum)) continue;
00792 
00793       PixRGB<byte> circleColor;
00794       Token tk = currEvent->getToken(frameNum);
00795       Point2D<int> center = tk.location.getPoint2D();
00796 
00797       if (isEventInteresting(pvs.getPropertyVectorForEvent
00798                              (currEvent->getEventNum())))
00799         circleColor = colorInteresting;
00800       else
00801         circleColor = colorCandidate;
00802 
00803       // if requested, prepare the event labels
00804       Image< PixRGB<byte> > textImg;
00805       if (showEventLabels)
00806         {
00807           // write the text and create the overlay image
00808           std::string numText = toStr(currEvent->getEventNum());
00809           textImg.resize(numW * numText.length(), numH, NO_INIT);
00810           textImg.clear(COL_WHITE);
00811           writeText(textImg, Point2D<int>(0,0), numText.c_str());
00812         }
00813 
00814       // draw the event object itself if requested
00815       if (circleColor != COL_TRANSPARENT)
00816         {
00817           // the box so that the text knows where to go
00818           Rectangle bbox;
00819 
00820           // draw rectangle or circle and determine the pos of the number label
00821           if (tk.bitObject.isValid())
00822             {
00823               tk.bitObject.draw(mode, img, circleColor, opacity);
00824               bbox = tk.bitObject.getBoundingBox(BitObject::IMAGE);
00825               //drawRect(img, bbox,circleColor);
00826             }
00827           else
00828             {
00829               LINFO("BitObject is invalid: area: %i;",tk.bitObject.getArea());
00830               LFATAL("bounding box: %s",toStr(tk.bitObject.getBoundingBox()).c_str());
00831               drawCircle(img, center, circleRadius, circleColor);
00832               bbox = Rectangle::tlbrI(center.j - circleRadius, center.i - circleRadius,
00833                                center.j + circleRadius, center.i + circleRadius);
00834               bbox = bbox.getOverlap(img.getBounds());
00835             }
00836 
00837           // if requested, write the event labels into the image
00838           if (showEventLabels)
00839             {
00840               Point2D<int> numLoc = getLabelPosition(img.getDims(),bbox,textImg.getDims());
00841               Image<PixRGB <byte> > textImg2 = replaceVals(textImg,COL_BLACK,circleColor);
00842               textImg2 = replaceVals(textImg2,COL_WHITE,COL_TRANSPARENT);
00843               pasteImage(img,textImg2,COL_TRANSPARENT, numLoc, opacity);
00844 
00845             } // end if (showEventLabels)
00846 
00847         } // end if we're not transparent
00848 
00849       // now do the same for the predicted value
00850       if ((colorPred != COL_TRANSPARENT) && tk.prediction.isValid())
00851         {
00852           Point2D<int> ctr = tk.prediction.getPoint2D();
00853           drawCircle(img, ctr,10,colorPred);
00854           Rectangle ebox =
00855             Rectangle::tlbrI(ctr.j - 10, ctr.i - 10, ctr.j + 10, ctr.i + 10);
00856           ebox = ebox.getOverlap(img.getBounds());
00857           if (showEventLabels)
00858             {
00859               Point2D<int> numLoc = getLabelPosition(img.getDims(), ebox, textImg.getDims());
00860               Image< PixRGB<byte> > textImg2 = replaceVals(textImg,COL_BLACK,colorPred);
00861               textImg2 = replaceVals(textImg2,COL_WHITE,COL_TRANSPARENT);
00862               pasteImage(img,textImg2,COL_TRANSPARENT, numLoc, opacity);
00863             }
00864         }
00865 
00866     } // end loop over events
00867 
00868   // draw the focus of expansion
00869   if ((colorFOE != COL_TRANSPARENT) && getFOE(frameNum).isValid())
00870     {
00871       Point2D<int> ctr = getFOE(frameNum).getPoint2D();
00872       drawDisk(img, ctr,2,colorFOE);
00873     }
00874 
00875 }
00876 
00877 // ######################################################################
00878 Point2D<int> VisualEventSet::getLabelPosition(Dims imgDims,
00879                                          Rectangle bbox,
00880                                          Dims textDims) const
00881 {
00882   // distance of the text label from the bbox
00883   const int dist = 2;
00884 
00885   Point2D<int> loc(bbox.left(),(bbox.top() - dist - textDims.h()));
00886 
00887   // not enough space to the right? -> shift as apropriate
00888   if ((loc.i + textDims.w()) > imgDims.w())
00889     loc.i = imgDims.w() - textDims.w() - 1;
00890 
00891   // not enough space on the top? -> move to the bottom
00892   if (loc.j < 0)
00893     loc.j = bbox.bottomI() + dist;
00894 
00895   return loc;
00896 }
00897 
00898 // ######################################################################
00899 PropertyVectorSet VisualEventSet::getPropertyVectorSet()
00900 {
00901   PropertyVectorSet pvs;
00902 
00903   std::list<VisualEvent>::iterator currEvent;
00904   for (currEvent = itsEvents.begin(); currEvent != itsEvents.end();
00905        ++currEvent)
00906     pvs.itsVectors.push_back(currEvent->getPropertyVector());
00907 
00908   return pvs;
00909 }
00910 
00911 
00912 // ######################################################################
00913 int VisualEventSet::getAllClosedFrameNum(uint currFrame)
00914 {
00915   std::list<VisualEvent>::iterator currEvent;
00916   for (int frame = (int)currFrame; frame >= -1; --frame)
00917     {
00918       bool done = true;
00919 
00920       for (currEvent = itsEvents.begin(); currEvent != itsEvents.end();
00921            ++currEvent)
00922         {
00923           done &= ((frame < (int)currEvent->getStartFrame())
00924                    || currEvent->isClosed());
00925           if (!done) break;
00926         }
00927 
00928       if (done) return frame;
00929     }
00930   return -1;
00931 }
00932 
00933 // ######################################################################
00934 bool VisualEventSet::isEventInteresting(std::vector<float> propVec) const
00935 {
00936   const float interestThresh = 5;
00937   const float uxyThresh = 0.4F;
00938 
00939   // did we get set from outside? -> threshold with interstingness
00940   if (propVec[1] >= 0.0F)
00941     return (propVec[1] >= interestThresh);
00942   // otherwise threshold uxy and set interestingness value
00943   else
00944     return (fabs(propVec[5]) >= uxyThresh);
00945 }
00946 
00947 // ######################################################################
00948 bool VisualEventSet::doesEventExist(uint eventNum) const
00949 {
00950   std::list<VisualEvent>::const_iterator evt;
00951   for (evt = itsEvents.begin(); evt != itsEvents.end(); ++evt)
00952     if (evt->getEventNum() == eventNum) return true;
00953 
00954   return false;
00955 }
00956 
00957 // ######################################################################
00958 VisualEvent VisualEventSet::getEventByNumber(uint eventNum) const
00959 {
00960   std::list<VisualEvent>::const_iterator evt;
00961   for (evt = itsEvents.begin(); evt != itsEvents.end(); ++evt)
00962     if (evt->getEventNum() == eventNum) return *evt;
00963 
00964   LFATAL("Event with number %i does not exist.",eventNum);
00965 
00966   return *evt;
00967 }
00968 
00969 // ######################################################################
00970 std::vector<std::list<VisualEvent>::iterator>
00971 VisualEventSet::getEventsForFrame(uint framenum)
00972 {
00973   std::vector<std::list<VisualEvent>::iterator> result;
00974   std::list<VisualEvent>::iterator event;
00975   for (event = itsEvents.begin(); event != itsEvents.end(); ++event)
00976     if (event->isFrameOk(framenum)) result.push_back(event);
00977 
00978   return result;
00979 }
00980 
00981 // ######################################################################
00982 /* So things look consistent in everyone's emacs... */
00983 /* Local Variables: */
00984 /* indent-tabs-mode: nil */
00985 /* End: */
Generated on Sun May 8 08:05:20 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3