Skip to content

Commit b293db2

Browse files
committed
update
Current Status ============== 1. complete the training part of JDA 2. use three scaled image for feature extraction according to #6 3. test the training with small model K=5, pos size = 3000, background image size = 9000 TODO ==== 0. fix bugs of training part 1. impl the test part of JDA 2. impl the detect part of JDA 3. may use relateive delta shape in global regression, currently use absolute shape 4. data augmentation during the hard negative mining due to lacking of negative samples
1 parent 1115dbd commit b293db2

14 files changed

+512
-242
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ build/
44
*.zip
55
*.jpg
66
*.png
7+
*.JPEG

CMakeLists.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ include(libjda.cmake)
77

88
file(GLOB SRC src/*.cpp)
99

10-
add_executable(${PROJECT_NAME} ${SRC})
11-
target_link_libraries(${PROJECT_NAME} libjda ${OpenCV_LIBS})
10+
add_executable(jda ${SRC})
11+
target_link_libraries(jda libjda ${OpenCV_LIBS})

include/jda/cart.hpp

+37-18
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,19 @@ class Cart {
2626
public:
2727
Cart();
2828
~Cart();
29-
Cart(const Cart& other);
30-
Cart& operator=(const Cart& other);
29+
//Cart(const Cart& other);
30+
//Cart& operator=(const Cart& other);
3131
/**
3232
* Initialize Cart
33+
* :input stage: which stage this cart lie in
34+
* :input landmark_id: which landmark this cart training for regression
3335
*/
3436
void Initialize(int stage, int landmark_id);
3537

3638
public:
3739
/**
38-
* Generate feature pool
40+
* Generate feature pool, the pool size is determined by Config.feats[stage]
41+
* :output feature_pool: feature pool
3942
*/
4043
void GenFeaturePool(std::vector<Feature>& feature_pool);
4144
/**
@@ -44,35 +47,50 @@ class Cart {
4447
void Train(DataSet& pos, DataSet& neg);
4548
/**
4649
* Split node with training data
50+
* :input pos: positive dataset
51+
* :input neg: negative dataset
52+
* :input pos_idx: index of used positive dataset
53+
* :input neg_idx: index of used negative dataset
54+
* :input node_idx: index of current node in this cart
4755
*/
4856
void SplitNode(DataSet& pos, std::vector<int>& pos_idx, \
4957
DataSet& neg, std::vector<int>& neg_idx, \
5058
int node_idx);
5159
/**
5260
* Classification
61+
* :input pos_feature: pos feature
62+
* :input neg_feature: neg feature
63+
* :output feature_id: which feature we should use
64+
* :output threshold: split threshold
5365
*
5466
* split node with classification, minimize binary entropy of pos and neg
5567
* `f = argmax_{f \in F} H_{root} - (H_{left} + H_{right})`
5668
*/
57-
void SplitNodeWithClassification(cv::Mat_<int>& pos_feature, \
58-
cv::Mat_<int>& neg_feature, \
59-
int& feature_id, int& threshold);
69+
static void SplitNodeWithClassification(const cv::Mat_<int>& pos_feature, \
70+
const cv::Mat_<int>& neg_feature, \
71+
int& feature_id, int& threshold);
6072
/**
6173
* Regression
74+
* :input pos_feature: pos feature
75+
* :input neg_feature: neg feature
76+
* :output feature_id: which feature we should use
77+
* :output threshold: split threshold
6278
*
6379
* split node with regression, minimize variance of shape_residual
6480
* `f = argmax_{f \in F} S_{root} - (S_{left} + S_{right})`
6581
*/
66-
void SplitNodeWithRegression(cv::Mat_<int>& pos_feature, \
67-
cv::Mat_<double>& shape_residual, \
68-
int& feature_id, int& threshold);
82+
static void SplitNodeWithRegression(const cv::Mat_<int>& pos_feature, \
83+
const cv::Mat_<double>& shape_residual, \
84+
int& feature_id, int& threshold);
6985

7086
public:
7187
/**
7288
* Forward a data point to leaf node
73-
* :return: leaf node index in this tree, start from 0
89+
* :input img: region
90+
* :input shape: shape
91+
* :return: leaf node index in this tree, start from 0
7492
*/
75-
int Forward(const cv::Mat& img, const cv::Mat_<double>& shape);
93+
int Forward(const cv::Mat& img, const cv::Mat_<double>& shape) const;
7694

7795
public:
7896
int stage; // cascade stage
@@ -100,8 +118,8 @@ class BoostCart {
100118
public:
101119
BoostCart();
102120
~BoostCart();
103-
BoostCart(const BoostCart& other);
104-
BoostCart& operator=(const BoostCart& other);
121+
//BoostCart(const BoostCart& other);
122+
//BoostCart& operator=(const BoostCart& other);
105123
void Initialize(int stage);
106124

107125
public:
@@ -115,7 +133,7 @@ class BoostCart {
115133
* we only use DataSet of pos, X = lbf, Y = shape_residual
116134
* see more detail on paper in section 4
117135
*/
118-
void GlobalRegression(const cv::Mat_<int>& lbf, \
136+
void GlobalRegression(const std::vector<cv::Mat_<int> >& lbf, \
119137
const cv::Mat_<double>& shape_residual);
120138
/**
121139
* Set Join Cascador
@@ -125,20 +143,21 @@ class BoostCart {
125143
public:
126144
/**
127145
* Generate Local Binary Feature
146+
* :input img: region
147+
* :input shape: shape
128148
* :return: one row of local binary feature
129149
*/
130-
cv::Mat_<int> GenLBF(const cv::Mat& img, const cv::Mat_<double>& shape);
150+
cv::Mat_<int> GenLBF(const cv::Mat& img, const cv::Mat_<double>& shape) const;
131151
/**
132152
* Generate delta shape with given lbf
153+
* :input lbf: lbf generated by `GenLBF`
133154
* :return: one row of delta shape
134155
*/
135-
cv::Mat_<double> GenDeltaShape(const cv::Mat_<int>& lbf);
156+
cv::Mat_<double> GenDeltaShape(const cv::Mat_<int>& lbf) const;
136157

137158
public:
138159
int K; // number of carts
139160
int stage; // which stage this boost cart lies
140-
double tp_rate; // true positive rate
141-
double fn_rate; // false negative rate
142161

143162
std::vector<Cart> carts; // boosted carts
144163
cv::Mat_<double> w; // weight of global regression

include/jda/cascador.hpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ class JoinCascador {
1515
public:
1616
JoinCascador();
1717
~JoinCascador();
18-
JoinCascador(const JoinCascador& other);
19-
JoinCascador& operator=(const JoinCascador& other);
18+
//JoinCascador(const JoinCascador& other);
19+
//JoinCascador& operator=(const JoinCascador& other);
2020
void Initialize(int T);
2121

2222
public:
@@ -26,6 +26,10 @@ class JoinCascador {
2626
* See Full Algorithm on paper `Algorithm 3`
2727
*/
2828
void Train(DataSet& pos, DataSet& neg);
29+
/**
30+
* Snapshot current model
31+
*/
32+
void Snapshot();
2933
/**
3034
* Write parameters to a binary file
3135
*/
@@ -48,7 +52,7 @@ class JoinCascador {
4852
* a face score for this region. The training status is based on `current_stage_idx`
4953
* and `current_cart_idx`.
5054
*/
51-
bool Validate(cv::Mat& region, double& score, cv::Mat_<double>& shape);
55+
bool Validate(const cv::Mat& region, double& score, cv::Mat_<double>& shape) const;
5256

5357
public:
5458
int T; // number of stages

include/jda/common.hpp

+67-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef COMMON_HPP_
22
#define COMMON_HPP_
33

4+
#include <cassert>
45
#include <opencv2/core/core.hpp>
56

67
/**
@@ -9,31 +10,62 @@
910
* usage:
1011
* TIMER_BEGIN
1112
* ....
12-
* TIMER_NOW // get delta time from TIMER_BEGIN
13+
* TIMER_NOW # get delta time from TIMER_BEGIN
1314
* ....
1415
* TIMER_END
16+
*
17+
* The Timer can be cascaded
18+
*
19+
* TIMER_BEGIN # TIMER-1
20+
* ....
21+
* TIMER_BEGIN # TIMER-2
22+
* ....
23+
* TIMER_NOW # delta time from TIMER-2
24+
* ....
25+
* TIMER_END # End of TIMER-2
26+
* ....
27+
* TIMER_NOW # delta time from TIMER-1
28+
* ....
29+
* TIMER_END # End of TIMER-1
1530
*/
1631
#define TIMER_BEGIN { double __time__ = cv::getTickCount();
1732
#define TIMER_NOW ((cv::getTickCount() - __time__) / cv::getTickFrequency())
1833
#define TIMER_END }
1934

35+
#define JDA_Assert(expr, msg) assert((expr) && (msg))
36+
2037
namespace jda {
2138

2239
/**
23-
* Feature used by Cart
24-
*
25-
* see more detail on paper in section 4.2
26-
*/
40+
* Feature used by Cart
41+
*
42+
* see more detail on paper in section 4.2
43+
*/
2744
class Feature {
2845
public:
2946
static const int ORIGIN = 0;
3047
static const int HALF = 1;
3148
static const int QUARTER = 2;
3249

50+
public:
51+
/**
52+
* Calculate feature value
53+
* :input o: original image
54+
* :input h: half of original image
55+
* :input q: quanter of original image
56+
* :input s: shape of origin image
57+
* :return: feature value
58+
*
59+
* We have three scaled image and one shape of original image, the shape of half size
60+
* and quarter size will be calculated in this function for feature value
61+
*/
62+
int CalcFeatureValue(const cv::Mat& o, const cv::Mat& h, const cv::Mat& q, \
63+
const cv::Mat_<double>& s) const;
64+
3365
public:
3466
int scale;
3567
int landmark_id1, landmark_id2;
36-
double offset1_x, offset1_y;
68+
double offset1_x, offset1_y; // relative offset range in [0, 1]
3769
double offset2_x, offset2_y;
3870

3971
static inline Feature Default() {
@@ -61,14 +93,19 @@ class Config {
6193
int K; // number of boost carts in each stage
6294
int landmark_n; // number of landmarks
6395
int tree_depth; // depth of cart
64-
double tp_rate, fn_rate;
65-
int img_width, img_height; // size of all training data
96+
double accept_rate, reject_rate;
97+
int img_o_width, img_o_height; // size of all training data
98+
int img_h_width, img_h_height;
99+
int img_q_width, img_q_height;
66100
int shift_size; // maximum random shift size on mean shape range [0, shift_size]
67101
double np_ratio; // N(negative) / N(postive)
68102
std::vector<double> radius; // sample radius of feature points in each stages
69103
std::vector<int> feats; // feature numbers used by carts in each stages
70104
std::vector<double> probs; // probability of classification in each stages
71105

106+
double scale_factor; // hard negative mining parameters
107+
int x_step, y_step;
108+
72109
std::string train_txt; // a text file for train dataset
73110
std::string nega_txt; // a text file for negative dataset
74111
std::string test_txt; // a text file for test dataset
@@ -81,24 +118,40 @@ class Config {
81118
};
82119

83120
/**
84-
* printf with timestamp
121+
* Printf with timestamp
85122
*/
86123
void LOG(const char* fmt, ...);
87124

125+
/**
126+
* Terminate the program with a message
127+
* **NOTICE** the message shouldn't be too long
128+
*/
129+
void dieWithMsg(const char* fmt, ...);
130+
88131
/**
89132
* Calculate Variance of vector
90133
*/
91134
double calcVariance(const cv::Mat_<double>& vec);
92135
double calcVariance(const std::vector<double>& vec);
93136

137+
/**
138+
* Calculate Mean Error between gt_shapes and current_shapes
139+
*/
140+
double calcMeanError(const std::vector<cv::Mat_<double> >& gt_shapes, \
141+
const std::vector<cv::Mat_<double> >& current_shapes);
142+
94143
/**
95144
* Check the point (x, y) in Image, modify if needed
145+
* :input w: width of image
146+
* :input h: height of image
147+
* :output x: x of point
148+
* :output y: y of point
96149
*/
97-
inline void checkBoundaryOfImage(int w, int h, double& x, double& y) {
98-
if (x < 0) x = 0.0;
99-
if (y < 0) y = 0.0;
100-
if (x > w) x = double(w);
101-
if (y > h) y = double(h);
150+
inline void checkBoundaryOfImage(int w, int h, int& x, int& y) {
151+
if (x < 0) x = 0;
152+
if (y < 0) y = 0;
153+
if (x >= w) x = w - 1;
154+
if (y >= h) y = w - 1;
102155
}
103156

104157
} // namespace jda

0 commit comments

Comments
 (0)