Commit 5d001f4dba69bccdeb5e3db905b69cdaf18235dd
1 parent
d24c2952
Unimplemented header files for adaboost
Showing
9 changed files
with
177 additions
and
1 deletions
openbr/CMakeLists.txt
| ... | ... | @@ -11,6 +11,7 @@ add_definitions(-DJANUS_LIBRARY) |
| 11 | 11 | # Collect source files |
| 12 | 12 | aux_source_directory(. SRC) |
| 13 | 13 | aux_source_directory(core BR_CORE) |
| 14 | +aux_source_directory(learning BR_LEARNING) | |
| 14 | 15 | include(plugins/plugins.cmake) |
| 15 | 16 | |
| 16 | 17 | # Optional GUI module |
| ... | ... | @@ -21,7 +22,7 @@ if(NOT ${BR_EMBEDDED}) |
| 21 | 22 | install(FILES ${HEADERS} DESTINATION include/openbr/gui) |
| 22 | 23 | endif() |
| 23 | 24 | |
| 24 | -add_library(openbr SHARED ${SRC} ${BR_CORE} ${BR_JANUS} ${BR_GUI} ${BR_ICONS} ${BR_THIRDPARTY_SRC} ${BR_RESOURCES} ${NATURALSTRINGCOMPARE_SRC}) | |
| 25 | +add_library(openbr SHARED ${SRC} ${BR_CORE} ${BR_LEARNING} ${BR_JANUS} ${BR_GUI} ${BR_ICONS} ${BR_THIRDPARTY_SRC} ${BR_RESOURCES} ${NATURALSTRINGCOMPARE_SRC}) | |
| 25 | 26 | qt5_use_modules(openbr ${QT_DEPENDENCIES}) |
| 26 | 27 | set_target_properties(openbr PROPERTIES |
| 27 | 28 | DEFINE_SYMBOL BR_LIBRARY | ... | ... |
openbr/learning/adaboost.cpp
0 → 100644
openbr/learning/adaboost.h
0 → 100644
| 1 | +#ifndef ADABOOST_H | |
| 2 | +#define ADABOOST_H | |
| 3 | + | |
| 4 | +#include "trainingdata.h" | |
| 5 | +#include <openbr/openbr_plugin.h> | |
| 6 | + | |
| 7 | +namespace br | |
| 8 | +{ | |
| 9 | + | |
| 10 | +struct Node | |
| 11 | +{ | |
| 12 | + Node(int feature_idx, float threshold, int polarity, float weight) : feature_idx(feature_idx), threshold(threshold), polarity(polarity), weight(weight) {} | |
| 13 | + int predict(float feature_response) const { return (polarity * (feature_response - threshold)) > 0 ? 1 : -1; } | |
| 14 | + | |
| 15 | + int feature_idx; // index of the feature corresponding to this weak classifier | |
| 16 | + float threshold; // threshold at which classifier predicts yes or no | |
| 17 | + int polarity; // 1 or -1. 1 if high responses correspond to positives, -1 if low values do. | |
| 18 | + float weight; // weight of this classifier. Higher weight = more accurate classifier | |
| 19 | +}; | |
| 20 | + | |
| 21 | +struct DecisionTree | |
| 22 | +{ | |
| 23 | + DecisionTree() {} | |
| 24 | + void append(Node node); // add a node to the tree | |
| 25 | + float predict(QList<float> responses) const; // progress down the tree. Return value should be the | |
| 26 | + // sum of the weights of the correct nodes. | |
| 27 | + | |
| 28 | + QList<Node> tree; // List of the weak classifiers | |
| 29 | +}; | |
| 30 | + | |
| 31 | +class AdaBoost | |
| 32 | +{ | |
| 33 | +public: | |
| 34 | + AdaBoost(); | |
| 35 | + DecisionTree train(int num_classifiers); // mostly a wrapper to call selectBestNode() and updateWeights() num_classifiers times. | |
| 36 | + | |
| 37 | +private: | |
| 38 | + Node selectBestNode(); // search through all possible features to find one that improves performance the most | |
| 39 | + void updateWeights(); // successful classification lowers weights, unsuccesful raises weights. After changes weights are normalized between 0 and 1 | |
| 40 | + | |
| 41 | + TrainingData td; // training data to train on | |
| 42 | + DecisionTree classifier; // classifier to be trained | |
| 43 | +}; | |
| 44 | + | |
| 45 | +} | |
| 46 | +#endif // ADABOOST_H | ... | ... |
openbr/learning/cascade.cpp
0 → 100644
openbr/learning/cascade.h
0 → 100644
| 1 | +#ifndef CASCADE_H | |
| 2 | +#define CASCADE_H | |
| 3 | + | |
| 4 | +#include "feature.h" | |
| 5 | +#include "adaboost.h" | |
| 6 | +#include <openbr/openbr_plugin.h> | |
| 7 | + | |
| 8 | +namespace br | |
| 9 | +{ | |
| 10 | + | |
| 11 | +// I'm not sure if this class can be made general enough (i.e not just for face detection) to live here. | |
| 12 | +// Ideally, it should handle model i/o, and probably detection as well. Perhaps it is better in plugins/cascade.cpp | |
| 13 | +class Cascade | |
| 14 | +{ | |
| 15 | +public: | |
| 16 | + Cascade(const DecisionTree &classifier, const FeatureEvaluator &evaluator) : classifier(classifier), evaluator(evaluator) {} | |
| 17 | + void detect(const cv::Mat &img, QList<QRectF> &detections, QList<float> &confidences); | |
| 18 | + | |
| 19 | + void write(QString path); | |
| 20 | + static Cascade read(QString path); | |
| 21 | + | |
| 22 | +private: | |
| 23 | + DecisionTree classifier; | |
| 24 | + FeatureEvaluator evaluator; | |
| 25 | +}; | |
| 26 | + | |
| 27 | +} | |
| 28 | + | |
| 29 | +#endif // CASCADE_H | ... | ... |
openbr/learning/feature.cpp
0 → 100644
openbr/learning/feature.h
0 → 100644
| 1 | +#ifndef FEATURE_H | |
| 2 | +#define FEATURE_H | |
| 3 | + | |
| 4 | +#include <openbr/openbr_plugin.h> | |
| 5 | + | |
| 6 | +// These two classes should be subclassed to handle any type of feature. In a perfect world I would like to subclass | |
| 7 | +// only Feature, and have FeatureEvaluator just call randomize and evaluate (and thus not have to be subclassed) as | |
| 8 | +// that would be simpler. | |
| 9 | +namespace br | |
| 10 | +{ | |
| 11 | + | |
| 12 | +class Feature | |
| 13 | +{ | |
| 14 | +public: | |
| 15 | + Feature(); | |
| 16 | + QList<int> get_definition() { return definition; } | |
| 17 | + | |
| 18 | + virtual void randomize(int height, int width, int channels) = 0; // Initialize the feature within these dimensions | |
| 19 | + virtual float evaluate(const QList<cv::Mat> &img, const cv::Size &pos) const = 0; // img is a list of mats to support multiple channels | |
| 20 | + // if the image is larger than the feature model (i.e | |
| 21 | + // a real image instead of a training image) pos determines | |
| 22 | + // the top left corner of the feature. | |
| 23 | + | |
| 24 | +protected: | |
| 25 | + QList<int> definition; // The definition of the feature (usually these are coords) | |
| 26 | +}; | |
| 27 | + | |
| 28 | +class FeatureEvaluator | |
| 29 | +{ | |
| 30 | +public: | |
| 31 | + FeatureEvaluator(int num_features_) : num_features(num_features_) {} | |
| 32 | + int get_num_features() const { return num_features; } | |
| 33 | + QList<Feature> get_features() const { return features; } | |
| 34 | + | |
| 35 | + virtual void generateRandomFeatures(int height, int width, int channels) = 0; // initialize num_features random features within these dimensions. | |
| 36 | + // will call Feature->randomize() | |
| 37 | + virtual QList<float> evaluate(const QList<cv::Mat> &img, cv::Size pos) const = 0; // return the response of all features on the given image | |
| 38 | + // will call Feature->evaluate() | |
| 39 | + | |
| 40 | +private: | |
| 41 | + int num_features; | |
| 42 | + QList<Feature> features; | |
| 43 | +}; | |
| 44 | + | |
| 45 | +} | |
| 46 | + | |
| 47 | +#endif // FEATURE_H | ... | ... |
openbr/learning/trainingdata.cpp
0 → 100644
openbr/learning/trainingdata.h
0 → 100644
| 1 | +#ifndef TRAININGDATA_H | |
| 2 | +#define TRAININGDATA_H | |
| 3 | + | |
| 4 | +#include "feature.h" | |
| 5 | +#include <openbr/openbr_plugin.h> | |
| 6 | + | |
| 7 | +namespace br | |
| 8 | +{ | |
| 9 | + | |
| 10 | +struct FeatureResponse // Feature vectors need to be sorted to do boosting. This keeps the weights and labels properly associated with the response without headaches. | |
| 11 | +{ | |
| 12 | + FeatureResponse(float response, int label, float weight) : response(response), label(label), weight(weight) {} | |
| 13 | + | |
| 14 | + float response; | |
| 15 | + int label; | |
| 16 | + float weight; | |
| 17 | +}; | |
| 18 | + | |
| 19 | +typedef QList<FeatureResponse> FeatureVector; | |
| 20 | + | |
| 21 | +class TrainingData | |
| 22 | +{ | |
| 23 | +public: | |
| 24 | + TrainingData(); | |
| 25 | + // This can have getters and setters to make manipulating feature vectors easier | |
| 26 | + | |
| 27 | +private: | |
| 28 | + QList<FeatureVector> data; | |
| 29 | + QList<bool> visited_features; | |
| 30 | +}; | |
| 31 | + | |
| 32 | +} | |
| 33 | +#endif // TRAININGDATA_H | ... | ... |