00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Beobot/BeobotVisualCortex.H"
00039
00040 #include "Beobot/beobot-defs.H"
00041 #include "Channels/Jet.H"
00042 #include "Image/ColorOps.H"
00043 #include "Image/MathOps.H"
00044 #include "Image/Pixels.H"
00045 #include "Image/PyramidOps.H"
00046 #include "Image/ShapeOps.H"
00047 #include "Image/Transforms.H"
00048 #include "Image/fancynorm.H"
00049 #include "Util/Assert.H"
00050 #include "Util/Timer.H"
00051
00052 #include <cmath>
00053 #include <limits>
00054
00055
00056
00057 BeobotVisualCortex::BeobotVisualCortex()
00058 { initialized = false; }
00059
00060
00061 void BeobotVisualCortex::init(const int imgw, const int imgh,
00062 const int lev_min, const int lev_max,
00063 const int delta_min, const int delta_max,
00064 const int smlev, const int nborient,
00065 const MaxNormType normtype, const int jlev,
00066 const int jdepth, const int nbneig,
00067 nub::soft_ref<Beowulf> beow)
00068 {
00069 iw = imgw; ih = imgh;
00070 lmin = lev_min; lmax = lev_max; dmin = delta_min; dmax = delta_max;
00071 sml = smlev; nori = nborient; nortyp = normtype; beo = beow;
00072 jetlevel = jlev; jetdepth = jdepth; nbneigh = nbneig;
00073
00074 scene.resize(iw, ih, true);
00075
00076 JetSpec *js = new JetSpec;
00077 js->addIndexRange(RG, RAW, jlev, jlev + jdepth - 1);
00078 js->addIndexRange(BY, RAW, jlev, jlev + jdepth - 1);
00079 js->addIndexRange(INTENS, RAW, jlev, jlev + jdepth - 1);
00080 js->addIndexRange(ORI, RAW, 0, nborient - 1);
00081 js->addIndexRange(ORI, RAW, jlev, jlev + jdepth - 1);
00082 js->print();
00083 jetSpec = rutz::make_shared(js);
00084
00085 jets.init(iw >> jetlevel, ih >> jetlevel, nbneigh);
00086 ImageSpring<Jet <float> >::iterator itr = jets.beginw(), stop = jets.endw();
00087 while (itr != stop) { itr->init(jetSpec); itr ++; }
00088
00089 sminput.resize(iw >> sml, ih >> sml, true);
00090 initialized = true;
00091 }
00092
00093
00094 void BeobotVisualCortex::newVisualInput(Image< PixRGB<byte> >& newscene)
00095 { scene = newscene; iw = scene.getWidth(); ih = scene.getHeight(); }
00096
00097
00098 Image< PixRGB<byte> >* BeobotVisualCortex::getScenePtr()
00099 { return &scene; }
00100
00101
00102 void BeobotVisualCortex::process(const int frame)
00103 {
00104 currframe = frame;
00105 sminput.clear(); nbcmap = 0; nbjmap = 0;
00106
00107 if (beo.get())
00108 {
00109 masterProcess(frame);
00110
00111 while (nbcmap != NBCMAP || nbjmap != NBJMAP) masterCollect();
00112 }
00113 else
00114 singleCPUprocess(frame);
00115
00116
00117 sminput = maxNormalize(sminput, 0.0f, 9.0f, nortyp);
00118
00119
00120 float maxval;
00121 findMax(sminput, winner, maxval);
00122
00123
00124 winner.i <<= sml; winner.i += 1 << (sml - 1);
00125 winner.j <<= sml; winner.j += 1 << (sml - 1);
00126 }
00127
00128
00129 void BeobotVisualCortex::processStart(const int frame)
00130 {
00131 if (beo.isInvalid()) LFATAL("This is for parallel processing only!");
00132 currframe = frame;
00133 masterProcess(frame);
00134 }
00135
00136
00137 void BeobotVisualCortex::processEnd(const int frame)
00138 {
00139 if (beo.isInvalid()) LFATAL("This is for parallel processing only!");
00140 sminput.clear(); nbcmap = 0; nbjmap = 0; currframe = frame; Timer tim;
00141 while((nbcmap != NBCMAP || nbjmap != NBJMAP) && tim.get() < 80)
00142 {
00143 masterCollect();
00144
00145 }
00146
00147
00148 sminput = maxNormalize(sminput, 0.0f, 9.0f, nortyp);
00149
00150
00151 float maxval;
00152 findMax(sminput, winner, maxval);
00153
00154
00155 winner.i <<= sml; winner.i += 1 << (sml - 1);
00156 winner.j <<= sml; winner.j += 1 << (sml - 1);
00157 }
00158
00159
00160 void BeobotVisualCortex::singleCPUprocess(const int frame)
00161 {
00162 currframe = frame;
00163
00164 Image<float> lumf = luminance(scene);
00165
00166 Image<float> rgf, byf;
00167 getRGBY(scene, rgf, byf, byte(25));
00168
00169
00170 ImageSet<float> intensPyr = buildPyrGaussian(lumf, 0, sml + dmax + 1, 5);
00171
00172
00173 ImageSet<float> rgPyr = buildPyrGaussian(rgf, 0, sml + dmax + 1, 5);
00174 ImageSet<float> byPyr = buildPyrGaussian(byf, 0, sml + dmax + 1, 5);
00175
00176
00177 ImageSet<float> oriPyr[nori];
00178 for (int i = 0; i < nori; i ++)
00179 {
00180 oriPyr[i] = buildPyrOriented(lumf, 0, sml + dmax + 1, 5,
00181 float(i) * 180.0f / float(nori));
00182 }
00183
00184
00185 if (prevlum.initialized() == false) prevlum = lumf;
00186 prevlum -= lumf;
00187 ImageSet<float> flickPyr = buildPyrGaussian(prevlum, 0, sml + dmax + 1, 5);
00188 prevlum = lumf;
00189
00190
00191 Image<float> cmap;
00192 sminput.resize(intensPyr[sml].getDims(), true);
00193 computeCmap(intensPyr, cmap); sminput += cmap;
00194 computeCmap(rgPyr, cmap); sminput += cmap;
00195 computeCmap(byPyr, cmap); sminput += cmap;
00196 computeCmap(flickPyr, cmap); sminput += cmap;
00197 for (int i = 0; i < nori; i++)
00198 { computeCmap(oriPyr[i], cmap); sminput += cmap; }
00199
00200
00201 ImageSpring< Jet<float> >::iterator jt = jets.beginw();
00202 Point2D<int> p; int step = 1 << jetlevel;
00203 int jmax = jets.getHeight() * step, imax = jets.getWidth() * step;
00204 for (p.j = 0; p.j < jmax; p.j += step)
00205 for (p.i = 0; p.i < imax; p.i += step)
00206 {
00207 for (int k = jetlevel; k < jetlevel + jetdepth; k ++)
00208 {
00209 float rgval = getPyrPixel(rgPyr, p, k); jt->setVal(rgval, RG, RAW, k);
00210 float byval = getPyrPixel(byPyr, p, k); jt->setVal(byval, BY, RAW, k);
00211 float ival = getPyrPixel(intensPyr, p, k); jt->setVal(ival, INTENS, RAW, k);
00212 for (int o = 0; o < nori; o ++)
00213 {
00214 float oval = getPyrPixel(oriPyr[o], p, k);
00215 jt->setVal(oval, ORI, RAW, o, k);
00216 }
00217 }
00218 jt ++;
00219 }
00220
00221 nbcmap = NBCMAP; nbjmap = NBJMAP;
00222 }
00223
00224
00225 void BeobotVisualCortex::masterProcess(const int frame)
00226 {
00227 ASSERT(initialized);
00228
00229 TCPmessage smsg;
00230 currframe = frame; nbcmap = 0;
00231
00232
00233 Image<byte> lum = luminance(scene);
00234 smsg.reset(frame, BEO_LUMFLICK);
00235 smsg.addImage(lum);
00236 beo->send(0, smsg);
00237 smsg.setAction(BEO_ORI0_45);
00238 beo->send(1, smsg);
00239 smsg.setAction(BEO_ORI90_135);
00240 beo->send(2, smsg);
00241
00242
00243 Image<byte> r, g, b, y; getRGBY(scene, r, g, b, y, (byte)25);
00244 smsg.reset(frame, BEO_REDGREEN);
00245 smsg.addImage(r); smsg.addImage(g);
00246 beo->send(0, smsg);
00247 smsg.reset(frame, BEO_BLUEYELLOW);
00248 smsg.addImage(b); smsg.addImage(y);
00249 beo->send(0, smsg);
00250 }
00251
00252
00253 void BeobotVisualCortex::slaveProcess()
00254 {
00255 TCPmessage rmsg; int rframe, raction, rnode = -1;
00256 int nbrec = 0;
00257 while (beo->receive(rnode, rmsg, rframe, raction, 5))
00258 {
00259
00260
00261 switch(raction)
00262 {
00263 case BEO_INIT:
00264 {
00265
00266
00267 }
00268 break;
00269 case BEO_LUMFLICK:
00270 {
00271
00272 Image<byte> ima = rmsg.getElementByteIma();
00273 Image<float> fima = ima;
00274
00275
00276 computeFeature(fima, Gaussian5, 0.0, rframe, BEO_FMAP_I);
00277
00278
00279 if (prevlum.initialized() == false) prevlum = fima;
00280 prevlum -= fima;
00281 computeFeature(prevlum, Gaussian5, 0.0, rframe, BEO_FMAP_F);
00282 prevlum = fima;
00283 }
00284 break;
00285 case BEO_REDGREEN:
00286 computeFeature2(rmsg, Gaussian5, 0.0, BEO_FMAP_RG);
00287 break;
00288 case BEO_BLUEYELLOW:
00289 computeFeature2(rmsg, Gaussian5, 0.0, BEO_FMAP_BY);
00290 break;
00291 case BEO_ORI0_45:
00292 {
00293
00294 Image<byte> ima = rmsg.getElementByteIma();
00295 Image<float> fima = ima;
00296
00297
00298 computeFeature(fima, Oriented5, 0.0, rframe, BEO_FMAP_O0);
00299
00300
00301 computeFeature(fima, Oriented5, 45.0, rframe, BEO_FMAP_O45);
00302 }
00303 break;
00304 case BEO_ORI90_135:
00305 {
00306
00307 Image<byte> ima = rmsg.getElementByteIma();
00308 Image<float> fima = ima;
00309
00310
00311 computeFeature(fima, Oriented5, 90.0, rframe, BEO_FMAP_O90);
00312
00313
00314 computeFeature(fima, Oriented5, 135.0, rframe, BEO_FMAP_O135);
00315 }
00316 break;
00317 default:
00318 LERROR("Bogus action %d -- IGNORING.", raction);
00319 break;
00320 }
00321
00322
00323
00324
00325 nbrec ++; if (nbrec > 3) break;
00326 }
00327 }
00328
00329
00330 void BeobotVisualCortex::masterCollect()
00331 {
00332
00333 int32 rframe, raction, rnode = -1, recnb = 0;
00334 TCPmessage rmsg;
00335 while(beo->receive(rnode, rmsg, rframe, raction, 5))
00336 {
00337
00338
00339 if (rframe != currframe)
00340 {
00341 LERROR("Dropping old map, type %d for frame %d while at frame %d",
00342 raction, rframe, currframe);
00343 continue;
00344 }
00345
00346
00347 if (raction == BEO_CMAP)
00348 {
00349 nbcmap ++;
00350
00351
00352 Image<float> ima = rmsg.getElementFloatIma();
00353
00354
00355 sminput += ima;
00356 }
00357
00358
00359 if (raction >= BEO_FMAP_RG && raction <= BEO_FMAP_O135)
00360 {
00361 nbjmap ++;
00362
00363 VisualFeature jf = COLOR;
00364 std::vector<int> v;
00365 switch(raction)
00366 {
00367 case BEO_FMAP_RG: jf = RG; break;
00368 case BEO_FMAP_BY: jf = BY; break;
00369 case BEO_FMAP_I: jf = INTENS; break;
00370 case BEO_FMAP_F: jf = FLICKER; break;
00371 case BEO_FMAP_O0: jf = ORI; v.push_back(0); break;
00372 case BEO_FMAP_O45: jf = ORI; v.push_back(1); break;
00373 case BEO_FMAP_O90: jf = ORI; v.push_back(2); break;
00374 case BEO_FMAP_O135: jf = ORI; v.push_back(3); break;
00375 default: LFATAL("Bogus feature map type %d", raction);
00376 }
00377 v.push_back(0);
00378
00379
00380 Image<float> ima[jetdepth];
00381 for (int i = 0; i < jetdepth; i ++)
00382 {
00383 ima[i] = rmsg.getElementFloatIma();
00384 }
00385
00386
00387 if (jf != FLICKER) {
00388 ImageSpring< Jet<float> >::iterator jet_itr = jets.beginw();
00389
00390 for (int j = 0; j < jets.getHeight(); j ++)
00391 for (int i = 0; i < jets.getWidth(); i ++)
00392 {
00393 float ii = float(i), jj = float(j);
00394 for (int k = 0; k < jetdepth; k ++)
00395 {
00396 float ii2 = ii, jj2 = jj;
00397 if (ii2 > ima[k].getWidth()-1)
00398 ii2 = ima[k].getWidth()-1;
00399 if (jj2 > ima[k].getHeight()-1)
00400 jj2 = ima[k].getHeight()-1;
00401
00402 v[v.size() - 1] = k + jetlevel;
00403
00404
00405 jet_itr->setValV(ima[k].getValInterp(ii2, jj2),
00406 jf, RAW, v);
00407
00408
00409 ii *= 0.5f; jj *= 0.5f;
00410 }
00411 }
00412 }
00413 }
00414
00415
00416
00417 recnb ++; if (recnb > 20) break;
00418 }
00419 }
00420
00421
00422 void BeobotVisualCortex::getWinner(Point2D<int>& win) const
00423 { win.i = winner.i; win.j = winner.j; }
00424
00425
00426 void BeobotVisualCortex::initSprings(bool initPosMasses)
00427 { jets.initClustering(initPosMasses); }
00428
00429
00430
00431 void BeobotVisualCortex::iterateSprings(const float dt)
00432 { jets.computePos(dt); }
00433
00434
00435 void BeobotVisualCortex::getClusteredImage(Image< PixRGB<byte> >
00436 &clusteredImage,
00437 Point2D<int> &supposedTrackCentroid,
00438 const Point2D<int>&
00439 previousTrackCentroid)
00440 {
00441 jets.getClusteredImage(scene, clusteredImage, supposedTrackCentroid,
00442 previousTrackCentroid);
00443 }
00444
00445
00446 void BeobotVisualCortex::getPositions(Image< PixRGB<byte> > &img,
00447 const int zoom)
00448 { jets.getPositions(img, zoom); }
00449
00450
00451 void BeobotVisualCortex::computeFeature(TCPmessage &rmsg,
00452 const PyramidType ptyp,
00453 const float ori,
00454 const int maptype)
00455 {
00456
00457 Image<byte> ima = rmsg.getElementByteIma();
00458 Image<float> fima = ima;
00459
00460
00461 computeFeature(fima, ptyp, ori, rmsg.getID(), maptype);
00462 }
00463
00464
00465 void BeobotVisualCortex::computeFeature2(TCPmessage &rmsg,
00466 const PyramidType ptyp,
00467 const float ori,
00468 const int maptype)
00469 {
00470
00471 Image<byte> ima1 = rmsg.getElementByteIma();
00472 Image<byte> ima2 = rmsg.getElementByteIma();
00473 Image<float> fima = ima1 - ima2;
00474
00475
00476 computeFeature(fima, ptyp, ori, rmsg.getID(), maptype);
00477 }
00478
00479
00480 void BeobotVisualCortex::computeFeature(const Image<float>& fima,
00481 const PyramidType ptyp,
00482 const float ori,
00483 const int32 id, const int32 maptype)
00484 {
00485
00486 ImageSet<float> pyr = buildPyrGeneric(fima, 0, lmax + dmax + 1,
00487 ptyp, ori);
00488
00489
00490 TCPmessage smsg(id, maptype);
00491 for (int i = 0; i < jetdepth; i ++)
00492 smsg.addImage(pyr.getImage(i + jetlevel));
00493 beo->send(-1, smsg);
00494
00495
00496 Image<float> cmap;
00497 computeCmap(pyr, cmap);
00498
00499
00500 smsg.reset(id, BEO_CMAP);
00501 smsg.addImage(cmap);
00502 beo->send(-1, smsg);
00503 }
00504
00505
00506 void BeobotVisualCortex::computeCmap(const ImageSet<float>& pyr,
00507 Image<float>& cmap)
00508 {
00509
00510 cmap.resize(pyr[sml].getDims(), true);
00511
00512
00513 for (int delta = dmin; delta <= dmax; delta ++)
00514 for (int lev = lmin; lev <= lmax; lev ++)
00515 {
00516 Image<float> tmp = centerSurround(pyr, lev, lev + delta, true);
00517 tmp = downSize(tmp, cmap.getWidth(), cmap.getHeight());
00518 inplaceAddBGnoise(tmp, 255.0);
00519 tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, nortyp);
00520 cmap += tmp;
00521 }
00522 if (nortyp == VCXNORM_MAXNORM)
00523 cmap = maxNormalize(cmap, MAXNORMMIN, MAXNORMMAX, nortyp);
00524 else
00525 cmap = maxNormalize(cmap, 0.0f, 0.0f, nortyp);
00526 }
00527
00528
00529
00530
00531
00532