From 0d18691fb0c9b559857a2920a59a4be0a88ff6c4 Mon Sep 17 00:00:00 2001
From: even <philippe.even@loria.fr>
Date: Mon, 6 May 2019 17:36:34 +0200
Subject: [PATCH] Double edge detection modes

---
 Code/FBSD/BSTools/bsdetectionwidget.cpp | 65 +++++++++++++++++--------
 Code/FBSD/BSTools/bsrandomtester.cpp    |  6 ++-
 Code/FBSD/BlurredSegment/bsdetector.cpp | 33 ++++++++++---
 Code/FBSD/BlurredSegment/bsdetector.h   | 55 ++++++++++++++-------
 Methode/ctrl.tex                        |  5 +-
 5 files changed, 116 insertions(+), 48 deletions(-)

diff --git a/Code/FBSD/BSTools/bsdetectionwidget.cpp b/Code/FBSD/BSTools/bsdetectionwidget.cpp
index e50ef5c..979fe68 100755
--- a/Code/FBSD/BSTools/bsdetectionwidget.cpp
+++ b/Code/FBSD/BSTools/bsdetectionwidget.cpp
@@ -481,9 +481,9 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
     case Qt::Key_D :
       if (event->modifiers () & Qt::ControlModifier)
       {
-        // Switches density test at initial step
+        // Switches sparsity test at initial step
         detector.switchInitialSparsityTest ();
-        cout << "Initial density test : "
+        cout << "Initial sparsity test : "
              << (detector.isInitialSparsityTestOn () ? "on" : "off") << endl;
         extract ();
       }
@@ -491,23 +491,30 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
 // DEV OUT
 
     case Qt::Key_E :
-      // Handles directed edge or stroke detection
-      if (event->modifiers () & Qt::ControlModifier)
-        detector.switchEdgeDirectionConstraint ();
-      else detector.invertEdgeDirection ();
-      switch (detector.edgeDirectionConstraint ())
       {
-        case 0 :
-          cout << "Line detection mode set" << endl;
-          break;
-        case 1 :
-          cout << "Main edge detection mode set" << endl;
-          break;
-        case -1 :
-          cout << "Opposite edge detection mode set" << endl;
-          break;
+        // Handles single or double edge detection
+        if (event->modifiers () & Qt::ControlModifier)
+        {
+          detector.switchSingleOrDoubleEdge ();
+          if (detector.isSingleEdgeModeOn ())
+            cout << "Single edge detection set ("
+                 << (detector.isOppositeGradientOn () ?
+                     "opposite" : "main") << ")" << endl;
+          else cout << "Double edge detection set" << endl;
+          extract ();
+        }
+        // Handles gradient orientation direction for the detection
+        else
+        {
+          if (detector.switchOppositeGradient ())
+          {
+            cout << "Single edge detection set ("
+                 << (detector.isOppositeGradientOn () ?
+                     "opposite" : "main") << ")" << endl;
+            extract ();
+          }
+        }
       }
-      extract ();
       break;
 
     case Qt::Key_F :
@@ -542,6 +549,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
       }
       break;
 
+// DEV IN
     case Qt::Key_J :
       if (event->modifiers () & Qt::ControlModifier)
       {
@@ -562,6 +570,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
         extract ();
       }
       break;
+// DEV OUT
 
     case Qt::Key_K :
       if (event->modifiers () & Qt::ControlModifier)
@@ -646,6 +655,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
       break;
 
     case Qt::Key_O :
+// DEV IN
       if (event->modifiers () & Qt::ControlModifier)
       {
         // Switches the scan directionality
@@ -655,6 +665,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
         extract ();
       }
       else
+// DEV OUT
       {
         // Outputs the detected segment
         cout << "Outputs detection result" << endl;
@@ -663,15 +674,17 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
       break;
 
     case Qt::Key_P :
+// DEV IN
       if (event->modifiers () & Qt::ControlModifier)
       {
-        // Switchues the preliminary detection
+        // Switches the preliminary detection
         detector.switchPreliminary ();
         cout << "Initial detection duplication "
              << (detector.isPreliminary () ? "on" : "off") << endl;
         extract ();
       }
       else
+// DEV OUT
       {
         // Captures main window
         cout << "Saves main window in capture.png" << endl;
@@ -697,6 +710,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
       break;
 
     case Qt::Key_R :
+// DEV IN
       if (event->modifiers () & Qt::ControlModifier)
       {
         // Toggles the occupancy mask dilation type
@@ -706,6 +720,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
         extract ();
       }
       else
+// DEV OUT
       {
         // Tunes the sweeping step value for automatic detections
         detector.setAutoSweepingStep (detector.getAutoSweepingStep () +
@@ -779,6 +794,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
         switchVerbose ();
       break;
 
+// DEV IN
     case Qt::Key_W :
       if (event->modifiers () & Qt::ControlModifier)
       {
@@ -789,6 +805,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
         extract ();
       }
       break;
+// DEV OUT
 
     case Qt::Key_X :
       if (event->modifiers () & Qt::ControlModifier)
@@ -880,6 +897,14 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
         gtview = new BSGroundtruthView (&loadedImage, &detector);
       gtview->show ();
       break;
+
+    case Qt::Key_Question :
+      detector.switchSingleOrDoubleMultiDetection ();
+      cout << "Multi-detection of "
+           << (detector.isSingleMultiOn () ? "single edges" : "double edges")
+           << endl;
+      extract ();
+      break;
 // DEV OUT
 
     case Qt::Key_Plus :
@@ -956,7 +981,6 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
     case Qt::Key_4 :
       switchIdetAnalyzer ();
       break;
-// DEV OUT
 
     case Qt::Key_5 :
       // Switches the crosswise segment detection
@@ -965,11 +989,13 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
       cout << "Crosswise segment detection "
            << (detector.trackCrosswiseOn () ? "on" : "off") << endl;
       break;
+// DEV OUT
 
     case Qt::Key_7 :
       storeUserInput ();
       break;
 
+// DEV IN
     case Qt::Key_8 :
       alternateTest ();
       break;
@@ -977,6 +1003,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
     case Qt::Key_9 :
       performanceTest ();
       break;
+// DEV OUT
 
     case Qt::Key_0 :
       localTest ();
diff --git a/Code/FBSD/BSTools/bsrandomtester.cpp b/Code/FBSD/BSTools/bsrandomtester.cpp
index 91df0c5..b11ac91 100755
--- a/Code/FBSD/BSTools/bsrandomtester.cpp
+++ b/Code/FBSD/BSTools/bsrandomtester.cpp
@@ -139,10 +139,12 @@ void BSRandomTester::randomTest ()
     if (gMap != NULL) delete gMap;
     gMap = new VMap (width, height, getBitmap (image), VMap::TYPE_SOBEL_5X5);
     gMap->incGradientThreshold (50 - gMap->getGradientThreshold ());
-    if (gMap->isOrientationConstraintOn ())
-      gMap->switchOrientationConstraint ();
     for (int det = 0; det < nbdets; det ++)
+    {
       detectors[det].setGradientMap (gMap);
+      if (detectors[det].isSingleEdgeModeOn ())
+        detectors[det].switchSingleOrDoubleEdge ();
+    }
 
     for (int det = 0; det < nbdets; det ++)
     {
diff --git a/Code/FBSD/BlurredSegment/bsdetector.cpp b/Code/FBSD/BlurredSegment/bsdetector.cpp
index bcb64bb..0872508 100755
--- a/Code/FBSD/BlurredSegment/bsdetector.cpp
+++ b/Code/FBSD/BlurredSegment/bsdetector.cpp
@@ -42,6 +42,7 @@ BSDetector::BSDetector ()
   inThick = DEFAULT_ASSIGNED_THICKNESS;
   prelimDetectionOn = false;
   staticDetOn = false;
+  singleMultiOn = true;
 
   bst0 = (prelimDetectionOn ? new BSTracker () : NULL);
   bst1 = new BSTracker ();
@@ -63,7 +64,7 @@ BSDetector::BSDetector ()
   //lsf2 = (filteringOn ? new LineSpaceFilter () : NULL);
   lsf2 = (filteringOn ? new BSFilter () : NULL);
 
-  edgeDirection = 0;   // detects strokes (not only edges)
+  oppositeGradientDir = false;   // main edge detection
   initialMinSize = DEFAULT_INITIAL_MIN_SIZE;
   finalFragmentationTestOn = false;
   fragmentMinSize = DEFAULT_FRAGMENT_MIN_SIZE;
@@ -236,9 +237,11 @@ bool BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2)
     Pt2i ptstart = pts.at (locmax[i]);
     if (gMap->isFree (ptstart))
     {
-      int oldEdgeDir = edgeDirection;
-      if (edgeDirection != 0) edgeDirection = 1;
-      while (isnext && edgeDirection >= -1)
+      bool savedOppDir = oppositeGradientDir;
+      oppositeGradientDir = false;
+      int nbDets = (gMap->isOrientationConstraintOn () ? 2 : 1);
+      if (singleMultiOn) nbDets = 1;
+      while (isnext && nbDets != 0)
       {
         int res = RESULT_VOID;
         if (staticDetOn) res = staticDetect (p1, p2, true, ptstart);
@@ -250,10 +253,11 @@ bool BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2)
           bsf = NULL; // to avoid BS deletion
           if ((int) (mbsf.size ()) == maxtrials) isnext = false;
         }
+        oppositeGradientDir = ! oppositeGradientDir;
+        nbDets --;
         nbtrials ++;
-        edgeDirection -= 2;
       }
-      edgeDirection = oldEdgeDir;
+      oppositeGradientDir = savedOppDir;
     }
   }
   return (isnext);
@@ -366,7 +370,8 @@ int BSDetector::detect (const Pt2i &p1, const Pt2i &p2,
   //-----------------------------
   Pt2i pCenter = bsini->getCenter ();
   Vr2i gRef = gMap->getValue (pCenter);
-  if (edgeDirection == -1) gRef.invert ();
+  if (oppositeGradientDir && gMap->isOrientationConstraintOn ())
+    gRef.invert ();
 
   // Scan recentering and fitting
   //-----------------------------
@@ -488,7 +493,8 @@ int BSDetector::staticDetect (const Pt2i &p1, const Pt2i &p2,
   //-----------------------------
   Pt2i pCenter = bsini->getCenter ();
   Vr2i gRef = gMap->getValue (pCenter);
-  if (edgeDirection == -1) gRef.invert ();
+  if (oppositeGradientDir && gMap->isOrientationConstraintOn ())
+    gRef.invert ();
 
   // Scan recentering and fitting
   //-----------------------------
@@ -677,6 +683,17 @@ void BSDetector::switchPreliminary ()
 }
 
 
+bool BSDetector::switchOppositeGradient ()
+{
+  if (gMap != NULL && gMap->isOrientationConstraintOn ())
+  {
+    oppositeGradientDir = ! oppositeGradientDir;
+    return true;
+  }
+  return false;
+}
+
+
 void BSDetector::setStaticDetector (bool status)
 {
   if (staticDetOn && ! status)
diff --git a/Code/FBSD/BlurredSegment/bsdetector.h b/Code/FBSD/BlurredSegment/bsdetector.h
index 4ecb328..9952068 100755
--- a/Code/FBSD/BlurredSegment/bsdetector.h
+++ b/Code/FBSD/BlurredSegment/bsdetector.h
@@ -269,31 +269,51 @@ public:
   void switchPreliminary ();
 
   /**
-   * \brief Returns the edge direction constraint status.
-   *    +1 : Edge direction constrained to the initial direction.
-   *    -1 : Edge direction constrained to the initial direction opposite.
-   *     0 : Edge constraint free (detects lines as well as edges).
+   * \brief Returns whether opposite edge direction is set in double edge mode.
    */
-  inline int edgeDirectionConstraint ()
+  inline bool isOppositeGradientOn () const
   {
-    return (edgeDirection);
+    return (oppositeGradientDir);
   }
 
   /**
    * \brief Inverts the edge direction for detection stage.
+   * Effective only in single edge detection mode.
+   * Returns whether the modification was actually made.
    */
-  inline void invertEdgeDirection ()
+  bool switchOppositeGradient ();
+
+  /**
+   * \brief Returns whether opposite edge direction is set in double edge mode.
+   */
+  inline bool isSingleEdgeModeOn () const
+  {
+    if (gMap != NULL) return (gMap->isOrientationConstraintOn ());
+    return (true);
+  }
+
+  /**
+   * \brief Switches between single and double edge detection.
+   */
+  inline void switchSingleOrDoubleEdge ()
+  {
+    if (gMap != NULL) gMap->switchOrientationConstraint ();
+  }
+
+  /**
+   * \brief Returns whether a single edge mode is set for multidetections.
+   */
+  inline bool isSingleMultiOn () const
   {
-    edgeDirection = - edgeDirection;
+    return (singleMultiOn);
   }
 
   /**
-   * \brief Switches the edge direction constraint.
+   * \brief Switches between single and double edge mode for multidetections.
    */
-  inline void switchEdgeDirectionConstraint ()
+  inline void switchSingleOrDoubleMultiDetection ()
   {
-    edgeDirection = (edgeDirection == 0 ? 1 : 0);
-    gMap->switchOrientationConstraint ();
+    singleMultiOn = ! singleMultiOn;
   }
 
   /**
@@ -626,12 +646,11 @@ private :
   /** Gradient map. */
   VMap *gMap;
 
-  /** Direction constraint of the detected edge :
-   *    +1 : complies to initial direction
-   *    -1 : complies to initial direction opposite
-   *     0 : no direction condition (detects lines as well as edges)
+  /** Selects points with opposite gradient direction.
+   *  Opposite to gradient direction at start point.
+   *  Used to detect two close edges with opposite gradients.
    */
-  int edgeDirection;
+  bool oppositeGradientDir;
   /** Minimal size of the initial segment. */
   int initialMinSize;
   /** Final fragmentation test status. */
@@ -652,6 +671,8 @@ private :
   int nbSmallBS;
   /** Segment multi-selection modality status. */
   bool multiSelection;
+  /** Single or double mode for multi-selections. */
+  bool singleMultiOn;
   /** Count of trials in a multi-detection. */
   int nbtrials;
   /** Maximum number of trials in a multi-detection. */
diff --git a/Methode/ctrl.tex b/Methode/ctrl.tex
index aafa0e5..dbcf967 100755
--- a/Methode/ctrl.tex
+++ b/Methode/ctrl.tex
@@ -29,7 +29,7 @@ e && Inverse la direction de r\'ef\'erence (autre bord) \\
 g && Ajuste le seuil du gradient \\
 j && Ajuste le seuil de voisinage pour les suivis rapides \\
 k && Ajuste la taille minimale des fragments \\
-l && Ajuste la taille minimale du segment final \\
+l && Ajuste la taille minimale du segment initial \\
 m && D\'etection exhaustive de tous les segments \\
 n && Allume le segment suivant dans une d\'etection multiple \\
 o && Edite le segment d\'etect\'e (seg.txt) \\
@@ -42,12 +42,13 @@ x && Ajuste la marge de consigne d'\'epaisseur du segment flou pour le suivi rap
 y && Ajuste le contraste de l'image \\
 z && Ajuste le d\'elai de d\'eclenchement du contr\^ole de la consigne d'\'epaisseur \\
 Ctrl-b && Commute le fond d'\'ecran de la fen\^etre principale \\
-Ctrl-d && Commute le test de densit\'e \\
+Ctrl-d && Commute le test initial de densit\'e \\
 Ctrl-e && Commute la prise en compte de la direction du bord (trait / contour) \\
 Ctrl-f && Commute le pr\'e-filtrage (segment initial) \\
 Ctrl-h && Commute le filtrage du segment final \\
 Ctrl-j && Commute la contrainte de voisinage pour les suivis rapides \\
 Ctrl-k && Commute le test de fragmentation \\
+Ctrl-l && Commute le test de densit\'e final \\
 Ctrl-m && Commute la d\'etection multiple \\
 Ctrl-n && Commute la limitation de l'extension de la d\'etection initiale \\
 Ctrl-o && Commute la directionnalit\'e des scans \\
-- 
GitLab