00001
00007 #include <cmath>
00008 #include <iomanip>
00009 #include <strstream.h>
00010 #include <numeric>
00011 #include <fstream>
00012 #include <utility>
00013
00014 #include "retinalobjs.h"
00015
00016 #ifndef NO_VALGEN_STRINGS
00017 #include <stdio.h>
00018 #include "stringutils.h"
00019 #endif
00020
00021 #ifdef ANSI_COMPATIBLE
00022
00023 #include "ind_types.h"
00024 #endif
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifndef M_PI
00034 #define M_PI 3.14159265358979323846
00035 #endif
00036
00037 #ifndef RADIANS_TO_DEGREES
00038 #define RADIANS_TO_DEGREES(theta) (180.0*(theta)/M_PI)
00039 #endif
00040
00041 #ifndef CONSTRAIN_ANGLE
00042 #define CONSTRAIN_ANGLE(angle) \
00043 (((angle)>=0) ? \
00044 fmod( (angle), M_PI ) : \
00045 fmod( (angle) + 2*M_PI*(-1*floor((angle)/(M_PI*2))+1), M_PI) )
00046 #endif
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 string Retinal_Object::stringrep() const
00057 {
00058 00059
00060 const char bufsize=100;
00061 static char buf[bufsize];
00062 ostrstream os(buf, bufsize);
00063 os.setf(ios::fixed,ios::floatfield);
00064
00065 if (name!="") os << name << " ";
00066 os << setprecision(1)
00067 << "cx:" << setw(4) << setfill('0') << get_var("cx")
00068 << " cy:" << setw(4) << setfill('0') << get_var("cy")
00069 << " theta:" << setw(5) << setfill('0')
00070 << RADIANS_TO_DEGREES(CONSTRAIN_ANGLE( get_var("theta")));
00071
00072
00073
00074
00075
00076
00077
00078
00079 os << ends;
00080
00081 return buf;
00082 }
00083
00084
00085
00086 #ifndef NO_VALGEN_STRINGS
00087 Retinal_Object::VarMap RetinalObjectStringArgs::vars(const ParamList& params)
00088 {
00089 Retinal_Object::VarMap vars;
00090
00091
00092 for (ParamList::const_iterator paramptr=params.begin();
00093 paramptr!=params.end(); paramptr++) {
00094 const string& name = *paramptr;
00095 const bool positionalargsremain = !args.empty() && !args.lookaheadone(string("="));
00096 const string value = (positionalargsremain ? args.next(string("")) : get_default(name));
00097 set_linked(name,value,vars);
00098 }
00099
00100
00101 while (!args.empty()) {
00102 const string name = args.next(string(""));
00103 if (args.empty() || !args.nextis(string("=")) || args.empty()) {
00104 error("Syntax error in retinal object parameter specification");
00105 return vars;
00106 }
00107 const string value = args.next(string(""));
00108 set_linked(name,value,vars);
00109 }
00110
00111 return vars;
00112 }
00113 #endif
00114
00115
00116
00117
00118
00119
00120
00121
00122 bool Retinal_Composite::next()
00123 {
00124 return
00125 !std::count_if(ISEQ(children),not1(mem_fun(&ValueGen::next)))
00126 && Retinal_Object::next();
00127 }
00128
00129
00130
00131 void Retinal_Composite::reset() {
00132 dominant_child = (accum_type==OneHot && children.size() ? children[0] : 0);
00133 std::for_each(ISEQ(children),mem_fun(&Retinal_Object::reset));
00134 Retinal_Object::reset();
00135 }
00136
00137
00138
00139 #ifndef NO_VALGEN_STRINGS
00140 RetinalObjectStringArgs::ParamList Retinal_Composite::paramlist() {
00141 RetinalObjectStringArgs::ParamList p;
00142 p.push_back("theta");
00143 p.push_back("cx");
00144 p.push_back("cy");
00145 p.push_back("size_scale");
00146 p.push_back("scale");
00147 p.push_back("offset");
00148 p.push_back("hot");
00149 p.push_back("accum_type");
00150 return p;
00151 }
00152 #endif
00153
00154
00155
00156 bool Retinal_Composite::update() const
00157 {
00158 std::for_each(ISEQ(children),mem_fun(&Retinal_Object::update));
00159
00160
00161 if (accum_type==OneHot && children.size()) {
00162 const Variable hot = get_var("hot");
00163 const Variable relative_index = hot-int(hot);
00164 const int child_index = (int)( children.size()*relative_index );
00165 assert(child_index<(int)children.size());
00166 dominant_child = children[child_index];
00167 }
00168 else
00169 dominant_child=0;
00170
00171
00172 cx = get_var("cx");
00173 cy = get_var("cy");
00174 const Variable mt = -get_var("theta");
00175 cosmt = cos(mt);
00176 sinmt = sin(mt);
00177 const Variable size_scale = get_var("size_scale");
00178 div_size = 1/size_scale;
00179
00180
00181
00182 bounding_box.set(0,0,0,0);
00183 for(const_iterator i=children.begin(); i!=children.end(); i++)
00184 bounding_box += (*i)->bounding_box;
00185
00186
00187 bounding_box.scale(size_scale,size_scale).rotate(mt).translate(cx,cy);
00188
00189 return Retinal_Object::update();
00190 }
00191
00192
00194 class ActivityAccumulator : public binary_function<Retinal_Object*,Retinal_Object*,bool> {
00195 public:
00196 explicit ActivityAccumulator(const Retinal_Obj::Coordinate xi, const Retinal_Obj::Coordinate yi,
00197 Retinal_Composite::AccumulationType accum_type_i)
00198 : x(xi), y(yi), accum_type(accum_type_i) { }
00199
00201 Retinal_Obj::Activity operator() (Retinal_Obj::Activity prev, const Retinal_Object* r) {
00202 const Retinal_Obj::Activity now=r->activation(x,y);
00203 switch (accum_type) {
00204 case Retinal_Composite::Max: return std::max(prev,now);
00205 case Retinal_Composite::Min: return std::min(prev,now);
00206 case Retinal_Composite::Add: return prev+now;
00207 default: return prev+now;
00208 }
00209 }
00210
00211 private:
00212 Retinal_Obj::Coordinate x,y;
00213 const Retinal_Composite::AccumulationType accum_type;
00214 };
00215
00216
00217
00224 class DefaultActivityAccumulator : public binary_function<Retinal_Object*,Retinal_Object*,bool> {
00225 public:
00226 explicit DefaultActivityAccumulator(Retinal_Composite::AccumulationType accum_type_i)
00227 : accum_type(accum_type_i) { }
00228
00230 Retinal_Obj::Activity operator() (Retinal_Obj::Activity prev, const Retinal_Object* r) {
00231 const Retinal_Obj::Activity now=r->default_activation();
00232 switch (accum_type) {
00233 case Retinal_Composite::Max: return std::max(prev,now);
00234 case Retinal_Composite::Min: return std::min(prev,now);
00235 case Retinal_Composite::Add: return prev+now;
00236 default: return prev+now;
00237 }
00238 }
00239
00240 private:
00241 const Retinal_Composite::AccumulationType accum_type;
00242 };
00243
00244
00245
00247 Retinal_Obj::Activity Retinal_Composite::accum_base() const {
00248 switch (accum_type) {
00249 case Min: return 10000000;
00250 case Max: return -10000000;
00251 default: return 0;
00252 }
00253 }
00254
00255
00256
00257 Retinal_Object::Activity Retinal_Composite::default_activ() const
00258 {
00259
00260 return
00261 (children.empty() ? 0
00262 : (dominant_child? dominant_child->default_activation()
00263 : std::accumulate(ISEQ(children),accum_base(),DefaultActivityAccumulator(accum_type))));
00264 }
00265
00266
00267
00268 Retinal_Object::Activity Retinal_Composite::activ(Coordinate x, Coordinate y) const
00269 {
00270 const Coordinate dx = (x-cx)*div_size;
00271 const Coordinate dy = (y-cy)*div_size;
00272 const Coordinate xp = dx*cosmt-dy*sinmt;
00273 const Coordinate yp = dx*sinmt+dy*cosmt;
00274
00275 return (dominant_child ? dominant_child->activation(xp,yp)
00276 : std::accumulate(ISEQ(children),accum_base(),ActivityAccumulator(xp,yp,accum_type)));
00277 }
00278
00279
00280
00283 const Retinal_Object& Retinal_Composite::mostactive(Coordinate x, Coordinate y) const
00284 {
00285 if (children.begin()==children.end())
00286 return *this;
00287 else {
00288 Retinal_Object* champ = *children.begin();
00289 Activity high_act = champ->activation(x,y);
00290 Activity act;
00291 for (Retinal_Composite::const_iterator i = children.begin()+1; i!= children.end(); i++) {
00292 act = (*i)->activation(x,y);
00293 if (act>high_act) {
00294 champ = *i;
00295 high_act=act;
00296 }
00297 }
00298 return *champ;
00299 }
00300 }
00301
00302
00303
00306 string accumulate_stringreps(string val, Retinal_Object* r)
00307 { return val + " [" + r->stringrep() + "]"; }
00308
00309
00310
00311 string Retinal_Composite::stringrep() const
00312 {
00313 return Retinal_Object::stringrep() +
00314 (dominant_child ? " " + dominant_child->stringrep()
00315 : std::accumulate(ISEQ(children),string(""),accumulate_stringreps));
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325 bool Retinal_ManagedComposite::distance_valid (const Retinal_Object& obj1, const Retinal_Object& obj2)
00326 {
00327 if (!*min_dist_enforce && !*max_dist_enforce)
00328 return true;
00329
00330 const Coordinate dist = hypot(obj1.get_var("cx") - obj2.get_var("cx"),
00331 obj1.get_var("cy") - obj2.get_var("cy"));
00332
00333 return ((!*min_dist_enforce || dist >= *min_dist) &&
00334 (!*max_dist_enforce || dist <= *max_dist) );
00335 }
00336
00337
00338
00339 bool Retinal_ManagedComposite::accumulate_managed_next(bool val, Retinal_Object* r)
00340 {
00341 00342 00343 00344 00345
00346 const int max_trials=100;
00347
00348
00349 for (int trial=0; trial<max_trials; trial++) {
00350 r->next();
00351
00352 iterator it = children.begin();
00353 while (*it != r && distance_valid(*r,**it))
00354 it++;
00355
00356 if (*it == r) {
00357 r->set_active(true);
00358 return val;
00359 }
00360 }
00361
00362 r->set_active(false);
00363 return false;
00364 }
00365
00366
00367
00368 bool Retinal_ManagedComposite::next()
00369 {
00370 bool val=true;
00371 for (iterator i = Retinal_Composite::children.begin();
00372 i != children.end(); i++) {
00373 val = accumulate_managed_next(val,*i);
00374 }
00375
00376 return val && Retinal_Object::next();
00377 }
00378
00379
00380
00381
00382
00383
00384
00386 Retinal_Object::Activity Retinal_AnchoredManagedComposite::activ(Coordinate x, Coordinate y) const
00387 {
00388 return (dominant_child ? dominant_child->activation(x,y)
00389 : std::accumulate(ISEQ(children),accum_base(),ActivityAccumulator(x,y,accum_type)));
00390 }
00391
00392
00393
00395 string Retinal_AnchoredManagedComposite::stringrep() const
00396 {
00397 return get_name() +
00398 (dominant_child ? " " + dominant_child->stringrep()
00399 : std::accumulate(ISEQ(children),string(""),accumulate_stringreps));
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 #ifndef NO_VALGEN_STRINGS
00416 RetinalObjectStringArgs::ParamList Retinal_CircularGaussian::paramlist() {
00417 RetinalObjectStringArgs::ParamList p;
00418 p.push_back("cx");
00419 p.push_back("cy");
00420 p.push_back("xsigma");
00421 p.push_back("scale");
00422 p.push_back("offset");
00423 return p;
00424 }
00425 #endif
00426
00427
00428 bool Retinal_CircularGaussian::update() const
00429 {
00430
00431 cx = get_var("cx");
00432 cy = get_var("cy");
00433 const Variable xsigma = get_var("xsigma");
00434 div_sigmasq = 1/(xsigma*xsigma);
00435
00436
00437 const Coordinate boundrad=bound_mult*xsigma;
00438 bounding_box.set(cx-boundrad,cy-boundrad,
00439 cx+boundrad,cy+boundrad);
00440
00441 return Retinal_Object::update();
00442 }
00443
00444
00445 Retinal_Object::Activity Retinal_CircularGaussian::activ(Coordinate x, Coordinate y) const
00446 {
00447 const Coordinate dx = x-cx;
00448 const Coordinate dy = y-cy;
00449
00450 return exp( -(dx*dx+dy*dy)*div_sigmasq);
00451 }
00452
00453
00454
00455 #ifndef NO_VALGEN_STRINGS
00456 RetinalObjectStringArgs::ParamList Retinal_Gaussian::paramlist() {
00457 RetinalObjectStringArgs::ParamList p;
00458 p.push_back("theta");
00459 p.push_back("cx");
00460 p.push_back("cy");
00461 p.push_back("xsigma");
00462 p.push_back("ysigma");
00463 p.push_back("scale");
00464 p.push_back("offset");
00465 return p;
00466 }
00467 #endif
00468
00469
00470 bool Retinal_Gaussian::update() const
00471 {
00472
00473 cx = get_var("cx");
00474 cy = get_var("cy");
00475 const Variable t = get_var("theta");
00476 cost = cos(t);
00477 sint = sin(t);
00478 const Variable xsigma = get_var("xsigma");
00479 const Variable ysigma = get_var("ysigma");
00480 div_xsigma = 1/xsigma;
00481 div_ysigma = 1/ysigma;
00482
00483
00484 const Variable xrad=bound_mult*xsigma;
00485 const Variable yrad=bound_mult*ysigma;
00486 bounding_box.set(-xrad,-yrad,xrad,yrad).rotate(t).translate(cx,cy);
00487
00488 return Retinal_Object::update();
00489 }
00490
00491
00492 Retinal_Object::Activity Retinal_Gaussian::activ(Coordinate x, Coordinate y) const
00493 {
00494 const Coordinate dx = x-cx;
00495 const Coordinate dy = y-cy;
00496 const Coordinate xp = ( dx * cost + dy * sint)*div_xsigma;
00497 const Coordinate yp = (-dx * sint + dy * cost)*div_ysigma;
00498
00499 return exp(-(xp*xp + yp*yp));
00500 }
00501
00502
00503
00504 #ifndef NO_VALGEN_STRINGS
00505 RetinalObjectStringArgs::ParamList Retinal_Rectangle::paramlist() {
00506 RetinalObjectStringArgs::ParamList p;
00507 p.push_back("cx");
00508 p.push_back("cy");
00509 p.push_back("xsigma");
00510 p.push_back("ysigma");
00511 p.push_back("scale");
00512 p.push_back("offset");
00513 return p;
00514 }
00515 #endif
00516
00517
00518 bool Retinal_Rectangle::update() const
00519 {
00520
00521 const Coordinate xrad = get_var("xsigma");
00522 const Coordinate yrad = get_var("ysigma");
00523 const Coordinate cx = get_var("cx");
00524 const Coordinate cy = get_var("cy");
00525 bounding_box.set(-xrad,-yrad,xrad,yrad).translate(cx,cy);
00526
00527 return Retinal_Object::update();
00528 }
00529
00530
00531
00532 #ifndef NO_VALGEN_STRINGS
00533 RetinalObjectStringArgs::ParamList Retinal_SineGrating::paramlist() {
00534 RetinalObjectStringArgs::ParamList p;
00535 p.push_back("theta");
00536 p.push_back("freq");
00537 p.push_back("phase");
00538 p.push_back("scale");
00539 p.push_back("offset");
00540 return p;
00541 }
00542 #endif
00543
00544
00545 bool Retinal_SineGrating::update() const
00546 {
00547
00548 const Variable t = get_var("theta");
00549 cost = cos(t);
00550 sint = sin(t);
00551 phase = get_var("phase");
00552 freq = get_var("freq");
00553
00554 return Retinal_Object::update();
00555 }
00556
00557
00558 Retinal_Object::Activity Retinal_SineGrating::activ(Coordinate x, Coordinate y) const
00559 { return sin( freq*(x*sint-y*cost+1.0) + phase); }
00560
00561
00562
00563 #ifndef NO_VALGEN_STRINGS
00564 RetinalObjectStringArgs::ParamList Retinal_Gabor::paramlist() {
00565 RetinalObjectStringArgs::ParamList p;
00566 p.push_back("theta");
00567 p.push_back("cx");
00568 p.push_back("cy");
00569 p.push_back("xsigma");
00570 p.push_back("ysigma");
00571 p.push_back("freq");
00572 p.push_back("phase");
00573 p.push_back("scale");
00574 p.push_back("offset");
00575 return p;
00576 }
00577 #endif
00578
00579
00580 bool Retinal_Gabor::update() const
00581 {
00582
00583 cx = get_var("cx");
00584 cy = get_var("cy");
00585 const Variable t = get_var("theta");
00586 cost = cos(t);
00587 sint = sin(t);
00588 phase = get_var("phase");
00589 freq = get_var("freq");
00590 const Variable xsigma = get_var("xsigma");
00591 const Variable ysigma = get_var("ysigma");
00592 div_xsigmasq = 1/(xsigma*xsigma);
00593 div_ysigmasq = 1/(ysigma*ysigma);
00594
00595
00596 const Variable xrad=bound_mult*xsigma;
00597 const Variable yrad=bound_mult*ysigma;
00598 bounding_box.set(-xrad,-yrad,xrad,yrad).rotate(t).translate(cx,cy);
00599
00600 return Retinal_Object::update();
00601 }
00602
00603
00604 Retinal_Object::Activity Retinal_Gabor::activ(Coordinate x, Coordinate y) const
00605 {
00606 const Coordinate dx = x-cx;
00607 const Coordinate dy = y-cy;
00608 const Coordinate xp = ( dx * cost + dy * sint);
00609 const Coordinate yp = (-dx * sint + dy * cost);
00610
00611 const Activity gaussian = exp(-(xp*xp*div_xsigmasq + yp*yp*div_ysigmasq));
00612 const Activity grating = 0.5+0.5*cos( freq*yp + phase );
00613
00614 return grating * gaussian;
00615 }
00616
00617
00618
00619 #ifndef NO_VALGEN_STRINGS
00620 RetinalObjectStringArgs::ParamList Retinal_FuzzyLine::paramlist() {
00621 RetinalObjectStringArgs::ParamList p;
00622 p.push_back("theta");
00623 p.push_back("cx");
00624 p.push_back("cy");
00625 p.push_back("ysigma");
00626 p.push_back("center_width");
00627 p.push_back("scale");
00628 p.push_back("offset");
00629 return p;
00630 }
00631 #endif
00632
00633
00634 bool Retinal_FuzzyLine::update() const
00635 {
00636
00637 cx = get_var("cx");
00638 cy = get_var("cy");
00639 centerw = get_var("center_width");
00640 const Variable t = get_var("theta");
00641 cost = cos(t);
00642 sint = sin(t);
00643 const Variable ysigma = get_var("ysigma");
00644 div_ysigmasq = 1/(ysigma*ysigma);
00645
00646 return Retinal_Object::update();
00647 }
00648
00649
00650 Retinal_Object::Activity Retinal_FuzzyLine::activ(Coordinate x, Coordinate y) const
00651 {
00652 const Coordinate dx = x-cx;
00653 const Coordinate dy = y-cy;
00654 const Coordinate distance_from_line = fabs(dy*cost - dx*sint);
00655 const Coordinate gaussian_x_coord = (distance_from_line - centerw/2);
00656 return (gaussian_x_coord<=0 ? 1.0
00657 : exp(-gaussian_x_coord*gaussian_x_coord*div_ysigmasq));
00658 }
00659
00660
00661
00662 #ifndef NO_VALGEN_STRINGS
00663 RetinalObjectStringArgs::ParamList Retinal_FuzzyRing::paramlist() {
00664 RetinalObjectStringArgs::ParamList p;
00665 p.push_back("cx");
00666 p.push_back("cy");
00667 p.push_back("ysigma");
00668 p.push_back("center_width");
00669 p.push_back("radius");
00670 p.push_back("scale");
00671 p.push_back("offset");
00672 return p;
00673 }
00674 #endif
00675
00676
00677 bool Retinal_FuzzyRing::update() const
00678 {
00679
00680 cx = get_var("cx");
00681 cy = get_var("cy");
00682 centerw = get_var("center_width");
00683 radius = get_var("radius");
00684 const Variable ysigma = get_var("ysigma");
00685 div_ysigmasq = 1/(ysigma*ysigma);
00686
00687 return Retinal_Object::update();
00688 }
00689
00690
00691 Retinal_Object::Activity Retinal_FuzzyRing::activ(Coordinate x, Coordinate y) const
00692 {
00693 const Coordinate dx = x-cx;
00694 const Coordinate dy = y-cy;
00695 const Coordinate distance_from_line = fabs(radius - sqrt(dx*dx+dy*dy));
00696 const Coordinate gaussian_x_coord = (distance_from_line - centerw/2);
00697 return (gaussian_x_coord<=0 ? 1.0
00698 : exp(-gaussian_x_coord*gaussian_x_coord*div_ysigmasq));
00699 }
00700
00701
00702
00703
00704
00705
00706
00707 #ifndef NO_VALGEN_STRINGS
00708
00710 string pgm_full_pathname(const string& filename, const string& paths="")
00711 {
00712 StringParser::arglist words;
00713 const StringParser p;
00714 p.parse(paths,words);
00715
00716 StringParser::arglist::iterator i=words.begin();
00717 FILE *file=NULL;
00718 string name=filename;
00719
00720
00721 for (;;) {
00722 file=fopen(name.c_str(),"r");
00723 if (file) {
00724 fclose(file);
00725 return name;
00726 }
00727 if (i==words.end())
00728 return filename;
00729 name = (*i++)+filename;
00730 }
00731 #ifdef __GNUC__
00732 return "";
00733 #endif
00734 }
00735
00736
00737 RetinalObjectStringArgs::ParamList Retinal_PGM::paramlist() {
00738 RetinalObjectStringArgs::ParamList p;
00739 p.push_back("theta");
00740 p.push_back("cx");
00741 p.push_back("cy");
00742 p.push_back("size_scale");
00743 p.push_back("scale");
00744 p.push_back("offset");
00745 return p;
00746 }
00747
00748
00749 Retinal_PGM::Retinal_PGM( const string& name_val, RetinalObjectStringArgs& sa,
00750 Coordinate visible_width, Coordinate visible_height )
00751 : Retinal_Object(name_val)
00752 {
00753 const string filename = sa.parsed_next("image_filename");
00754 const string paths = sa.parsed_get_default("image_paths");
00755 basename=pgm_full_pathname(filename, paths);
00756 const pair<int,int> size = pnm_size(basename);
00757 const int width = size.first;
00758 const int height = size.second;
00759
00760
00761 if (width<=0 || height<=0) {
00762 sa.error("Problem reading image file `"+basename+"'");
00763 return;
00764 }
00765 set_active(pgm_read(basename,image));
00766 border=mat::edge_average(image);
00767
00768 00769 00770 00771 00772 00773 00774 00775 00776 00777 00778 00779 00780 00781 00782 00783 00784
00785 if (width>=visible_width && height>=visible_height) {
00786 double dummy;
00787 const string size_scale_str = sa.parsed_get_default("size_scale");
00788 const double size_scale = sa.parse(size_scale_str,dummy);
00789
00790 sa.set_default("cx", "Random "+
00791 String::stringrep(visible_width /2)+" "+
00792 String::stringrep(( width*size_scale-visible_width )/2));
00793 sa.set_default("cy", "Random "+
00794 String::stringrep(visible_height/2)+" "+
00795 String::stringrep((height*size_scale-visible_height)/2));
00796 sa.set_default("theta", "PI/2");
00797 }
00798
00799
00800 merge_vars(sa.vars(paramlist()));
00801 }
00802 #endif
00803
00804
00805 bool Retinal_PGM::update() const
00806 {
00807
00808 const Variable mt = -get_var("theta");
00809 cx = get_var("cx");
00810 cy = get_var("cy");
00811 cosmt = cos(mt);
00812 sinmt = sin(mt);
00813 const Variable size_scale = get_var("size_scale");
00814 div_size = 1/size_scale;
00815 00816
00817 xoff = image.nrows()/2;
00818 yoff = image.ncols()/2;
00819
00820
00821 bounding_box.set(-xoff,-yoff,+xoff,+yoff);
00822 bounding_box.scale(size_scale,size_scale).rotate(mt).translate(cx,cy);
00823
00824 return Retinal_Object::update();
00825 }
00826
00827
00828
00830 Retinal_Object::Activity Retinal_PGM::activ(Coordinate x, Coordinate y) const
00831 {
00832 const Coordinate dx = (x-cx)*div_size;
00833 const Coordinate dy = (y-cy)*div_size;
00834 const image_type::size_type xp = static_cast<image_type::size_type>(dx*cosmt-dy*sinmt+xoff);
00835 const image_type::size_type yp = static_cast<image_type::size_type>(dx*sinmt+dy*cosmt+yoff);
00836
00837 00838 00839 00840 00841
00842 return
00843 ( int(xp) > 0 && int(yp) > 0 && xp < image.nrows() && yp < image.ncols() ) ?
00844 image[image.nrows()-xp-1][image.ncols()-yp-1]
00845 : border;
00846
00847 }
00848
00849
00850