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.
wheeldetect/3part/Cyclops/include/CircleDetector.h

207 lines
7.3 KiB
C++

/*!
* \file CircleDetector.h
* \date 2018/08/06
*
* \author Lin, Chi
* Contact: lin.chi@hzleaper.com
*
*
* \note
*/
#ifndef __CircleDetector_h_
#define __CircleDetector_h_
#include "StdUtils.h"
#include "CVUtils.h"
#include "CyclopsEnums.h"
#include "CyclopsModules.h"
struct PeakCircleParamPack;
enum PeakAlgoAccLevel;
/*! \brief Located single or multiple circles in the given image and ROI.
*
* We support several algorithms in this detector, choose one suitable for your scenario.
* If you are pretty sure where the circle center is, use PeakCircle;
* otherwise, you should use either HoughCircle or EDCircle depending on the performance and accuracy requirement.
*
* 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 CircleDetector::getInstance().
* Example:
* \code{.cpp}
* CircleDetector::Ptr cdPtr = CircleDetector::getInstance("detect sth");
* cdPtr->setAlgoType(CircleDetector::PeakCircle); // use peakcircle algorithm
* cdPtr->setLineType(Polarity::Black2White); // set polarity
* cdPtr->setLineBasis(Findby::Best); // set findby strategy
* cdPtr->setRadii(90, 110); // set radii range
* Vec3f bestCircle; // result circle
* float bestScore = cdPtr->detectBest(img, Point2f(200, 300), // give estimated center point, and run the detection
* bestCircle, nullptr);
*
* // delete it later
* CircleDetector::deleteInstance("detect sth");
* \endcode
*
* 1.2) or, if you wish to manage the detector yourself:
* \code{.cpp}
* CircleDetector::Ptr ldPtr = std::make_shared<CircleDetector>(); // 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
* CircleDetector::Ptr cdPtr = GetModuleInstance<CircleDetector>("detect sth");
* // get for temporary usage
* CircleDetector::Ptr localCdPtr = GetModuleInstance<CircleDetector>();
*
* // delete it later
* DeleteModuleInstance<CircleDetector>("detect sth");
* \endcode
*
* see SingleCircleTest and MultiCircleTest for unit test
*/
class CircleDetector : public ICyclopsModuleInstance
{
public:
enum CircleDetectAlgoType
{
/*! Classic algorithm using hough transform, similar as Matlab's imfindcircles */
HoughCircle = 0,
/*! Approach based on sub-pixel peaks. Limitation: detect only almost concentric circles near center of image */
PeakCircle = 1,
/*! Approach adopted from "EDCircles: A Real-time Parameter-free Circle Detector with a False Detection Control"
\link http://ceng.anadolu.edu.tr/cv/edcircles/
*/
EDCircle = 2,
};
/*! \fn setPolarity
* Define polarity of circle edge, Polarity::Black2White to Polarity::Either, default to Polarity::Either, see also getPolarity()
* \fn getPolarity
* Get value of polarity of circle edge, see also setPolarity()
*/
DECLARE_PARAMETER2(Polarity, Polarity, Polarity::Black2White, Polarity::Either)
/*! \fn setFindBy
* Define find-by stategy of detector, FindBy::Best to FindBy::Last, 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 setACThres
* Define minimum acceptable score, 0 to 100, default to 0, see also getACThres()
* \fn getACThres
* Get value of minimum acceptable score, see also setACThres()
*/
DECLARE_PARAMETER2(int, ACThres, 0, 100)
/*! \fn setEdgeWidth
* Define edge width, default to 3, see also getEdgeWidth()
* The value should match the real edge width, which means the range that the edge transit from black to white or vice versa.
* \fn getEdgeWidth
* Get value of edge width, see also setEdgeWidth()
*/
DECLARE_PARAMETER(int, EdgeWidth)
/*! \fn setAlgoType
* Define which algorithm we should use for detection, default to PeakCircle, see also getAlgoType()
* \fn getAlgoType
* Get which algorithm we are using for detection, see also setAlgoType()
*/
DECLARE_PARAMETER2(CircleDetectAlgoType, AlgoType, HoughCircle, PeakCircle)
/*! \fn setRadii
* Define the radii range [val1, val2]
* \fn getRadiiStart
* Get value of minimum circle radii
* \fn getRadiiEnd
* Get value of maximum circle radii
*/
DECLARE_PARAMETER_PAIR(unsigned int, Radii)
/*! \fn setAccLevel
* Define accuracy level of the algorithm, default to -1 means hardcoded defaults, see also getAccLevel()
* Note: this value only works for PeakCircle.
* \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:
CircleDetector(Polarity polarity, FindBy findby, CircleDetectAlgoType algoType) :
mPolarity(polarity), mFindBy(findby), mAlgoType(algoType),
mACThres(0), mEdgeWidth(3), mAccLevel(-1), mNormBy(NormBy::RegionMax)
{}
CircleDetector() :
mPolarity(Polarity::Either), mFindBy(FindBy::Best), mAlgoType(PeakCircle),
mACThres(0), mEdgeWidth(3), mAccLevel(-1), mNormBy(NormBy::RegionMax)
{}
virtual ~CircleDetector() {}
//! Smart pointer to hold an instance of CircleDetector
typedef std::shared_ptr<CircleDetector> Ptr;
DECL_GET_INSTANCE(CircleDetector::Ptr)
/*! Detect the best single circle edge using the detector
* @param img input image for detection
* @param bestCircle output circle: center.x, center.y, radii
* @param allScores output, represent the score distribution among defined radii range,
* pass null if you don't want it
* @param mask input mask for exclude some pixel from detection
* @return score of the best one, 0 if we found nothing good
*/
virtual float detectBest(const Mat& img,
Vec3f& bestCircle,
vector<float>* allScores = nullptr,
Mat* mask = nullptr);
/** @overload */
virtual float detectBest(const Mat& img,
const Point2f& estCenter,
Vec3f& bestCircle,
vector<float>* allScores = nullptr);
/*! Detect multiple circle edge using the detector
* @param img input image for detection
* @param bestCircles output circles: center.x, center.y, radii
* @param bestScoresoutput scores of several best circles
* @param allScores output, represent the score distribution among defined radii range,
* pass null if you don't want it
* @param minCount minimum number of circles there should be
* @param maxCount maximum number of circles there should be
* @param mask input mask for exclude some pixel from detection
* @return real number of lines found in the image, it may exceed the provided limitation
*/
virtual int detectMulti(const Mat& img,
vector<Vec3f>* bestCircles,
vector<float>* bestScores,
vector<float>* allScores = nullptr,
int minCount = 0,
int maxCount = 10,
Mat* mask = nullptr);
/** @overload */
virtual int detectMulti(const Mat& img,
const Point2f& estCenter,
vector<Vec3f>* bestCircles,
vector<float>* bestScores,
vector<float>* allScores = nullptr,
int minCount = 0,
int maxCount = 10);
private:
void genPeakCircleParamPack(PeakCircleParamPack& pack, PeakAlgoAccLevel defaultAccLevel);
};
#endif // CircleDetector_h_