28 #include <opencv2/opencv.hpp>
30 #include <yarp/os/all.h>
31 #include <yarp/sig/all.h>
32 #include <yarp/cv/Cv.h>
35 #define NODE_OFF Scalar(0,0,255)
36 #define NODE_ON Scalar(0,255,0)
40 using namespace yarp::os;
41 using namespace yarp::sig;
42 using namespace yarp::cv;
99 BufferedPort<ImageOf<PixelBgr>>
inPort;
113 name=rf.check(
"name",Value(
"motionCUT")).asString();
114 coverXratio=rf.check(
"coverXratio",Value(0.75)).asFloat64();
115 coverYratio=rf.check(
"coverYratio",Value(0.75)).asFloat64();
116 nodesStep=rf.check(
"nodesStep",Value(6)).asInt32();
117 winSize=rf.check(
"winSize",Value(15)).asInt32();
118 recogThres=rf.check(
"recogThres",Value(0.01)).asFloat64();
119 adjNodesThres=rf.check(
"adjNodesThres",Value(4)).asInt32();
120 blobMinSizeThres=rf.check(
"blobMinSizeThres",Value(10)).asInt32();
121 framesPersistence=rf.check(
"framesPersistence",Value(3)).asInt32();
125 if (rf.check(
"cropSize"))
127 Value &vCropSize=rf.find(
"cropSize");
128 if (!vCropSize.isString())
129 cropSize=vCropSize.asInt32();
132 recogThresAbs=recogThres*((256*winSize*winSize)/100.0);
136 coverXratio=
std::min(coverXratio,1.0);
137 coverYratio=
std::min(coverYratio,1.0);
139 inPort.open(
"/"+name+
"/img:i");
140 outPort.open(
"/"+name+
"/img:o");
141 optPort.open(
"/"+name+
"/opt:o");
142 nodesPort.open(
"/"+name+
"/nodes:o");
143 blobsPort.open(
"/"+name+
"/blobs:o");
144 cropPort.open(
"/"+name+
"/crop:o");
146 firstConsistencyCheck=
true;
156 yInfo(
"Process started successfully");
158 yInfo(
"name = %s",name.c_str());
159 yInfo(
"coverXratio = %g",coverXratio);
160 yInfo(
"coverYratio = %g",coverYratio);
161 yInfo(
"nodesStep = %d",nodesStep);
162 yInfo(
"winSize = %d",winSize);
163 yInfo(
"recogThres = %g",recogThres);
164 yInfo(
"recogThresAbs = %g",recogThresAbs);
165 yInfo(
"adjNodesThres = %d",adjNodesThres);
166 yInfo(
"blobMinSizeThres = %d",blobMinSizeThres);
167 yInfo(
"framesPersistence = %d",framesPersistence);
169 yInfo(
"cropSize = %d",cropSize);
171 yInfo(
"cropSize = auto");
172 yInfo(
"verbosity = %s",
verbosity?
"on":
"off");
175 yError(
"Process did not start");
181 double latch_t, dt0, dt1, dt2;
183 while (!isStopping())
186 ImageOf<PixelBgr> *pImgBgrIn=
inPort.read(
true);
187 if (isStopping() || (pImgBgrIn==NULL))
192 inPort.getEnvelope(stamp);
194 double t0=Time::now();
197 if (firstConsistencyCheck || (pImgBgrIn->width()!=imgMonoIn.width()) ||
198 (pImgBgrIn->height()!=imgMonoIn.height()))
200 firstConsistencyCheck=
false;
202 imgMonoIn.resize(*pImgBgrIn);
203 imgMonoPrev.resize(*pImgBgrIn);
205 int min_x=(int)(((1.0-coverXratio)/2.0)*imgMonoIn.width());
206 int min_y=(int)(((1.0-coverYratio)/2.0)*imgMonoIn.height());
208 nodesX=((int)imgMonoIn.width()-2*min_x)/nodesStep+1;
209 nodesY=((int)imgMonoIn.height()-2*min_y)/nodesStep+1;
211 int nodesNum=nodesX*nodesY;
212 nodesPrev.assign(nodesNum,Point2f(0.0f,0.0f));
213 nodesCurr.assign(nodesNum,Point2f(0.0f,0.0f));
214 featuresFound.assign(nodesNum,0);
215 featuresErrors.assign(nodesNum,0.0f);
216 nodesPersistence.assign(nodesNum,0);
220 for (
int y=min_y;
y<=(imgMonoIn.height()-min_y);
y+=nodesStep)
221 for (
int x=min_x;
x<=(imgMonoIn.width()-min_x);
x+=nodesStep)
222 nodesPrev[cnt++]=Point2f((
float)
x,(float)
y);
225 cvtColor(toCvMat(*pImgBgrIn),toCvMat(imgMonoPrev),CV_BGR2GRAY);
230 yInfo(
"Detected image of size %zdx%zd; using %dx%d=%d nodes; populated %zd nodes",
231 imgMonoIn.width(),imgMonoIn.height(),nodesX,nodesY,nodesNum,cnt);
239 cvtColor(toCvMat(*pImgBgrIn),toCvMat(imgMonoIn),CV_BGR2GRAY);
242 ImageOf<PixelBgr> imgBgrOut=*pImgBgrIn;
243 Mat imgBgrOutMat=toCvMat(imgBgrOut);
246 ImageOf<PixelMono> imgMonoOpt;
247 imgMonoOpt.resize(imgBgrOut);
249 Mat imgMonoOptMat=toCvMat(imgMonoOpt);
255 Bottle &nodesStepBottle=nodesBottle.addList();
256 nodesStepBottle.addString(
"nodesStep");
257 nodesStepBottle.addInt32(nodesStep);
260 activeNodesIndexSet.clear();
261 blobSortedList.clear();
265 constexpr
int maxLevel=5;
266 Size ws(winSize,winSize);
267 buildOpticalFlowPyramid(toCvMat(imgMonoPrev),pyrPrev,ws,maxLevel);
268 buildOpticalFlowPyramid(toCvMat(imgMonoIn),pyrCurr,ws,maxLevel);
269 calcOpticalFlowPyrLK(pyrPrev,pyrCurr,nodesPrev,nodesCurr,
270 featuresFound,featuresErrors,ws,maxLevel,
271 TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,30,0.3));
272 dt0=Time::now()-latch_t;
276 for (
size_t i=0; i<nodesPrev.size(); i++)
278 bool persistentNode=
false;
279 Point node=Point((
int)nodesPrev[i].
x,(
int)nodesPrev[i].
y);
282 if (!inhibition && (nodesPersistence[i]!=0))
284 circle(imgBgrOutMat,node,1,
NODE_ON,2);
285 circle(imgMonoOptMat,node,1,Scalar(255),2);
287 Bottle &nodeBottle=nodesBottle.addList();
288 nodeBottle.addInt32((
int)nodesPrev[i].
x);
289 nodeBottle.addInt32((
int)nodesPrev[i].
y);
292 activeNodesIndexSet.insert((
int)i);
294 nodesPersistence[i]--;
298 circle(imgBgrOutMat,node,1,
NODE_OFF,1);
302 bool skip=inhibition || (i<nodesX) || (i>=(nodesPrev.size()-nodesX)) || (row==0) || (row==(nodesX-1));
304 if (!skip && (featuresFound[i]!=0) && (featuresErrors[i]>recogThresAbs))
308 int cntAdjNodesOn=-1;
311 for (
int j=i-nodesX; j<=(i+nodesX); j+=nodesX)
312 for (
int k=j-1; k<=(j+1); k++)
313 cntAdjNodesOn+=(
int)((featuresFound[k]!=0)&&(featuresErrors[k]>recogThresAbs));
316 if (cntAdjNodesOn>=adjNodesThres)
319 nodesPersistence[i]=framesPersistence;
324 circle(imgBgrOutMat,node,1,
NODE_ON,2);
325 circle(imgMonoOptMat,node,1,Scalar(255),2);
327 Bottle &nodeBottle=nodesBottle.addList();
328 nodeBottle.addInt32((
int)nodesPrev[i].
x);
329 nodeBottle.addInt32((
int)nodesPrev[i].
y);
332 activeNodesIndexSet.insert((
int)i);
337 dt1=Time::now()-latch_t;
344 for (
int i=0; i<(int)blobSortedList.size(); i++)
346 Blob &blob=blobSortedList[i];
347 int blueLev=255-((100*i)%255);
348 int redLev=(100*i)%255;
352 Bottle &blobBottle=blobsBottle.addList();
353 blobBottle.addInt32(centroid.x);
354 blobBottle.addInt32(centroid.y);
355 blobBottle.addInt32(blob.
size);
357 circle(imgBgrOutMat,centroid,4,Scalar(blueLev,0,redLev),3);
359 dt2=Time::now()-latch_t;
362 if (outPort.getOutputCount()>0)
364 outPort.prepare()=imgBgrOut;
365 outPort.setEnvelope(stamp);
369 if (optPort.getOutputCount()>0)
371 optPort.prepare()=imgMonoOpt;
372 optPort.setEnvelope(stamp);
377 if ((nodesPort.getOutputCount()>0) && (nodesBottle.size()>1))
379 nodesPort.prepare()=nodesBottle;
380 nodesPort.setEnvelope(stamp);
384 if ((blobsPort.getOutputCount()>0) && (blobsBottle.size()>0))
386 blobsPort.prepare()=blobsBottle;
387 blobsPort.setEnvelope(stamp);
391 if ((cropPort.getOutputCount()>0) && (blobsBottle.size()>0))
393 Bottle &blob=*blobsBottle.get(0).asList();
394 int x=blob.get(0).asInt32();
395 int y=blob.get(1).asInt32();
396 int d=(cropSize>0)?cropSize:(
int)(nodesStep*sqrt((
double)blob.get(2).asInt32()));
400 Point br=Point(
std::min(
x+d2,(
int)pImgBgrIn->width()-1),
std::min(
y+d2,(
int)pImgBgrIn->height()-1));
401 Point cropSize=Point(br.x-tl.x,br.y-tl.y);
403 ImageOf<PixelBgr> &cropImg=cropPort.prepare();
404 cropImg.resize(cropSize.x,cropSize.y);
405 toCvMat(*pImgBgrIn)(Rect(tl.x,tl.y,cropSize.x,cropSize.y)).copyTo(toCvMat(cropImg));
407 cropPort.setEnvelope(stamp);
412 imgMonoPrev=imgMonoIn;
414 double t1=Time::now();
418 yInfo(
"cycle timing [ms]: optflow(%g), colorgrid(%g), blobdetection(%g), overall(%g)",
419 1000.0*dt0,1000.0*dt1,1000.0*dt2,1000.0*(t1-t0));
451 while (activeNodesIndexSet.size())
457 floodFill(*(activeNodesIndexSet.begin()),&blob);
464 if (blob.
size>blobMinSizeThres)
472 auto el=activeNodesIndexSet.find(i);
473 if ((el!=activeNodesIndexSet.end()) && (pBlob!=NULL))
481 activeNodesIndexSet.erase(el);
484 for (
int j=i-nodesX; j<=(i+nodesX); j+=nodesX)
485 for (
int k=j-1; k<=(j+1); k++)
495 for (deque<Blob>::iterator el=blobSortedList.begin(); el!=blobSortedList.end(); el++)
497 if (el->size<blob.
size)
499 blobSortedList.insert(el,blob);
506 blobSortedList.push_back(blob);
510 bool execReq(
const Bottle &req, Bottle &reply)
514 string cmd=req.get(0).asString();
521 string subcmd=req.get(1).asString();
523 if (subcmd==
"winSize")
525 winSize=req.get(2).asInt32();
526 reply.addString(
"ack");
528 else if (subcmd==
"recogThres")
530 recogThres=req.get(2).asFloat64();
531 recogThresAbs=recogThres*((256*winSize*winSize)/100.0);
532 reply.addString(
"ack");
534 else if (subcmd==
"adjNodesThres")
536 adjNodesThres=req.get(2).asInt32();
537 reply.addString(
"ack");
539 else if (subcmd==
"blobMinSizeThres")
541 blobMinSizeThres=req.get(2).asInt32();
542 reply.addString(
"ack");
544 else if (subcmd==
"framesPersistence")
546 framesPersistence=req.get(2).asInt32();
547 reply.addString(
"ack");
549 else if (subcmd==
"cropSize")
551 Value &vCropSize=req.get(2);
552 if (!vCropSize.isString())
553 cropSize=vCropSize.asInt32();
557 reply.addString(
"ack");
559 else if (subcmd==
"verbosity")
562 reply.addString(
"ack");
564 else if (subcmd==
"inhibition")
566 inhibition=req.get(2).asString()==
"on";
567 reply.addString(
"ack");
577 string subcmd=req.get(1).asString();
579 if (subcmd==
"winSize")
580 reply.addInt32(winSize);
581 else if (subcmd==
"recogThres")
582 reply.addFloat64(recogThres);
583 else if (subcmd==
"adjNodesThres")
584 reply.addInt32(adjNodesThres);
585 else if (subcmd==
"blobMinSizeThres")
586 reply.addInt32(blobMinSizeThres);
587 else if (subcmd==
"framesPersistence")
588 reply.addInt32(framesPersistence);
589 else if (subcmd==
"cropSize")
592 reply.addInt32(cropSize);
594 reply.addString(
"auto");
596 else if (subcmd==
"verbosity")
598 else if (subcmd==
"inhibition")
599 reply.addString(inhibition?
"on":
"off");
635 rpcPort.open(
"/"+thr->
getName()+
"/rpc");
642 bool respond(
const Bottle &command, Bottle &reply)
644 if (thr->
execReq(command,reply))
647 return RFModule::respond(command,reply);
685 rf.configure(
argc,argv);
687 if (rf.check(
"help"))
689 cout<<
"Available options:"<<endl;
690 cout<<
"\t--name <string>"<<endl;
691 cout<<
"\t--coverXratio <double>"<<endl;
692 cout<<
"\t--coverYratio <double>"<<endl;
693 cout<<
"\t--nodesStep <int>"<<endl;
694 cout<<
"\t--winSize <int>"<<endl;
695 cout<<
"\t--recogThres <double>"<<endl;
696 cout<<
"\t--adjNodesThres <int>"<<endl;
697 cout<<
"\t--blobMinSizeThres <int>"<<endl;
698 cout<<
"\t--framesPersistence <int>"<<endl;
699 cout<<
"\t--cropSize \"auto\" or <int>"<<endl;
700 cout<<
"\t--verbosity"<<endl;
705 if (!
yarp.checkNetwork())
707 yError(
"YARP server not available!");
712 return mod.runModule(rf);
bool configure(ResourceFinder &rf)
bool respond(const Bottle &command, Bottle &reply)
ProcessThread(ResourceFinder &_rf)
BufferedPort< ImageOf< PixelBgr > > cropPort
void floodFill(const int i, Blob *pBlob)
bool firstConsistencyCheck
void insertBlob(const Blob &blob)
BufferedPort< ImageOf< PixelBgr > > outPort
vector< Point2f > nodesPrev
ImageOf< PixelMono > imgMonoIn
ImageOf< PixelMono > imgMonoPrev
BufferedPort< Bottle > nodesPort
set< int > activeNodesIndexSet
deque< Blob > blobSortedList
BufferedPort< ImageOf< PixelBgr > > inPort
vector< uchar > featuresFound
BufferedPort< Bottle > blobsPort
BufferedPort< ImageOf< PixelMono > > optPort
vector< Point2f > nodesCurr
vector< float > featuresErrors
vector< int > nodesPersistence
bool execReq(const Bottle &req, Bottle &reply)
int main(int argc, char *argv[])
Copyright (C) 2008 RobotCub Consortium.