Skip to content
Snippets Groups Projects
bsdetector.h 14.79 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:

  /** 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 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 p0 Initial segment start point (if different from NULL).
   */
  void detect (const Pt2i &p1, const Pt2i &p2, Pt2i *p0 = NULL);

  /**
   * \brief Returns the last detected blurred segment at given step.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline BlurredSegment *getBlurredSegment (int step) {
    return (step == 0 ? bsini : bsf); }

  /**
   * \brief Returns the list of detected blurred segments at given step.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline vector<BlurredSegment *> getBlurredSegments (int step) {
    return (step == 0 ? mbsini : 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 input maximal width of the initial segment.
   */
  inline int getInputMaxWidth () const { return bst1->inputMaxWidth (); }

  /**
   * \brief Sets the maximal width of the initial segment.
   */
  inline void setInputMaxWidth (int value) {
    bst1->setInputMaxWidth (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 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 (prelim); }

  /**
   * \brief Switches preliminary detection modality.
   */
  inline void switchPreliminary () { prelim = ! prelim; }

  /**
   * \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 automatic width selection is set.
   */
  inline bool autoWidthOn () { return autowidth; }

  /**
   * \brief Switches on or off the automatic width selection.
   */
  inline void switchAutoWidth () { autowidth = ! autowidth; }

  /**
   * \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 upper bound of the final scan of the given step.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline vector<Pt2i> getScanBound1 (int step) const {
    return (step != 0 ? bst2->getScanBound1 () : bst1->getScanBound1 ()); }

  /**
   * \brief Returns the lower bound of the final scan of the given step.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline vector<Pt2i> getScanBound2 (int step) const {
    return (step != 0 ? bst2->getScanBound2 () : bst1->getScanBound2 ()); }

  /**
   * \brief Returns the scan lines of the given step.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline vector <vector <Pt2i> > getScans (int step) const {
    return (step != 0 ? bst2->getScans () : bst1->getScans ()); }

  /**
   * \brief Returns whether the scan record modality is set for the given step.
   * @param step Initial step addressed if set to 0, final step otherwise.
   */
  inline bool scanRecordOn (int step) {
    return (step != 0 ? bst2->scanRecordOn () : bst1->scanRecordOn ()); }

  /**
   * \brief Sets the scan record modality of initial or final step.
   * @param step Initial step addressed if set to 0, final step otherwise.
   * @param status Sets on if true, off otherwise.
   */
  inline void setScanRecord (int step, bool status) {
    if (step != 0) bst2->setScanRecord (status);
    else bst1->setScanRecord (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 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 thinning is activated.
   */
  inline bool isThinningActivated () { 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 != 0 ? 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 != 0 ?
      (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 {
    return (step != 0 ? filteringOn : prefilteringOn); }

  /**
   * \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 connectedComponentMinSize () { return connectMinSize; }

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


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 half the preliminary stroke size. */
  static const int PRELIM_SIZE;


  /** 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 length of scan lines. */
  int minScanLength;
  /** Connectivity constraint status. */
  bool ccOn;
  /** Minimal size of the detected blurred segment. */
  int bsMinSize;
  /** Minimal size of the connected components to validate a blurred segment. */
  int connectMinSize;
  /** Automatic width selection (based on previous detection). */
  bool autowidth;
  /** Density test modality after initial detection. */
  bool densityTestOn;
  /** Segment multi-selection modality status. */
  bool multiSelection;
  /** Grid resolution for the automatic extraction. */
  int autoResol;
  /** Preliminary stage modality. */
  bool prelim;


  /** Gradient map. */
  VMap *gMap;

  /** Initial rough tracker */
  BSTracker *bst1;
  /** Initially detected blurred segment (initial step result). */
  BlurredSegment *bsini;
  /** Detected blurred segments in case of multi-detection (initial step). */
  vector<BlurredSegment *> mbsini;

  /** 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;

  /** Result of the blurred segment extraction */
  int resultValue;


  /**
   * \brief Detects all blurred segments between two input points.
   * @param p1 First input point.
   * @param p2 Second input point.
   * @param dir Direction of the selection (factored P1P2).
   */
  void runMultiDetection (const Pt2i &p1, const Pt2i &p2,
                          const Vr2i &dir);

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

};
#endif