#include "bsdetector.h" 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_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_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; const int BSDetector::PRELIM_MIN_HALF_WIDTH = 10; BSDetector::BSDetector () { gMap = NULL; bst1 = new BSTracker (); // bst1->setPixelLackTolerence (bst1->getVicinityThreshold ()); bst2 = new BSTracker (); prefilteringOn = true; lsf1 = (prefilteringOn ? new LineSpaceFilter () : NULL); filteringOn = false; lsf2 = (filteringOn ? new LineSpaceFilter () : NULL); edgeDirection = 0; // detects strokes (not only edges) bsMinSize = DEFAULT_BS_MIN_SIZE; ccOn = true; ccMinSize = DEFAULT_CONNECT_MIN_SIZE; recenteringOn = true; fittingOn = false; densityTestOn = true; multiSelection = false; autoResol = DEFAULT_AUTO_RESOLUTION; prelimDetectionOn = false; bspre = NULL; 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 = mbsini.begin (); while (it != mbsini.end ()) delete (*it++); it = mbsf.begin (); while (it != mbsf.end ()) delete (*it++); } void BSDetector::setGradientMap (VMap *data) { gMap = data; bst1->setGradientMap (data); bst2->setGradientMap (data); } void BSDetector::detectAll () { freeMultiSelection (); gMap->setMasking (true); int width = gMap->getWidth (); int height = gMap->getHeight (); for (int x = width / 2; x > 0; x -= autoResol) runMultiDetection (Pt2i (x, 0), Pt2i (x, height - 1), Vr2i (0, 1)); for (int x = width / 2 + autoResol; x < width - 1; x += autoResol) runMultiDetection (Pt2i (x, 0), Pt2i (x, height - 1), Vr2i (0, 1)); for (int y = height / 2; y > 0; y -= autoResol) runMultiDetection (Pt2i (0, y), Pt2i (width - 1, y), Vr2i (1, 0)); for (int y = height / 2 + autoResol; y < height - 1; y += autoResol) runMultiDetection (Pt2i (0, y), Pt2i (width - 1, y), Vr2i (1, 0)); gMap->clearMask (); gMap->setMasking (false); } void BSDetector::detectSelection (const Pt2i &p1, const Pt2i &p2) { freeMultiSelection (); if (multiSelection) { gMap->setMasking (true); runMultiDetection (p1, p2, p1.vectorTo (p2)); gMap->clearMask (); gMap->setMasking (false); } else detect (p1, p2); } void BSDetector::freeMultiSelection () { vector<BlurredSegment *>::iterator it = mbsini.begin (); while (it != mbsini.end ()) delete (*it++); mbsini.clear (); it = mbsf.begin (); while (it != mbsf.end ()) delete (*it++); mbsf.clear (); } void BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2, const Vr2i &dir) { vector<Pt2i> pts; p1.draw (pts, p2); int locmax[pts.size ()]; gMap->releaseOrientationConstraint (); int nlm = gMap->localMax (locmax, pts, dir); gMap->restoreOrientationConstraint (); for (int i = 0; i < nlm; i++) { detect (p1, p2, &(pts.at (locmax[i]))); if (bsf != NULL) { gMap->setMask (bsf->getAllPoints ()); mbsf.push_back (bsf); mbsini.push_back (bsini); bsf = NULL; // to avoid BS deletion bsini = NULL; // to avoid BS deletion } } } void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, Pt2i *p0) { // Clearance //---------- resultValue = RESULT_UNDETERMINED; bst1->clear (); bst2->clear (); if (prefilteringOn) lsf1->clear (); if (filteringOn) lsf2->clear (); if (bspre != NULL) delete bspre; bspre = NULL; if (bsini != NULL) delete bsini; bsini = NULL; if (bsf != NULL) delete bsf; bsf = NULL; if (p1.equals (p2)) return; Pt2i pt1 (p1); Pt2i pt2 (p2); // Preliminary based on highest gradient without orientation constraint //--------------------------------------------------------------------- if (prelimDetectionOn) { bspre = bst1->fastTrack (p1, p2, p0); if (bspre == NULL || bspre->size () < bsMinSize) { resultValue = (bspre == NULL ? RESULT_PRELIM_NO_DETECTION : RESULT_PRELIM_TOO_FEW); return; } Vr2i v0 = bspre->getSupportVector (); int l = v0.chessboard (); if (l != 0) { Pt2i pc = bspre->getSegment()->centerOfIntersection (p1, p2); AbsRat sw = bspre->segmentRationalWidth (); int detw = 2 * (1 + bspre->segmentRationalWidth().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); pt1 = Pt2i (pc.x () + dx, pc.y () + dy); pt2 = Pt2i (pc.x () - dx, pc.y () - dy); p0 = NULL; } bst1->clear (); } // Initial detection based on highest gradient without orientation constraint //--------------------------------------------------------------------------- bsini = bst1->fastTrack (pt1, pt2, p0); if (bsini == NULL || bsini->size () < bsMinSize) { resultValue = (bsini == NULL ? RESULT_INITIAL_NO_DETECTION : RESULT_INITIAL_TOO_FEW); return; } // Density test //------------- if (densityTestOn) { DigitalStraightLine mydsl (pt1, pt2, 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; } } // 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; } // 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 (pt1, pt2); int bswidth = bst1->fineTracksMaxWidth (); if (fittingOn) { DigitalStraightSegment *dss = bsini->getSegment (); if (dss != NULL) bswidth = 1 + dss->width () / dss->period (); } int scanwidth = bswidth + bswidth / 2; // Finer detection based on gradient maxima with orientation constraint //--------------------------------------------------------------------- bsf = bst2->fineTrack (pCenter, bsini->getSupportVector(), scanwidth, bswidth, gRef); if (bsf == NULL || bsf->size () < bsMinSize) { resultValue = (bsf == NULL ? RESULT_FINAL_NO_DETECTION : RESULT_FINAL_TOO_FEW); 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; } } // 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; } void BSDetector::switchOrthoScans () { bst1->switchOrthoScans (); bst2->switchOrthoScans (); } vector<Pt2i> BSDetector::getRejected (int step) const { vector<Pt2i> res; if (step == STEP_FINAL) { if (filteringOn) res = lsf2->getRejected (); } else if (prefilteringOn) res = lsf1->getRejected (); return res; } void BSDetector::switchFiltering (int step) { if (step == STEP_FINAL) { filteringOn = ! filteringOn; if (filteringOn && lsf2 == NULL) lsf2 = new LineSpaceFilter (); } else { prefilteringOn = ! prefilteringOn; if (prefilteringOn && lsf1 == NULL) lsf1 = new LineSpaceFilter (); } } bool BSDetector::incConnectedComponentMinSize (bool increase) { if ((! increase) && ccMinSize <= 1) return false; ccMinSize += (increase ? 1 : -1); return true; }