#include #include #include #include #include #include #include #include #include #include #include int error_counter = 0; int error_frames = 0; int frame_counter = 0; int error_counter_save = 0; void update_error_frames_A(){ error_counter_save = error_counter; } void update_error_frames_B(){ if(error_counter_save != error_counter){ error_frames++; } } struct InputGrabber : public Grabber{ struct Blob{ unsigned int x; unsigned int y; unsigned int r; float vx; float vy; icl8u color[3]; int id; void set_new_id(int new_id){ if(id != new_id && id != -1){ error_counter++; } id = new_id; } void show(int idx=-1){ printf("Blob idx=%d pos=(%d,%d) r=%d vx=%f vy=%f color=(%d,%d,%d)\n", idx,x,y,r,vx,vy,color[0],color[1],color[2]); } }; static inline unsigned int distance(int x1, int y1, int x2, int y2){ return (unsigned int)round(::sqrt(pow(float(x1-x2),2)+pow(float(y1-y2),2))); } static inline void memline(icl8u *p, icl8u v, int len){ for(icl8u *c = p+len-1; c >= p; --c){ *c = v; } } template static inline void draw_blob(Img8u &image, Blob &b){ Channel8u c[N]; image.extractChannels(c); b.r +=2; { int rr = b.r*b.r; int h = image.getHeight(); int w = image.getWidth(); int ystart = iclMax(-b.r,-b.y); int yend = iclMin(b.r,h-b.y-1); for(int dy = ystart;dy<=yend;++dy){ int y = dy+b.y; int dx = (int)round(::sqrt(rr-dy*dy)); int xstart = iclMax((unsigned int)(0),b.x-dx); int xend = iclMin(b.x+dx,(unsigned int)(w-1)); for(unsigned int i=0;i("-mingap",0,3); minr = pa_subarg("-minr",0,10); maxr = pa_subarg("-maxr",0,20); maxv = pa_subarg("-maxv",0,10); maxdv = pa_subarg("-maxdv",0,2); maxtrys = 100; blobcolor[0] = 255; blobcolor[1] = 0; blobcolor[2] = 0; setBlobCount(nBlobs); } int find_blob(int x, int y){ for(unsigned int i=0;i= maxtrys){ throw(ICLException("Max trys reached!")); } }while(!ok(b)); b.id = -1; return b; } void setBlobCount(unsigned int nBlobs){ if(nBlobs < blobs.size()){ blobs.resize(nBlobs); }else{ try{ for(unsigned int i=blobs.size();i= image.getWidth()-b.r){ b.vx*=-1; cont = true; } if(b.y < b.r || b.y >= image.getHeight()-b.r){ b.vy*=-1; cont = true; } if(cont) continue; if(!ok(b,i)){ if(++t > maxtrys){ err = true; break; }else{ b = bSave; if(random(1.0) > 0.5){ b.vx*=-1; }else{ b.vy*=-1; } continue; } }else{ b.vx = clip(b.vx+(float)random(-maxdv,maxdv),-maxv, maxv); b.vy = clip(b.vy+(float)random(-maxdv,maxdv),-maxv, maxv); break; } } } } virtual const ImgBase *grabUD(ImgBase **dst=0){ ICLASSERT_RETURN_VAL(!dst,0); ICLASSERT_RETURN_VAL(getDesiredDepth() == depth8u,0); image.setSize(getDesiredSize()); image.setFormat(getDesiredFormat()); image.clear(); iterate(); if(image.getChannels() == 1){ for(unsigned int i=0;i(image,blobs[i]); } }else if(image.getChannels() == 3){ for(unsigned int i=0;i(image,blobs[i]); } }else{ ERROR_LOG("invalid channel count! (allowed is 1 or 3 but found " << image.getChannels() << ")"); } return ℑ } private: Img8u image; vector blobs; unsigned int mingap; unsigned int minr; unsigned int maxr; float maxv; float maxdv; unsigned int maxtrys; icl8u blobcolor[3]; }; typedef std::vector vec; GUI gui; static inline vec getCenters(const Img8u &image){ static RegionDetector rd; rd.setRestrictions(10,10000,1,255); const std::vector &bd = rd.detect(&image); static vec v; v.clear(); for(unsigned int i=0;i("-nblobs",0,30)); } grabber->setDesiredSize(Size(640,480)); grabber->setDesiredFormat(formatGray); gui << "draw[@handle=image@minsize=32x24]"; gui << ( GUI("hbox") << string("slider(0,100,")+pa_subarg("-sleeptime",0,"10") + ")[@handle=Hsl@out=Vsl@label=sleeptime]" << "togglebutton(!off,on)[@out=Vlo@label=Show labels]" ); gui.show(); } virtual void run(){ while(1){ static ICLDrawWidget *w = *gui.getValue("image"); const ImgBase *image = grabber->grab(); vec v = getCenters(*(image->asImg())); w->setImage(image); w->lock(); w->reset(); if(v.size()){ static PositionTracker pt(pa_subarg("-thresh",0,2)); pt.pushData(v.data(),v.size()/2); w->color(255,0,0); update_error_frames_A(); for(unsigned int i=0;isym(v[i],v[i+1],ICLDrawWidget::symCross); static bool &labelsOnFlag = gui.getValue("Vlo"); int curr_x = v[i]; int curr_y = v[i+1]; int curr_id = pt.getID(i/2); int blob_list_idx = ((InputGrabber*)grabber)->find_blob(curr_x,curr_y); if(blob_list_idx == -1){ ERROR_LOG("no blob at location found ???"); }else{ InputGrabber::Blob &b=((InputGrabber*)grabber)->get_blob((unsigned int)blob_list_idx); b.set_new_id(curr_id); } if(labelsOnFlag){ static char buf[100]; w->text(toStr(curr_id,buf),curr_x,curr_y,10); } } update_error_frames_B(); } frame_counter++; static FPSEstimator fps(10); w->color(255,255,255); char buf[40]; sprintf(buf,"blobs:%4d frames:%6d E:frames:%4d all:%4d ",v.size()/2,frame_counter,error_frames,error_counter); w->text(string(buf)+" "+fps.getFPSString().c_str(),5,5); w->unlock(); w->update(); static int &sleepTime = gui.getValue("Vsl"); msleep(sleepTime); } } private: Grabber *grabber; }; int main(int n, char **ppc){ pa_explain("-input","if used, an external image source is connected (e.g. -input dc 0, or -input unicap '*')"); pa_explain("-nblobs","(int) number of blobs to use"); pa_explain("-sleeptime","(int) initial sleeptime value"); pa_explain("-mingap","(int) minimal distance between two blobs"); pa_explain("-minr","(int) minimal radius of blobs"); pa_explain("-maxr","(int) maxinal radius of blobs"); pa_explain("-maxv","(int) maxinal speed of blobs (in pixles per frame)"); pa_explain("-maxdv","(int) maximal acceleration of blobs"); pa_explain("-thresh","(int) position tracker threshold for trivial association step"); pa_init(n,ppc,"-input(2) -nblobs(1) -sleeptime(1) -mingap(1) -minr(1) -maxr(1) -maxv(1) -maxdv(1) -thresh(1)"); QApplication app(n,ppc); WorkThread a; a.start(); return app.exec(); }