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.
491 lines
14 KiB
C
491 lines
14 KiB
C
|
4 years ago
|
/*!
|
||
|
|
* \file CyclopsFeature.h
|
||
|
|
* \date 2019/11/12
|
||
|
|
*
|
||
|
|
* \author Lin, Chi
|
||
|
|
* Contact: lin.chi@hzleaper.com
|
||
|
|
*
|
||
|
|
*
|
||
|
|
* \note
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef __CyclopsFeature_h_
|
||
|
|
#define __CyclopsFeature_h_
|
||
|
|
|
||
|
|
#include "CyclopsParam.h"
|
||
|
|
#include "CyclopsEnums.h"
|
||
|
|
#include "CyclopsGrid.h"
|
||
|
|
|
||
|
|
/*! \brief External properties that would affect feature's computation.
|
||
|
|
It's stored inside sample instance's user data */
|
||
|
|
enum CyclopsFeatureExtProp
|
||
|
|
{
|
||
|
|
CFExtPropStart = 9000,
|
||
|
|
|
||
|
|
/*! Used by SizeFeature, instead of image/bounding rect size of sample instance, 2 float */
|
||
|
|
CFExtPropSize,
|
||
|
|
/*! Used by PPFeature, instead of max-value normalization, 1 double */
|
||
|
|
CFExtPropNormValue,
|
||
|
|
|
||
|
|
CFExtPropEnd = 10000,
|
||
|
|
};
|
||
|
|
|
||
|
|
class SampleInstance;
|
||
|
|
|
||
|
|
/*! \brief Base class for feature extractor */
|
||
|
|
class CyclopsFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
/*! Parameter configurations */
|
||
|
|
CyclopsParams mParams;
|
||
|
|
/*! Default auto-tune search grid */
|
||
|
|
CyclopsGrids mDefaultGrids;
|
||
|
|
|
||
|
|
virtual ~CyclopsFeature() {}
|
||
|
|
typedef std::shared_ptr<CyclopsFeature> Ptr;
|
||
|
|
|
||
|
|
/*! Feature's type */
|
||
|
|
FeatureType getType() const { return mType; }
|
||
|
|
|
||
|
|
/*! Enable or disable this feature */
|
||
|
|
void setEnabled(bool val = true) { mDisable = !val; }
|
||
|
|
|
||
|
|
/*! Check if this feature is enabled or not */
|
||
|
|
bool isEnabled() const { return !mDisable; }
|
||
|
|
|
||
|
|
/*! Change weight of this feature */
|
||
|
|
void setWeight(double w) { mWeight = w; mParams.setDirtyBit(true); }
|
||
|
|
|
||
|
|
/*! Get weight of this feature */
|
||
|
|
double getWeight() const { return mWeight; }
|
||
|
|
|
||
|
|
/*! Serialized to file or in-memory string */
|
||
|
|
void serialize(FileStorage& fs) const {
|
||
|
|
mParams.serialize(fs);
|
||
|
|
fs << "name" << mName;
|
||
|
|
fs << "disable" << mDisable;
|
||
|
|
fs << "weight" << mWeight;
|
||
|
|
fs << "feature" << "{:";
|
||
|
|
serializeFeature(fs);
|
||
|
|
fs << "}";
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! Deserialize from file or in-memory string */
|
||
|
|
void deserialize(const FileNode& node) {
|
||
|
|
mParams.deserialize(node);
|
||
|
|
node["name"] >> mName;
|
||
|
|
node["disable"] >> mDisable;
|
||
|
|
node["weight"] >> mWeight;
|
||
|
|
deserializeFeature(node["feature"]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! @overload */
|
||
|
|
Mat compute(const SampleInstance* pinst) {
|
||
|
|
Mat f;
|
||
|
|
compute(pinst, f);
|
||
|
|
return f;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! Compute feature vector for provided image
|
||
|
|
* @param pinst pointer to sample instance for computation
|
||
|
|
* @param f output feature vector
|
||
|
|
* @return size of feature vector, 0 for fail
|
||
|
|
*/
|
||
|
|
int compute(const SampleInstance* pinst, Mat& f) {
|
||
|
|
if (mDisable) return 0;
|
||
|
|
syncParam();
|
||
|
|
int ret = doCompute(pinst, f);
|
||
|
|
if (!f.empty() && mWeight != 1) f *= mWeight;
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! Get size of feature vector for given normalized image size */
|
||
|
|
int getSize(const Size& sampleSize) {
|
||
|
|
if (mDisable) return 0;
|
||
|
|
syncParam();
|
||
|
|
return doGetSize(sampleSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! Set parameter configuration for definition to real implementation */
|
||
|
|
void syncParam() {
|
||
|
|
if (mParams.isDirty()) {
|
||
|
|
doSyncParam();
|
||
|
|
mParams.setDirtyBit(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! Backup parameters */
|
||
|
|
virtual void backupAll() { mParams.backupAll(); }
|
||
|
|
/*! Restore parameter from last backup */
|
||
|
|
virtual void restoreAll() { mParams.restoreAll(); }
|
||
|
|
|
||
|
|
/*! Whether any parameter is modified */
|
||
|
|
virtual bool isDirty() { return mParams.isDirty(); }
|
||
|
|
|
||
|
|
/*! Do training of given samples */
|
||
|
|
virtual bool train(const std::vector<const SampleInstance*>& trainSamples) { return true; }
|
||
|
|
/*! Whether we need to re-train this feature */
|
||
|
|
virtual bool needTrain() { return false; }
|
||
|
|
/*! Whether we need to fix some bad parameter configuration
|
||
|
|
* @param sampleSize uniformed sample size
|
||
|
|
* @param doFix true if we should also do the real fix
|
||
|
|
* @return true if fix is needed
|
||
|
|
*/
|
||
|
|
virtual bool needFix(const Size& sampleSize, bool doFix) {
|
||
|
|
return !mParams.isValid(sampleSize, doFix).empty();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! Clear trained cache */
|
||
|
|
virtual void clear() {}
|
||
|
|
|
||
|
|
/*! Get feature's name */
|
||
|
|
const std::string& getName() const {
|
||
|
|
return mName;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
virtual void doSyncParam() {}
|
||
|
|
virtual int doCompute(const SampleInstance* pinst, Mat& f) { return 0; }
|
||
|
|
virtual int doGetSize(const Size& sampleSize) const { return 0; }
|
||
|
|
virtual void serializeFeature(FileStorage& fs) const {}
|
||
|
|
virtual void deserializeFeature(const FileNode& node) {}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
FeatureType mType;
|
||
|
|
std::string mName;
|
||
|
|
bool mDisable = false;
|
||
|
|
double mWeight = 1.;
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Base class for Bag-of-words feature */
|
||
|
|
class BOWFeature : public CyclopsFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~BOWFeature() {}
|
||
|
|
typedef std::shared_ptr<BOWFeature> Ptr;
|
||
|
|
|
||
|
|
enum Param {
|
||
|
|
/*! Count of vocabulary */
|
||
|
|
VocCount = 0,
|
||
|
|
};
|
||
|
|
|
||
|
|
virtual bool isDirty();
|
||
|
|
virtual bool train(const std::vector<const SampleInstance*>& trainSamples);
|
||
|
|
virtual bool needTrain() { return true; }
|
||
|
|
virtual void clear();
|
||
|
|
|
||
|
|
protected:
|
||
|
|
explicit BOWFeature();
|
||
|
|
virtual int doCompute(const SampleInstance* pinst, Mat& f);
|
||
|
|
virtual int doGetSize(const Size& sampleSize) const;
|
||
|
|
virtual void serializeFeature(FileStorage& fs) const;
|
||
|
|
virtual void deserializeFeature(const FileNode& node);
|
||
|
|
|
||
|
|
virtual int computeRaw(const Mat& img, Mat& f) { return 0; }
|
||
|
|
virtual void serializeRaw(FileStorage& fs) const {}
|
||
|
|
virtual void deserializeRaw(const FileNode& node) {}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
cv::Ptr<BOWImgDescriptorExtractor> mExt;
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Image feature: ORB (oriented BRIEF) */
|
||
|
|
class ORBFeature : public BOWFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~ORBFeature() {}
|
||
|
|
typedef std::shared_ptr<ORBFeature> Ptr;
|
||
|
|
/*! Create an ORB feature with default parameters(recommended for 128x128 sample size) */
|
||
|
|
static ORBFeature::Ptr create();
|
||
|
|
|
||
|
|
enum Param {
|
||
|
|
/*! Size of patch, 4 ~ 256 */
|
||
|
|
PatchSize = VocCount + 1,
|
||
|
|
/*! Scale factor for pyramid, 1 ~ 2 */
|
||
|
|
ScaleFactor,
|
||
|
|
/*! Level of pyramid (scale down) */
|
||
|
|
DownLevel,
|
||
|
|
/* UpLevel, remove scale up level, as there's some bug in image pyramid generation code in opencv.
|
||
|
|
add it back some day if they fix the issue https://github.com/opencv/opencv/issues/16197
|
||
|
|
*/
|
||
|
|
/*! The number of points that produce each element of ORB, 2, 3, or 4 */
|
||
|
|
RandomPairCount,
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Image feature: AKAZE */
|
||
|
|
class AKAZEFeature : public BOWFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
~AKAZEFeature() {}
|
||
|
|
typedef std::shared_ptr<AKAZEFeature> Ptr;
|
||
|
|
/*! Create an AKAZE feature with default parameters(recommended for 128x128 sample size) */
|
||
|
|
static AKAZEFeature::Ptr create();
|
||
|
|
|
||
|
|
enum Param {
|
||
|
|
/*! Whether this feature is rotation-invariant, true or false */
|
||
|
|
RotationInvariant = VocCount + 1,
|
||
|
|
/*! Threshold to accept key point, > 0, usualy a small value */
|
||
|
|
Threshold,
|
||
|
|
/*! Maximum octave evolution */
|
||
|
|
Octave,
|
||
|
|
/*! Number of sub-levels per scale level (octave) */
|
||
|
|
SubLevel,
|
||
|
|
/*! Diffusivity type, see DiffusivityType */
|
||
|
|
DiffusivityType
|
||
|
|
};
|
||
|
|
enum DiffusivityType {
|
||
|
|
G1 = 0, G2, Weickert, Charbonnier
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Image feature: HOG */
|
||
|
|
class HOGFeature : public CyclopsFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~HOGFeature() {}
|
||
|
|
typedef std::shared_ptr<HOGFeature> Ptr;
|
||
|
|
/*! Create a HOG feature with default parameters(recommended for 128x128 sample size) */
|
||
|
|
static HOGFeature::Ptr create();
|
||
|
|
|
||
|
|
enum Param {
|
||
|
|
/*! Size of a cell for histogram, 2x2 ~ 128x128, should be 2^x */
|
||
|
|
CellSize = 0,
|
||
|
|
/*! Bins of histogram, should be factor of 360(or 180 depending on SignedGradient) */
|
||
|
|
BinSize,
|
||
|
|
/*! Count of cells in a block, block size = cell in block * cell size */
|
||
|
|
CellInBlock,
|
||
|
|
/*! Count of cells in a block stride, block stride = cell in block stride * cell size */
|
||
|
|
CellInBlockStride,
|
||
|
|
/*! Count of block in stride, win size = block size + block stride * block stride step */
|
||
|
|
BlockStrideStep,
|
||
|
|
/*! use signed gradient or not, directions are analyzed in 180 or 360 */
|
||
|
|
SignedGradient,
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Image feature: Pixel-by-pixel */
|
||
|
|
class PPFeature : public CyclopsFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~PPFeature() {}
|
||
|
|
typedef std::shared_ptr<PPFeature> Ptr;
|
||
|
|
/*! Create a pixel-by-pixel feature with default parameters(recommended for 128x128 sample size) */
|
||
|
|
static PPFeature::Ptr create();
|
||
|
|
|
||
|
|
enum Param {
|
||
|
|
/*! Uniformed image size */
|
||
|
|
UniSize = 0,
|
||
|
|
/*! Pixel value type, see PixelValue */
|
||
|
|
PixelValue,
|
||
|
|
/*! Projection type , see ProjectionType */
|
||
|
|
Projection,
|
||
|
|
};
|
||
|
|
|
||
|
|
enum PixelValueType {
|
||
|
|
/*! Gray value in 0 ~ 1 */
|
||
|
|
GrayValue = 0,
|
||
|
|
/*! Normalized gray value with maximum scaling to 0 ~ 1 */
|
||
|
|
GrayNormValue,
|
||
|
|
/*! Binary value after auto-thresholding, bigger report 1, otherwise report 0.
|
||
|
|
If roi is available, use roi's mask as source.
|
||
|
|
If roi is using soft mask, report floating value between 0 ~ 1.
|
||
|
|
*/
|
||
|
|
BinaryValue,
|
||
|
|
/*! Fraction of pixels in the foreground after auto-thresholding, bigger report foreground
|
||
|
|
If roi is available, use roi's mask as source
|
||
|
|
*/
|
||
|
|
FractionValue,
|
||
|
|
};
|
||
|
|
|
||
|
|
enum ProjectionType {
|
||
|
|
/*! No projection */
|
||
|
|
None = 0,
|
||
|
|
/*! Horizontal projection, report average of each row */
|
||
|
|
Horinzontal,
|
||
|
|
/*! Vertical projection, report average of each column */
|
||
|
|
Vertical,
|
||
|
|
/*! Horizontal and vertical projection, report average of each row and column */
|
||
|
|
HorinzontalAndVertical,
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Image feature: percentage of foreground pixels */
|
||
|
|
class FGFFeature : public CyclopsFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~FGFFeature() {}
|
||
|
|
typedef std::shared_ptr<FGFFeature> Ptr;
|
||
|
|
/*! Create a foreground fraction feature with default parameters */
|
||
|
|
static FGFFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Base class for geometric features based on contours defined in sample's detect roi. Usually no parameter. */
|
||
|
|
class GeomFeature : public CyclopsFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~GeomFeature() {}
|
||
|
|
typedef std::shared_ptr<GeomFeature> Ptr;
|
||
|
|
protected:
|
||
|
|
virtual int doGetSize(const Size& sampleSize) const;
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Geometric feature: How the sample looks like a circle: contour area / (pi * r ^ 2)\n
|
||
|
|
For multiple contours, report the smallest value */
|
||
|
|
class CircularityFeature : public GeomFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~CircularityFeature() {}
|
||
|
|
typedef std::shared_ptr<CircularityFeature> Ptr;
|
||
|
|
/*! Create a circularity feature with no parameters */
|
||
|
|
static CircularityFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Geometric feature: How the sample looks like a convex hull: contour area / bounding hull area\n
|
||
|
|
For multiple contours, report the smallest value */
|
||
|
|
class ConvexityFeature : public GeomFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~ConvexityFeature() {}
|
||
|
|
typedef std::shared_ptr<ConvexityFeature> Ptr;
|
||
|
|
/*! Create a convexity feature with no parameters */
|
||
|
|
static ConvexityFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Geometric feature: difference between the contour and its convex hull: sum(distance of defect)
|
||
|
|
A convex contour report 0, for multiple contours, report the biggest value */
|
||
|
|
class ConvDefectsFeature : public GeomFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~ConvDefectsFeature() {}
|
||
|
|
typedef std::shared_ptr<ConvDefectsFeature> Ptr;
|
||
|
|
/*! Create a convexity defects feature with no parameters */
|
||
|
|
static ConvDefectsFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Geometric feature: Sin value of orientation of the bonding convex hull of the sample, not rotation-invariant. */
|
||
|
|
class OrientationFeature : public GeomFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~OrientationFeature() {}
|
||
|
|
typedef std::shared_ptr<OrientationFeature> Ptr;
|
||
|
|
/*! Create a orientation feature with no parameters */
|
||
|
|
static OrientationFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Geometric feature: Ratio of convex hull's min axes and max axes, whether the sample is long or like a square. */
|
||
|
|
class InertiaFeature : public GeomFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~InertiaFeature() {}
|
||
|
|
typedef std::shared_ptr<InertiaFeature> Ptr;
|
||
|
|
/*! Create a inertia feature with no parameters */
|
||
|
|
static InertiaFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Base class for features count components the sample's contour has. */
|
||
|
|
class CompCountFeature : public GeomFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~CompCountFeature() {}
|
||
|
|
typedef std::shared_ptr<CompCountFeature> Ptr;
|
||
|
|
virtual bool train(const std::vector<const SampleInstance*>& trainSamples);
|
||
|
|
virtual bool needTrain() { return true; }
|
||
|
|
protected:
|
||
|
|
virtual void serializeFeature(FileStorage& fs) const;
|
||
|
|
virtual void deserializeFeature(const FileNode& node);
|
||
|
|
float mNormCounts;
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Geometric feature: How many contours the sample has.\n
|
||
|
|
Number of connected contour components, aka, count of adding sub-rois in sample's detect roi */
|
||
|
|
class ContourCountFeature : public CompCountFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~ContourCountFeature() {}
|
||
|
|
typedef std::shared_ptr<ContourCountFeature> Ptr;
|
||
|
|
/*! Create a contour count feature with no parameters */
|
||
|
|
static ContourCountFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Geometric feature: How many holes the sample has.\n
|
||
|
|
Number of holes, aka, count of subtracting sub-rois in sample's detect roi */
|
||
|
|
class HoleCountFeature : public CompCountFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~HoleCountFeature() {}
|
||
|
|
typedef std::shared_ptr<HoleCountFeature> Ptr;
|
||
|
|
/*! Create a hole count feature with no parameters */
|
||
|
|
static HoleCountFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Base class for size features based on sample's original and uniformed image size. Usually no parameter. */
|
||
|
|
class SizeFeature : public CyclopsFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~SizeFeature() {}
|
||
|
|
typedef std::shared_ptr<SizeFeature> Ptr;
|
||
|
|
protected:
|
||
|
|
virtual int doGetSize(const Size& sampleSize) const;
|
||
|
|
Size2f getSampleInstSize(const SampleInstance* pinst);
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Size feature: Aspect ratio of sample image: width / height */
|
||
|
|
class AspectRatioFeature : public SizeFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~AspectRatioFeature() {}
|
||
|
|
typedef std::shared_ptr<AspectRatioFeature> Ptr;
|
||
|
|
/*! Create a aspect ratio feature with no parameters */
|
||
|
|
static AspectRatioFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Base class for features report the abstract size of sample image */
|
||
|
|
class AbstractSizeFeature : public SizeFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~AbstractSizeFeature() {}
|
||
|
|
typedef std::shared_ptr<AbstractSizeFeature> Ptr;
|
||
|
|
virtual bool train(const std::vector<const SampleInstance*>& trainSamples);
|
||
|
|
virtual bool needTrain() { return true; }
|
||
|
|
protected:
|
||
|
|
virtual void serializeFeature(FileStorage& fs) const;
|
||
|
|
virtual void deserializeFeature(const FileNode& node);
|
||
|
|
float mNormSize;
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Size feature: Width of sample image, not scale-invariant */
|
||
|
|
class WidthFeature : public AbstractSizeFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~WidthFeature() {}
|
||
|
|
typedef std::shared_ptr<WidthFeature> Ptr;
|
||
|
|
/*! Create a width feature with no parameters */
|
||
|
|
static WidthFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Size feature: Height of sample image, not scale-invariant */
|
||
|
|
class HeightFeature : public AbstractSizeFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~HeightFeature() {}
|
||
|
|
typedef std::shared_ptr<HeightFeature> Ptr;
|
||
|
|
/*! Create a height feature with no parameters */
|
||
|
|
static HeightFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
/*! \brief Size feature: Difference in size between the sample image and uniformed image's sizes:
|
||
|
|
min(uniformed width / width, uniformed height / height) */
|
||
|
|
class ZoomFactorFeature : public SizeFeature
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual ~ZoomFactorFeature() {}
|
||
|
|
typedef std::shared_ptr<ZoomFactorFeature> Ptr;
|
||
|
|
/*! Create a zoom factor feature with no parameters */
|
||
|
|
static ZoomFactorFeature::Ptr create();
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
#endif // CyclopsFeature_h_
|
||
|
|
|