You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
12 KiB
C++

#ifndef LineDetector_h__
#define LineDetector_h__
#include "StdUtils.h"
#include "CVUtils.h"
#include "CyclopsEnums.h"
#include "CyclopsModules.h"
struct PeakLineParamPack;
enum PeakAlgoAccLevel;
/*! \brief Locate single or multiple line edge in the given image and ROI.
*
* The algorithm is real-time, while its limitation is it could only detect
* parallel lines with small angel range (-10, +10), relative to the scan direction of roi.
* So, using this detector, you should have a basic idea of the line's direction.
*
* 1) If you are using Cyclops as static library,
* 1.1) and you want global factory to manage the detector for you, initialize the detector
* via LineDetector::getInstance().
* Example:
* \code{.cpp}
* LineDetector::Ptr ldPtr = LineDetector::getInstance("detect sth");
* ldPtr->setLineDetectType(LineDetector::PEAKLINE); // use peakline algorithm
* ldPtr->setLineType(Polarity::Black2White); // set polarity
* ldPtr->setLineBasis(Findby::Best); // set findby strategy
* Vec4f bestLine; // result line
* float bestScore = ldPtr->detectBest(img, roiVertexes, roiDir,
* bestLine, nullptr, 1, 10);
* \endcode
*
* 1.2) or, if you wish to manage the detector yourself:
* \code{.cpp}
* LineDetector::Ptr ldPtr = std::make_shared<LineDetector>(); // remember to hold the smart pointer
* // balabala, same as above
* // ...
* \endcode
*
* 2) If you are using Cyclops as dynamic library,
* initialize and manipulate the detector via CyclopsModules APIs.
* Example:
* \code{.cpp}
* // get a long-term detector, and give it an unique name
* LineDetector::Ptr pdPtr = GetModuleInstance<LineDetector>("detect sth");
* // get for temporary usage
* LineDetector::Ptr pdPtr = GetModuleInstance<LineDetector>();
* \endcode
*
* see SingleLineTest and MultiLineTest for unit test
*/
class LineDetector : public ICyclopsModuleInstance
{
public:
// For backward compatibility, define LineType using the same value as Polarity.
typedef Polarity LineType;
static const int DARK_TO_BRIGHT;
static const int BRIGHT_TO_DARK;
static const int BRIGHT_AND_DARK;
static LineType LineTypeFromName(const char* enum_name) {
return LineType::FromName(enum_name);
}
/*! \deprecated Get polarity of target line edge. Use getPolarity() instead. */
DEPRECATED int getLineType() const { return mPolarity.value; }
/*! \deprecated Set polarity of target line edge. Use setPolarity() instead. */
DEPRECATED void setLineType(int val) { mPolarity = val; }
// For backward compatibility, define LineBasis using the same value as FindBy.
typedef FindBy LineBasis;
static const int BEST_LINE;
static const int FIRST_LINE;
static const int LAST_LINE;
static LineBasis LineBasisFromName(const char* enum_name) {
return LineBasis::FromName(enum_name);
}
/*! \deprecated Get find-by strategy. Use getFindBy() instead. */
DEPRECATED int getLineBasis() const { return mFindBy.value; }
/*! \deprecated Set find-by strategy. Use setFindBy() instead. */
DEPRECATED void setLineBasis(int val) { mFindBy = val; }
enum LineDetectType
{
/*! Classic algorithm using hough transform */
HOUGHLINE = 0,
/*! Hough transform adopted image pyramid technology */
HOUGHLINE_PYR = 1,
/*! Approach based on sub-pixel peaks */
PEAKLINE = 2,
// add more detect type before this line...
};
/*! \fn setPolarity
* Define polarity of line edge, default to Polarity::Either, see also getPolarity()
* \fn getPolarity
* Get value of polarity of line edge, see also setPolarity()
*/
DECLARE_PARAMETER2(Polarity, Polarity, Polarity::Black2White, Polarity::Either)
/*! \fn setFindBy
* Define find-by stategy of detector, default to FindBy::Best, see also getFindBy()
* \fn getFindBy
* Get value of find-by stategy of detector, see also setFindBy()
*/
DECLARE_PARAMETER2(FindBy, FindBy, FindBy::Best, FindBy::All)
/*! \fn setLineEdgeRatio
* Define minimum contrast of the edge, 0 to 100, default to 0, see also getLineEdgeRatio()
* \fn getLineEdgeRatio
* Get value of minimum contrast of the edge, see also setLineEdgeRatio()
*/
DECLARE_PARAMETER2(float, LineEdgeRatio, 0, 100)
/*! \fn setLineEdgeWidth
* Define edge width, default to 3, see also getLineEdgeWidth()
* The value should match the real edge width, which means the range that the edge transit from black to white or vice versa.
* \fn getLineEdgeWidth
* Get value of edge width, see also setLineEdgeWidth()
*/
DECLARE_PARAMETER(int, LineEdgeWidth)
/*! \fn setLineDetectType(LineDetectType)
* Define which algorithm we should use for detection, default to HOUGHLINE, see also getLineDetectType()
* \fn getLineDetectType
* Get which algorithm we are using for detection, see also setLineDetectType()
*/
DECLARE_PARAMETER(LineDetectType, LineDetectType)
/*! \fn setAccLevel
* Define accuracy level of the algorithm, default to -1 means hardcoded defaults, see also getAccLevel()
* Note: this value only works for PEAKLINE.
* \fn getAccLevel
* Get value of accuracy level of the algorithm, see also setAccLevel()
*/
DECLARE_PARAMETER(int, AccLevel)
/*! \fn setNormBy
* Define how to normalized scores, default to NormBy::RegionMax, see also getNormBy()
* \fn getNormBy
* Get value of how to normalized scores, see also setNormBy()
*/
DECLARE_PARAMETER(NormBy, NormBy)
public:
LineDetector(LineType lineType, LineBasis lineBasis, LineDetectType detectType) :
mPolarity(lineType), mLineDetectType(detectType), mFindBy(lineBasis),
mAccLevel(-1), mLineEdgeRatio(0), mLineEdgeWidth(3), mNormBy(NormBy::RegionMax)
{}
LineDetector() :
mPolarity(Polarity::Either), mLineDetectType(HOUGHLINE), mFindBy(FindBy::Best),
mAccLevel(-1), mLineEdgeRatio(0), mLineEdgeWidth(3), mNormBy(NormBy::RegionMax)
{}
virtual ~LineDetector() {}
//! Smart pointer to hold an instance of LineDetector
typedef std::shared_ptr<LineDetector> Ptr;
DECL_GET_INSTANCE(LineDetector::Ptr)
/*! \deprecated detect a set of candidates lines. Use detectBest() instead. */
DEPRECATED void detect(const Mat& img, vector<Vec4f>& bestLines,
vector<float>& bestScores, float ds, Range y0Range, Range y1Range,
float maxAngleDeg);
/*! \deprecated detect a set of candidates lines in provided roi. Use detectBest() instead. */
DEPRECATED void detect(const Mat& img, const vector<Point2f>& roiVertexes,
const Point2f& roiDir,
vector<Vec4f>& bestLines, vector<float>& bestScores, float ds,
float maxAngleDeg);
/*! \deprecated detect a set of candidates lines in provided roi. Use detectBest() instead. */
DEPRECATED void detect(const Mat& img, const RotatedRect& rotatedRect,
vector<Vec4f>& bestLines, vector<float>& bestScores, float ds,
float maxAngleDeg);
/*! \deprecated detect a set of candidates lines in provided roi. Use detectBest() instead. */
DEPRECATED float detect(const Mat& img, const RotatedRect& rotatedRect,
Vec4f& bestLine, float ds, float maxAngleDeg);
/*! \deprecated detect a set of candidates lines in provided roi. Use detectBest() instead. */
DEPRECATED void detect(const Mat& img, const vector<Point2f>& roiVertexes, float angleDeg,
vector<Vec4f>& bestLines, vector<float>& bestScores, float ds, float maxAngleDeg);
/*! Detect the best single line using the detector.
* @param img input image for detection
* @param bestLine output line represented using endpoints: p1.x, p1.y, p2.x, p2.y
* @param allScores output, represent the score distribution along the scan direction of roi,
* pass null if you don't want it
* @param ds control the search step
* @param maxAngleDeg angel range of the line, -10 ~ +10
* @return score of the best one, 0 if we found nothing good
*/
virtual float detectBest(const Mat& img,
Vec4f& bestLine, vector<float>* allScores, // null is acceptable for no need
float ds, float maxAngleDeg);
/** @overload
* @param roiVertexes roi for detection
* @param angleDeg scan direction of roi
*/
virtual float detectBest(const Mat& img,
const vector<Point2f>& roiVertexes, float angleDeg,
Vec4f& bestLine, vector<float>* allScores, // null is acceptable for no need
float ds, float maxAngleDeg);
/** @overload
* @param roiVertexes roi for detection
* @param roiDir scan direction of roi
*/
virtual float detectBest(const Mat& img,
const vector<Point2f>& roiVertexes, const Point2f& roiDir,
Vec4f& bestLine, vector<float>* allScores, // null is acceptable for no need
float ds, float maxAngleDeg);
/*! Detect multiple lines using the detector.
* @param img input image for detection
* @param bestLines output lines represented using endpoints: p1.x, p1.y, p2.x, p2.y
* @param bestScores output, represent the scores of detected lines,
* pass null if you don't want it
* @param allScores output, represent the score distribution along the scan direction of roi,
* pass null if you don't want it
* @param minLineCount minimum number of lines there should be
* @param maxLineCount maximum number of lines there should be
* @param ds control the search step
* @param maxAngleDeg angel range of the line, -10 ~ +10
* @return real number of lines found in the image, it may exceed the provided limitation
*/
virtual int detectMulti(const Mat& img,
vector<Vec4f>* bestLines, // null if you don't want the exact line pos
vector<float>* bestScores, // null if you don't want the scores of each best lines
vector<float>* allScores, // null if you don't want the all scores along y axis
int minLineCount,
int maxLineCount,
float ds, float maxAngleDeg);
/** @overload
* @param roiVertexes roi for detection
* @param angleDeg scan direction of roi
*/
virtual int detectMulti(const Mat& img,
const vector<Point2f>& roiVertexes, float angleDeg,
vector<Vec4f>* bestLines, // null if you don't want the exact line pos
vector<float>* bestScores, // null if you don't want the scores of each best lines
vector<float>* allScores, // null if you don't want the all scores along y axis
int minLineCount,
int maxLineCount,
float ds, float maxAngleDeg);
/** @overload
* @param roiVertexes roi for detection
* @param roiDir scan direction of roi
*/
virtual int detectMulti(const Mat& img,
const vector<Point2f>& roiVertexes, const Point2f& roiDir,
vector<Vec4f>* bestLines, // null if you don't want the exact line pos
vector<float>* bestScores, // null if you don't want the scores of each best lines
vector<float>* allScores, // null if you don't want the all scores along y axis
int minLineCount,
int maxLineCount,
float ds, float maxAngleDeg);
/*! \deprecated select the best line of black-to-white polarity among a set of candidates lines.
* Use detectBest() instead.
*/
DEPRECATED float bestPositiveLine(const vector<Vec4f>& lines, const vector<float>& scores,
Vec4f& bestLine);
/*! \deprecated select the best line of white-to-black polarity among a set of candidates lines.
* Use detectBest() instead.
*/
DEPRECATED float bestNegativeLine(const vector<Vec4f>& lines, const vector<float>& scores,
Vec4f& bestLine);
/*! \deprecated select the best line of either black-to-white or white-to-black polarity among a set of candidates lines.
* Use detectBest() instead.
*/
DEPRECATED float bestAbsLine(const vector<Vec4f>& lines, const vector<float>& scores,
Vec4f& bestLine);
/*! convenient api to define which algorithm we should use for detection
* @param val integer value of detect algorithm type
*/
DEPRECATED void setLineDetectType(int val) { mLineDetectType = static_cast<LineDetectType>(val); }
/*! \deprecated select the best line of provided polarity and find-by strategy among a set of candidates lines.
* Use detectBest() instead.
*/
DEPRECATED bool selectBest(vector<Vec4f>& bestLines, vector<float>& bestScores, Vec4f& bestLine, float& bestScore);
protected:
float houghWithPyr(const Mat& gray, Vec4f& bestLine,
vector<float>& bestScores, float ds, Range y0Range, Range y1Range,
float maxAngleDeg,
unsigned int totalLevel = 2,
float startScale = 0.5);
private:
void genPeakLineParamPack(PeakLineParamPack& pack, float maxAngleDeg, PeakAlgoAccLevel defaultAccLevel);
};
#endif // LineDetector_h__