ViSP  2.9.0
vpMbtKltPolygon.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMbtKltPolygon.cpp 4661 2014-02-10 19:34:58Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  * Description:
34  * Generic model polygon, containing points of interest.
35  *
36  * Authors:
37  * Romain Tallonneau
38  * Aurelien Yol
39  *
40  *****************************************************************************/
41 
42 
43 #include <visp/vpMbtKltPolygon.h>
44 
45 #ifdef VISP_HAVE_OPENCV
46 
52  : H(), N(), N_cur(), invd0(1.), cRc0_0n(), initPoints(), curPoints(), curPointsInd(),
53  nbPointsCur(0), nbPointsInit(0), minNbPoint(4), enoughPoints(false), dt(1.), d0(1.), cam()
54 {
55  initPoints = std::map<int, vpImagePoint>();
56  curPoints = std::map<int, vpImagePoint>();
57  curPointsInd = std::map<int, int>();
58 
59  isvisible = false;
60 }
61 
67 {}
68 
76 void
78 {
79  // extract ids of the points in the face
80  nbPointsInit = 0;
81  nbPointsCur = 0;
82  initPoints = std::map<int, vpImagePoint>();
83  curPoints = std::map<int, vpImagePoint>();
84  curPointsInd = std::map<int, int>();
85  std::vector<vpImagePoint> roi;
86  getRoiClipped(cam, roi);
87 
88  for (unsigned int i = 0; i < static_cast<unsigned int>(_tracker.getNbFeatures()); i ++){
89  int id;
90  float x_tmp, y_tmp;
91  _tracker.getFeature((int)i, id, x_tmp, y_tmp);
92 
93  if(isInside(roi, y_tmp, x_tmp)){
94  initPoints[id] = vpImagePoint(y_tmp, x_tmp);
95  curPoints[id] = vpImagePoint(y_tmp, x_tmp);
96  curPointsInd[id] = (int)i;
97  nbPointsInit++;
98  nbPointsCur++;
99  }
100  }
101 
102  // initialisation of the value for the computation in SE3
103  vpPlane plan(p[0], p[1], p[2]);
104 
105  d0 = plan.getD();
106  N = plan.getNormal();
107 
108  N.normalize();
109  N_cur = N;
110  invd0 = 1.0 / d0;
111 }
112 
120 unsigned int
122 {
123  int id;
124  float x, y;
125  nbPointsCur = 0;
126  curPoints = std::map<int, vpImagePoint>();
127  curPointsInd = std::map<int, int>();
128 
129  for (unsigned int i = 0; i < static_cast<unsigned int>(_tracker.getNbFeatures()); i++){
130  _tracker.getFeature((int)i, id, x, y);
131  if(isTrackedFeature(id)){
132  curPoints[id] = vpImagePoint(static_cast<double>(y),static_cast<double>(x));
133  curPointsInd[id] = (int)i;
134  nbPointsCur++;
135  }
136  }
137 
138  if(nbPointsCur >= minNbPoint) enoughPoints = true;
139  else enoughPoints = false;
140 
141  return nbPointsCur;
142 }
143 
154 void
156 {
157  unsigned int index_ = 0;
158 
159  std::map<int, vpImagePoint>::const_iterator iter = curPoints.begin();
160  for( ; iter != curPoints.end(); iter++){
161  int id(iter->first);
162  double i_cur(iter->second.get_i()), j_cur(iter->second.get_j());
163 
164  double x_cur(0), y_cur(0);
165  vpPixelMeterConversion::convertPoint(cam, j_cur, i_cur, x_cur, y_cur);
166 
167  vpImagePoint iP0 = initPoints[id];
168  double x0(0), y0(0);
169  vpPixelMeterConversion::convertPoint(cam, iP0, x0, y0);
170 
171  double x0_transform, y0_transform ;// equivalent x and y in the first image (reference)
172  computeP_mu_t(x0, y0, x0_transform, y0_transform, H );
173 
174  double invZ = compute_1_over_Z(x_cur, y_cur);
175 
176  _J[2*index_][0] = - invZ;
177  _J[2*index_][1] = 0;
178  _J[2*index_][2] = x_cur * invZ;
179  _J[2*index_][3] = x_cur * y_cur;
180  _J[2*index_][4] = -(1+x_cur*x_cur);
181  _J[2*index_][5] = y_cur;
182 
183  _J[2*index_+1][0] = 0;
184  _J[2*index_+1][1] = - invZ;
185  _J[2*index_+1][2] = y_cur * invZ;
186  _J[2*index_+1][3] = (1+y_cur*y_cur);
187  _J[2*index_+1][4] = - y_cur * x_cur;
188  _J[2*index_+1][5] = - x_cur;
189 
190  _R[2*index_] = (x0_transform - x_cur);
191  _R[2*index_+1] = (y0_transform - y_cur);
192  index_++;
193  }
194 }
195 
196 double
197 vpMbtKltPolygon::compute_1_over_Z(const double x, const double y)
198 {
199  double num = cRc0_0n[0] * x + cRc0_0n[1] * y + cRc0_0n[2];
200  double den = -(d0 - dt);
201  return num/den;
202 }
203 
216 inline void
217 vpMbtKltPolygon::computeP_mu_t(const double x_in, const double y_in, double& x_out, double& y_out, const vpMatrix& _cHc0)
218 {
219  double p_mu_t_2 = x_in * _cHc0[2][0] + y_in * _cHc0[2][1] + _cHc0[2][2];
220 
221  if( fabs(p_mu_t_2) < std::numeric_limits<double>::epsilon()){
222  x_out = 0.0;
223  y_out = 0.0;
224  throw vpException(vpException::divideByZeroError, "the depth of the point is calculated to zero");
225  }
226 
227  x_out = (x_in * _cHc0[0][0] + y_in * _cHc0[0][1] + _cHc0[0][2]) / p_mu_t_2;
228  y_out = (x_in * _cHc0[1][0] + y_in * _cHc0[1][1] + _cHc0[1][2]) / p_mu_t_2;
229 }
230 
243 void
245 {
246  vpRotationMatrix cRc0;
247  vpTranslationVector ctransc0;
248 
249  _cTc0.extract(cRc0);
250  _cTc0.extract(ctransc0);
251  vpMatrix cHc0(_cHc0);
252 
253 // vpGEMM(cRc0, 1.0, invd0, cRc0, -1.0, _cHc0, VP_GEMM_A_T);
254  vpGEMM(ctransc0, N, -invd0, cRc0, 1.0, cHc0, VP_GEMM_B_T);
255  cHc0 /= cHc0[2][2];
256 
257  H = cHc0;
258 
259 // vpQuaternionVector NQuat(N[0], N[1], N[2], 0.0);
260 // vpQuaternionVector RotQuat(cRc0);
261 // vpQuaternionVector RotQuatConj(-RotQuat.x(), -RotQuat.y(), -RotQuat.z(), RotQuat.w());
262 // vpQuaternionVector partial = RotQuat * NQuat;
263 // vpQuaternionVector resQuat = (partial * RotQuatConj);
264 //
265 // cRc0_0n = vpColVector(3);
266 // cRc0_0n[0] = resQuat.x();
267 // cRc0_0n[1] = resQuat.y();
268 // cRc0_0n[2] = resQuat.z();
269 
270  cRc0_0n = cRc0*N;
271 
272 // vpPlane p(corners[0], corners[1], corners[2]);
273 // vpColVector Ncur = p.getNormal();
274 // Ncur.normalize();
275  N_cur = cRc0_0n;
276  dt = 0.0;
277  for (unsigned int i = 0; i < 3; i += 1){
278  dt += ctransc0[i] * (N_cur[i]);
279  }
280 }
281 
289 bool
290 vpMbtKltPolygon::isTrackedFeature(const int _id)
291 {
292 // std::map<int, vpImagePoint>::const_iterator iter = initPoints.begin();
293 // while(iter != initPoints.end()){
294 // if(iter->first == _id){
295 // return true;
296 // }
297 // iter++;
298 // }
299 
300  std::map<int, vpImagePoint>::iterator iter = initPoints.find(_id);
301  if(iter != initPoints.end())
302  return true;
303 
304  return false;
305 }
306 
315 void
316 vpMbtKltPolygon::updateMask(IplImage* _mask, unsigned char _nb, unsigned int _shiftBorder)
317 {
318  int width = _mask->width;
319  int i_min, i_max, j_min, j_max;
320  cam.computeFov((unsigned)_mask->width, (unsigned)_mask->height);
321  computeRoiClipped(cam);
322  std::vector<vpImagePoint> roi;
323  getRoiClipped(cam, roi);
324  vpMbtPolygon::getMinMaxRoi(roi, i_min, i_max, j_min,j_max);
325 
326  /* check image boundaries */
327  if(i_min > _mask->height){ //underflow
328  i_min = 0;
329  }
330  if(i_max > _mask->height){
331  i_max = _mask->height;
332  }
333  if(j_min > _mask->width){ //underflow
334  j_min = 0;
335  }
336  if(j_max > _mask->width){
337  j_max = _mask->width;
338  }
339 
340  double shiftBorder_d = (double) _shiftBorder;
341  unsigned char* ptrData = (unsigned char*)_mask->imageData + i_min*width+j_min;
342  for(int i=i_min; i< i_max; i++){
343  double i_d = (double) i;
344  for(int j=j_min; j< j_max; j++){
345  double j_d = (double) j;
346  if(_shiftBorder != 0){
347  if( vpMbtKltPolygon::isInside(roi, i_d, j_d)
348  && vpMbtKltPolygon::isInside(roi, i_d+shiftBorder_d, j_d+shiftBorder_d)
349  && vpMbtKltPolygon::isInside(roi, i_d-shiftBorder_d, j_d+shiftBorder_d)
350  && vpMbtKltPolygon::isInside(roi, i_d+shiftBorder_d, j_d-shiftBorder_d)
351  && vpMbtKltPolygon::isInside(roi, i_d-shiftBorder_d, j_d-shiftBorder_d) ){
352  *(ptrData++) = _nb;
353  }
354  else{
355  ptrData++;
356  }
357  }
358  else{
359  if(vpMbtKltPolygon::isInside(roi, i, j)){
360  *(ptrData++) = _nb;
361  }
362  else{
363  ptrData++;
364  }
365  }
366  }
367  ptrData += width - j_max + j_min;
368  }
369 
370 }
371 
379 void
380 vpMbtKltPolygon::removeOutliers(const vpColVector& _w, const double &threshold_outlier)
381 {
382  std::map<int, vpImagePoint> tmp;
383  std::map<int, int> tmp2;
384  unsigned int nbSupp = 0;
385  unsigned int k = 0;
386 
387  nbPointsCur = 0;
388  std::map<int, vpImagePoint>::const_iterator iter = curPoints.begin();
389  for( ; iter != curPoints.end(); iter++){
390  if(_w[k] > threshold_outlier && _w[k+1] > threshold_outlier){
391 // if(_w[k] > threshold_outlier || _w[k+1] > threshold_outlier){
392  tmp[iter->first] = vpImagePoint(iter->second.get_i(), iter->second.get_j());
393  tmp2[iter->first] = curPointsInd[iter->first];
394  nbPointsCur++;
395  }
396  else{
397  nbSupp++;
398  initPoints.erase(iter->first);
399  }
400 
401  k+=2;
402  }
403 
404  if(nbSupp != 0){
405  curPoints = std::map<int, vpImagePoint>();
406  curPointsInd = std::map<int, int>();
407 
408  curPoints = tmp;
409  curPointsInd = tmp2;
410  if(nbPointsCur >= minNbPoint) enoughPoints = true;
411  else enoughPoints = false;
412  }
413 }
414 
420 void
422 {
423  std::map<int, vpImagePoint>::const_iterator iter = curPoints.begin();
424  for( ; iter != curPoints.end(); iter++){
425  int id(iter->first);
426  vpImagePoint iP;
427  iP.set_i(static_cast<double>(iter->second.get_i()));
428  iP.set_j(static_cast<double>(iter->second.get_j()));
429 
431 
432  iP.set_i( vpMath::round( iP.get_i() + 7 ) );
433  iP.set_j( vpMath::round( iP.get_j() + 7 ) );
434  char ide[10];
435  sprintf(ide, "%ld", static_cast<long int>(id));
437  }
438 }
439 
445 void
447 {
448  std::map<int, vpImagePoint>::const_iterator iter = curPoints.begin();
449  for( ; iter != curPoints.end(); iter++){
450  int id(iter->first);
451  vpImagePoint iP;
452  iP.set_i(static_cast<double>(iter->second.get_i()));
453  iP.set_j(static_cast<double>(iter->second.get_j()));
454 
456 
457  iP.set_i( vpMath::round( iP.get_i() + 7 ) );
458  iP.set_j( vpMath::round( iP.get_j() + 7 ) );
459  char ide[10];
460  sprintf(ide, "%ld", static_cast<long int>(id));
462  }
463 }
464 
465 //###################################
466 // Static functions
467 //###################################
468 
469 bool vpMbtKltPolygon::intersect(const vpImagePoint& p1, const vpImagePoint& p2, const double i_test, const double j_test, const double i, const double j)
470 {
471  double dx = p2.get_j() - p1.get_j();
472  double dy = p2.get_i() - p1.get_i();
473  double ex = j - j_test;
474  double ey = i - i_test;
475 
476  double den = dx * ey - dy * ex;
477  double t = 0, u = 0;
478  //if(den != 0){
479  if(std::fabs(den) > std::fabs(den)*std::numeric_limits<double>::epsilon()){
480  t = -( ey * ( p1.get_j() - j_test ) + ex * ( -p1.get_i() + i_test ) ) / den;
481  u = -( dx * ( -p1.get_i() + i_test ) + dy * ( p1.get_j() - j_test ) ) / den;
482  }
483  else{
484  throw vpException(vpException::divideByZeroError, "denominator null");
485  }
486  return ( t >= std::numeric_limits<double>::epsilon() && t < 1.0 && u >= std::numeric_limits<double>::epsilon() && u < 1.0);
487 }
488 
489 bool vpMbtKltPolygon::isInside(const std::vector<vpImagePoint>& roi, const double i, const double j)
490 {
491  double i_test = 100000.;
492  double j_test = 100000.;
493  unsigned int nbInter = 0;
494  bool computeAgain = true;
495 
496  if(computeAgain){
497  computeAgain = false;
498  for(unsigned int k=0; k< roi.size(); k++){
499  try{
500  if(vpMbtKltPolygon::intersect(roi[k], roi[(k+1)%roi.size()], i, j, i_test, j_test)){
501  nbInter++;
502  }
503  }
504  catch(...){
505  computeAgain = true;
506  break;
507  }
508  }
509 
510  if(computeAgain){
511  i_test += 100;
512  j_test -= 100;
513  nbInter = 0;
514  }
515  }
516  return ((nbInter%2) == 1);
517 }
518 
519 #endif // VISP_HAVE_OPENCV
Definition of the vpMatrix class.
Definition: vpMatrix.h:98
void init(const vpKltOpencv &_tracker)
void updateMask(IplImage *_mask, unsigned char _nb=255, unsigned int _shiftBorder=0)
double get_i() const
Definition: vpImagePoint.h:194
The class provides a data structure for the homogeneous matrices as well as a set of operations on th...
error that can be emited by ViSP classes.
Definition: vpException.h:76
void displayPrimitive(const vpImage< unsigned char > &_I)
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
Point coordinates conversion from pixel coordinates to normalized coordinates in meter...
void removeOutliers(const vpColVector &weight, const double &threshold_outlier)
void getRoiClipped(const vpCameraParameters &cam, std::vector< vpImagePoint > &roi)
static int round(const double x)
Definition: vpMath.h:228
double get_j() const
Definition: vpImagePoint.h:205
static const vpColor red
Definition: vpColor.h:167
The vpRotationMatrix considers the particular case of a rotation matrix.
This class aims to compute the homography wrt.two images.
Definition: vpHomography.h:178
void set_i(const double ii)
Definition: vpImagePoint.h:158
unsigned int computeNbDetectedCurrent(const vpKltOpencv &_tracker)
void computeInteractionMatrixAndResidu(vpColVector &_R, vpMatrix &_J)
void getFeature(int index, int &id, float &x, float &y) const
virtual ~vpMbtKltPolygon()
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void extract(vpRotationMatrix &R) const
void computeHomography(const vpHomogeneousMatrix &_cTc0, vpHomography &cHc0)
void computeRoiClipped(const vpCameraParameters &cam=vpCameraParameters())
vpColVector getNormal() const
Definition: vpPlane.cpp:218
void set_j(const double jj)
Definition: vpImagePoint.h:169
Class that provides a data structure for the column vectors as well as a set of operations on these v...
Definition: vpColVector.h:72
virtual void displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color=vpColor::green)=0
Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented in OpenCV.
Definition: vpKltOpencv.h:103
int getNbFeatures() const
Get the current number of features.
Definition: vpKltOpencv.h:187
static void getMinMaxRoi(const std::vector< vpImagePoint > &roi, int &i_min, int &i_max, int &j_min, int &j_max)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
This class defines the container for a plane geometrical structure.
Definition: vpPlane.h:67
bool isvisible
flag to specify whether the face is visible or not
Definition: vpMbtPolygon.h:91
vpColVector & normalize()
normalise the vector
Class that consider the case of a translation vector.
double getD() const
Definition: vpPlane.h:117
void computeFov(const unsigned int &w, const unsigned int &h)
vpPoint * p
corners in the object frame
Definition: vpMbtPolygon.h:95