-
even authored83d82ad0
bstracker.cpp 10.43 KiB
#include "bstracker.h"
#include "blurredsegmentproto.h"
const int BSTracker::DEFAULT_FAST_TRACK_MAX_WIDTH = 5;
const int BSTracker::DEFAULT_FINE_TRACK_MAX_WIDTH = 8;
const int BSTracker::DEFAULT_ACCEPTED_LACKS = 5;
const int BSTracker::NO_VICINITY = 10000;
const int BSTracker::DEFAULT_VICINITY_THRESHOLD = 10;
const int BSTracker::MIN_SCAN = 8;
const int BSTracker::DEFAULT_MAX_SCAN = 32;
const int BSTracker::DEFAULT_FITTING_DELAY = 20;
const int BSTracker::DEFAULT_THICKENNING_LIMIT = 20;
const int BSTracker::DEFAULT_THINNING_DELAY = 20;
const int BSTracker::DEFAULT_THINNING_SPEED = 2;
const int BSTracker::DEFAULT_THINNING_REACH = 50;
const int BSTracker::DEFAULT_THINNING_RESOLUTION = 1000;
const int BSTracker::FAILURE_NO_START = 1;
const int BSTracker::FAILURE_IMAGE_BOUND_ON_RIGHT = 2;
const int BSTracker::FAILURE_IMAGE_BOUND_ON_LEFT = 4;
const int BSTracker::FAILURE_LOST_ORIENTATION = 32;
BSTracker::BSTracker ()
{
vicinityThreshold = NO_VICINITY + DEFAULT_VICINITY_THRESHOLD;
imaxWidth = DEFAULT_FAST_TRACK_MAX_WIDTH;
fmaxWidth = DEFAULT_FINE_TRACK_MAX_WIDTH;
acceptedLacks = DEFAULT_ACCEPTED_LACKS;
minRestart = acceptedLacks;
dynamicScans = true;
fittingDelay = DEFAULT_FITTING_DELAY;
recordScans = false;
orthoScan = false;
thickenningOn = true;
thickenningLimit = DEFAULT_THICKENNING_LIMIT;
thinningOn = false;
thinningDelay = DEFAULT_THINNING_DELAY;
thinningSpeed.set (DEFAULT_THINNING_SPEED, 100);
thinningReach.set (100 + DEFAULT_THINNING_REACH, 100);
gMap = NULL;
maxScan = DEFAULT_MAX_SCAN;
fail = 0;
cand = new int[1]; // to avoid systematic tests
lscan = 0;
rscan = 0;
}
BSTracker::~BSTracker ()
{
delete cand;
}
void BSTracker::clear ()
{
scanBound1.clear ();
scanBound2.clear ();
scanLine.clear ();
}
void BSTracker::setGradientMap (VMap *data)
{
gMap = data;
scanp.setSize (gMap->getWidth (), gMap->getHeight ());
delete cand;
cand = new int[data->getHeightWidthMax ()];
}
BlurredSegment *BSTracker::fastTrack (const Pt2i &p1, const Pt2i &p2,
bool centralp, const Pt2i &pc)
{
// Creates the scanner
DirectionalScanner *ds = NULL;
if (centralp)
ds = scanp.getScanner (pc, p1.vectorTo (p2), 4 * imaxWidth, false);
else ds = scanp.getScanner (p1, p2);
if (ds == NULL) return NULL;
// Builds a BS builder around a central point
vector<Pt2i> pix;
if (ds->first (pix) < MIN_SCAN)
{
delete ds;
return NULL;
}
if (recordScans)
{
scanBound1.push_back (pix.front ());
scanBound2.push_back (pix.back ());
scanLine.push_back (pix);
}
int candide;
Pt2i pfirst;
if (centralp) pfirst.set (pc.x (), pc.y ());
else
{
candide = gMap->largestIn (pix);
if (candide == -1)
{
delete ds;
return NULL;
}
pfirst.set (pix.at (candide));
}
BlurredSegmentProto bs (imaxWidth, pfirst);
Pt2i lastLeft (pfirst);
Pt2i lastRight (pfirst);
// Extends the segment
int lstop = 0;
int rstop = 0;
int lstart = 0;
int rstart = 0;
bool added = false;
bool scanningRight = true;
bool scanningLeft = true;
int fsCount = maxScan;
while ((scanningRight || scanningLeft) && (fsCount--))
{
// Extends on right
if (scanningRight)
{
if (ds->nextOnRight (pix) < MIN_SCAN) scanningRight = false;
else
{
if (recordScans)
{
scanBound1.push_back (pix.front ());
scanBound2.push_back (pix.back ());
scanLine.push_back (pix);
}
added = false;
candide = gMap->largestIn (pix);
if (candide != -1)
{
if (lastRight.manhattan (pix.at (candide)) <= vicinityThreshold)
added = bs.addRight (pix.at (candide));
}
if (added)
{
lastRight = pix.at (candide);
if (rstop != 0) rstop = 0;
}
else if (++rstop > acceptedLacks)
scanningRight = false;
}
}
// Extends on left
if (scanningLeft)
{
if (ds->nextOnLeft (pix) < MIN_SCAN) scanningLeft = false;
else
{
if (recordScans)
{
scanBound1.push_back (pix.front ());
scanBound2.push_back (pix.back ());
scanLine.push_back (pix);
}
added = false;
candide = gMap->largestIn (pix);
if (candide != -1)
{
if (lastLeft.manhattan (pix.at (candide)) < vicinityThreshold)
added = bs.addLeft (pix.at (candide));
}
if (added)
{
lastLeft = pix.at (candide);
if (lstop != 0) lstop = 0;
}
else if (++lstop > acceptedLacks)
scanningLeft = false;
}
}
}
if (rstart) bs.removeRight (rstart);
if (lstart) bs.removeLeft (lstart);
delete ds;
return (bs.endOfBirth ());
}
BlurredSegment *BSTracker::fineTrack (const Pt2i ¢er, const Vr2i &scandir,
int scanwidth, int bswidth,
const Vr2i &gref)
{
// Checks scan width minimal size
if (scanwidth < MIN_SCAN) scanwidth = MIN_SCAN;
// Gets detected segment normal vector
Vr2i normal = scandir.orthog ();
if (! normal.orientedAs (gref)) normal.invert ();
fail = 0;
// Creation of the directional scanner and the array of candidates
DirectionalScanner *ds = scanp.getScanner (center, normal,
scanwidth, dynamicScans);
if (ds == NULL)
{
fail = FAILURE_NO_START;
return NULL;
}
// Looking for a central point
vector<Pt2i> pix;
if (ds->first (pix) < MIN_SCAN)
{
delete ds;
fail = FAILURE_NO_START;
return NULL;
}
if (recordScans)
{
scanBound1.push_back (pix.front ());
scanBound2.push_back (pix.back ());
scanLine.push_back (pix);
}
int nbc = gMap->localMax (cand, pix, normal);
if (nbc == 0)
{
delete ds;
fail = FAILURE_NO_START;
return NULL;
}
BlurredSegmentProto bs (bswidth, pix[cand[0]]);
// Handles thickenning
bool thickenOn = thickenningOn;
int stableWidthCount = 0;
// Handles thinning
int count = 0;
AbsRat maxw (bswidth * DEFAULT_THINNING_RESOLUTION,
DEFAULT_THINNING_RESOLUTION);
// Extends the segment
lscan = 0;
rscan = 0;
int lstop = 0;
int rstop = 0;
int lstart = 0;
int rstart = 0;
bool added = false;
bool scanningRight = true;
bool scanningLeft = true;
bool thon = thinningOn;
while (scanningRight || scanningLeft)
{
count ++;
AbsRat sw = bs.minimalWidth ();
// Handles thickenning
if (thickenOn && stableWidthCount >= thickenningLimit)
{
AbsRat finalWidth (sw.sum (1));
if (finalWidth.lessThan (bs.getMaxWidth ())) bs.setMaxWidth (finalWidth);
thickenOn = false;
}
// Handles thinning
if (thon)
{
if (count > thinningDelay)
{
AbsRat oldmaxw (maxw);
maxw.attractsTo (sw, thinningSpeed);
AbsRat msw (sw);
msw.mult (thinningReach);
if (maxw.lessThan (msw))
{
maxw.sticksTo (msw);
if (oldmaxw.lessThan (maxw)) maxw.set (oldmaxw);
thon = false; // thinning deactivation
}
bs.setMaxWidth (maxw);
}
}
// Resets the scan stripe
if (dynamicScans && count > fittingDelay && bs.getLine () != NULL)
{
// Stops the detection if the segment gets crosswise
if (count == fittingDelay + 1)
{
Vr2i dirn = bs.getSupportVector ();
if (4 * dirn.squaredScalarProduct (scandir)
< dirn.norm2 () * scandir.norm2 ())
{
scanningLeft = false;
scanningRight = false;
fail += FAILURE_LOST_ORIENTATION;
}
}
int ppa, ppb, ppc;
bs.getLine()->getMedialAxis (ppa, ppb, ppc);
ds->bindTo (ppa, ppb, ppc);
}
// Extends on right
if (scanningRight)
{
added = false;
if (ds->nextOnRight (pix) < MIN_SCAN)
{
fail += FAILURE_IMAGE_BOUND_ON_RIGHT;
scanningRight = false;
}
else
{
if (recordScans)
{
scanBound1.push_back (pix.front ());
scanBound2.push_back (pix.back ());
scanLine.push_back (pix);
}
added = false;
nbc = gMap->localMax (cand, pix, normal);
for (int i = 0; ! added && i < nbc; i++)
added = bs.addRight (pix[cand[i]]);
stableWidthCount ++;
if (added)
{
if (sw.lessThan (bs.minimalWidth ())) stableWidthCount = 0;
rscan = count;
if (rstop == 0) rstart = 0;
else
{
rstart ++;
//if (rstart >= minRestart || rstart >= rstop)
if (rstart >= rstop)
{
rstop = 0;
rstart = 0;
}
}
}
else
{
if (++rstop - rstart > acceptedLacks)
{
if (bs.size () <= 3) fail = FAILURE_NO_START;
scanningRight = false;
}
}
}
}
// Extends on left
if (scanningLeft)
{
if (ds->nextOnLeft (pix) < MIN_SCAN)
{
fail += FAILURE_IMAGE_BOUND_ON_LEFT;
scanningLeft = false;
}
else
{
if (recordScans)
{
scanBound1.push_back (pix.front ());
scanBound2.push_back (pix.back ());
scanLine.push_back (pix);
}
added = false;
nbc = gMap->localMax (cand, pix, normal);
for (int i = 0; ! added && i < nbc; i++)
added = bs.addLeft (pix[cand[i]]);
stableWidthCount ++;
if (added)
{
if (sw.lessThan (bs.minimalWidth ())) stableWidthCount = 0;
lscan = count;
if (lstop == 0) lstart = 0;
else
{
lstart ++;
//if (lstart >= minRestart || lstart >= lstop)
if (lstart >= lstop)
{
lstop = 0;
lstart = 0;
}
}
}
else
{
if (++lstop - lstart > acceptedLacks)
{
if (bs.size () <= 3) fail = FAILURE_NO_START;
scanningLeft = false;
}
}
}
}
}
if (rstart) bs.removeRight (rstart);
if (lstart) bs.removeLeft (lstart);
delete ds;
return (bs.endOfBirth ());
}
void BSTracker::switchOrthoScans ()
{
orthoScan = ! orthoScan;
scanp.setOrtho (orthoScan);
}
void BSTracker::switchScanExtent ()
{
maxScan = (maxScan == gMap->getHeightWidthMax () ?
DEFAULT_MAX_SCAN : gMap->getHeightWidthMax ());
}