Skip to content
Snippets Groups Projects
bsdetector.h 17.96 KiB
#ifndef BLURRED_SEGMENT_DETECTOR_H
#define BLURRED_SEGMENT_DETECTOR_H

#include "bstracker.h"
#include "linespacefilter.h"

using namespace std;


/** 
 * @class BSDetector bsdetector.h
 * \brief Blurred segment detector in grey level images.
 * \author {P. Even}
 */
class BSDetector
{

public:

  /** Identifier for the final detection step. */
  static const int STEP_FINAL;
  /** Identifier for the initial detection step. */
  static const int STEP_INITIAL;
  /** Identifier for the preliminary detection step. */
  static const int STEP_PRELIM;

  /** Extraction result : successful extraction. */
  static const int RESULT_UNDETERMINED;
  /** Extraction result : successful extraction. */
  static const int RESULT_OK;
  /** Extraction result : no initial detection (bsini == NULL). */
  static const int RESULT_PRELIM_NO_DETECTION;
  /** Extraction result : too few points at initial detection. */
  static const int RESULT_PRELIM_TOO_FEW;
  /** Extraction result : no initial detection (bsini == NULL). */
  static const int RESULT_INITIAL_NO_DETECTION;
  /** Extraction result : too few points at initial detection. */
  static const int RESULT_INITIAL_TOO_FEW;
  /** Extraction result : unsuccessful density test at initial detection. */
  static const int RESULT_INITIAL_TOO_SPARSE;
  /** Extraction result : unsuccessful filter test at initial detection. */
  static const int RESULT_INITIAL_TOO_MANY_OUTLIERS;
  /** Extraction result : no final detection (bsf == NULL). */
  static const int RESULT_FINAL_NO_DETECTION;
  /** Extraction result : too few points at final detection. */
  static const int RESULT_FINAL_TOO_FEW;
  /** Extraction result : unsuccessful connectivity test at final detection. */
  static const int RESULT_FINAL_TOO_SPARSE;
  /** Extraction result : unsuccessful filter test at final detection. */
  static const int RESULT_FINAL_TOO_MANY_OUTLIERS;

  
  /**
   * \brief Creates a segment detector.
   */
  BSDetector ();

  /**
   * \brief Deletes the segment detector.
   */
  ~BSDetector ();

  /**
   * \brief Returns the minimal vertical or horizontal width.
   */
  inline int result () const { return resultValue; }

  /**
   * \brief Sets the gradient map.
   */
  void setGradientMap (VMap *data);

  /**
   * \brief Detects all blurred segments in the picture.
   */
  void detectAll ();

  /**
   * \brief Detects blurred segments between two input points.
   * @param p1 First input point.
   * @param p2 Second input point.
   */
  void detectSelection (const Pt2i &p1, const Pt2i &p2);

  /**
   * \brief Runs the last detection again.
   */
  void redetect ();

  /**
   * \brief Detects a blurred segment between two input points.
   * Step 1: For each scan line, one candidate is selected
   *         based on the gradient norm only (no direction test).
   * Step 2: Outliers pruning based on parameter space pre-filtering.
   * Step 3: For each scan line, local candidates are detected
   *         on top of gradient ridges with closest direction.
   *         The first candidates that prolongates the segment are retained.
   * Step 4: Outliers pruning based on parameter space filtering.
   * Note : Multi-detection along a stroke requires an initial start point.
   * @param p1 First input point.
   * @param p2 Second input point.
   * @param centralp Set to true if the central point is provided.
   * @param pc Initial central point.
   */
  void detect (const Pt2i &p1, const Pt2i &p2,
               bool centralp = false, const Pt2i &pc = Pt2i ());

  /**
   * \brief Returns the detected blurred segment at given step.
   * @param step Detection step.
   */
  BlurredSegment *getBlurredSegment (int step = STEP_FINAL) const;
    
  /**
   * \brief Returns the list of detected blurred segments at final step.
   */
  inline const vector<BlurredSegment *> getBlurredSegments () const {
    return (mbsf); }

  /**
   * \brief Avoids the deletion of the last extracted blurred segment.
   */
  inline void preserveFormerBlurredSegment () { bsf = NULL; }

  /**
   * \brief Avoids the deletion of the last extracted blurred segments.
   */
  inline void preserveFormerBlurredSegments () { mbsf.clear (); }

  /**
   * \brief Returns the assigned maximal width for the fast tracks.
   */
  inline int fastTracksMaxWidth () const {
    return bst1->fastTracksMaxWidth (); }

  /**
   * \brief Sets the assigned width for the fast tracks.
   */
  inline void setFastTracksMaxWidth (int value) {
    bst1->setFastTracksMaxWidth (value); }

  /**
   * \brief Returns the assigned maximal width for the fine tracks.
   */
  inline int fineTracksMaxWidth () const {
    return bst1->fineTracksMaxWidth (); }

  /**
   * \brief Sets the assigned maximal width for the fine tracks.
   */
  inline void setFineTracksMaxWidth (int value) {
    bst1->setFineTracksMaxWidth (value); }

  /**
   * \brief Returns the output blurred segment minimal size.
   */
  inline int getBSminSize () const { return bsMinSize; }

  /**
   * \brief Sets the output blurred segment minimal size.
   */
  inline void setBSminSize (int value) {
    if (value >= ABSOLUTE_BS_MIN_SIZE) bsMinSize = value; }

  /**
   * \brief Returns the threshold used for maximal gradient detection.
   */
  inline int getGradientThreshold () const {
    return (gMap->getGradientThreshold ()); }

  /**
   * \brief Increments the threshold used for maximal gradient detection.
   * @param inc Increment value.
   */
  inline void incGradientThreshold (int inc) {
    return (gMap->incGradientThreshold (inc)); }

  /**
   * \brief Returns the automatic detection grid resolution.
   */
  inline int getAutoGridResolution () const { return autoResol; }

  /**
   * \brief Sets the automatic detection grid resolution.
   */
  inline void setAutoGridResolution (int number) {
    if (number > 0 && number < gMap->getWidth () / 8) autoResol = number; }

  /**
   * \brief Returns the pixel lack tolerence.
   */
  inline int getPixelLackTolerence () const {
    return bst2->pixelLackTolerence (); }

  /**
   * \brief Sets the pixel lack tolerence.
   */
  inline void setPixelLackTolerence (int number) {
    bst2->setPixelLackTolerence (number); }

  /**
   * \brief Returns the count of accepted points to release a failure.
   */
  inline int getRestartOnLack () { return bst2->getRestartOnLack (); }

  /**
   * \brief Switches on or off the automatic restart after failure.
   */
  inline void switchAutoRestart () { bst2->switchAutoRestart (); }
  /**
   * \brief Returns the preliminary detection modality status.
   */
  inline bool isPreliminary () { return (prelimDetectionOn); }

  /**
   * \brief Switches preliminary detection modality.
   */
  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).
   */
  inline int edgeDirectionConstraint ()
  {
    return (edgeDirection);
  }

  /**
   * \brief Inverts the edge direction for detection stage.
   */
  inline void invertEdgeDirection ()
  {
    edgeDirection = - edgeDirection;
  }

  /**
   * \brief Switches the edge direction constraint.
   */
  inline void switchEdgeDirectionConstraint ()
  {
    edgeDirection = (edgeDirection == 0 ? 1 : 0);
    gMap->switchOrientationConstraint ();
  }

  /**
   * \brief Returns true if the fine scan is recentred on the detected segment.
   */
  inline bool isScanRecentering () { return recenteringOn; }

  /**
   * \brief Switches on or off the scan recentering modality.
   */
  inline void switchScanRecentering () { recenteringOn = ! recenteringOn; }

  /**
   * \brief Returns true if the fine scan is fitted to the detected segment.
   */
  inline bool isScanFitting () { return fittingOn; }

  /**
   * \brief Switches on or off the scan fitting modality.
   */
  inline void switchScanFitting () { fittingOn = ! fittingOn; }

  /**
   * \brief Returns true if the multi-selection modality is set.
   */
  inline bool isMultiSelection () { return multiSelection; }

  /**
   * \brief Switches on or off the multi-selection modality.
   */
  inline void switchMultiSelection () { multiSelection = ! multiSelection; }

  /**
   * \brief Returns the scan lines at final step.
   */
  const vector <vector <Pt2i> > getFinalScans () const;

  /**
   * \brief Returns whether the final scan record modality is set.
   */
  bool finalScansRecordOn () const;

  /**
   * \brief Sets the scan record modality at final step.
   * @param status Sets on if true, off otherwise.
   */
  void setFinalScansRecord (bool status);

  /**
   * \brief Toggles the initial step bounding.
   */
  inline void switchInitialBounding () { bst1->switchScanExtent (); }

  /**
   * \brief Returns the maximal scan extent of the initial detection.
   */
  inline int initialDetectionMaxExtent () { return (bst1->maxScanExtent ()); }

  /**
   * \brief Returns the vicinity threshold used for fast tracking.
   */
  inline int getVicinityThreshold () { return (bst1->getVicinityThreshold ()); }

  /**
   * \brief Increments the vicinity threshold used for fast tracking.
   * @param inc Increment value.
   */
  inline void incVicinityThreshold (int inc) {
    bst1->incVicinityThreshold (inc); }
    
  /**
   * \brief Returns the vicinity test status.
   */
  inline bool vicinityConstraintOn () { return (bst1->vicinityConstraintOn ()); }

  /**
   * \brief Switches the vicinity test used for fast tracking.
   */
  inline void switchVicinityConstraint () { bst1->switchVicinityConstraint (); }

  /**
   * \brief Returns if the dynamic scans modality is set.
   */
  inline bool dynamicScansOn () { return bst2->dynamicScansOn (); }

  /**
   * \brief Switches on or off the dynamic scans modality.
   */
  inline void switchDynamicScans () { bst2->toggleDynamicScans (); }

  /**
   * \brief Sets the dynamic scans modality on or off.
   */
  inline void setDynamicScans (bool onOff) { bst2->setDynamicScans (onOff); }

  /**
   * \brief Returns if the orthographic scans modality set.
   */
  inline bool orthoScansOn () { return bst1->orthoScansOn (); }

  /**
   * \brief Switches on or off the orthogonal scans modality.
   */
  void switchOrthoScans ();

  /**
   * \brief Returns if the thickenning control is activated.
   */
  inline bool isThickenningOn () const { return bst2->isThickenningOn (); }

  /**
   * \brief Toggles the thickenning control.
   */
  inline void toggleThickenning () { bst2->toggleThickenning (); }

  /**
   * \brief Returns the thickenning limit.
   */
  inline int getThickenningLimit () const {
    return bst2->getThickenningLimit (); }

  /**
   * \brief Increments the thickenning limit.
   */
  inline void incThickenningLimit (int val) { bst2->incThickenningLimit (val); }

  /**
   * \brief Returns if the thinning is activated.
   */
  inline bool isThinningActivated () const {
    return bst2->isThinningActivated (); }

  /**
   * \brief Toggles the thinning strategy.
   */
  inline void toggleThinning () { bst2->toggleThinning (); }

  /**
   * \brief Returns if one of the filter is activated.
   */
  inline bool isOneFilterSet () { return (filteringOn || prefilteringOn); }

  /**
   * \brief Returns the line space based filter.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline LineSpaceFilter *getFilter (int step) const {
    return (step == STEP_FINAL ? lsf2 : lsf1); }

  /**
   * \brief Returns the accepted points by the line space based filter.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline vector<Pt2i> getAccepted (int step) const {
    return (step == STEP_FINAL ?
      (filteringOn ? lsf2->getAccepted () : bsf->getAllPoints ()) :
      (prefilteringOn ? lsf1->getAccepted () : bsini->getAllPoints ())); }

  /**
   * \brief Returns the rejected points by the line space based filter.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  vector<Pt2i> getRejected (int step) const;

  /**
   * \brief Returns if the given line space based filter is activated.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline bool isFiltering (int step) const {
    if (step == STEP_FINAL) return (filteringOn);
    else if (step == STEP_INITIAL) return (prefilteringOn);
    else return false; }

  /**
   * \brief Toggles the use of the given line space based filter.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  void switchFiltering (int step);

  /**
   * \brief Returns the blurred segment size before pre-filtering.
   */
  inline int prefilteringInputSize () {
    return (prefilteringOn ? lsf1->blurredSegmentInitialSize () : 0); }

  /**
   * \brief Returns the blurred segment size after pre-filtering.
   */
  inline int prefilteringOutputSize () {
    return (prefilteringOn ? lsf1->blurredSegmentFinalSize () : 0); }

  /**
   * \brief Returns whether the density test at initial step is set.
   */
  inline bool isSetDensityTest () { return (densityTestOn); }

  /**
   * \brief Switches on or off the density test modality.
   */
  inline void switchDensityTest () { densityTestOn = ! densityTestOn; }

  /**
   * \brief Switches on or off the connectivity constraint.
   */
  inline void switchConnectivityConstraint () { ccOn = ! ccOn; }

  /**
   * \brief Returns the connectivity constraint status.
   */
  inline bool isSetConnectivityConstraint () { return (ccOn); }

  /**
   * \brief Returns the minimal size of the segment connected components.
   */
  inline int getConnectedComponentMinSize () { return ccMinSize; }

  /**
   * \brief Increments the minimal size of the connected components.
   * @param increase Positive increment if true, negative otherwise.
   */
  bool incConnectedComponentMinSize (bool increase);

  /*
   * \brief Returns the count of trials in a multi-detection.
   */
  inline int countOfTrials () const { return (nbtrials); }

  /**
   * \brief Sets the maximum number of trials in a multi-detection.
   * @param nb Number of trials (0 if illimited).
   */
  inline void setMaxTrials (int nb) { nbmaxtrials = nb; }

  /**
   * \brief Returns the maximum number of trials for a multi-detection.
   */
  inline int getMaxTrials () const { return nbmaxtrials; }

  /**
   * \brief Retuns whether the last trial was successful.
   */
  inline bool isLastTrialOk () { return lastTrialOk; }

  /**
   * \brief Gets the last detection inputs.
   * @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 pc Input central point to fill in.
   */
  void getScanInput (int step, Pt2i &p1, Pt2i &p2, int &width, Pt2i &pc) const;


private :

  /** 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. */
  static const int ABSOLUTE_BS_MIN_SIZE;
  /** Default value for the minimal size of connected components. */
  static const int DEFAULT_CONNECT_MIN_SIZE;
  /** Default value for the automatic detection grid resolution. */
  static const int DEFAULT_AUTO_RESOLUTION;
  /** Default value for the preliminary stroke half length. */
  static const int PRELIM_MIN_HALF_WIDTH;


  /** 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)
   */
  int edgeDirection;
  /** Minimal size of the detected blurred segment. */
  int bsMinSize;
  /** Connectivity constraint status. */
  bool ccOn;
  /** Minimal size of the connected components to validate a blurred segment. */
  int ccMinSize;
  /** Automatic scan recentering (based on previous detection). */
  bool recenteringOn;
  /** Automatic scan width selection (based on previous detection). */
  bool fittingOn;
  /** Density test modality after initial detection. */
  bool densityTestOn;
  /** Segment multi-selection modality status. */
  bool multiSelection;
  /** Flag indicating if the last trial was successful. */
  bool lastTrialOk;
  /** Count of trials in a multi-detection. */
  int nbtrials;
  /** Maximum number of trials in a multi-detection. */
  int nbmaxtrials;
  /** Automatic detection modality. */
  bool autodet;
  /** Grid resolution for the automatic extraction. */
  int autoResol;
  /** Result of the blurred segment extraction */
  int resultValue;

  /** 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 stage modality. */
  bool prelimDetectionOn;
  /** Preliminary rough tracker. */
  BSTracker *bst0;
  /** Preliminary detected blurred segment. */
  BlurredSegment *bspre;

  /** Initial rough tracker. */
  BSTracker *bst1;
  /** Last input start point for initial step. */
  Pt2i inip1;
  /** Last input end point for initial step. */
  Pt2i inip2;
  /** Last input central point for initial step. */
  Pt2i inipc;
  /** Last input central point modality for initial step. */
  bool inicentralp;
  /** Initially detected blurred segment (initial step result). */
  BlurredSegment *bsini;

  /** Fine tracker. */
  BSTracker *bst2;
  /** Detected blurred segment (final result). */
  BlurredSegment *bsf;
  /** Detected blurred segments in case of multi-detection (final results). */
  vector<BlurredSegment *> mbsf;

  /** Initial segment filtering modality. */
  bool prefilteringOn;
  /** Line space based pre-filter. */
  LineSpaceFilter *lsf1;

  /** Detected segment filtering modality. */
  bool filteringOn;
  /** Line space based post-filter. */
  LineSpaceFilter *lsf2;


  /**
   * \brief Detects all blurred segments between two input points.
   *   Returns the continuation modality.
   * @param p1 First input point.
   * @param p2 Second input point.
   */
  bool runMultiDetection (const Pt2i &p1, const Pt2i &p2);

  /**
   * \brief Resets the multi-selection list.
   */
  void freeMultiSelection ();

};
#endif