MTF
ESMH.h
1 #ifndef MTF_ESMH_H
2 #define MTF_ESMH_H
3 
4 #include "SearchMethod.h"
5 
6 #define ESMH_MAX_ITERS 10
7 #define ESMH_EPSILON 0.01
8 #define ESMH_JAC_TYPE 0
9 #define ESMH_HESS_TYPE 0
10 #define ESMH_SEC_ORD_HESS false
11 #define ESMH_ENABLE_SPI false
12 #define ESMH_SPI_THRESH 10
13 #define ESMH_DEBUG_MODE false
14 
15 _MTF_BEGIN_NAMESPACE
16 
17 struct ESMHParams{
18 
19  enum class JacType{ Original, DiffOfJacs };
20  enum class HessType {
21  Original, SumOfStd, SumOfSelf,
22  InitialSelf, CurrentSelf, Std
23  };
24 
25  int max_iters;
26  double epsilon;
27 
28  JacType jac_type;
29  HessType hess_type;
30  bool sec_ord_hess;
31 
32  bool enable_spi;
33  double spi_thresh;
34  bool debug_mode;
35 
37  // value constructor
38  ESMHParams(int _max_iters, double _epsilon,
39  JacType _jac_type, HessType _hess_type, bool _sec_ord_hess,
40  bool _enable_spi, double _spi_thresh,
41  bool _debug_mode){
42  max_iters = _max_iters;
43  epsilon = _epsilon;
44  jac_type = _jac_type;
45  hess_type = _hess_type;
46  sec_ord_hess = _sec_ord_hess;
47  enable_spi = _enable_spi;
48  spi_thresh = _spi_thresh;
49  debug_mode = _debug_mode;
50  }
51  // default and copy constructor
52  ESMHParams(ESMHParams *params = nullptr) :
53  max_iters(ESMH_MAX_ITERS), epsilon(ESMH_EPSILON),
54  jac_type(static_cast<JacType>(ESMH_JAC_TYPE)),
55  hess_type(static_cast<HessType>(ESMH_HESS_TYPE)),
56  sec_ord_hess(ESMH_SEC_ORD_HESS),
57  enable_spi(ESMH_ENABLE_SPI), spi_thresh(ESMH_SPI_THRESH),
58  debug_mode(ESMH_DEBUG_MODE){
59  if(params){
60  max_iters = params->max_iters;
61  epsilon = params->epsilon;
62  jac_type = params->jac_type;
63  hess_type = params->hess_type;
64  sec_ord_hess = params->sec_ord_hess;
65  enable_spi = params->enable_spi;
66  spi_thresh = params->spi_thresh;
67  debug_mode = params->debug_mode;
68  }
69  }
70 };
71 
72 template<class AM, class SSM>
73 class ESMH : public SearchMethod < AM, SSM > {
74 
75 public:
76  typedef ESMHParams ParamType;
77 
78  typedef ParamType::JacType JacType;
79  typedef ParamType::HessType HessType;
80 
81  using SearchMethod<AM, SSM> ::am;
82  using SearchMethod<AM, SSM> ::ssm;
83  using typename SearchMethod<AM, SSM> ::AMParams;
84  using typename SearchMethod<AM, SSM> ::SSMParams;
85  using SearchMethod<AM, SSM> ::cv_corners_mat;
86  using SearchMethod<AM, SSM> ::name;
87  using SearchMethod<AM, SSM> ::initialize;
88  using SearchMethod<AM, SSM> ::update;
89 
90 protected:
91  ParamType params;
92 
93  int frame_id;
94  VectorXc pix_mask2;
95  VectorXb pix_mask;
96  VectorXd rel_pix_diff;
97  double max_pix_diff;
98 
99  Matrix24d prev_corners;
102  MatrixXd init_pix_jacobian, curr_pix_jacobian, mean_pix_jacobian;
103  MatrixXd init_pix_hessian, curr_pix_hessian, mean_pix_hessian;
104  VectorXd ssm_update;
106  RowVectorXd jacobian;
108  MatrixXd hessian, init_self_hessian;
109 
110 public:
111 
112  ESMH(const ParamType *esm_params,
113  const AMParams *am_params, const SSMParams *ssm_params) :
114  SearchMethod<AM, SSM>(am_params, ssm_params),
115  params(esm_params){
116  printf("\n");
117  printf("Using ESM tracker with:\n");
118  printf("max_iters: %d\n", params.max_iters);
119  printf("epsilon: %f\n", params.epsilon);
120  printf("jac_type: %d\n", params.jac_type);
121  printf("hess_type: %d\n", params.hess_type);
122  printf("sec_ord_hess: %d\n", params.sec_ord_hess);
123  printf("enable_spi: %d\n", params.enable_spi);
124  printf("spi_thresh: %f\n", params.spi_thresh);
125  printf("debug_mode: %d\n", params.debug_mode);
126 
127  printf("appearance model: %s\n", am.name.c_str());
128  printf("state space model: %s\n", ssm.name.c_str());
129  printf("\n");
130 
131  name = "esm";
132 
133  frame_id = 0;
134  max_pix_diff = 0;
135 
136  switch(params.jac_type){
137  case JacType::Original:
138  printf("Using original ESM Jacobian\n");
139  break;
140  case JacType::DiffOfJacs:
141  printf("Using Difference of Jacobians\n");
142  break;
143  default:
144  throw utils::InvalidArgument("Invalid Jacobian type provided");
145  }
146 
147  const char *hess_order = params.sec_ord_hess ? "Second" : "First";
148  switch(params.hess_type){
149  case HessType::Original:
150  printf("Using %s order original ESM Hessian\n", hess_order);
151  break;
152  case HessType::SumOfStd:
153  printf("Using Sum of %s order Standard Hessians\n", hess_order);
154  break;
155  case HessType::SumOfSelf:
156  printf("Using Sum of %s order Self Hessians\n", hess_order);
157  break;
158  case HessType::InitialSelf:
159  printf("Using %s order Initial Self Hessian\n", hess_order);
160  break;
161  case HessType::CurrentSelf:
162  printf("Using %s order Current Self Hessian\n", hess_order);
163  break;
164  case HessType::Std:
165  printf("Using %s order Standard Hessian\n", hess_order);
166  break;
167  default:
168  throw utils::InvalidArgument("Invalid Hessian type provided");
169  }
170 
171  ssm_update.resize(ssm.getStateSize());
172  jacobian.resize(ssm.getStateSize());
173  hessian.resize(ssm.getStateSize(), ssm.getStateSize());
174 
175  init_pix_jacobian.resize(am.getNPix(), ssm.getStateSize());
176  curr_pix_jacobian.resize(am.getNPix(), ssm.getStateSize());
177 
178  if(params.jac_type == JacType::Original || params.hess_type == HessType::Original){
179  mean_pix_jacobian.resize(am.getNPix(), ssm.getStateSize());
180  }
181  if(params.hess_type == HessType::SumOfSelf){
182  init_self_hessian.resize(ssm.getStateSize(), ssm.getStateSize());
183  }
184  if(params.sec_ord_hess){
185  init_pix_hessian.resize(ssm.getStateSize()*ssm.getStateSize(), am.getNPix());
186  if(params.hess_type != HessType::InitialSelf){
187  curr_pix_hessian.resize(ssm.getStateSize()*ssm.getStateSize(), am.getNPix());
188  if(params.hess_type == HessType::Original){
189  mean_pix_hessian.resize(ssm.getStateSize()*ssm.getStateSize(), am.getNPix());
190  }
191  }
192  }
193  }
194 
195  void initialize(const cv::Mat &corners) override{
196  frame_id = 0;
197  ssm.initialize(corners);
198  am.initializePixVals(ssm.getPts());
199 
200  if(params.enable_spi){
201  if(!ssm.supportsSPI())
202  throw utils::InvalidArgument("ESM::initialize : SSM does not support SPI");
203  if(!am.supportsSPI())
204  throw utils::InvalidArgument("ESM::initialize : AM does not support SPI");
205 
206  printf("Using Selective Pixel Integration\n");
207  pix_mask.resize(am.getNPix());
208  ssm.setSPIMask(pix_mask.data());
209  am.setSPIMask(pix_mask.data());
210  }
211 
212  ssm.initializeGradPts(am.getGradOffset());
213  am.initializePixGrad(ssm.getGradPts());
214  ssm.cmptInitPixJacobian(init_pix_jacobian, am.getInitPixGrad());
215 
216  if(params.sec_ord_hess){
217  ssm.initializeHessPts(am.getHessOffset());
218  am.initializePixHess(ssm.getPts(), ssm.getHessPts());
219  ssm.cmptInitPixHessian(init_pix_hessian, am.getInitPixHess(), am.getInitPixGrad());
220  }
221  am.initializeSimilarity();
222  am.initializeGrad();
223  am.initializeHess();
224 
225  if(params.hess_type == HessType::InitialSelf || params.hess_type == HessType::SumOfSelf){
226  if(params.sec_ord_hess){
227  am.cmptSelfHessian(hessian, init_pix_jacobian, init_pix_hessian);
228  } else{
229  am.cmptSelfHessian(hessian, init_pix_jacobian);
230  }
231  if(params.hess_type == HessType::SumOfSelf){
232  init_self_hessian = hessian;
233  }
234  }
235  ssm.getCorners(cv_corners_mat);
236  }
237 
238  void update() override{
239  ++frame_id;
240  am.setFirstIter();
241  for(int iter_id = 0; iter_id < params.max_iters; iter_id++){
242  // extract pixel values from the current image at the latest known position of the object
243  am.updatePixVals(ssm.getPts());
244 
245  if(params.enable_spi){
246  rel_pix_diff = (am.getInitPixVals() - am.getCurrPixVals()) / max_pix_diff;
247  pix_mask = rel_pix_diff.cwiseAbs().array() < params.spi_thresh;
248  }
249  // compute pixel gradient of the current image warped with the current warp
250  ssm.updateGradPts(am.getGradOffset());
251  am.updatePixGrad(ssm.getGradPts());
252  // multiply the pixel gradient with the SSM Jacobian to get the Jacobian of pixel values w.r.t. SSM parameters
253  ssm.cmptInitPixJacobian(curr_pix_jacobian, am.getCurrPixGrad());
254 
255  if(params.jac_type == JacType::Original || params.hess_type == HessType::Original){
256  mean_pix_jacobian = (init_pix_jacobian + curr_pix_jacobian) / 2.0;
257  }
258  if(params.sec_ord_hess && params.hess_type != HessType::InitialSelf){
259  ssm.updateHessPts(am.getHessOffset());
260  am.updatePixHess(ssm.getPts(), ssm.getHessPts());
261  ssm.cmptInitPixHessian(curr_pix_hessian, am.getCurrPixHess(), am.getCurrPixGrad());
262  }
263  // compute the prerequisites for the gradient functions
264  am.updateSimilarity();
265  // update the gradient of the error norm w.r.t. current pixel values
266  am.updateCurrGrad();
267  // update the gradient of the error norm w.r.t. initial pixel values
268  am.updateInitGrad();
269 
270  switch(params.jac_type){
271  case JacType::Original:
272  // take the mean at the level of the jacobian of the pixel values wrt SSM parameters,
273  //then use this mean jacobian to compute the Jacobian of the error norm wrt SSM parameters
274  am.cmptCurrJacobian(jacobian, mean_pix_jacobian);
275  break;
276  case JacType::DiffOfJacs:
277  // compute the mean difference between the Jacobians of the error norm w.r.t. initial AND current values of SSM parameters
278  am.cmptDifferenceOfJacobians(jacobian, init_pix_jacobian, curr_pix_jacobian);
279  jacobian *= 0.5;
280  break;
281  }
282  switch(params.hess_type){
283  case HessType::InitialSelf:
284  break;
285  case HessType::Original:
286  if(params.sec_ord_hess){
287  mean_pix_hessian = (init_pix_hessian + curr_pix_hessian) / 2.0;
288  am.cmptCurrHessian(hessian, mean_pix_jacobian, mean_pix_hessian);
289  } else{
290  am.cmptCurrHessian(hessian, mean_pix_jacobian);
291  }
292  break;
293  case HessType::SumOfStd:
294  if(params.sec_ord_hess){
295  am.cmptSumOfHessians(hessian, init_pix_jacobian, curr_pix_jacobian,
296  init_pix_hessian, curr_pix_hessian);
297  } else{
298  am.cmptSumOfHessians(hessian, init_pix_jacobian, curr_pix_jacobian);
299  }
300  hessian *= 0.5;
301  break;
302  case HessType::SumOfSelf:
303  if(params.sec_ord_hess){
304  am.cmptSelfHessian(hessian, curr_pix_jacobian, curr_pix_hessian);
305  } else{
306  am.cmptSelfHessian(hessian, curr_pix_jacobian);
307  }
308  hessian = (hessian + init_self_hessian) * 0.5;
309  break;
310  case HessType::CurrentSelf:
311  if(params.sec_ord_hess){
312  am.cmptSelfHessian(hessian, curr_pix_jacobian, curr_pix_hessian);
313  } else{
314  am.cmptSelfHessian(hessian, curr_pix_jacobian);
315  }
316  break;
317  case HessType::Std:
318  if(params.sec_ord_hess){
319  am.cmptCurrHessian(hessian, curr_pix_jacobian, curr_pix_hessian);
320  } else{
321  am.cmptCurrHessian(hessian, curr_pix_jacobian);
322  }
323  break;
324  }
325  ssm_update = -hessian.colPivHouseholderQr().solve(jacobian.transpose());
326  prev_corners = ssm.getCorners();
327  ssm.compositionalUpdate(ssm_update);
328  double update_norm = (prev_corners - ssm.getCorners()).squaredNorm();
329  if(update_norm < params.epsilon){
330  break;
331  }
332  am.clearFirstIter();
333  }
334  ssm.getCorners(cv_corners_mat);
335  }
336 };
337 _MTF_END_NAMESPACE
338 
339 #endif
340 
Definition: ESMH.h:73
MatrixXd init_pix_jacobian
N x S jacobians of the pixel values w.r.t the SSM state vector where N = resx * resy is the no...
Definition: ESMH.h:102
MatrixXd hessian
S x S Hessian of the AM error norm w.r.t. SSM state vector.
Definition: ESMH.h:108
Definition: StateSpaceModel.h:35
double epsilon
maximum iterations of the ESMH algorithm to run for each frame
Definition: ESMH.h:26
RowVectorXd jacobian
1 x S Jacobian of the AM error norm w.r.t. SSM state vector
Definition: ESMH.h:106
Definition: AMParams.h:12
Definition: SearchMethod.h:10
JacType jac_type
maximum L1 norm of the state update vector at which to stop the iterations
Definition: ESMH.h:28
Definition: ESMH.h:17
ESMHParams(int _max_iters, double _epsilon, JacType _jac_type, HessType _hess_type, bool _sec_ord_hess, bool _enable_spi, double _spi_thresh, bool _debug_mode)
decides whether logging data will be printed for debugging purposes;
Definition: ESMH.h:38