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

5 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_