Newer
Older
const string BSDetector::VERSION = "0.1.1";
const int BSDetector::STEP_FINAL = 0;
const int BSDetector::STEP_INITIAL = 1;
const int BSDetector::STEP_PRELIM = 2;
const int BSDetector::RESULT_UNDETERMINED = -1;
const int BSDetector::RESULT_OK = 0;
const int BSDetector::RESULT_PRELIM_NO_DETECTION = 1;
const int BSDetector::RESULT_PRELIM_TOO_FEW = 2;
const int BSDetector::RESULT_INITIAL_NO_DETECTION = 11;
const int BSDetector::RESULT_INITIAL_TOO_FEW = 12;
const int BSDetector::RESULT_INITIAL_TOO_SPARSE = 13;
const int BSDetector::RESULT_INITIAL_TOO_MANY_OUTLIERS = 14;
const int BSDetector::RESULT_INITIAL_CLOSE_ORIENTATION = 15;
const int BSDetector::RESULT_FINAL_NO_DETECTION = 21;
const int BSDetector::RESULT_FINAL_TOO_FEW = 22;
const int BSDetector::RESULT_FINAL_TOO_SPARSE = 23;
const int BSDetector::RESULT_FINAL_TOO_MANY_OUTLIERS = 24;
const int BSDetector::DEFAULT_FAST_TRACK_SCAN_WIDTH = 16;
const int BSDetector::DEFAULT_FINE_TRACK_MAX_WIDTH = 3;
const int BSDetector::DEFAULT_FAST_TRACK_MAX_MARGIN = 2;
const int BSDetector::DEFAULT_BS_MIN_SIZE = 5;
const int BSDetector::ABSOLUTE_BS_MIN_SIZE = 3;
const int BSDetector::DEFAULT_CONNECT_MIN_SIZE = 5;
const int BSDetector::DEFAULT_AUTO_RESOLUTION = 10;
fmaxWidth = DEFAULT_FINE_TRACK_MAX_WIDTH;
imaxMargin = DEFAULT_FAST_TRACK_MAX_MARGIN;
prelimDetectionOn = false;
bst0 = (prelimDetectionOn ? new BSTracker () : NULL);
// bst1->setPixelLackTolerence (bst1->getVicinityThreshold ());
bstold = new BSTracker ();
if (bstold->dynamicScansOn ()) bstold->toggleDynamicScans ();
if (bstold->isThinningOn ()) bstold->toggleThinning ();
if (bstold->isThickenningOn ()) bstold->toggleThickenning ();
lsf1 = (prefilteringOn ? new LineSpaceFilter () : NULL);
filteringOn = false;
lsf2 = (filteringOn ? new LineSpaceFilter () : NULL);
edgeDirection = 0; // detects strokes (not only edges)
finalDensityTestOn = false;
finalLengthTestOn = false;
bsini = NULL;
bsf = NULL;
resultValue = RESULT_UNDETERMINED;
}
BSDetector::~BSDetector ()
{
delete bst1;
delete bst2;
if (lsf1 != NULL) delete lsf1;
if (lsf2 != NULL) delete lsf2;
if (bsini != NULL) delete bsini;
if (bsf != NULL) delete bsf;
vector <BlurredSegment *>::iterator it = mbsf.begin ();
}
void BSDetector::setGradientMap (VMap *data)
{
gMap = data;
if (prelimDetectionOn) bst0->setGradientMap (data);
for (int x = width / 2; isnext && x > 0; x -= autoResol)
isnext = runMultiDetection (Pt2i (x, 0), Pt2i (x, height - 1));
for (int x = width / 2 + autoResol; isnext && x < width - 1; x += autoResol)
isnext = runMultiDetection (Pt2i (x, 0), Pt2i (x, height - 1));
for (int y = height / 2; isnext && y > 0; y -= autoResol)
isnext = runMultiDetection (Pt2i (0, y), Pt2i (width - 1, y));
for (int y = height / 2 + autoResol; isnext && y < height - 1; y += autoResol)
isnext = runMultiDetection (Pt2i (0, y), Pt2i (width - 1, y));
if (maxtrials > (int) (mbsf.size ())) maxtrials = 0;
void BSDetector::detectAllWithBalancedXY ()
{
autodet = true;
freeMultiSelection ();
gMap->setMasking (true);
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
bool isnext = true;
nbtrials = 0;
int width = gMap->getWidth ();
int height = gMap->getHeight ();
int xg = width / 2, yb = height / 2;
int xd = xg + autoResol, yh = yb + autoResol;
bool agauche = true, enbas = true, adroite = true, enhaut = true;
while (isnext && (agauche || enbas || adroite || enhaut))
{
if (agauche)
{
isnext = runMultiDetection (Pt2i (xg, 0), Pt2i (xg, height - 1));
xg -= autoResol;
if (xg <= 0) agauche = false;
}
if (isnext && enbas)
{
isnext = runMultiDetection (Pt2i (0, yb), Pt2i (width - 1, yb));
yb -= autoResol;
if (yb <= 0) enbas = false;
}
if (isnext && adroite)
{
isnext = runMultiDetection (Pt2i (xd, 0), Pt2i (xd, height - 1));
xd += autoResol;
if (xd >= width - 1) adroite = false;
}
if (isnext && enhaut)
{
isnext = runMultiDetection (Pt2i (0, yh), Pt2i (width - 1, yh));
yh += autoResol;
if (yh >= height - 1) enhaut = false;
}
}
if (maxtrials > (int) (mbsf.size ())) maxtrials = 0;
void BSDetector::detectSelection (const Pt2i &p1, const Pt2i &p2)
{
freeMultiSelection ();
if (multiSelection)
{
gMap->setMasking (true);
if (maxtrials > (int) (mbsf.size ())) maxtrials = 0;
else
if (oldp) olddetect (p1, p2);
else detect (p1, p2);
void BSDetector::redetect ()
{
if (autodet) detectAll ();
else detectSelection (inip1, inip2);
}
vector<BlurredSegment *>::iterator it = mbsf.begin ();
while (it != mbsf.end ()) delete (*it++);
mbsf.clear ();
}
bool BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2)
{
vector<Pt2i> pts;
p1.draw (pts, p2);
int locmax[pts.size ()];
int nlm = gMap->localMax (locmax, pts);
bool isnext = true;
for (int i = 0; isnext && i < nlm; i++)
Pt2i ptstart = pts.at (locmax[i]);
if (gMap->isFree (ptstart))
int oldEdgeDir = edgeDirection;
if (edgeDirection != 0) edgeDirection = 1;
if (oldp) olddetect (p1, p2, true, ptstart);
else detect (p1, p2, true, ptstart);
if (bsf != NULL)
{
gMap->setMask (bsf->getAllPoints ());
mbsf.push_back (bsf);
bsf = NULL; // to avoid BS deletion
if ((int) (mbsf.size ()) == maxtrials) isnext = false;
void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2,
bool centralp, const Pt2i &pc)
{
// Entry check
//------------
if (p1.equals (p2)
|| ((! centralp) && p1.chessboard (p2) < BSTracker::MIN_SCAN)) return;
// Clearance
//----------
resultValue = RESULT_UNDETERMINED;
bst1->clear ();
bst2->clear ();
if (bsini != NULL) delete bsini;
bsini = NULL;
if (bsf != NULL) delete bsf;
bsf = NULL;
inip1.set (p1);
inip2.set (p2);
iniwidth = (centralp ? DEFAULT_FAST_TRACK_SCAN_WIDTH : 0);
inipc.set (pc);
// Initial detection based on highest gradient without orientation constraint
//---------------------------------------------------------------------------
bsini = bst1->fastTrack (DEFAULT_FAST_TRACK_SCAN_WIDTH / 4,
inip1, inip2, iniwidth, inipc);
if (bsini == NULL || bsini->size () < bsMinSize)
{
resultValue = (bsini == NULL ? RESULT_INITIAL_NO_DETECTION
: RESULT_INITIAL_TOO_FEW);
return;
}
// Density test
//-------------
/*
if (densityTestOn)
{
DigitalStraightLine mydsl (inip1, inip2, DigitalStraightLine::DSL_NAIVE);
int mydrlf = mydsl.manhattan (bsini->getLastRight ())
- mydsl.manhattan (bsini->getLastLeft ());
if (mydrlf < 0) mydrlf = -mydrlf; // Case of horizontal P1P2
int expansion = 1 + mydrlf;
if (bsini->size () < expansion / 2)
{
resultValue = RESULT_INITIAL_TOO_SPARSE;
return;
}
}
*/
// Orientation test for automatic extractions
//-------------------------------------------
Vr2i bsinidir = bsini->getSupportVector();
if (bsinidir.orientedAs (inip1.vectorTo (inip2)))
{
resultValue = RESULT_INITIAL_CLOSE_ORIENTATION;
return;
}
// Gradient reference selection
//-----------------------------
Pt2i pCenter = bsini->getCenter ();
Vr2i gRef = gMap->getValue (pCenter);
if (edgeDirection == -1) gRef.invert ();
// Scan recentering and fitting
//-----------------------------
if (recenteringOn)
pCenter = bsini->getSegment()->centerOfIntersection (inip1, inip2);
// Finer detection based on gradient maxima with orientation constraint
//---------------------------------------------------------------------
bsf = bstold->fineTrack (fmaxWidth, pCenter, bsinidir,
4 * fmaxWidth, gRef);
if (bsf == NULL || bsf->size () < bsMinSize)
{
resultValue = (bsf == NULL ? RESULT_FINAL_NO_DETECTION
: RESULT_FINAL_TOO_FEW);
return;
}
// Scan recentering and fitting
//-----------------------------
pCenter = bsini->getCenter ();
if (recenteringOn)
pCenter = bsf->getSegment()->centerOfIntersection (inip1, inip2);
// Third detection based on gradient maxima with orientation constraint
//---------------------------------------------------------------------
BlurredSegment *bsf2 = bstold->fineTrack (fmaxWidth,
pCenter, bsf->getSupportVector(),
4 * fmaxWidth, gRef);
if (bsf2 == NULL || bsf2->size () < bsMinSize)
{
resultValue = (bsf2 == NULL ? RESULT_FINAL_NO_DETECTION
: RESULT_FINAL_TOO_FEW);
if (bsf2 != NULL) delete bsf2;
return;
}
else
{
delete bsf;
bsf = bsf2;
}
// Length test
//------------
if (finalLengthTestOn)
{
DigitalStraightSegment *dss = bsf->getSegment ();
if (dss == NULL || (int) (bsf->getAllPoints().size ())
< (10 * dss->period ()) / dss->width ())
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
{
resultValue = RESULT_FINAL_TOO_SPARSE;
delete bsf;
bsf = NULL;
return;
}
}
// New density test
//-----------------
if (finalDensityTestOn)
{
DigitalStraightLine mydsl (inip1, inip2, DigitalStraightLine::DSL_NAIVE);
int mydrlf = mydsl.manhattan (bsf->getLastRight ())
- mydsl.manhattan (bsf->getLastLeft ());
if (mydrlf < 0) mydrlf = -mydrlf; // Case of horizontal P1P2
int expansion = 1 + mydrlf;
if (bsf->size () < expansion / 2)
{
resultValue = RESULT_FINAL_TOO_SPARSE;
delete bsf;
bsf = NULL;
return;
}
}
// Connected components analysis
//------------------------------
if (ccOn)
{
int bsccp = bsf->countOfConnectedPoints (ccMinSize);
int bssize = bsf->getAllPoints().size ();
if (bsccp < bssize / 2)
{
resultValue = RESULT_FINAL_TOO_SPARSE;
delete bsf;
bsf = NULL;
return;
}
/*
if (bssize < 20 || bsf->countOfConnectedComponents (bssize / 4) == 0)
{
resultValue = RESULT_FINAL_TOO_SPARSE;
delete bsf;
bsf = NULL;
return;
}
*/
void BSDetector::detect (const Pt2i &p1, const Pt2i &p2,
bool centralp, const Pt2i &pc)
// Entry check
//------------
if (p1.equals (p2)
|| ((! centralp) && p1.chessboard (p2) < BSTracker::MIN_SCAN)) return;
// Clearance
//----------
resultValue = RESULT_UNDETERMINED;
bst1->clear ();
bst2->clear ();
if (prefilteringOn) lsf1->clear ();
if (filteringOn) lsf2->clear ();
prewidth = (centralp ? DEFAULT_FAST_TRACK_SCAN_WIDTH : 0);
// Preliminary based on highest gradient without orientation constraint
//---------------------------------------------------------------------
bspre = bst0->fastTrack (fmaxWidth + imaxMargin,
prep1, prep2, prewidth, prepc);
resultValue = (bspre == NULL ? RESULT_PRELIM_NO_DETECTION
: RESULT_PRELIM_TOO_FEW);
Pt2i pcentral = bspre->getSegment()->centerOfIntersection (prep1, prep2);
int detw = 2 * (1 + bspre->minimalWidth().floor ());
if (detw < PRELIM_MIN_HALF_WIDTH) detw = PRELIM_MIN_HALF_WIDTH;
int dx = (int) ((v0.y () * detw) / l);
int dy = (int) (- (v0.x () * detw) / l);
inip1 = Pt2i (pcentral.x () + dx, pcentral.y () + dy);
inip2 = Pt2i (pcentral.x () - dx, pcentral.y () - dy);
}
else
{
inip1.set (p1);
inip2.set (p2);
iniwidth = (centralp ? DEFAULT_FAST_TRACK_SCAN_WIDTH : 0);
// Initial detection based on highest gradient without orientation constraint
//---------------------------------------------------------------------------
bsini = bst1->fastTrack (fmaxWidth + imaxMargin,
inip1, inip2, iniwidth, inipc);
if (bsini == NULL || bsini->size () < bsMinSize)
{
resultValue = (bsini == NULL ? RESULT_INITIAL_NO_DETECTION
: RESULT_INITIAL_TOO_FEW);
return;
}
// Density test
//-------------
if (densityTestOn)
{
DigitalStraightLine mydsl (inip1, inip2, DigitalStraightLine::DSL_NAIVE);
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
int mydrlf = mydsl.manhattan (bsini->getLastRight ())
- mydsl.manhattan (bsini->getLastLeft ());
if (mydrlf < 0) mydrlf = -mydrlf; // Case of horizontal P1P2
int expansion = 1 + mydrlf;
if (bsini->size () < expansion / 2)
{
resultValue = RESULT_INITIAL_TOO_SPARSE;
return;
}
}
// Hough filtering on the initial segment
//---------------------------------------
if (prefilteringOn)
{
BlurredSegment *fbs = lsf1->filter (bsini);
if (fbs != NULL)
{
delete bsini;
bsini = fbs;
}
}
if (bsini->size () < bsMinSize)
{
resultValue = RESULT_INITIAL_TOO_MANY_OUTLIERS;
return;
}
// Orientation test for automatic extractions
//-------------------------------------------
Vr2i bsinidir = bsini->getSupportVector();
if (bsinidir.orientedAs (inip1.vectorTo (inip2)))
{
resultValue = RESULT_INITIAL_CLOSE_ORIENTATION;
return;
}
// Gradient reference selection
//-----------------------------
// Scan recentering and fitting
//-----------------------------
if (recenteringOn)
pCenter = bsini->getSegment()->centerOfIntersection (inip1, inip2);
{
DigitalStraightSegment *dss = bsini->getSegment ();
if (dss != NULL)
// Finer detection based on gradient maxima with orientation constraint
//---------------------------------------------------------------------
bsf = bst2->fineTrack (bswidth, pCenter, bsinidir, 2 * bswidth, gRef);
if (bsf == NULL || bsf->size () < bsMinSize)
{
resultValue = (bsf == NULL ? RESULT_FINAL_NO_DETECTION
: RESULT_FINAL_TOO_FEW);
return;
}
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
// Length test
//------------
if (finalLengthTestOn)
{
DigitalStraightSegment *dss = bsf->getSegment ();
if ((int) (bsf->getAllPoints().size ())
< (3 * dss->width ()) / dss->period ())
// if ((int) (bsf->getAllPoints().size ()) < 10)
{
resultValue = RESULT_FINAL_TOO_SPARSE;
delete bsf;
bsf = NULL;
return;
}
}
// New density test
//-----------------
if (finalDensityTestOn)
{
DigitalStraightLine mydsl (inip1, inip2, DigitalStraightLine::DSL_NAIVE);
int mydrlf = mydsl.manhattan (bsf->getLastRight ())
- mydsl.manhattan (bsf->getLastLeft ());
if (mydrlf < 0) mydrlf = -mydrlf; // Case of horizontal P1P2
int expansion = 1 + mydrlf;
if (expansion < 20 && bsf->size () < (expansion * 4) / 5)
{
resultValue = RESULT_FINAL_TOO_SPARSE;
delete bsf;
bsf = NULL;
return;
}
}
// Connected components analysis */
//------------------------------*/
if (ccOn)
{
int bssize = bsf->getAllPoints().size ();
if (bsccp < bssize / 2)
{
resultValue = RESULT_FINAL_TOO_SPARSE;
delete bsf;
bsf = NULL;
return;
}
/*
if (bssize < 20 || bsf->countOfConnectedComponents (bssize / 2) == 0)
{
resultValue = RESULT_FINAL_TOO_SPARSE;
delete bsf;
bsf = NULL;
return;
}
*/
// Line space filtering
//---------------------
if (filteringOn)
{
BlurredSegment *fbsf = lsf2->filter (bsf);
if (fbsf != NULL)
{
resultValue = RESULT_FINAL_TOO_MANY_OUTLIERS;
delete bsf;
bsf = fbsf;
}
}
resultValue = RESULT_OK;
}
BlurredSegment *BSDetector::getBlurredSegment (int step) const
{
if (step == STEP_PRELIM) return (bspre);
else if (step == STEP_INITIAL) return (bsini);
else if (mbsf.empty ()) return (bsf);
void BSDetector::incMaxDetections (bool dir)
{
maxtrials = maxtrials + (dir ? -1 : 1);
if (maxtrials < 0) maxtrials = (int) (mbsf.size ());
}
void BSDetector::getScanInput (int step,
Pt2i &p1, Pt2i &p2, int &swidth, Pt2i &pc) const
{
if (step == STEP_PRELIM)
{
if (prelimDetectionOn)
{
p1.set (prep1);
p2.set (prep2);
pc.set (prepc);
}
}
else if (step == STEP_INITIAL)
{
p1.set (inip1);
p2.set (inip2);
pc.set (inipc);
}
}
const vector <vector <Pt2i> > BSDetector::getFinalScans () const
{
return (bst2->getScans ());
}
bool BSDetector::finalScansRecordOn () const
{
return (bst2->scanRecordOn ());
}
void BSDetector::setFinalScansRecord (bool status)
{
bst2->setScanRecord (status);
if (status) redetect ();
}
if (prelimDetectionOn) bst0->switchOrthoScans ();
bst1->switchOrthoScans ();
bst2->switchOrthoScans ();
}
vector<Pt2i> BSDetector::getRejected (int step) const
{
vector<Pt2i> res;
return res;
}
void BSDetector::switchFiltering (int step)
{
{
filteringOn = ! filteringOn;
if (filteringOn && lsf2 == NULL) lsf2 = new LineSpaceFilter ();
}
{
prefilteringOn = ! prefilteringOn;
if (prefilteringOn && lsf1 == NULL) lsf1 = new LineSpaceFilter ();
}
}
bool BSDetector::incConnectedComponentMinSize (bool increase)
{
if ((! increase) && ccMinSize <= 1) return false;
ccMinSize += (increase ? 1 : -1);
void BSDetector::switchPreliminary ()
{
if (prelimDetectionOn)
{
delete bst0;
prelimDetectionOn = false;
}
else
{
prelimDetectionOn = true;
bst0 = new BSTracker ();
bst0->setGradientMap (gMap);
if (bst1->orthoScansOn ()) bst0->switchOrthoScans ();
}
}
std::string BSDetector::version ()
{
return BSDetector::VERSION;
}