From c05dce56820b4e2ff9128844b3e346e88c601a81 Mon Sep 17 00:00:00 2001
From: even <philippe.even@loria.fr>
Date: Sat, 22 Dec 2018 23:58:42 +0100
Subject: [PATCH] occ mask dilation and both edges in multidetection

---
 Code/Seg/BSTools/bsdetectionwidget.cpp | 16 +++--
 Code/Seg/BlurredSegment/bsdetector.cpp | 34 ++++++++--
 Code/Seg/BlurredSegment/bsdetector.h   |  3 +-
 Code/Seg/BlurredSegment/bstracker.h    |  2 +-
 Code/Seg/ImageTools/vmap.cpp           | 90 +++++++++++++++-----------
 Code/Seg/ImageTools/vmap.h             | 28 ++++++--
 6 files changed, 115 insertions(+), 58 deletions(-)

diff --git a/Code/Seg/BSTools/bsdetectionwidget.cpp b/Code/Seg/BSTools/bsdetectionwidget.cpp
index 06f0acf..67a6ae5 100755
--- a/Code/Seg/BSTools/bsdetectionwidget.cpp
+++ b/Code/Seg/BSTools/bsdetectionwidget.cpp
@@ -52,6 +52,7 @@ BSDetectionWidget::BSDetectionWidget (QWidget *parent)
   bsHighColor = Qt::yellow;
   bsPointsVisible = true;
   boundColor = Qt::green;
+  //boundHighColor = Qt::black;
   boundHighColor = Qt::magenta;
 }
 
@@ -594,11 +595,11 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
     case Qt::Key_R :
       if (event->modifiers () & Qt::ControlModifier)
       {
-        // Switches the occupancy mask dilation modality
-        gMap->switchMaskDilation ();
+        // Toggles the occupancy mask dilation type
+        gMap->toggleMaskDilation ();
         extract ();
-        cout << "Occupancy mask dilation : "
-             << (gMap->isMaskDilationOn () ? "on" : "off") << endl;
+        cout << "Occupancy mask dilation size : "
+             << gMap->getMaskDilation () << endl;
       }
       else
       {
@@ -635,11 +636,11 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
       {
         // Switches the progressive thinning
         detector.toggleThinning ();
-        if (detector.isThinningActivated () && detector.isThickenningOn ())
+        if (detector.isThinningOn () && detector.isThickenningOn ())
           detector.toggleThickenning ();
         extract ();
         cout << "Thinning "
-             << (detector.isThinningActivated () ? "on" : "off") << endl;
+             << (detector.isThinningOn () ? "on" : "off") << endl;
       }
       break;
 
@@ -730,7 +731,7 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
       {
         // Switches the thickenning control
         detector.toggleThickenning ();
-        if (detector.isThickenningOn () && detector.isThinningActivated ())
+        if (detector.isThickenningOn () && detector.isThinningOn ())
           detector.toggleThinning ();
         extract ();
         cout << "Thickenning "
@@ -996,6 +997,7 @@ void BSDetectionWidget::displaySavedSegments ()
   else if (background == BACK_WHITE) augmentedImage.fill (qRgb (255, 255, 255));
   else if (background == BACK_IMAGE) augmentedImage = loadedImage;
   else augmentedImage = gradImage;
+  lighten (augmentedImage);
   QPainter painter (&augmentedImage);
   if (! extractedSegments.empty ())
   {
diff --git a/Code/Seg/BlurredSegment/bsdetector.cpp b/Code/Seg/BlurredSegment/bsdetector.cpp
index 27510ed..5cf09f3 100755
--- a/Code/Seg/BlurredSegment/bsdetector.cpp
+++ b/Code/Seg/BlurredSegment/bsdetector.cpp
@@ -38,7 +38,7 @@ BSDetector::BSDetector ()
   bst2 = new BSTracker ();
   bstold = new BSTracker ();
   if (bstold->dynamicScansOn ()) bstold->toggleDynamicScans ();
-  if (bstold->isThinningActivated ()) bstold->toggleThinning ();
+  if (bstold->isThinningOn ()) bstold->toggleThinning ();
   if (bstold->isThickenningOn ()) bstold->toggleThickenning ();
 
   oldp = false;
@@ -203,13 +203,20 @@ bool BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2)
     Pt2i ptstart = pts.at (locmax[i]);
     if (gMap->isFree (ptstart))
     {
-      detect (p1, p2, true, ptstart);
-      if (bsf != NULL)
+      int oldEdgeDir = edgeDirection;
+      if (edgeDirection != 0) edgeDirection = 1;
+      while (edgeDirection >= -1)
       {
-        gMap->setMask (bsf->getAllPoints ());
-        mbsf.push_back (bsf);
-        bsf = NULL; // to avoid BS deletion
+        detect (p1, p2, true, ptstart);
+        if (bsf != NULL)
+        {
+          gMap->setMask (bsf->getAllPoints ());
+          mbsf.push_back (bsf);
+          bsf = NULL; // to avoid BS deletion
+        }
+        edgeDirection -= 2;
       }
+      edgeDirection = oldEdgeDir;
       if (++nbtrials == nbmaxtrials) isnext = false;
     }
   }
@@ -320,6 +327,21 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2,
     bsf = bsf2;
   }
 
+  // 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;
+    }
+  }
+
   lastTrialOk = true;
   resultValue = RESULT_OK;
 }
diff --git a/Code/Seg/BlurredSegment/bsdetector.h b/Code/Seg/BlurredSegment/bsdetector.h
index 8944d97..dcbf930 100755
--- a/Code/Seg/BlurredSegment/bsdetector.h
+++ b/Code/Seg/BlurredSegment/bsdetector.h
@@ -414,8 +414,7 @@ public:
   /**
    * \brief Returns if the thinning is activated.
    */
-  inline bool isThinningActivated () const {
-    return bst2->isThinningActivated (); }
+  inline bool isThinningOn () const { return bst2->isThinningOn (); }
 
   /**
    * \brief Toggles the thinning strategy.
diff --git a/Code/Seg/BlurredSegment/bstracker.h b/Code/Seg/BlurredSegment/bstracker.h
index 309953e..26a8b3c 100755
--- a/Code/Seg/BlurredSegment/bstracker.h
+++ b/Code/Seg/BlurredSegment/bstracker.h
@@ -213,7 +213,7 @@ public:
   /**
    * \brief Returns if the thinning is activated.
    */
-  inline bool isThinningActivated () const { return thinningOn; }
+  inline bool isThinningOn () const { return thinningOn; }
 
   /**
    * \brief Toggles the thinning strategy.
diff --git a/Code/Seg/ImageTools/vmap.cpp b/Code/Seg/ImageTools/vmap.cpp
index 26a82ee..b2b5f70 100755
--- a/Code/Seg/ImageTools/vmap.cpp
+++ b/Code/Seg/ImageTools/vmap.cpp
@@ -18,12 +18,13 @@ const int VMap::NEAR_SQ_ANGLE = 80;  // 80% (roughly 25 degrees)
 const int VMap::DEFAULT_GRADIENT_THRESHOLD = 30;
 const int VMap::DEFAULT_GRADIENT_RESOLUTION = 100;
 
+const int VMap::MAX_BOWL = 20;
+const int VMap::NB_DILATIONS = 5;
+const int VMap::DEFAULT_DILATION = 4;
+
 
 VMap::VMap (int width, int height, int *data, int type)
 {
-  gradientThreshold = DEFAULT_GRADIENT_THRESHOLD;
-  gmagThreshold = gradientThreshold;
-  gradres = DEFAULT_GRADIENT_RESOLUTION;
   this->width = width;
   this->height = height;
   this->gtype = type;
@@ -114,21 +115,12 @@ VMap::VMap (int width, int height, int *data, int type)
       imap[i] = (int) sqrt (map[i].norm2 ());
     gmagThreshold *= gradientThreshold;
   }
-
-  mask = new bool[width * height];
-  for (int i = 0; i < width * height; i++) mask[i] = false;
-  masking = false;
-  maskDilationOn = true;
-  angleThreshold = NEAR_SQ_ANGLE;
-  orientedGradient = false;
+  init ();
 }
 
 
 VMap::VMap (int width, int height, int **data, int type)
 {
-  gradientThreshold = DEFAULT_GRADIENT_THRESHOLD;
-  gmagThreshold = gradientThreshold;
-  gradres = DEFAULT_GRADIENT_RESOLUTION;
   this->width = width;
   this->height = height;
   this->gtype = type;
@@ -219,13 +211,7 @@ VMap::VMap (int width, int height, int **data, int type)
       imap[i] = (int) sqrt (map[i].norm2 ());
     gmagThreshold *= gradientThreshold;
   }
-
-  mask = new bool[width * height];
-  for (int i = 0; i < width * height; i++) mask[i] = false;
-  masking = false;
-  maskDilationOn = true;
-  angleThreshold = NEAR_SQ_ANGLE;
-  orientedGradient = false;
+  init ();
 }
 
 
@@ -234,6 +220,49 @@ VMap::~VMap ()
   delete map;
   delete imap;
   delete mask;
+  delete [] dilations;
+  delete [] bowl;
+}
+
+
+void VMap::init ()
+{
+  gradientThreshold = DEFAULT_GRADIENT_THRESHOLD;
+  gmagThreshold = gradientThreshold;
+  gradres = DEFAULT_GRADIENT_RESOLUTION;
+  mask = new bool[width * height];
+  for (int i = 0; i < width * height; i++) mask[i] = false;
+  masking = false;
+  angleThreshold = NEAR_SQ_ANGLE;
+  orientedGradient = false;
+  bowl = new Vr2i[MAX_BOWL];
+  bowl[0] = Vr2i (1, 0);
+  bowl[1] = Vr2i (0, 1);
+  bowl[2] = Vr2i (-1, 0);
+  bowl[3] = Vr2i (0, -1);
+  bowl[4] = Vr2i (1, 1);
+  bowl[5] = Vr2i (1, -1);
+  bowl[6] = Vr2i (-1, -1);
+  bowl[7] = Vr2i (-1, 1);
+  bowl[8] = Vr2i (2, 0);
+  bowl[9] = Vr2i (0, 2);
+  bowl[10] = Vr2i (-2, 0);
+  bowl[11] = Vr2i (0, -2);
+  bowl[12] = Vr2i (2, 1);
+  bowl[13] = Vr2i (1, 2);
+  bowl[14] = Vr2i (-1, 2);
+  bowl[15] = Vr2i (-2, 1);
+  bowl[16] = Vr2i (-2, -1);
+  bowl[17] = Vr2i (-1, -2);
+  bowl[18] = Vr2i (1, -2);
+  bowl[19] = Vr2i (2, -1);
+  dilations = new int[NB_DILATIONS];
+  dilations[0] = 0;
+  dilations[1] = 4;
+  dilations[2] = 8;
+  dilations[3] = 12;
+  dilations[4] = 20;
+  maskDilation = DEFAULT_DILATION;
 }
 
 
@@ -702,23 +731,12 @@ void VMap::setMask (const vector<Pt2i> &pts)
   {
     Pt2i pt = *it++;
     mask[pt.y () * width + pt.x ()] = true;
-    if (maskDilationOn)
+    for (int i = 0; i < dilations[maskDilation]; i++)
     {
-      int x = pt.x (), y = pt.y ();
-      if (x > 0)
-      {
-        mask[y * width + x - 1] = true;
-        if (y > 0) mask[(y - 1) * width + x - 1] = true;
-        if (y + 1 < height) mask[(y + 1) * width + x - 1] = true;
-      }
-      if (x + 1 < width)
-      {
-        mask[y * width + x + 1] = true;
-        if (y > 0) mask[(y - 1) * width + x + 1] = true;
-        if (y + 1 < height) mask[(y + 1) * width + x + 1] = true;
-      }
-      if (y > 0) mask[(y - 1) * width + x] = true;
-      if (y + 1 < height) mask[(y + 1) * width + x] = true;
+      int x = pt.x () + bowl[i].x ();
+      int y = pt.y () + bowl[i].y ();
+      if (x >= 0 && x < width && y >= 0 && y < height)
+        mask[y * width + x] = true;
     }
   }
 }
diff --git a/Code/Seg/ImageTools/vmap.h b/Code/Seg/ImageTools/vmap.h
index 9f76483..f31a507 100755
--- a/Code/Seg/ImageTools/vmap.h
+++ b/Code/Seg/ImageTools/vmap.h
@@ -259,14 +259,15 @@ public:
   inline void setMasking (bool status) { masking = status; }
 
   /**
-   * \brief Retuns the mask dilation modality.
+   * \brief Retuns the mask dilation size.
    */
-  inline bool isMaskDilationOn () const { return (maskDilationOn); }
+  inline int getMaskDilation () const { return (dilations[maskDilation]); }
 
   /**
-   * \brief Sets mask activation on or off.
+   * \brief Toggles the mask dilation size.
    */
-  inline void switchMaskDilation () { maskDilationOn = ! maskDilationOn; }
+  inline void toggleMaskDilation () {
+    if (++maskDilation == NB_DILATIONS) maskDilation = 0; }
 
   /**
    * \brief Tests the occupancy of a mask cell.
@@ -286,6 +287,12 @@ private:
   static const int DEFAULT_GRADIENT_THRESHOLD;
   /** Default threshold value for the gradient resolution (filtering). */
   static const int DEFAULT_GRADIENT_RESOLUTION;
+  /** Size of the maximal dilation bowl. */
+  static const int MAX_BOWL;
+  /** Number of dilation types. */
+  static const int NB_DILATIONS;
+  /** Default dilation for the points added to the mask. */
+  static const int DEFAULT_DILATION;
 
   /** Image width. */
   int width;
@@ -302,8 +309,12 @@ private:
   bool *mask;
   /** Flag indicating whether the occupancy mask is in use. */
   bool masking;
-  /** Flag indicating whether input points should be dilated. */
-  bool maskDilationOn;
+  /** Type of dilation applied to the points added to the mask. */
+  int maskDilation;
+  /** Number of neighbours in the applied dilation. */
+  int *dilations;
+  /** Dilation bowl. */
+  Vr2i *bowl;
   /** Standardized gradient threshold for highest value detection. */
   int gradientThreshold;
   /** Gradient magnitude threshold for highest value detection. */
@@ -314,6 +325,11 @@ private:
   bool orientedGradient;
 
 
+  /** 
+   * \brief Initializes the internal data of the vector map.
+   */
+  void init ();
+
   /** 
    * \brief Builds the vector map as a gradient map from provided data.
    * Uses a Sobel 3x3 kernel.
-- 
GitLab