ViSP  2.8.0
vpKltOpencv.cpp
1 /****************************************************************************
2  *
3  * $Id: vpKltOpencv.cpp 4198 2013-04-05 12:13:23Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 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  *
34  * Description:
35  * Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented
36  * with opencv.
37  *
38  * Authors:
39  * Fabien Servant
40  * Fabien Spindler
41  *
42  *****************************************************************************/
43 
51 #include "visp/vpConfig.h"
52 
53 #ifdef VISP_HAVE_OPENCV
54 
55 #include <string>
56 
57 #include "vpKltOpencv.h"
58 
59 void vpKltOpencv::clean()
60 {
61  if (image) cvReleaseImage(&image);
62  if (prev_image) cvReleaseImage(&prev_image);
63  if (pyramid) cvReleaseImage(&pyramid);
64  if (prev_pyramid) cvReleaseImage(&prev_pyramid);
65 
66  image = 0;
67  prev_image = 0;
68  pyramid = 0;
69  prev_pyramid = 0;
70 
71  swap_temp = 0;
72  countFeatures = 0;
73  countPrevFeatures = 0;
74  flags = 0;
75  initialized = 0;
76  globalcountFeatures = 0;
77 }
78 
79 void vpKltOpencv::cleanAll()
80 {
81  clean();
82  if (features) cvFree(&features);
83  if (prev_features) cvFree(&prev_features);
84  if (status) cvFree(&status);
85  if (lostDuringTrack) cvFree(&lostDuringTrack);
86  if (featuresid) cvFree(&featuresid);
87  if (prev_featuresid) cvFree(&prev_featuresid);
88  features = 0;
89  prev_features = 0;
90  status = 0;
91  lostDuringTrack = 0;
92  featuresid = 0;
93  prev_featuresid = 0;
94 }
95 
96 void vpKltOpencv::reset()
97 {
98  clean();
99 
100 }
101 
103 {
104  //Valeurs par d�faut pour le KLT
105  initialized = 0;
106  maxFeatures = 50;
107  countFeatures = 0;
108  countPrevFeatures = 0;
109  globalcountFeatures = 0;
110  win_size = 10;
111  quality = 0.01;
112  min_distance = 10;
113  block_size = 3;
114  use_harris = 1;
115  pyramid_level = 3;
116  harris_free_parameter = 0.04;
117 
118  //Zeroing pointers
119  image = 0;
120  prev_image = 0;
121  pyramid = 0;
122  prev_pyramid = 0;
123  swap_temp = 0;
124  features = 0;
125  prev_features = 0;
126  flags = 0;
127  status = 0;
128  lostDuringTrack = 0;
129  featuresid = 0;
130  prev_featuresid = 0;
131  OnInitialize = 0;
132  OnFeatureLost = 0;
133  OnNewFeature = 0;
134  OnMeasureFeature = 0;
135  IsFeatureValid = 0;
136  initial_guess = false;
137 
138  features = (CvPoint2D32f*)cvAlloc((unsigned int)maxFeatures*sizeof(features[0]));
139  prev_features = (CvPoint2D32f*)cvAlloc((unsigned int)maxFeatures*sizeof(prev_features[0]));
140  status = (char*)cvAlloc((size_t)maxFeatures);
141  lostDuringTrack = (bool*)cvAlloc((size_t)maxFeatures);
142  featuresid = (long*)cvAlloc((unsigned int)maxFeatures*sizeof(long));
143  prev_featuresid = (long*)cvAlloc((unsigned int)maxFeatures*sizeof(long));
144 
145 
146  _tid = -1;
147 }
148 
150 {
151  //Shallow copy of primitives
152  initialized = copy.initialized;
153  maxFeatures = copy.maxFeatures;
154  countFeatures = copy.countFeatures;
155  countPrevFeatures = copy.countPrevFeatures;
156  globalcountFeatures = copy.globalcountFeatures;
157  flags = copy.flags;
158  win_size = copy.win_size;
159  quality = copy.quality;
160  min_distance = copy.min_distance;
161  harris_free_parameter = copy.harris_free_parameter;
162  block_size = copy.block_size;
163  use_harris = copy.use_harris;
164  pyramid_level = copy.pyramid_level;
165  _tid = copy._tid;
166 
167  OnInitialize = copy.OnInitialize;
168  OnFeatureLost = copy.OnFeatureLost;
169  OnNewFeature = copy.OnNewFeature;
170  OnMeasureFeature = copy.OnMeasureFeature;
171  IsFeatureValid = copy.IsFeatureValid;
172 
173  if (!initialized) {
174  image = 0;
175  prev_image = 0;
176  pyramid = 0;
177  prev_pyramid = 0;
178  features = 0;
179  prev_features = 0;
180  status = 0;
181  lostDuringTrack = 0;
182  featuresid = 0;
183  prev_featuresid = 0;
184  swap_temp = 0;
185  countFeatures = 0;
186  countPrevFeatures = 0;
187  flags = 0;
188  initialized = 0;
189  globalcountFeatures = 0;
190  }
191 
192  if (copy.image)
193  {
194  image = cvCreateImage(cvGetSize(copy.image), 8, 1);
195  // /*IplImage **/cvCopyImage(copy.image,image);
196  cvCopy(copy.image, image, 0);
197  }
198 
199  if (copy.prev_image)
200  {
201  prev_image = cvCreateImage(cvGetSize(copy.prev_image), IPL_DEPTH_8U, 1);
202  // /*IplImage **/ cvCopyImage(copy.prev_image,prev_image);
203  cvCopy(copy.prev_image, prev_image, 0);
204  }
205 
206  if (copy.pyramid)
207  {
208  pyramid = cvCreateImage(cvGetSize(copy.pyramid), IPL_DEPTH_8U, 1);
209  // /*IplImage **/cvCopyImage(copy.pyramid,pyramid);
210  cvCopy(copy.pyramid, pyramid, 0);
211  }
212 
213  if (copy.prev_pyramid)
214  {
215  prev_pyramid = cvCreateImage(cvGetSize(copy.prev_pyramid), IPL_DEPTH_8U, 1);
216  // /*IplImage **/cvCopyImage(copy.prev_pyramid,prev_pyramid);
217  cvCopy(copy.prev_pyramid, prev_pyramid, 0);
218  }
219 
220  //Deep copy of arrays
221  if (copy.features) {
222  /*CvPoint2D32f **/features =
223  (CvPoint2D32f*)cvAlloc((unsigned int)copy.maxFeatures*sizeof(CvPoint2D32f));
224  for (int i = 0; i < copy.maxFeatures; i++)
225  features[i] = copy.features[i];
226  }
227 
228  if (copy.prev_features) {
229  /*CvPoint2D32f **/prev_features =
230  (CvPoint2D32f*)cvAlloc((unsigned int)copy.maxFeatures*sizeof(CvPoint2D32f));
231  for (int i = 0; i < copy.maxFeatures; i++)
232  prev_features[i] = copy.prev_features[i];
233  }
234 
235  if (copy.featuresid) {
236  /*long **/featuresid = (long*)cvAlloc((unsigned int)copy.maxFeatures*sizeof(long));
237  for (int i = 0; i < copy.maxFeatures; i++)
238  featuresid[i] = copy.featuresid[i];
239  }
240 
241  if (copy.prev_featuresid) {
242  /*long **/prev_featuresid = (long*)cvAlloc((unsigned int)copy.maxFeatures*sizeof(long));
243  for (int i = 0; i < copy.maxFeatures; i++)
244  prev_featuresid[i] = copy.prev_featuresid[i];
245  }
246 
247  if (copy.status) {
248  /*char **/status = (char*)cvAlloc((unsigned int)copy.maxFeatures*sizeof(char));
249  for (int i = 0; i < copy.maxFeatures; i++)
250  status[i] = copy.status[i];
251  }
252 
253  if (copy.lostDuringTrack) {
254  /*bool **/lostDuringTrack = (bool*)cvAlloc((unsigned int)copy.maxFeatures*sizeof(bool));
255  for (int i = 0; i < copy.maxFeatures; i++)
256  lostDuringTrack[i] = copy.lostDuringTrack[i];
257  }
258 }
259 
261 {
262  cleanAll();
263 }
264 
272 void vpKltOpencv::setMaxFeatures(const int input) {
273  initialized = 0; maxFeatures=input;
274 
275  if (features) cvFree(&features);
276  if (prev_features) cvFree(&prev_features);
277  if (status) cvFree(&status);
278  if (lostDuringTrack) cvFree(&lostDuringTrack);
279  if (featuresid) cvFree(&featuresid);
280  if (prev_featuresid) cvFree(&prev_featuresid);
281 
282 
283  features = (CvPoint2D32f*)cvAlloc((unsigned int)maxFeatures*sizeof(CvPoint2D32f));
284  prev_features = (CvPoint2D32f*)cvAlloc((unsigned int)maxFeatures*sizeof(CvPoint2D32f));
285  status = (char*)cvAlloc((unsigned int)maxFeatures*sizeof(char));
286  lostDuringTrack = (bool*)cvAlloc((unsigned int)maxFeatures*sizeof(bool));
287  featuresid = (long*)cvAlloc((unsigned int)maxFeatures*sizeof(long));
288  prev_featuresid = (long*)cvAlloc((unsigned int)maxFeatures*sizeof(long));
289 }
290 
301 void vpKltOpencv::initTracking(const IplImage *I, const IplImage *mask)
302 {
303  if (!I) {
304  throw(vpException(vpTrackingException::initializationError, "Image Not initialized")) ;
305  }
306 
307  if (I->depth != IPL_DEPTH_8U || I->nChannels != 1) {
308  throw(vpException(vpTrackingException::initializationError, "Bad Image format")) ;
309  }
310 
311  if (mask) {
312  if (mask->depth != IPL_DEPTH_8U || I->nChannels != 1) {
313  throw(vpException(vpTrackingException::initializationError, "Bad Image format")) ;
314  }
315  }
316 
317  //Creation des buffers
318  CvSize Sizeim, SizeI;
319  SizeI = cvGetSize(I);
320  bool b_imOK = true;
321  if(image != NULL){
322  Sizeim = cvGetSize(image);
323  if(SizeI.width != Sizeim.width || SizeI.height != Sizeim.height) b_imOK = false;
324  }
325  if(image == NULL || prev_image == NULL || pyramid==NULL || prev_pyramid ==NULL || !b_imOK){
326  reset();
327  image = cvCreateImage(cvGetSize(I), 8, 1);image->origin = I->origin;
328  prev_image = cvCreateImage(cvGetSize(I), IPL_DEPTH_8U, 1);
329  pyramid = cvCreateImage(cvGetSize(I), IPL_DEPTH_8U, 1);
330  prev_pyramid = cvCreateImage(cvGetSize(I), IPL_DEPTH_8U, 1);
331  }else{
332  swap_temp = 0;
333  countFeatures = 0;
334  countPrevFeatures = 0;
335  flags = 0;
336  initialized = 0;
337  globalcountFeatures = 0;
338  }
339 
340  initialized = 1;
341 
342  //Import
343  cvCopy(I, image, 0);
344 
345  //Recherche de points d'int�rets
346  countFeatures = maxFeatures;
347  countPrevFeatures = 0;
348  IplImage* eig = cvCreateImage(cvGetSize(image), 32, 1);
349  IplImage* temp = cvCreateImage(cvGetSize(image), 32, 1);
350  cvGoodFeaturesToTrack(image, eig, temp, features,
351  &countFeatures, quality, min_distance,
352  mask, block_size, use_harris, harris_free_parameter);
353  cvFindCornerSubPix(image, features, countFeatures, cvSize(win_size, win_size),
354  cvSize(-1,-1),cvTermCriteria(CV_TERMCRIT_ITER|
355  CV_TERMCRIT_EPS,20,0.03));
356  cvReleaseImage(&eig);
357  cvReleaseImage(&temp);
358 
359  if (OnInitialize)
360  OnInitialize(_tid);
361 
362  //printf("Number of features at init: %d\n", countFeatures);
363  for (int boucle=0; boucle<countFeatures;boucle++) {
364  featuresid[boucle] = globalcountFeatures;
365  globalcountFeatures++;
366 
367  if (OnNewFeature){
368  OnNewFeature(_tid, boucle, featuresid[boucle], features[boucle].x,
369  features[boucle].y);
370  }
371  }
372 }
373 
374 
375 void vpKltOpencv::track(const IplImage *I)
376 {
377  if (!initialized) {
378  vpERROR_TRACE("KLT Not initialized") ;
380  "KLT Not initialized")) ;
381  }
382 
383  if (!I) {
385  "Image Not initialized")) ;
386  }
387 
388  if (I->depth != IPL_DEPTH_8U || I->nChannels != 1) {
390  "Bad Image format")) ;
391  }
392 
393 
394 
395  CV_SWAP(prev_image, image, swap_temp);
396  CV_SWAP(prev_pyramid, pyramid, swap_temp);
397 
398  cvCopy(I, image, 0);
399 
400  if(!initial_guess){
401  // Save current features as previous features
402  countPrevFeatures = countFeatures;
403  for (int boucle=0; boucle<countFeatures;boucle++) {
404  prev_featuresid[boucle] = featuresid[boucle];
405  }
406 
407  CvPoint2D32f *swap_features = 0;
408  CV_SWAP(prev_features, features, swap_features);
409  }
410 
411  if (countFeatures <= 0) return;
412 
413  cvCalcOpticalFlowPyrLK( prev_image, image, prev_pyramid, pyramid,
414  prev_features, features, countFeatures,
415  cvSize(win_size, win_size), pyramid_level,
416  status, 0, cvTermCriteria(CV_TERMCRIT_ITER
417  |CV_TERMCRIT_EPS,20,0.03),
418  flags );
419 
420  if(!initial_guess)
421  flags |= CV_LKFLOW_PYR_A_READY;
422  else{
423  flags = CV_LKFLOW_PYR_A_READY;
424  initial_guess = false;
425  }
426 
427  int i,k;
428  for (i = k = 0; i < countFeatures ; i++) {
429  if (!status[i]) {
430  lostDuringTrack[i] = 1;
431  if (OnFeatureLost)
432  OnFeatureLost(_tid, i, featuresid[i], features[i].x,
433  features[i].y);
434  continue;
435  }
436 
437  if (IsFeatureValid) {
438  if (!IsFeatureValid(_tid, features[i].x, features[i].y)) {
439  lostDuringTrack[i] = 1;
440  if (OnFeatureLost)
441  OnFeatureLost(_tid, i, featuresid[i], features[i].x, features[i].y);
442  continue;
443  }
444  }
445  features[k] = features[i];
446  featuresid[k] = featuresid[i];
447 
448  if (OnMeasureFeature) OnMeasureFeature(_tid, k, featuresid[k], features[k].x, features[k].y);
449 
450  lostDuringTrack[i] = 0;
451  k++;
452  }
453  countFeatures = k;
454 }
455 
464  vpColor color, unsigned int thickness)
465 {
466  if ((features == 0) || (I.bitmap==0) || (!initialized))
467  {
468  vpERROR_TRACE(" Memory problem ");
469  throw(vpException(vpException::memoryAllocationError," Memory problem"));
470  }
471 
472  vpKltOpencv::display(I, features, featuresid, countFeatures, color, thickness);
473 }
474 
488 void vpKltOpencv::getFeature(int index, int &id, float &x, float &y) const
489 {
490  if (index >= countFeatures)
491  {
492  vpERROR_TRACE(" Memory problem ");
493  throw(vpException(vpException::memoryAllocationError," Memory problem"));
494  }
495 
496  x = features[index].x;
497  y = features[index].y;
498  id = featuresid[index];
499 }
500 
501 
509 void
510 vpKltOpencv::setInitialGuess(CvPoint2D32f **guess_pts)
511 {
512  // Save current features as previous features
513  countPrevFeatures = countFeatures;
514  for (int boucle=0; boucle<countFeatures;boucle++) {
515  prev_featuresid[boucle] = featuresid[boucle];
516  }
517 
518  CvPoint2D32f *swap_features = NULL;
519  CV_SWAP(prev_features, *guess_pts, swap_features);
520 
521  CV_SWAP(features, prev_features, swap_features);
522 
523  flags |= CV_LKFLOW_INITIAL_GUESSES;
524 
525  initial_guess = true;
526 }
527 
536 void vpKltOpencv::getPrevFeature(int index, int &id, float &x, float &y) const
537 {
538  if (index >= countPrevFeatures)
539  {
540  vpERROR_TRACE(" Memory problem ");
541  throw(vpException(vpException::memoryAllocationError," Memory problem"));
542  }
543 
544  x = prev_features[index].x;
545  y = prev_features[index].y;
546  id = prev_featuresid[index];
547 }
548 
555 void vpKltOpencv::addFeature(const int &id,
556  const float &x, const float &y)
557 {
558  if (maxFeatures == countFeatures)
559  {
560  vpERROR_TRACE(" Cannot add the feature ");
561  return;
562  }
563 
564  CvPoint2D32f f;
565  f.x = x;
566  f.y = y;
567  features[countFeatures] = f;
568  featuresid[countFeatures] = id;
569  countFeatures ++;
570 }
571 
573 {
574  if (index >= countFeatures)
575  {
576  vpERROR_TRACE(" Memory problem ");
577  throw(vpException(vpException::memoryAllocationError," Memory problem"));
578  }
579 
580  countFeatures --;
581 
582  for (int i=index ; i < countFeatures; i ++) {
583  features[i] = features[i+1];
584  featuresid[i] = featuresid[i+1];
585  }
586 }
587 
602 void vpKltOpencv::display(const vpImage<unsigned char>& I,const CvPoint2D32f* features_list,
603  const int &nbFeatures, vpColor color, unsigned int thickness)
604 {
605  vpImagePoint ip;
606  for (int i = 0 ; i < nbFeatures ; i++)
607  {
608  ip.set_u( vpMath::round(features_list[i].x ) );
609  ip.set_v( vpMath::round(features_list[i].y ) );
610  vpDisplay::displayCross(I, ip, 10+thickness, color, thickness) ;
611  }
612 }
627 void vpKltOpencv::display(const vpImage<vpRGBa>& I,const CvPoint2D32f* features_list,
628  const int &nbFeatures, vpColor color, unsigned int thickness)
629 {
630  vpImagePoint ip;
631  for (int i = 0 ; i < nbFeatures ; i++)
632  {
633  ip.set_u( vpMath::round(features_list[i].x ) );
634  ip.set_v( vpMath::round(features_list[i].y ) );
635  vpDisplay::displayCross(I, ip, 10+thickness, color, thickness) ;
636  }
637 }
638 
655 void vpKltOpencv::display(const vpImage<unsigned char>& I,const CvPoint2D32f* features_list,
656  const long *featuresid_list, const int &nbFeatures,
657  vpColor color, unsigned int thickness)
658 {
659  vpImagePoint ip;
660  for (int i = 0 ; i < nbFeatures ; i++)
661  {
662  ip.set_u( vpMath::round(features_list[i].x ) );
663  ip.set_v( vpMath::round(features_list[i].y ) );
664  vpDisplay::displayCross(I, ip, 10+thickness, color, thickness) ;
665 
666  char id[10];
667  sprintf(id, "%ld", featuresid_list[i]);
668  ip.set_u( vpMath::round( features_list[i].x + 5 ) );
669  vpDisplay::displayCharString(I, ip, id, color);
670  }
671 }
672 
689 void vpKltOpencv::display(const vpImage<vpRGBa>& I,const CvPoint2D32f* features_list,
690  const long *featuresid_list, const int &nbFeatures,
691  vpColor color, unsigned int thickness)
692 {
693  vpImagePoint ip;
694  for (int i = 0 ; i < nbFeatures ; i++)
695  {
696  ip.set_u( vpMath::round(features_list[i].x ) );
697  ip.set_v( vpMath::round(features_list[i].y ) );
698  vpDisplay::displayCross(I, ip, 10, color, thickness) ;
699 
700  char id[10];
701  sprintf(id, "%ld", featuresid_list[i]);
702  ip.set_u( vpMath::round( features_list[i].x + 5 ) );
703  vpDisplay::displayCharString(I, ip, id, color);
704  }
705 }
706 
707 #endif
void track(const IplImage *I)
#define vpERROR_TRACE
Definition: vpDebug.h:379
Type * bitmap
points toward the bitmap
Definition: vpImage.h:120
Class to define colors available for display functionnalities.
Definition: vpColor.h:125
void addFeature(const int &id, const float &x, const float &y)
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1)
error that can be emited by ViSP classes.
Definition: vpException.h:75
void setInitialGuess(CvPoint2D32f **guess_pts)
virtual ~vpKltOpencv()
static int round(const double x)
Definition: vpMath.h:228
void getFeature(int index, int &id, float &x, float &y) const
void set_u(const double u)
Definition: vpImagePoint.h:203
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void set_v(const double v)
Definition: vpImagePoint.h:214
void getPrevFeature(int index, int &id, float &x, float &y) const
void initTracking(const IplImage *I, const IplImage *mask=NULL)
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
void suppressFeature(int index)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
void setMaxFeatures(const int input)