From 298f24d4ef8757061a31114e6f5fe8f24b4b62e8 Mon Sep 17 00:00:00 2001 From: even <philippe.even@loria.fr> Date: Mon, 24 Dec 2018 00:40:33 +0100 Subject: [PATCH] Width control and post-filtering --- Code/Seg/BSTools/bsdetectionwidget.cpp | 98 ++++++++++----- Code/Seg/BSTools/bsidetitem.cpp | 2 +- Code/Seg/BSTools/bsstructureitem.cpp | 4 +- Code/Seg/BlurredSegment/bsdetector.cpp | 165 ++++++++++++++++++++----- Code/Seg/BlurredSegment/bsdetector.h | 114 ++++++++++++----- Code/Seg/BlurredSegment/bstracker.cpp | 56 +++++---- Code/Seg/BlurredSegment/bstracker.h | 113 +++++++---------- Code/Seg/ImageTools/pt2i.h | 12 ++ Code/Seg/ImageTools/vmap.cpp | 10 +- Code/Seg/ImageTools/vmap.h | 2 +- Methode/ctrl.tex | 6 +- 11 files changed, 384 insertions(+), 198 deletions(-) diff --git a/Code/Seg/BSTools/bsdetectionwidget.cpp b/Code/Seg/BSTools/bsdetectionwidget.cpp index 67a6ae5..bd1b18a 100755 --- a/Code/Seg/BSTools/bsdetectionwidget.cpp +++ b/Code/Seg/BSTools/bsdetectionwidget.cpp @@ -389,7 +389,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) detector.switchDensityTest (); extract (); cout << "Density test : " - << (detector.isSetDensityTest () ? "on" : "off") << endl; + << (detector.isDensityTestOn () ? "on" : "off") << endl; } break; @@ -426,12 +426,23 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) break; case Qt::Key_G : - // Tunes the gradient threshold for maximal value detection - detector.incGradientThreshold ( - (event->modifiers () & Qt::ShiftModifier ? -1 : 1)); - cout << "Gradient threshold = " - << detector.getGradientThreshold () << endl; - extract (); + if (event->modifiers () & Qt::ControlModifier) + { + // Switches length test at final step + detector.switchFinalLengthTest (); + extract (); + cout << "Final length test : " + << (detector.isFinalLengthTestOn () ? "on" : "off") << endl; + } + else + { + // Tunes the gradient threshold for maximal value detection + detector.incGradientThreshold ( + (event->modifiers () & Qt::ShiftModifier ? -1 : 1)); + cout << "Gradient threshold = " + << detector.getGradientThreshold () << endl; + extract (); + } break; case Qt::Key_H : @@ -449,20 +460,20 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) case Qt::Key_J : if (event->modifiers () & Qt::ControlModifier) { - // Switches the vicinity constraint for fast tracks - detector.switchVicinityConstraint (); - cout << "Vicinity constraint " - << (detector.vicinityConstraintOn () ? "on" : "off") + // Switches the proximity constraint for fast tracks + detector.switchFastTrackProximityConstraint (); + cout << "Proximity constraint on fast tracks " + << (detector.fastTrackProximityConstraintOn () ? "on" : "off") << endl; extract (); } - else + else if (detector.fastTrackProximityConstraintOn ()) { - // Tunes the vicinity threshold for fast tracks - detector.incVicinityThreshold( + // Tunes the proximity threshold for fast tracks + detector.incFastTrackProximityThreshold ( (event->modifiers () & Qt::ShiftModifier) == 0); - cout << "Vicinity threshold = " - << detector.getVicinityThreshold () << endl; + cout << "Proximity threshold for fast tracks = " + << detector.getFastTrackProximityThreshold () << endl; extract (); } break; @@ -473,7 +484,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) // Switches the final step connectivity constraint detector.switchConnectivityConstraint (); cout << "Connectivity constraint " - << (detector.isSetConnectivityConstraint () ? "on" : "off") + << (detector.isConnectivityConstraintOn () ? "on" : "off") << endl; extract (); } @@ -489,11 +500,22 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) break; case Qt::Key_L : - // Tunes the output blurred segment minimal size - detector.setBSminSize (detector.getBSminSize () + - (event->modifiers () & Qt::ShiftModifier ? -1 : 1)); - cout << "Output BS min size = " << detector.getBSminSize () << endl; - extract (); + if (event->modifiers () & Qt::ControlModifier) + { + // Switches density test at final step + detector.switchFinalDensityTest (); + extract (); + cout << "Final density test : " + << (detector.isFinalDensityTestOn () ? "on" : "off") << endl; + } + else + { + // Tunes the output blurred segment minimal size + detector.setBSminSize (detector.getBSminSize () + + (event->modifiers () & Qt::ShiftModifier ? -1 : 1)); + cout << "Output BS min size = " << detector.getBSminSize () << endl; + extract (); + } break; case Qt::Key_M : @@ -671,30 +693,30 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) case Qt::Key_W : if (event->modifiers () & Qt::ControlModifier) { - // Switches the setting of the assigned width on the detected segment - detector.switchScanFitting (); - cout << "Fine tracking fitted to " << (detector.isScanFitting () ? - "detected segment width" : "assigned width") << endl; + // Switches the scan centering on the detected segment + detector.switchScanRecentering (); + cout << "Fine tracking centered on " << (detector.isScanRecentering () ? + "detected segment" : "initial scan") << endl; extract (); } else { - // Tunes the assigned max width for fine tracks - detector.setFastTracksMaxWidth (detector.fastTracksMaxWidth () + + // Tunes the assigned max width margin for fine tracks + detector.setFastTracksMaxMargin (detector.fastTracksMaxMargin () + (event->modifiers () & Qt::ShiftModifier ? -1 : 1)); extract (); - cout << "Fast tracks max width = " - << detector.fastTracksMaxWidth () << endl; + cout << "Fast tracks max width margin = " + << detector.fastTracksMaxMargin () << endl; } break; case Qt::Key_X : if (event->modifiers () & Qt::ControlModifier) { - // Switches the scan centering on the detected segment - detector.switchScanRecentering (); - cout << "Fine tracking centered on " << (detector.isScanRecentering () ? - "detected segment" : "initial scan") << endl; + // Switches the setting of the assigned width on the detected segment + detector.switchScanFitting (); + cout << "Fine tracking fitted to " << (detector.isScanFitting () ? + "detected segment width" : "assigned width") << endl; extract (); } else @@ -764,6 +786,14 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) switchIdetAnalyzer (); break; + case Qt::Key_5 : + // Switches the crosswise segment detection + detector.switchTrackCrosswise (); + extract (); + cout << "Crosswise segment detection " + << (detector.trackCrosswiseOn () ? "on" : "off") << endl; + break; + case Qt::Key_6 : detector.switchDetector (); cout << (detector.oldDetectorOn () ? diff --git a/Code/Seg/BSTools/bsidetitem.cpp b/Code/Seg/BSTools/bsidetitem.cpp index c4ee2c4..6304da8 100755 --- a/Code/Seg/BSTools/bsidetitem.cpp +++ b/Code/Seg/BSTools/bsidetitem.cpp @@ -93,7 +93,7 @@ void BSIdetItem::buildScans () offy = 0; // Gets a scan iterator - if (scanw) + if (scanw != 0) ds = scanp.getScanner (ptc, pt1.vectorTo (pt2), scanw, false); else ds = scanp.getScanner (pt1, pt2); diff --git a/Code/Seg/BSTools/bsstructureitem.cpp b/Code/Seg/BSTools/bsstructureitem.cpp index ce96bb3..38d3000 100755 --- a/Code/Seg/BSTools/bsstructureitem.cpp +++ b/Code/Seg/BSTools/bsstructureitem.cpp @@ -190,7 +190,7 @@ void BSStructureItem::paintConnectedComponents (QPainter *painter, int step) int bsccp = bs->countOfConnectedPoints (ccs); int bssize = bs->getAllPoints().size (); bool ccon = (step == BSDetector::STEP_FINAL - && det->isSetConnectivityConstraint ()); + && det->isConnectivityConstraintOn ()); addText (painter, QString ("Connectivity constraint ") + (ccon ? QString ("on") : QString ("off"))); addText (painter, QString::number (bssize) + QString (" points")); @@ -224,7 +224,7 @@ void BSStructureItem::paintScansAndFilter (QPainter *painter, int step) ScannerProvider sp; sp.setSize (w, h); DirectionalScanner *ds = NULL; - if (swidth) + if (swidth != 0) ds = sp.getScanner (ptc, pt1.vectorTo (pt2), swidth, false); else ds = sp.getScanner (pt1, pt2); vector<Pt2i> pix; diff --git a/Code/Seg/BlurredSegment/bsdetector.cpp b/Code/Seg/BlurredSegment/bsdetector.cpp index 5cf09f3..d39d0b0 100755 --- a/Code/Seg/BlurredSegment/bsdetector.cpp +++ b/Code/Seg/BlurredSegment/bsdetector.cpp @@ -20,6 +20,10 @@ 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 = 32; +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; @@ -31,6 +35,9 @@ BSDetector::BSDetector () { gMap = NULL; + fmaxWidth = DEFAULT_FINE_TRACK_MAX_WIDTH; + imaxMargin = DEFAULT_FAST_TRACK_MAX_MARGIN; + prelimDetectionOn = false; bst0 = (prelimDetectionOn ? new BSTracker () : NULL); bst1 = new BSTracker (); @@ -54,6 +61,8 @@ BSDetector::BSDetector () recenteringOn = true; fittingOn = false; densityTestOn = true; + finalDensityTestOn = false; + finalLengthTestOn = false; multiSelection = false; autodet = false; autoResol = DEFAULT_AUTO_RESOLUTION; @@ -172,7 +181,9 @@ void BSDetector::detectSelection (const Pt2i &p1, const Pt2i &p2) gMap->clearMask (); gMap->setMasking (false); } - else detect (p1, p2); + else + if (oldp) olddetect (p1, p2); + else detect (p1, p2); } @@ -207,7 +218,8 @@ bool BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2) if (edgeDirection != 0) edgeDirection = 1; while (edgeDirection >= -1) { - detect (p1, p2, true, ptstart); + if (oldp) olddetect (p1, p2, true, ptstart); + else detect (p1, p2, true, ptstart); if (bsf != NULL) { gMap->setMask (bsf->getAllPoints ()); @@ -227,6 +239,11 @@ bool BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2) 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; @@ -238,15 +255,15 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, bsf = NULL; lastTrialOk = false; - if (p1.equals (p2)) return; inip1.set (p1); inip2.set (p2); - inicentralp = centralp; + iniwidth = (centralp ? DEFAULT_FAST_TRACK_SCAN_WIDTH : 0); inipc.set (pc); // Initial detection based on highest gradient without orientation constraint //--------------------------------------------------------------------------- - bsini = bst1->fastTrack (inip1, inip2, inicentralp, inipc); + 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 @@ -291,12 +308,11 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, //----------------------------- if (recenteringOn) pCenter = bsini->getSegment()->centerOfIntersection (inip1, inip2); - int bswidth = bst1->fastTracksMaxWidth (); - int scanwidth = 4 * bswidth; // Finer detection based on gradient maxima with orientation constraint //--------------------------------------------------------------------- - bsf = bstold->fineTrack (pCenter, bsinidir, scanwidth, bswidth, gRef); + bsf = bstold->fineTrack (fmaxWidth, pCenter, bsinidir, + 4 * fmaxWidth, gRef); if (bsf == NULL || bsf->size () < bsMinSize) { resultValue = (bsf == NULL ? RESULT_FINAL_NO_DETECTION @@ -312,8 +328,9 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, // Third detection based on gradient maxima with orientation constraint //--------------------------------------------------------------------- - BlurredSegment *bsf2 = bstold->fineTrack (pCenter, bsf->getSupportVector(), - scanwidth, bswidth, gRef); + BlurredSegment *bsf2 = bstold->fineTrack (fmaxWidth, + pCenter, bsf->getSupportVector(), + 4 * fmaxWidth, gRef); if (bsf2 == NULL || bsf2->size () < bsMinSize) { resultValue = (bsf2 == NULL ? RESULT_FINAL_NO_DETECTION @@ -327,8 +344,41 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, bsf = bsf2; } - // Connected components analysis */ - //------------------------------*/ + // Length test + //------------ + if (finalLengthTestOn) + { + DigitalStraightSegment *dss = bsf->getSegment (); + if ((int) (bsf->getAllPoints().size ()) + < (10 * dss->period ()) / dss->width ()) + { + 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); @@ -340,6 +390,16 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, bsf = NULL; return; } + +/* + if (bssize < 20 || bsf->countOfConnectedComponents (bssize / 4) == 0) + { + resultValue = RESULT_FINAL_TOO_SPARSE; + delete bsf; + bsf = NULL; + return; + } +*/ } lastTrialOk = true; @@ -350,11 +410,11 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, bool centralp, const Pt2i &pc) { - if (oldp) - { - olddetect (p1, p2, centralp, pc); - return; - } + // Entry check + //------------ + if (p1.equals (p2) + || ((! centralp) && p1.chessboard (p2) < BSTracker::MIN_SCAN)) return; + // Clearance //---------- @@ -372,17 +432,17 @@ void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, bsf = NULL; lastTrialOk = false; - if (p1.equals (p2)) return; prep1.set (p1); prep2.set (p2); - precentralp = centralp; + prewidth = (centralp ? DEFAULT_FAST_TRACK_SCAN_WIDTH : 0); prepc.set (pc); // Preliminary based on highest gradient without orientation constraint //--------------------------------------------------------------------- if (prelimDetectionOn) { - bspre = bst0->fastTrack (prep1, prep2, precentralp, prepc); + bspre = bst0->fastTrack (fmaxWidth + imaxMargin, + prep1, prep2, prewidth, prepc); if (bspre == NULL || bspre->size () < bsMinSize) { resultValue = (bspre == NULL ? RESULT_PRELIM_NO_DETECTION @@ -401,20 +461,21 @@ void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, int dy = (int) (- (v0.x () * detw) / l); inip1 = Pt2i (pcentral.x () + dx, pcentral.y () + dy); inip2 = Pt2i (pcentral.x () - dx, pcentral.y () - dy); - inicentralp = false; + iniwidth = 0; } } else { inip1.set (p1); inip2.set (p2); - inicentralp = centralp; + iniwidth = (centralp ? DEFAULT_FAST_TRACK_SCAN_WIDTH : 0); inipc.set (pc); } // Initial detection based on highest gradient without orientation constraint //--------------------------------------------------------------------------- - bsini = bst1->fastTrack (inip1, inip2, inicentralp, inipc); + bsini = bst1->fastTrack (fmaxWidth + imaxMargin, + inip1, inip2, iniwidth, inipc); if (bsini == NULL || bsini->size () < bsMinSize) { resultValue = (bsini == NULL ? RESULT_INITIAL_NO_DETECTION @@ -474,18 +535,17 @@ void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, //----------------------------- if (recenteringOn) pCenter = bsini->getSegment()->centerOfIntersection (inip1, inip2); - int bswidth = bst1->fineTracksMaxWidth (); + int bswidth = fmaxWidth; 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, bsinidir, scanwidth, bswidth, gRef); + bsf = bst2->fineTrack (bswidth, pCenter, bsinidir, 2 * bswidth, gRef); if (bsf == NULL || bsf->size () < bsMinSize) { resultValue = (bsf == NULL ? RESULT_FINAL_NO_DETECTION @@ -493,6 +553,40 @@ void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, return; } + // 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) @@ -506,8 +600,19 @@ void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, 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) @@ -536,8 +641,8 @@ BlurredSegment *BSDetector::getBlurredSegment (int step) const } -void BSDetector::getScanInput (int step, Pt2i &p1, Pt2i &p2, - int &width, Pt2i &pc) const +void BSDetector::getScanInput (int step, + Pt2i &p1, Pt2i &p2, int &swidth, Pt2i &pc) const { if (step == STEP_PRELIM) { @@ -545,7 +650,7 @@ void BSDetector::getScanInput (int step, Pt2i &p1, Pt2i &p2, { p1.set (prep1); p2.set (prep2); - width = (precentralp ? bst0->fastTrackDefaultWidth () : 0); + swidth = prewidth; pc.set (prepc); } } @@ -553,7 +658,7 @@ void BSDetector::getScanInput (int step, Pt2i &p1, Pt2i &p2, { p1.set (inip1); p2.set (inip2); - width = (inicentralp ? bst1->fastTrackDefaultWidth () : 0); + swidth = iniwidth; pc.set (inipc); } } diff --git a/Code/Seg/BlurredSegment/bsdetector.h b/Code/Seg/BlurredSegment/bsdetector.h index dcbf930..48e2a39 100755 --- a/Code/Seg/BlurredSegment/bsdetector.h +++ b/Code/Seg/BlurredSegment/bsdetector.h @@ -156,28 +156,27 @@ public: inline void preserveFormerBlurredSegments () { mbsf.clear (); } /** - * \brief Returns the assigned maximal width for the fast tracks. + * \brief Returns the assigned maximal width for the fine tracks. */ - inline int fastTracksMaxWidth () const { - return bst1->fastTracksMaxWidth (); } + inline int fineTracksMaxWidth () const { return fmaxWidth; } /** - * \brief Sets the assigned width for the fast tracks. + * \brief Sets the assigned maximal width for the fine tracks. + * @param val New width value. */ - inline void setFastTracksMaxWidth (int value) { - bst1->setFastTracksMaxWidth (value); } + inline void setFineTracksMaxWidth (int val) { if (val > 0) fmaxWidth = val; } /** - * \brief Returns the assigned maximal width for the fine tracks. + * \brief Returns the assigned maximal width margin for the fast tracks. */ - inline int fineTracksMaxWidth () const { - return bst1->fineTracksMaxWidth (); } + inline int fastTracksMaxMargin () const { return imaxMargin; } /** - * \brief Sets the assigned maximal width for the fine tracks. + * \brief Sets the assigned maximal width margin for the fast tracks. + * @param val New width value. */ - inline void setFineTracksMaxWidth (int value) { - bst1->setFineTracksMaxWidth (value); } + inline void setFastTracksMaxMargin (int val) { + if (val >= 0) imaxMargin = val; } /** * \brief Returns the output blurred segment minimal size. @@ -249,6 +248,16 @@ public: */ inline void switchAutoRestart () { bst2->switchAutoRestart (); } + /** + * \brief Returns whether the crosswise segment detection is set. + */ + inline bool trackCrosswiseOn () const { return bst2->trackCrosswiseOn (); } + + /** + * \brief Switches on or off the crosswise segment detection. + */ + inline void switchTrackCrosswise () { bst2->switchTrackCrosswise (); } + /** * \brief Returns the preliminary detection modality status. */ @@ -344,26 +353,29 @@ public: inline int initialDetectionMaxExtent () { return (bst1->maxScanExtent ()); } /** - * \brief Returns the vicinity threshold used for fast tracking. + * \brief Returns the proximity threshold used for fast tracking. */ - inline int getVicinityThreshold () { return (bst1->getVicinityThreshold ()); } + inline int getFastTrackProximityThreshold () const { + return (bst1->getProximityThreshold ()); } /** - * \brief Increments the vicinity threshold used for fast tracking. - * @param inc Increment value. + * \brief Increments the proximity threshold used for fast tracking. + * @param inc Increment sign. */ - inline void incVicinityThreshold (int inc) { - bst1->incVicinityThreshold (inc); } + inline void incFastTrackProximityThreshold (bool inc) { + bst1->incProximityThreshold (inc); } /** - * \brief Returns the vicinity test status. + * \brief Returns the proximity test status. */ - inline bool vicinityConstraintOn () { return (bst1->vicinityConstraintOn ()); } + inline bool fastTrackProximityConstraintOn () const { + return (bst1->proximityConstraintOn ()); } /** - * \brief Switches the vicinity test used for fast tracking. + * \brief Switches the proximity test used for fast tracking. */ - inline void switchVicinityConstraint () { bst1->switchVicinityConstraint (); } + inline void switchFastTrackProximityConstraint () { + bst1->switchProximityConstraint (); } /** * \brief Returns if the dynamic scans modality is set. @@ -478,7 +490,7 @@ public: /** * \brief Returns whether the density test at initial step is set. */ - inline bool isSetDensityTest () { return (densityTestOn); } + inline bool isDensityTestOn () const { return (densityTestOn); } /** * \brief Switches on or off the density test modality. @@ -486,14 +498,36 @@ public: inline void switchDensityTest () { densityTestOn = ! densityTestOn; } /** - * \brief Switches on or off the connectivity constraint. + * \brief Returns whether the density test at final step is set. */ - inline void switchConnectivityConstraint () { ccOn = ! ccOn; } + inline bool isFinalDensityTestOn () const { return (finalDensityTestOn); } + + /** + * \brief Switches on or off the final density test modality. + */ + inline void switchFinalDensityTest () { + finalDensityTestOn = ! finalDensityTestOn; } + + /** + * \brief Returns whether the length test at final step is set. + */ + inline bool isFinalLengthTestOn () const { return (finalLengthTestOn); } + + /** + * \brief Switches on or off the final length test modality. + */ + inline void switchFinalLengthTest () { + finalLengthTestOn = ! finalLengthTestOn; } /** * \brief Returns the connectivity constraint status. */ - inline bool isSetConnectivityConstraint () { return (ccOn); } + inline bool isConnectivityConstraintOn () const { return (ccOn); } + + /** + * \brief Switches on or off the connectivity constraint. + */ + inline void switchConnectivityConstraint () { ccOn = ! ccOn; } /** * \brief Returns the minimal size of the segment connected components. @@ -532,10 +566,11 @@ public: * @param step Detection step. * @param p1 Input stroke first point to fill in. * @param p2 Input stroke end point to fill in. - * @param width Input stroke width to fill in. + * @param swidth Scan width if not set by P1 and p2, otherwise 0. * @param pc Input central point to fill in. */ - void getScanInput (int step, Pt2i &p1, Pt2i &p2, int &width, Pt2i &pc) const; + void getScanInput (int step, + Pt2i &p1, Pt2i &p2, int &swidth, Pt2i &pc) const; /** * \brief Retuns whether the old detector (IWCIA '09) is used. @@ -550,6 +585,12 @@ public: private : + /** Default value for the scan width for fast tracks. */ + static const int DEFAULT_FAST_TRACK_SCAN_WIDTH; + /** Default value for the max segment width for fine tracks. */ + static const int DEFAULT_FINE_TRACK_MAX_WIDTH; + /** Default value for the max segment width margin for fast tracks. */ + static const int DEFAULT_FAST_TRACK_MAX_MARGIN; /** Default value for the minimal size of the detected blurred segment. */ static const int DEFAULT_BS_MIN_SIZE; /** Absolute value for the minimal size of the detected blurred segment. */ @@ -583,6 +624,10 @@ private : bool fittingOn; /** Density test modality after initial detection. */ bool densityTestOn; + /** Density test modality after final detection. */ + bool finalDensityTestOn; + /** Length test modality after final detection. */ + bool finalLengthTestOn; /** Segment multi-selection modality status. */ bool multiSelection; /** Flag indicating if the last trial was successful. */ @@ -600,14 +645,19 @@ private : /** Old detector (IWCIA'09) modality. */ bool oldp; + /** Assigned maximal width of the blurred segment for fine tracks. */ + int fmaxWidth; + /** Assigned maximal width margin for fast tracks. */ + int imaxMargin; + /** Last input start point. */ Pt2i prep1; /** Last input end point. */ Pt2i prep2; /** Last input central point. */ Pt2i prepc; - /** Last input central point modality. */ - bool precentralp; + /** Preliminary fast scan width if not set by an input selection. */ + int prewidth; /** Preliminary stage modality. */ bool prelimDetectionOn; /** Preliminary rough tracker. */ @@ -623,8 +673,8 @@ private : Pt2i inip2; /** Last input central point for initial step. */ Pt2i inipc; - /** Last input central point modality for initial step. */ - bool inicentralp; + /** Initial fast scan width if not set by an input selection. */ + int iniwidth; /** Initially detected blurred segment (initial step result). */ BlurredSegment *bsini; diff --git a/Code/Seg/BlurredSegment/bstracker.cpp b/Code/Seg/BlurredSegment/bstracker.cpp index b4c4b4f..798b49a 100755 --- a/Code/Seg/BlurredSegment/bstracker.cpp +++ b/Code/Seg/BlurredSegment/bstracker.cpp @@ -3,11 +3,8 @@ -const int BSTracker::DEFAULT_FAST_TRACK_MAX_WIDTH = 5; -const int BSTracker::DEFAULT_FINE_TRACK_MAX_WIDTH = 3; const int BSTracker::DEFAULT_ACCEPTED_LACKS = 5; -const int BSTracker::NO_VICINITY = 10000; -const int BSTracker::DEFAULT_VICINITY_THRESHOLD = 10; +const int BSTracker::DEFAULT_PROX_THRESHOLD = 10; const int BSTracker::MIN_SCAN = 8; const int BSTracker::DEFAULT_MAX_SCAN = 32; const int BSTracker::DEFAULT_FITTING_DELAY = 20; @@ -28,9 +25,8 @@ 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; + proxTestOff = true; + proxThreshold = DEFAULT_PROX_THRESHOLD; acceptedLacks = DEFAULT_ACCEPTED_LACKS; minRestart = acceptedLacks; @@ -38,6 +34,7 @@ BSTracker::BSTracker () fittingDelay = DEFAULT_FITTING_DELAY; recordScans = false; orthoScan = false; + trackCrosswise = false; thickenningOn = true; thickenningLimit = DEFAULT_THICKENNING_LIMIT; @@ -81,13 +78,17 @@ void BSTracker::setGradientMap (VMap *data) } -BlurredSegment *BSTracker::fastTrack (const Pt2i &p1, const Pt2i &p2, - bool centralp, const Pt2i &pc) +BlurredSegment *BSTracker::fastTrack (int bsMaxWidth, + const Pt2i &p1, const Pt2i &p2, + int swidth, const Pt2i &pc) { // Creates the scanner DirectionalScanner *ds = NULL; - if (centralp) - ds = scanp.getScanner (pc, p1.vectorTo (p2), 4 * imaxWidth, false); + if (swidth != 0) + { + if (swidth < MIN_SCAN) swidth = MIN_SCAN; + ds = scanp.getScanner (pc, p1.vectorTo (p2), swidth, false); + } else ds = scanp.getScanner (p1, p2); if (ds == NULL) return NULL; @@ -107,7 +108,7 @@ BlurredSegment *BSTracker::fastTrack (const Pt2i &p1, const Pt2i &p2, } int candide; Pt2i pfirst; - if (centralp) pfirst.set (pc.x (), pc.y ()); + if (swidth != 0) pfirst.set (pc.x (), pc.y ()); else { candide = gMap->largestIn (pix); @@ -119,7 +120,7 @@ BlurredSegment *BSTracker::fastTrack (const Pt2i &p1, const Pt2i &p2, pfirst.set (pix.at (candide)); } - BlurredSegmentProto bs (imaxWidth, pfirst); + BlurredSegmentProto bs (bsMaxWidth, pfirst); Pt2i lastLeft (pfirst); Pt2i lastRight (pfirst); @@ -151,7 +152,8 @@ BlurredSegment *BSTracker::fastTrack (const Pt2i &p1, const Pt2i &p2, candide = gMap->largestIn (pix); if (candide != -1) { - if (lastRight.manhattan (pix.at (candide)) <= vicinityThreshold) + if (proxTestOff + || lastRight.manhattan (pix.at (candide)) <= proxThreshold) added = bs.addRight (pix.at (candide)); } if (added) @@ -179,7 +181,8 @@ BlurredSegment *BSTracker::fastTrack (const Pt2i &p1, const Pt2i &p2, candide = gMap->largestIn (pix); if (candide != -1) { - if (lastLeft.manhattan (pix.at (candide)) < vicinityThreshold) + if (proxTestOff + || lastLeft.manhattan (pix.at (candide)) <= proxThreshold) added = bs.addLeft (pix.at (candide)); } if (added) @@ -200,9 +203,9 @@ BlurredSegment *BSTracker::fastTrack (const Pt2i &p1, const Pt2i &p2, -BlurredSegment *BSTracker::fineTrack (const Pt2i ¢er, const Vr2i &scandir, - int scanwidth, int bswidth, - const Vr2i &gref) +BlurredSegment *BSTracker::fineTrack (int bsMaxWidth, + const Pt2i ¢er, const Vr2i &scandir, + int scanwidth, const Vr2i &gref) { // Checks scan width minimal size if (scanwidth < MIN_SCAN) scanwidth = MIN_SCAN; @@ -244,7 +247,7 @@ BlurredSegment *BSTracker::fineTrack (const Pt2i ¢er, const Vr2i &scandir, return NULL; } - BlurredSegmentProto bs (bswidth, pix[cand[0]]); + BlurredSegmentProto bs (bsMaxWidth, pix[cand[0]]); // Handles thickenning bool thickenOn = thickenningOn; @@ -252,7 +255,7 @@ BlurredSegment *BSTracker::fineTrack (const Pt2i ¢er, const Vr2i &scandir, // Handles thinning int count = 0; - AbsRat maxw (bswidth * DEFAULT_THINNING_RESOLUTION, + AbsRat maxw (bsMaxWidth * DEFAULT_THINNING_RESOLUTION, DEFAULT_THINNING_RESOLUTION); // Extends the segment @@ -307,7 +310,7 @@ BlurredSegment *BSTracker::fineTrack (const Pt2i ¢er, const Vr2i &scandir, { Vr2i dirn = bs.getSupportVector (); if (4 * dirn.squaredScalarProduct (scandir) - < dirn.norm2 () * scandir.norm2 ()) + < 3 * dirn.norm2 () * scandir.norm2 ()) { scanningLeft = false; scanningRight = false; @@ -318,6 +321,17 @@ BlurredSegment *BSTracker::fineTrack (const Pt2i ¢er, const Vr2i &scandir, bs.getLine()->getMedialAxis (ppa, ppb, ppc); ds->bindTo (ppa, ppb, ppc); } + else if (trackCrosswise && count > 3 && bs.getLine () != NULL) + { + Vr2i dirn = bs.getSupportVector (); + if (4 * dirn.squaredScalarProduct (scandir) + < 3 * dirn.norm2 () * scandir.norm2 ()) + { + scanningLeft = false; + scanningRight = false; + fail += FAILURE_LOST_ORIENTATION; + } + } // Extends on right if (scanningRight) diff --git a/Code/Seg/BlurredSegment/bstracker.h b/Code/Seg/BlurredSegment/bstracker.h index 26a8b3c..2e9e102 100755 --- a/Code/Seg/BlurredSegment/bstracker.h +++ b/Code/Seg/BlurredSegment/bstracker.h @@ -16,8 +16,11 @@ using namespace std; */ class BSTracker { - public: + + /** Minimal length of scan length to be processed. */ + static const int MIN_SCAN; + /** * \brief Creates a blurred segment tracker. @@ -36,48 +39,28 @@ public: /** * \brief Builds and returns a blurred segment from only gradient maximum. + * @param bsMaxWidth Blurred segment assigned maximal width. * @param p1 Initial stroke start point. * @param p2 Initial stroke end point. - * @param centralp Set to true if a start point is provided. - * @param pc Initial segment start point (if centralp is true). + * @param swidth Set to 0 if no start point is provided. + * @param pc Initial segment start point (if swidth is set). */ - BlurredSegment *fastTrack (const Pt2i &p1, const Pt2i &p2, - bool centralp = false, const Pt2i &pc = Pt2i ()); + BlurredSegment *fastTrack (int bsMaxWidth, + const Pt2i &p1, const Pt2i &p2, + int swidth = 0, const Pt2i &pc = Pt2i ()); /** * \brief Builds and returns a blurred segment from local gradient maxima. * Finer detection using gradient ridges and direction input. + * @param bsMaxWidth Initial assigned maximal width of the blurred segment. * @param center Central point of the scan. * @param scandir Scan direction * @param scanwidth Width of the scan strip. - * @param bswidth Initial maximal width of the blurred segment to build. * @param gref Gradient vector reference to select candidates. */ - BlurredSegment *fineTrack (const Pt2i ¢er, const Vr2i &scandir, - int scanwidth, int bswidth, - const Vr2i &gref); - - /** - * \brief Returns the assigned maximal width for fast tracks. - */ - inline int fastTracksMaxWidth () const { return imaxWidth; } - - /** - * \brief Sets the assigned maximal width for fast tracks. - */ - inline void setFastTracksMaxWidth (int value) { - if (value > 0) imaxWidth = value; } - - /** - * \brief Returns the assigned maximal width for fine tracks. - */ - inline int fineTracksMaxWidth () const { return fmaxWidth; } - - /** - * \brief Sets the assigned maximal width for fine tracks. - */ - inline void setFineTracksMaxWidth (int value) { - if (value > 0) fmaxWidth = value; } + BlurredSegment *fineTrack (int bsMaxWidth, + const Pt2i ¢er, const Vr2i &scandir, + int scanwidth, const Vr2i &gref); /** * \brief Returns the pixel lack tolerence for exdending the blurred segment.. @@ -99,7 +82,7 @@ public: /** * \brief Returns the count of accepted points to release a failure. */ - inline int getRestartOnLack () { return minRestart; } + inline int getRestartOnLack () const { return minRestart; } /** * \brief Switches on or off the automatic restart after failure. @@ -109,37 +92,43 @@ public: minRestart = (minRestart == 1 ? acceptedLacks : 1); } + /** + * \brief Returns whether the crosswise segment detection is set. + */ + inline bool trackCrosswiseOn () const { return trackCrosswise; } + + /** + * \brief Switches on or off the crosswise segment detection. + */ + inline void switchTrackCrosswise () { trackCrosswise = ! trackCrosswise; } + /** * \brief Sets the image data. */ void setGradientMap (VMap *data); /** - * \brief Returns the vicinity threshold used for fast tracking. + * \brief Returns the proximity test status. */ - inline int getVicinityThreshold () { return vicinityThreshold; } + inline bool proximityConstraintOn () const { return (! proxTestOff); } /** - * \brief Increments the vicinity threshold used for fast tracking. - * @param inc Increment value. + * \brief Switches the proximity test used for fast tracking. */ - inline void incVicinityThreshold (int inc) { - if (vicinityThreshold < NO_VICINITY) { - vicinityThreshold += inc; - if (vicinityThreshold < 1) vicinityThreshold = 1; } } + inline void switchProximityConstraint () { proxTestOff = ! proxTestOff; } /** - * \brief Returns the vicinity test status. + * \brief Returns the proximity threshold used for fast tracking. */ - inline bool vicinityConstraintOn () { - return (vicinityThreshold < NO_VICINITY); } + inline int getProximityThreshold () const { return proxThreshold; } /** - * \brief Switches the vicinity test used for fast tracking. + * \brief Increments the proximity threshold used for fast tracking. + * @param bool Increment value. */ - inline void switchVicinityConstraint () { - vicinityThreshold += (vicinityThreshold > NO_VICINITY ? - - NO_VICINITY : NO_VICINITY); } + inline void incProximityThreshold (bool inc) { + proxThreshold += (inc ? 1 : -1); + if (proxThreshold < 1) proxThreshold = 1; } /** * \brief Returns the registered upper bounds of the final scan lines. @@ -230,28 +219,14 @@ public: */ inline bool orthoScansOn () { return orthoScan; } - /** - * \brief Returns the fast track default max width. - * This value is used when a central point is given. - */ - inline int fastTrackDefaultWidth () const { return (4 * imaxWidth); } - private : // Segment detection default parameters. - /** Default value for the max segment width for fast tracks. */ - static const int DEFAULT_FAST_TRACK_MAX_WIDTH; - /** Default value for the max segment width for fine tracks. */ - static const int DEFAULT_FINE_TRACK_MAX_WIDTH; /** Default value for the accepted number of successive lacks. */ static const int DEFAULT_ACCEPTED_LACKS; - /** Default value for the vicinity test used for fast tracking. */ - static const int DEFAULT_VICINITY_THRESHOLD; - /** Large value to release the vicinity constraint. */ - static const int NO_VICINITY; - /** Minimal length of scan length to be processed. */ - static const int MIN_SCAN; + /** Default value for the proximity test used for fast tracking. */ + static const int DEFAULT_PROX_THRESHOLD; /** Default value for the maximal number of scans processed on each side. */ static const int DEFAULT_MAX_SCAN; @@ -294,16 +269,14 @@ private : /** Scanned map height. */ int height; - /** Blurred segment max width for fast tracks. */ - int imaxWidth; - /** Blurred segment max width for fine tracks. */ - int fmaxWidth; /** Number of awaited points after each failure. */ int minRestart; /** Accepted number of successive lacks (wrt restart points). */ int acceptedLacks; - /** Vicinity threshold used for fast tracking. */ - int vicinityThreshold; + /** Status of the proximity constraint used for fast tracking. */ + bool proxTestOff; + /** Proximity threshold used for fast tracking. */ + int proxThreshold; /** Orthogonal scanning modality status */ bool orthoScan; @@ -311,6 +284,8 @@ private : bool dynamicScans; /** Minimal detection width before activating the dynamical scans. */ int fittingDelay; + /** Crosswise segment detection modality. */ + bool trackCrosswise; /** Segment thinning strategy. */ bool thinningOn; diff --git a/Code/Seg/ImageTools/pt2i.h b/Code/Seg/ImageTools/pt2i.h index fefb8ca..369e46e 100755 --- a/Code/Seg/ImageTools/pt2i.h +++ b/Code/Seg/ImageTools/pt2i.h @@ -118,6 +118,18 @@ public: + ((p.yp > yp) ? p.yp - yp : yp - p.yp)); } + /** + * @fn int chessboard (Pt2i p) + * \brief Returns the chessboard distance to the given point. + * @param p the given point. + */ + inline int chessboard (Pt2i p) const + { + int dx = (p.xp > xp ? p.xp - xp : xp - p.xp); + int dy = (p.yp > yp ? p.yp - yp : yp - p.yp); + return (dx > dy ? dx : dy); + } + /** * @fn int isConnectedTo (Pt2i p) * \brief Checks whether the point is connected (chessboard) to the given one. diff --git a/Code/Seg/ImageTools/vmap.cpp b/Code/Seg/ImageTools/vmap.cpp index b2b5f70..42e97fb 100755 --- a/Code/Seg/ImageTools/vmap.cpp +++ b/Code/Seg/ImageTools/vmap.cpp @@ -28,6 +28,7 @@ VMap::VMap (int width, int height, int *data, int type) this->width = width; this->height = height; this->gtype = type; + init (); imap = new int[width * height]; if (type == TYPE_TOP_HAT) { @@ -115,7 +116,6 @@ VMap::VMap (int width, int height, int *data, int type) imap[i] = (int) sqrt (map[i].norm2 ()); gmagThreshold *= gradientThreshold; } - init (); } @@ -124,6 +124,7 @@ VMap::VMap (int width, int height, int **data, int type) this->width = width; this->height = height; this->gtype = type; + init (); imap = new int[width * height]; if (type == TYPE_TOP_HAT) { @@ -211,15 +212,14 @@ VMap::VMap (int width, int height, int **data, int type) imap[i] = (int) sqrt (map[i].norm2 ()); gmagThreshold *= gradientThreshold; } - init (); } VMap::~VMap () { - delete map; - delete imap; - delete mask; + delete [] map; + delete [] map; + delete [] mask; delete [] dilations; delete [] bowl; } diff --git a/Code/Seg/ImageTools/vmap.h b/Code/Seg/ImageTools/vmap.h index f31a507..06671ce 100755 --- a/Code/Seg/ImageTools/vmap.h +++ b/Code/Seg/ImageTools/vmap.h @@ -220,7 +220,7 @@ public: if (gradientThreshold < 0) gradientThreshold = 0; if (gradientThreshold > 255) gradientThreshold = 255; gmagThreshold = gradientThreshold; - if (gtype <= TYPE_SOBEL_5X5) gmagThreshold *= gradientThreshold; + if (gtype <= TYPE_SOBEL_5X5) gmagThreshold *= gmagThreshold; } /** diff --git a/Methode/ctrl.tex b/Methode/ctrl.tex index f8abf6b..7647502 100755 --- a/Methode/ctrl.tex +++ b/Methode/ctrl.tex @@ -38,7 +38,7 @@ r && Ajuste la r\'esolution de la grille de d\'etection automatique \\ s && Ajuste la longueur tol\'er\'ee pour les sauts de d\'etection \\ u && Relance la d\'etection sur la derni\`ere s\'election (update) \\ w && Ajuste la consigne d'\'epaisseur du segment flou pour le suivi fin \\ -x && Ajuste la consigne d'\'epaisseur du segment flou pour le suivi rapide \\ +x && Ajuste la marge de consigne d'\'epaisseur du segment flou pour le suivi rapide \\ y && Ajuste le contraste de l'image \\ z && Ajuste le seuil du contr\^ole de la consigne d'\'epaisseur \\ Ctrl-b && Commute le fond d'\'ecran de la fen\^etre principale \\ @@ -58,8 +58,8 @@ Ctrl-s && Commute la gestion des reprises sur interruption (1 / longueur absence Ctrl-t && Commute l'amincissement progressif \\ Ctrl-u && Commute l'affichage des bords des segments flous. \\ Ctrl-v && Commute l'affichage du r\'esultat de la d\'etection en console (verbose) \\ -Ctrl-w && Commute l'ajustement de la consigne d'\'epaisseur sur le segment \\ -Ctrl-x && Commute le recentrage du scan sur le segment d\'etect\'e \\ +Ctrl-w && Commute le recentrage du scan sur le segment d\'etect\'e \\ +Ctrl-x && Commute l'ajustement de la consigne d'\'epaisseur sur le segment d\'etect\'e \\ Ctrl-y && Commute l'affichage des pixels des segments flous \\ Ctrl-z && Commute le contr\^ole de la consigne d'\'epaisseur \\ 1 && Commute la visu des segments (pixels) \\ -- GitLab