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
00034 string Retinal_Object::stringrep() const
00035 {
00036
00037
00038 const char bufsize=100;
00039 static char buf[bufsize];
00040 ostrstream os(buf, bufsize);
00041 os.setf(std::ios::fixed,std::ios::floatfield);
00042
00043 if (name()!="") os << name() << " ";
00044 if (get_active()) {
00045 os << std::setprecision(1)
00046 << "cx:" << std::setw(4) << std::setfill('0') << get_var("cx")
00047 << " cy:" << std::setw(4) << std::setfill('0') << get_var("cy")
00048 << " theta:" << std::setw(5) << std::setfill('0')
00049 << RADIANS_TO_DEGREES(CONSTRAIN_ANGLE( get_var("theta")));
00050 }
00051 else
00052 os << "inactive";
00053
00054
00055
00056
00057
00058
00059
00060
00061 os << std::ends;
00062
00063 return buf;
00064 }
00065
00066
00067 #ifndef NO_VALGEN_STRINGS
00068 Retinal_Object::VarMap RetinalObjectStringArgs::vars(const ParamList& params)
00069 {
00070 Retinal_Object::VarMap vars;
00071
00072
00073 for (ParamList::const_iterator paramptr=params.begin();
00074 paramptr!=params.end(); paramptr++) {
00075 const string& name = *paramptr;
00076 const string nextarg = args.top(string(""));
00077 const unsigned pos = nextarg.find("=");
00078 const bool nextarghaseq = (pos<nextarg.length());
00079 const bool positionalargsremain = !args.empty() && !nextarghaseq;
00080 const string value = (positionalargsremain ? args.next(string("")) : get_default(name));
00081 set_linked(name,value,vars);
00082 }
00083
00084
00085 while (!args.empty()) {
00086 const string arg = args.next(string(""));
00087 const unsigned pivot = arg.find("=");
00088 if (pivot>=arg.length()) {
00089 error("Syntax error in retinal object parameter specification");
00090 return vars;
00091 }
00092 const string name = string(arg,0,pivot);
00093 const string value = String::strip_quotes(string(arg,pivot+1,arg.length()-pivot-1));
00094 set_linked(name,value,vars);
00095 }
00096
00097 return vars;
00098 }
00099 #endif
00100
00101
00102
00103
00104
00105
00106
00107
00108 bool Retinal_Composite::next()
00109 {
00110 return
00111 !std::count_if(ISEQ(children),std::not1(std::mem_fun(&ValueGen::next)))
00112 && Retinal_Object::next();
00113 }
00114
00115
00116
00117 void Retinal_Composite::reset() {
00118 dominant_child = (accum_type==OneHot && children.size() ? children[0] : 0);
00119 std::for_each(ISEQ(children),std::mem_fun(&Retinal_Object::reset));
00120 Retinal_Object::reset();
00121 }
00122
00123
00124
00125 #ifndef NO_VALGEN_STRINGS
00126 RetinalObjectStringArgs::ParamList Retinal_Composite::paramlist() {
00127 RetinalObjectStringArgs::ParamList p;
00128 p.push_back("theta");
00129 p.push_back("cx");
00130 p.push_back("cy");
00131 p.push_back("size_scale");
00132 p.push_back("scale");
00133 p.push_back("offset");
00134 p.push_back("accum_type");
00135 p.push_back("hot");
00136 return p;
00137 }
00138 #endif
00139
00140
00141
00142 bool Retinal_Composite::update() const
00143 {
00144 std::for_each(ISEQ(children),std::mem_fun(&Retinal_Object::update));
00145
00146
00147 if (accum_type==OneHot && children.size()) {
00148 const Variable hot = get_var("hot");
00149 const Variable relative_index = hot-int(hot);
00150 const int child_index = (int)( children.size()*relative_index );
00151 assert(child_index<(int)children.size());
00152 dominant_child = children[child_index];
00153 }
00154 else
00155 dominant_child=0;
00156
00157
00158 cx = get_var("cx");
00159 cy = get_var("cy");
00160 const Variable mt = -get_var("theta");
00161 cosmt = cos(mt);
00162 sinmt = sin(mt);
00163 const Variable size_scale = get_var("size_scale");
00164 div_size = 1/size_scale;
00165
00166
00167
00168 bounding_box.set(0,0,0,0);
00169 for(const_iterator i=children.begin(); i!=children.end(); i++)
00170 bounding_box += (*i)->bounding_box;
00171
00172
00173 bounding_box.scale(size_scale,size_scale).rotate(mt).translate(cx,cy);
00174
00175 return Retinal_Object::update();
00176 }
00177
00178
00180 class ActivityAccumulator : public std::binary_function<Retinal_Object*,Retinal_Object*,bool> {
00181 public:
00182 explicit ActivityAccumulator(const Retinal_Obj::Coordinate xi, const Retinal_Obj::Coordinate yi,
00183 Retinal_Composite::AccumulationType accum_type_i)
00184 : x(xi), y(yi), accum_type(accum_type_i) { }
00185
00187 Retinal_Obj::Activity operator() (Retinal_Obj::Activity prev, const Retinal_Object* r) {
00188 const Retinal_Obj::Activity now=r->activation(x,y);
00189 switch (accum_type) {
00190 case Retinal_Composite::Max: return std::max(prev,now);
00191 case Retinal_Composite::Min: return std::min(prev,now);
00192 case Retinal_Composite::Add: return prev+now;
00193 case Retinal_Composite::Replace:
00194 return (r->inside(x,y)? now : prev);
00195 default: return prev+now;
00196 }
00197 }
00198
00199 private:
00200 Retinal_Obj::Coordinate x,y;
00201 const Retinal_Composite::AccumulationType accum_type;
00202 };
00203
00204
00205
00212 class DefaultActivityAccumulator : public std::binary_function<Retinal_Object*,Retinal_Object*,bool> {
00213 public:
00214 explicit DefaultActivityAccumulator(Retinal_Composite::AccumulationType accum_type_i)
00215 : accum_type(accum_type_i) { }
00216
00218 Retinal_Obj::Activity operator() (Retinal_Obj::Activity prev, const Retinal_Object* r) {
00219 const Retinal_Obj::Activity now=r->default_activation();
00220 switch (accum_type) {
00221 case Retinal_Composite::Max: return std::max(prev,now);
00222 case Retinal_Composite::Min: return std::min(prev,now);
00223 case Retinal_Composite::Add: return prev+now;
00224 case Retinal_Composite::Replace: return prev;
00225 default: return prev+now;
00226 }
00227 }
00228
00229 private:
00230 const Retinal_Composite::AccumulationType accum_type;
00231 };
00232
00233
00234
00236 Retinal_Obj::Activity Retinal_Composite::accum_base() const {
00237 switch (accum_type) {
00238
00239 case Min: return 10000000;
00240
00241
00242 case Max: return -10000000;
00243
00244
00245
00246 case Replace: return children.size()? children[0]->default_activation() : 0;
00247
00248 default: return 0;
00249 }
00250 }
00251
00252
00253
00254 Retinal_Object::Activity Retinal_Composite::default_activ() const
00255 {
00256
00257 return
00258 (children.empty() ? 0
00259 : (dominant_child? dominant_child->default_activation()
00260 : std::accumulate(ISEQ(children),accum_base(),DefaultActivityAccumulator(accum_type))));
00261 }
00262
00263
00264
00265 Retinal_Object::Activity Retinal_Composite::activ(Coordinate x, Coordinate y) const
00266 {
00267 const Coordinate dx = (x-cx)*div_size;
00268 const Coordinate dy = (y-cy)*div_size;
00269 const Coordinate xp = dx*cosmt-dy*sinmt;
00270 const Coordinate yp = dx*sinmt+dy*cosmt;
00271
00272 return (dominant_child ? dominant_child->activation(xp,yp)
00273 : std::accumulate(ISEQ(children),accum_base(),ActivityAccumulator(xp,yp,accum_type)));
00274 }
00275
00276
00277
00280 const Retinal_Object& Retinal_Composite::mostactive(Coordinate x, Coordinate y) const
00281 {
00282 if (children.begin()==children.end())
00283 return *this;
00284 else {
00285 Retinal_Object* champ = *children.begin();
00286 Activity high_act = champ->activation(x,y);
00287 Activity act;
00288 for (Retinal_Composite::const_iterator i = children.begin()+1; i!= children.end(); i++) {
00289 act = (*i)->activation(x,y);
00290 if (act>high_act) {
00291 champ = *i;
00292 high_act=act;
00293 }
00294 }
00295 return *champ;
00296 }
00297 }
00298
00299
00300
00303 string accumulate_stringreps(string val, Retinal_Object* r)
00304 { return val + " [" + r->stringrep() + "]"; }
00305
00306
00307
00308 string Retinal_Composite::stringrep() const
00309 {
00310 return Retinal_Object::stringrep() +
00311 (dominant_child ? " " + dominant_child->stringrep()
00312 : std::accumulate(ISEQ(children),string(""),accumulate_stringreps));
00313 }
00314
00315
00316
00317 bool Retinal_Composite::inside(Coordinate x, Coordinate y) const
00318 {
00319
00320 if (!(accum_type==OneHot && dominant_child))
00321 return bounding_box.inside(x,y);
00322
00323
00324 const Coordinate dx = (x-cx)*div_size;
00325 const Coordinate dy = (y-cy)*div_size;
00326 const Coordinate xp = dx*cosmt-dy*sinmt;
00327 const Coordinate yp = dx*sinmt+dy*cosmt;
00328
00329 return dominant_child->inside(xp,yp);
00330 }
00331
00332
00333
00334
00335
00336
00337
00338 bool Retinal_ManagedComposite::distance_valid (const Retinal_Object& obj1, const Retinal_Object& obj2)
00339 {
00340 if (!*min_dist_enforce && !*max_dist_enforce)
00341 return true;
00342
00343 const Coordinate dist = Generic::hypot(obj1.get_var("cx") - obj2.get_var("cx"),
00344 obj1.get_var("cy") - obj2.get_var("cy"));
00345
00346 return ((!*min_dist_enforce || dist >= *min_dist) &&
00347 (!*max_dist_enforce || dist <= *max_dist) );
00348 }
00349
00350
00351
00352 bool Retinal_ManagedComposite::accumulate_managed_next(bool val, Retinal_Object* r)
00353 {
00354
00355
00356
00357
00358
00359 const int max_trials=100;
00360
00361
00362 for (int trial=0; trial<max_trials; trial++) {
00363 r->next();
00364
00365 iterator it = children.begin();
00366 while (*it != r && distance_valid(*r,**it))
00367 it++;
00368
00369 if (*it == r) {
00370 r->set_active(true);
00371 return val;
00372 }
00373 }
00374
00375 r->set_active(false);
00376 return false;
00377 }
00378
00379
00380
00381 bool Retinal_ManagedComposite::next()
00382 {
00383 bool val=true;
00384 for (iterator i = Retinal_Composite::children.begin();
00385 i != children.end(); i++) {
00386 val = accumulate_managed_next(val,*i);
00387 }
00388
00389 return val && Retinal_Object::next();
00390 }
00391
00392
00393
00394
00395
00396
00397
00399 Retinal_Object::Activity Retinal_AnchoredManagedComposite::activ(Coordinate x, Coordinate y) const
00400 {
00401 return (dominant_child ? dominant_child->activation(x,y)
00402 : std::accumulate(ISEQ(children),accum_base(),ActivityAccumulator(x,y,accum_type)));
00403 }
00404
00405
00406
00408 string Retinal_AnchoredManagedComposite::stringrep() const
00409 {
00410 return name() +
00411 (dominant_child ? " " + dominant_child->stringrep()
00412 : std::accumulate(ISEQ(children),string(""),accumulate_stringreps));
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428 #ifndef NO_VALGEN_STRINGS
00429 RetinalObjectStringArgs::ParamList Retinal_CircularGaussian::paramlist() {
00430 RetinalObjectStringArgs::ParamList p;
00431 p.push_back("cx");
00432 p.push_back("cy");
00433 p.push_back("xsigma");
00434 p.push_back("scale");
00435 p.push_back("offset");
00436 return p;
00437 }
00438 #endif
00439
00440
00441 bool Retinal_CircularGaussian::update() const
00442 {
00443
00444 cx = get_var("cx");
00445 cy = get_var("cy");
00446 const Variable xsigma = get_var("xsigma");
00447 div_sigmasq = 1/(xsigma*xsigma);
00448
00449
00450 const Coordinate boundrad=bound_mult*xsigma;
00451 bounding_box.set(cx-boundrad,cy-boundrad,
00452 cx+boundrad,cy+boundrad);
00453
00454 return Retinal_Object::update();
00455 }
00456
00457
00458 Retinal_Object::Activity Retinal_CircularGaussian::activ(Coordinate x, Coordinate y) const
00459 {
00460 const Coordinate dx = x-cx;
00461 const Coordinate dy = y-cy;
00462
00463 return exp( -(dx*dx+dy*dy)*div_sigmasq);
00464 }
00465
00466
00467
00468 #ifndef NO_VALGEN_STRINGS
00469 RetinalObjectStringArgs::ParamList Retinal_Gaussian::paramlist() {
00470 RetinalObjectStringArgs::ParamList p;
00471 p.push_back("theta");
00472 p.push_back("cx");
00473 p.push_back("cy");
00474 p.push_back("xsigma");
00475 p.push_back("ysigma");
00476 p.push_back("scale");
00477 p.push_back("offset");
00478 return p;
00479 }
00480 #endif
00481
00482
00483 bool Retinal_Gaussian::update() const
00484 {
00485
00486 cx = get_var("cx");
00487 cy = get_var("cy");
00488 const Variable t = get_var("theta");
00489 cost = cos(t);
00490 sint = sin(t);
00491 const Variable xsigma = get_var("xsigma");
00492 const Variable ysigma = get_var("ysigma");
00493 div_xsigma = 1/xsigma;
00494 div_ysigma = 1/ysigma;
00495
00496
00497 const Variable xrad=bound_mult*xsigma;
00498 const Variable yrad=bound_mult*ysigma;
00499 bounding_box.set(-xrad,-yrad,xrad,yrad).rotate(t).translate(cx,cy);
00500
00501 return Retinal_Object::update();
00502 }
00503
00504
00505 Retinal_Object::Activity Retinal_Gaussian::activ(Coordinate x, Coordinate y) const
00506 {
00507 const Coordinate dx = x-cx;
00508 const Coordinate dy = y-cy;
00509 const Coordinate xp = ( dx * cost + dy * sint)*div_xsigma;
00510 const Coordinate yp = (-dx * sint + dy * cost)*div_ysigma;
00511
00512 return exp(-(xp*xp + yp*yp));
00513 }
00514
00515
00516
00517 #ifndef NO_VALGEN_STRINGS
00518 RetinalObjectStringArgs::ParamList Retinal_Rectangle::paramlist() {
00519 RetinalObjectStringArgs::ParamList p;
00520 p.push_back("cx");
00521 p.push_back("cy");
00522 p.push_back("xsigma");
00523 p.push_back("ysigma");
00524 p.push_back("scale");
00525 p.push_back("offset");
00526 return p;
00527 }
00528 #endif
00529
00530
00531 bool Retinal_Rectangle::update() const
00532 {
00533
00534 const Coordinate xrad = get_var("xsigma");
00535 const Coordinate yrad = get_var("ysigma");
00536 const Coordinate cx_ = get_var("cx");
00537 const Coordinate cy_ = get_var("cy");
00538 bounding_box.set(-xrad,-yrad,xrad,yrad).translate(cx_,cy_);
00539
00540 return Retinal_Object::update();
00541 }
00542
00543
00544
00545 #ifndef NO_VALGEN_STRINGS
00546 RetinalObjectStringArgs::ParamList Retinal_SineGrating::paramlist() {
00547 RetinalObjectStringArgs::ParamList p;
00548 p.push_back("theta");
00549 p.push_back("freq");
00550 p.push_back("phase");
00551 p.push_back("scale");
00552 p.push_back("offset");
00553 p.push_back("cx");
00554 p.push_back("cy");
00555 return p;
00556 }
00557 #endif
00558
00559
00560 bool Retinal_SineGrating::update() const
00561 {
00562
00563 const Variable t = get_var("theta");
00564 cost = cos(t);
00565 sint = sin(t);
00566 phase = get_var("phase");
00567 freq = get_var("freq");
00568 cx = get_var("cx");
00569 cy = get_var("cy");
00570
00571 return Retinal_Object::update();
00572 }
00573
00574
00575 Retinal_Object::Activity Retinal_SineGrating::activ(Coordinate x, Coordinate y) const
00576 { return sin( freq*((x-cx)*sint-(y-cy)*cost) + phase); }
00577
00578
00579
00580 #ifndef NO_VALGEN_STRINGS
00581 RetinalObjectStringArgs::ParamList Retinal_Gabor::paramlist() {
00582 RetinalObjectStringArgs::ParamList p;
00583 p.push_back("theta");
00584 p.push_back("cx");
00585 p.push_back("cy");
00586 p.push_back("xsigma");
00587 p.push_back("ysigma");
00588 p.push_back("freq");
00589 p.push_back("phase");
00590 p.push_back("scale");
00591 p.push_back("offset");
00592 return p;
00593 }
00594 #endif
00595
00596
00597 bool Retinal_Gabor::update() const
00598 {
00599
00600 cx = get_var("cx");
00601 cy = get_var("cy");
00602 const Variable t = get_var("theta");
00603 cost = cos(t);
00604 sint = sin(t);
00605 phase = get_var("phase");
00606 freq = get_var("freq");
00607 const Variable xsigma = get_var("xsigma");
00608 const Variable ysigma = get_var("ysigma");
00609 div_xsigmasq = 1/(xsigma*xsigma);
00610 div_ysigmasq = 1/(ysigma*ysigma);
00611
00612
00613 const Variable xrad=bound_mult*xsigma;
00614 const Variable yrad=bound_mult*ysigma;
00615 bounding_box.set(-xrad,-yrad,xrad,yrad).rotate(t).translate(cx,cy);
00616
00617 return Retinal_Object::update();
00618 }
00619
00620
00621 Retinal_Object::Activity Retinal_Gabor::activ(Coordinate x, Coordinate y) const
00622 {
00623 const Coordinate dx = x-cx;
00624 const Coordinate dy = y-cy;
00625 const Coordinate xp = ( dx * cost + dy * sint);
00626 const Coordinate yp = (-dx * sint + dy * cost);
00627
00628 const Activity gaussian = exp(-(xp*xp*div_xsigmasq + yp*yp*div_ysigmasq));
00629 const Activity grating = 0.5+0.5*cos( freq*yp + phase );
00630
00631 return grating * gaussian;
00632 }
00633
00634
00635
00636 #ifndef NO_VALGEN_STRINGS
00637 RetinalObjectStringArgs::ParamList Retinal_FuzzyLine::paramlist() {
00638 RetinalObjectStringArgs::ParamList p;
00639 p.push_back("theta");
00640 p.push_back("cx");
00641 p.push_back("cy");
00642 p.push_back("ysigma");
00643 p.push_back("center_width");
00644 p.push_back("scale");
00645 p.push_back("offset");
00646 return p;
00647 }
00648 #endif
00649
00650
00651 bool Retinal_FuzzyLine::update() const
00652 {
00653
00654 cx = get_var("cx");
00655 cy = get_var("cy");
00656 centerw = get_var("center_width");
00657 const Variable t = get_var("theta");
00658 cost = cos(t);
00659 sint = sin(t);
00660 const Variable ysigma = get_var("ysigma");
00661 div_ysigmasq = 1/(ysigma*ysigma);
00662
00663 return Retinal_Object::update();
00664 }
00665
00666
00667 Retinal_Object::Activity Retinal_FuzzyLine::activ(Coordinate x, Coordinate y) const
00668 {
00669 const Coordinate dx = x-cx;
00670 const Coordinate dy = y-cy;
00671 const Coordinate distance_from_line = fabs(dy*cost - dx*sint);
00672 const Coordinate gaussian_x_coord = (distance_from_line - centerw/2);
00673 return (gaussian_x_coord<=0 ? 1.0
00674 : exp(-gaussian_x_coord*gaussian_x_coord*div_ysigmasq));
00675 }
00676
00677
00678
00679 #ifndef NO_VALGEN_STRINGS
00680 RetinalObjectStringArgs::ParamList Retinal_FuzzyDisc::paramlist() {
00681 RetinalObjectStringArgs::ParamList p;
00682 p.push_back("cx");
00683 p.push_back("cy");
00684 p.push_back("ysigma");
00685 p.push_back("center_width");
00686 p.push_back("scale");
00687 p.push_back("offset");
00688 return p;
00689 }
00690 #endif
00691
00692
00693 bool Retinal_FuzzyDisc::update() const
00694 {
00695
00696 cx = get_var("cx");
00697 cy = get_var("cy");
00698 centerw = get_var("center_width");
00699 const Variable ysigma = get_var("ysigma");
00700 div_ysigmasq = 1/(ysigma*ysigma);
00701
00702 return Retinal_Object::update();
00703 }
00704
00705
00706 Retinal_Object::Activity Retinal_FuzzyDisc::activ(Coordinate x, Coordinate y) const
00707 {
00708 const Coordinate dx = x-cx;
00709 const Coordinate dy = y-cy;
00710 const Coordinate distance_from_line = sqrt(dx*dx+dy*dy);
00711 const Coordinate gaussian_x_coord = (distance_from_line - centerw/2);
00712 return (gaussian_x_coord<=0 ? 1.0
00713 : exp(-gaussian_x_coord*gaussian_x_coord*div_ysigmasq));
00714 }
00715
00716
00717
00718 #ifndef NO_VALGEN_STRINGS
00719 RetinalObjectStringArgs::ParamList Retinal_FuzzyRing::paramlist() {
00720 RetinalObjectStringArgs::ParamList p;
00721 p.push_back("cx");
00722 p.push_back("cy");
00723 p.push_back("ysigma");
00724 p.push_back("center_width");
00725 p.push_back("radius");
00726 p.push_back("scale");
00727 p.push_back("offset");
00728 return p;
00729 }
00730 #endif
00731
00732
00733 bool Retinal_FuzzyRing::update() const
00734 {
00735
00736 cx = get_var("cx");
00737 cy = get_var("cy");
00738 centerw = get_var("center_width");
00739 radius = get_var("radius");
00740 const Variable ysigma = get_var("ysigma");
00741 div_ysigmasq = 1/(ysigma*ysigma);
00742
00743 return Retinal_Object::update();
00744 }
00745
00746
00747 Retinal_Object::Activity Retinal_FuzzyRing::activ(Coordinate x, Coordinate y) const
00748 {
00749 const Coordinate dx = x-cx;
00750 const Coordinate dy = y-cy;
00751 const Coordinate distance_from_line = fabs(radius - sqrt(dx*dx+dy*dy));
00752 const Coordinate gaussian_x_coord = (distance_from_line - centerw/2);
00753 return (gaussian_x_coord<=0 ? 1.0
00754 : exp(-gaussian_x_coord*gaussian_x_coord*div_ysigmasq));
00755 }
00756
00757
00758
00759
00760
00761
00762
00763 #ifndef NO_VALGEN_STRINGS
00764
00766 string pgm_full_pathname(const string& filename, const string& paths="")
00767 {
00768 StringParser::arglist words;
00769 const StringParser p;
00770 p.parse(paths,words);
00771
00772 StringParser::arglist::iterator i=words.begin();
00773 FILE *file=NULL;
00774 string name=filename;
00775
00776
00777 for (;;) {
00778 file=fopen(name.c_str(),"r");
00779 if (file) {
00780 fclose(file);
00781 return name;
00782 }
00783 if (i==words.end())
00784 return filename;
00785 name = (*i++)+filename;
00786 }
00787 #ifdef __GNUC__
00788 return "";
00789 #endif
00790 }
00791
00792
00793 RetinalObjectStringArgs::ParamList Retinal_PGM::paramlist() {
00794 RetinalObjectStringArgs::ParamList p;
00795 p.push_back("theta");
00796 p.push_back("cx");
00797 p.push_back("cy");
00798 p.push_back("size_scale");
00799 p.push_back("autoscale");
00800 p.push_back("transparent");
00801 p.push_back("scale");
00802 p.push_back("offset");
00803 return p;
00804 }
00805
00806
00807 Retinal_PGM::Retinal_PGM( const string& name_val, RetinalObjectStringArgs& sa,
00808 Retinal_Composite* parent)
00809 : Retinal_Object(name_val), ascale(1.0), aoffset(0.0), transparent_level(-1)
00810 {
00811 const string filename = sa.parsed_next("image_filename");
00812 const string paths = sa.parsed_get_default("image_paths");
00813 basename=pgm_full_pathname(filename, paths);
00814 const std::pair<int,int> size = pnm_size(basename);
00815 const int width = size.first;
00816 const int height = size.second;
00817
00818
00819 if (width<=0 || height<=0) {
00820 sa.error("Could not read image file `"+basename+"'");
00821 return;
00822 }
00823 set_active(pgm_read(basename,image));
00824 if (!get_active())
00825 sa.error("Problem reading image file `"+basename+"'; not in .pgm or .pbm format?");
00826 border=mat::edge_average(image);
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847 if (parent) {
00848 double dummy;
00849 const string size_scale_str = sa.parsed_get_default("size_scale");
00850 const double size_scale = sa.parse(size_scale_str,dummy);
00851 const double parentwidth = parent->nominal_width();
00852 const double parentheight = parent->nominal_height();
00853 const double excesswidth = width*size_scale - parentwidth;
00854 const double excessheight = height*size_scale - parentheight;
00855
00856 if (excesswidth>=0 && excessheight>=0) {
00857
00858 const string cx_default = "Uncorrelate &uncorrelation " + String::stringrep(parentwidth/2-excesswidth/2) + " " + String::stringrep(parentwidth/2+excesswidth/2) + " Random " + String::stringrep(parentwidth/2)
00859 + " " + String::stringrep(excesswidth/2);
00860 const string cy_default = "Uncorrelate &uncorrelation " + String::stringrep(parentheight/2-excessheight/2) + " " + String::stringrep(parentheight/2+excessheight/2) + " Random " + String::stringrep(parentheight/2)
00861 + " " + String::stringrep(excessheight/2);
00862
00863 sa.set_default("cx", cx_default);
00864 sa.set_default("cy", cy_default);
00865 sa.set_default("theta", "PI/2");
00866 }
00867 }
00868
00869
00870 merge_vars(sa.vars(paramlist()));
00871
00872
00873 const Variable transparent = get_var("transparent");
00874 if (transparent>0)
00875 transparent_level=transparent;
00876 else if (pgm_white_is_transparent(basename))
00877 transparent_level=0.999;
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887 const Variable autoscale = get_var("autoscale");
00888 if (autoscale>0) {
00889 const double maxval = *(std::max_element(MSEQ(image)));
00890 const double minval = *(std::min_element(MSEQ(image)));
00891 const double range = maxval-minval;
00892 if (range>0) {
00893 ascale = 1/range;
00894 aoffset = minval;
00895 border = border*ascale+aoffset;
00896
00897 }
00898 }
00899 }
00900 #endif
00901
00902
00903 bool Retinal_PGM::update() const
00904 {
00905
00906 const Variable mt = -get_var("theta");
00907 cx = get_var("cx");
00908 cy = get_var("cy");
00909 cosmt = cos(mt);
00910 sinmt = sin(mt);
00911 const Variable size_scale = get_var("size_scale");
00912 div_size = 1/size_scale;
00913
00914
00915 xoff = image.nrows()/2;
00916 yoff = image.ncols()/2;
00917
00918
00919 bounding_box.set(-xoff-1,-yoff-1,+xoff+1,+yoff+1);
00920 bounding_box.scale(size_scale,size_scale).rotate(mt).translate(cx,cy);
00921
00922 return Retinal_Object::update();
00923 }
00924
00925
00926
00933 Retinal_Object::Activity Retinal_PGM::pixel_value(Coordinate x, Coordinate y, bool& inbounds) const
00934 {
00935 const Coordinate dx = (x-cx)*div_size;
00936 const Coordinate dy = (y-cy)*div_size;
00937 const Coordinate xp = dx*cosmt-dy*sinmt+xoff;
00938 const Coordinate yp = dx*sinmt+dy*cosmt+yoff;
00939
00940
00941
00942
00943
00944
00945 const int r = image.nrows()-int(xp+0.5)-1;
00946 const int c = image.ncols()-int(yp+0.5)-1;
00947
00948 inbounds = ( r >= 0 && c >= 0 && r < int(image.nrows()) && c < int(image.ncols()) );
00949 return inbounds? image[r][c] : 0;
00950 }
00951
00952
00953
00955 Retinal_Object::Activity Retinal_PGM::activ(Coordinate x, Coordinate y) const
00956 {
00957 bool inbounds;
00958 Retinal_Object::Activity pixval=pixel_value(x,y,inbounds);
00959 return inbounds? (ascale * (pixval-aoffset)) : border;
00960
00961 }
00962
00963
00964 bool Retinal_PGM::inside(Coordinate x, Coordinate y) const
00965 {
00966
00967 if (!bounding_box.inside(x,y)) return false;
00968
00969
00970 if (transparent_level<0) return true;
00971
00972
00973
00974 bool inbounds;
00975 Retinal_Object::Activity pixval=pixel_value(x,y,inbounds);
00976 return (inbounds && !(pixval>transparent_level));
00977 }
00978