ViSP  2.6.2
vpKeyPointSurf.cpp
1 /****************************************************************************
2  *
3  * $Id: vpKeyPointSurf.cpp 3730 2012-05-14 17:09:58Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2012 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  * Key point Surf.
36  *
37  * Authors:
38  * Nicolas Melchior
39  *
40  *****************************************************************************/
41 
42 
43 #include <visp/vpKeyPointSurf.h>
44 
45 #if VISP_HAVE_OPENCV_VERSION >= 0x010100 // Require opencv >= 1.1.0
46 
47 #include <visp/vpImageConvert.h>
48 #include <visp/vpImageTools.h>
49 #include <visp/vpDisplay.h>
50 #include <visp/vpDebug.h>
51 
52 #include <ctype.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <vector>
56 #include <list>
57 
58 // Compare two surf descriptors.
59 double compareSURFDescriptors( const float* d1, const float* d2,
60  double best, int length )
61 {
62  double total_cost = 0;
63  int i;
64  assert( length % 4 == 0 );
65  for( i = 0; i < length; i += 4 )
66  {
67  double t0 = d1[i] - d2[i];
68  double t1 = d1[i+1] - d2[i+1];
69  double t2 = d1[i+2] - d2[i+2];
70  double t3 = d1[i+3] - d2[i+3];
71  total_cost += t0*t0 + t1*t1 + t2*t2 + t3*t3;
72  if( total_cost > best )
73  break;
74  }
75  return total_cost;
76 }
77 
78 
79 //Find for a point candidate the most similar point in the reference point list.
80 int naiveNearestNeighbor( const float *vec, int laplacian,
81  const CvSeq *model_keypoints,
82  const CvSeq *model_descriptors )
83 {
84  int length = (int)(model_descriptors->elem_size/(int)sizeof(float));
85  int i, neighbor = -1;
86  double d, dist1 = 1e6, dist2 = 1e6;
87  CvSeqReader reader, kreader;
88  cvStartReadSeq( model_keypoints, &kreader, 0 );
89  cvStartReadSeq( model_descriptors, &reader, 0 );
90 
91  for( i = 0; i < model_descriptors->total; i++ )
92  {
93  const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;
94  const float* mvec = (const float*)reader.ptr;
95  CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
96  CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
97  if( laplacian != kp->laplacian )
98  continue;
99  d = compareSURFDescriptors( vec, mvec, dist2, length );
100  if( d < dist1 )
101  {
102  dist2 = dist1;
103  dist1 = d;
104  neighbor = i;
105  }
106  else if ( d < dist2 )
107  dist2 = d;
108  }
109  if ( dist1 < 0.6*dist2 )
110  return neighbor;
111  return -1;
112 }
113 
114 
115 //Find for a point candidate the most similar point in the reference point list.
116 int naiveNearestNeighbor( const float *vec,
117  const CvSeq *ref_keypoints,
118  const CvSeq *ref_descriptors )
119 {
120  int length = (int)(ref_descriptors->elem_size/(int)sizeof(float));
121  int i, neighbor = -1;
122  double d, dist1 = 1e6, dist2 = 1e6;
123  CvSeqReader reader, kreader;
124  cvStartReadSeq( ref_keypoints, &kreader, 0 );
125  cvStartReadSeq( ref_descriptors, &reader, 0 );
126 
127  for( i = 0; i < ref_descriptors->total; i++ )
128  {
129  const float* mvec = (const float*)reader.ptr;
130  CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
131  CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
132  d = compareSURFDescriptors( vec, mvec, dist2, length );
133  if( d < dist1 )
134  {
135  dist2 = dist1;
136  dist1 = d;
137  neighbor = i;
138  }
139  else if ( d < dist2 )
140  dist2 = d;
141  }
142  if ( dist1 < 0.6*dist2 )
143  return neighbor;
144  return -1;
145 }
146 
147 
148 
149 //Find all the matched points
150 void findPairs( const CvSeq* objectKeypoints,
151  const CvSeq* objectDescriptors,
152  const CvSeq* imageKeypoints,
153  const CvSeq* imageDescriptors,
154  std::vector<int>& ptpairs )
155 {
156  int i;
157  CvSeqReader reader, kreader;
158  cvStartReadSeq( objectKeypoints, &kreader );
159  cvStartReadSeq( objectDescriptors, &reader );
160  ptpairs.clear();
161 
162  for( i = 0; i < objectDescriptors->total; i++ )
163  {
164  const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;
165  const float* descriptor = (const float*)reader.ptr;
166  CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
167  CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
168  int nearest_neighbor = naiveNearestNeighbor( descriptor,
169  kp->laplacian,
170  imageKeypoints,
171  imageDescriptors );
172  if( nearest_neighbor >= 0 )
173  {
174  ptpairs.push_back(i);
175  ptpairs.push_back(nearest_neighbor);
176  }
177  }
178 }
179 
180 
181 
190 {
191  descriptorType = extendedDescriptor;
192  hessianThreshold = 500;
193  init();
194 
195  image_keypoints = NULL;
196  image_descriptors = NULL;
197  ref_keypoints = NULL;
198  ref_descriptors = NULL;
199 
200  storage_cur = NULL;
201 }
202 
206 void vpKeyPointSurf::init()
207 {
208 #if (VISP_HAVE_OPENCV_VERSION >= 0x020400) // Require opencv >= 2.4.0
209  cv::initModule_nonfree();
210 #endif
211 
212  storage = cvCreateMemStorage(0);
213  params = cvSURFParams(hessianThreshold, descriptorType);
214 }
215 
221 {
222  cvReleaseMemStorage(&storage);
223  if(storage_cur!=NULL){
224  cvReleaseMemStorage(&storage_cur);
225  }
226 }
227 
238 {
239  IplImage* model = NULL;
240 
241  if((I.getWidth() % 8) == 0){
242  int height = (int)I.getHeight();
243  int width = (int)I.getWidth();
244  CvSize size = cvSize(width, height);
245  model = cvCreateImageHeader(size, IPL_DEPTH_8U, 1);
246  model->imageData = (char*)I.bitmap;
247  }else{
248  vpImageConvert::convert(I,model);
249  }
250 
251  cvExtractSURF( model, 0, &ref_keypoints, &ref_descriptors, storage, params );
252 
253  const unsigned int nbPoints = (unsigned int)ref_keypoints->total;
254 
255  referenceImagePointsList.resize(nbPoints);
256 
257  for(unsigned int i = 0; i < nbPoints; i++ )
258  {
259  CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem(ref_keypoints, (int)i);
260 
261  referenceImagePointsList[i].set_i(r1->pt.y);
262  referenceImagePointsList[i].set_j(r1->pt.x);
263  }
264 
265  if((I.getWidth() % 8) == 0){
266  model->imageData = NULL;
267  cvReleaseImageHeader(&model);
268  }else{
269  cvReleaseImage(&model);
270  }
271 
272  _reference_computed = true;
273  return nbPoints;
274 }
275 
276 
295  const vpImagePoint &iP,
296  const unsigned int height, const unsigned int width)
297 {
298  if((iP.get_i()+height) >= I.getHeight()
299  || (iP.get_j()+width) >= I.getWidth())
300  {
301  vpTRACE("Bad size for the subimage");
303  "Bad size for the subimage"));
304  }
305 
306  vpImage<unsigned char> subImage;
307 
309  (unsigned int)iP.get_i(),
310  (unsigned int)iP.get_j(),
311  height, width, subImage);
312 
313  unsigned int nbRefPoint = this->buildReference(subImage);
314 
315  for(unsigned int k = 0; k < nbRefPoint; k++)
316  {
317  (referenceImagePointsList[k]).set_i((referenceImagePointsList[k]).get_i()
318  + iP.get_i());
319  (referenceImagePointsList[k]).set_j((referenceImagePointsList[k]).get_j()
320  + iP.get_j());
321  }
322  return(nbRefPoint);
323 }
324 
325 
340  const vpRect& rectangle)
341 {
342  vpImagePoint iP;
343  iP.set_i(rectangle.getTop());
344  iP.set_j(rectangle.getLeft());
345  return (this->buildReference(I, iP,
346  (unsigned int)rectangle.getHeight(),
347  (unsigned int)rectangle.getWidth()));
348 }
349 
350 
362 {
363  IplImage* currentImage = NULL;
364 
365  if((I.getWidth() % 8) == 0){
366  int height = (int)I.getHeight();
367  int width = (int)I.getWidth();
368  CvSize size = cvSize(width, height);
369  currentImage = cvCreateImageHeader(size, IPL_DEPTH_8U, 1);
370  currentImage->imageData = (char*)I.bitmap;
371  }else{
372  vpImageConvert::convert(I,currentImage);
373  }
374 
375  /* we release the memory storage for the current points (it has to be kept
376  allocated for the get descriptor points, ...) */
377  if(storage_cur != NULL){
378  cvReleaseMemStorage(&storage_cur);
379  storage_cur = NULL;
380  }
381  storage_cur = cvCreateMemStorage(0);
382 
383  cvExtractSURF( currentImage, 0, &image_keypoints, &image_descriptors,
384  storage_cur, params );
385 
386  CvSeqReader reader, kreader;
387  cvStartReadSeq( ref_keypoints, &kreader );
388  cvStartReadSeq( ref_descriptors, &reader );
389 
390 
391  std::list<int> indexImagePair;
392  std::list<int> indexReferencePair;
393 
394 
395  unsigned int nbrPair = 0;
396 
397  for(int i = 0; i < ref_descriptors->total; i++ )
398  {
399  const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;
400  const float* descriptor = (const float*)reader.ptr;
401  CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
402  CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
403  int nearest_neighbor = naiveNearestNeighbor( descriptor,
404  kp->laplacian,
405  image_keypoints,
406  image_descriptors );
407  if( nearest_neighbor >= 0 )
408  {
409  indexReferencePair.push_back(i);
410  indexImagePair.push_back(nearest_neighbor);
411  nbrPair++;
412  }
413  }
414 
415  std::list<int>::const_iterator indexImagePairIter = indexImagePair.begin();
416  std::list<int>::const_iterator indexReferencePairIter = indexReferencePair.begin();
417 
418  matchedReferencePoints.resize(0);
419 
420  if (nbrPair == 0)
421  return (0);
422 
423  currentImagePointsList.resize(nbrPair);
424  matchedReferencePoints.resize(nbrPair);
425 
426  for (unsigned int i = 0; i < nbrPair; i++)
427  {
428  int index = *indexImagePairIter;
429 
430  CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem(image_keypoints, index);
431 
432  currentImagePointsList[i].set_i(r1->pt.y);
433  currentImagePointsList[i].set_j(r1->pt.x);
434 
435  matchedReferencePoints[i] = (unsigned int)*indexReferencePairIter;
436 
437 
438  ++indexImagePairIter;
439  ++indexReferencePairIter;
440  }
441 
442  if((I.getWidth() % 8) == 0){
443  currentImage->imageData = NULL;
444  cvReleaseImageHeader(&currentImage);
445  }else{
446  cvReleaseImage(&currentImage);
447  }
448 
449  return nbrPair;
450 }
451 
452 
472  const vpImagePoint &iP,
473  const unsigned int height, const unsigned int width)
474 {
475  if((iP.get_i()+height) >= I.getHeight()
476  || (iP.get_j()+width) >= I.getWidth())
477  {
478  vpTRACE("Bad size for the subimage");
480  "Bad size for the subimage"));
481  }
482 
483  vpImage<unsigned char> subImage;
484 
486  (unsigned int)iP.get_i(),
487  (unsigned int)iP.get_j(),
488  height, width, subImage);
489 
490  unsigned int nbMatchedPoint = this->matchPoint(subImage);
491 
492  for(unsigned int k = 0; k < nbMatchedPoint; k++)
493  {
494  (currentImagePointsList[k]).set_i((currentImagePointsList[k]).get_i()
495  + iP.get_i());
496  (currentImagePointsList[k]).set_j((currentImagePointsList[k]).get_j()
497  + iP.get_j());
498  }
499 
500  return(nbMatchedPoint);
501 }
502 
503 
519  const vpRect& rectangle)
520 {
521  vpImagePoint iP;
522  iP.set_i(rectangle.getTop());
523  iP.set_j(rectangle.getLeft());
524  return (this->matchPoint(I, iP,
525  (unsigned int)rectangle.getHeight(),
526  (unsigned int)rectangle.getWidth()));
527 }
528 
529 
549  const vpImage<unsigned char> &Icurrent, unsigned int size)
550 {
551 // matchedPointsCurrentImageList.front();
552 // matchedPointsReferenceImageList.front();
553 
554 // if (matchedPointsCurrentImageList.nbElements()
555 // != matchedPointsReferenceImageList.nbElements())
556 // {
557 // vpTRACE("Numbers of points mismatch");
558 // throw(vpException(vpException::fatalError,"Numbers of points mismatch"));
559 // }
560 
561  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++)
562  {
565 // matchedPointsReferenceImageList.next();
566 // matchedPointsCurrentImageList.next();
567  }
568 }
569 
570 
583 void vpKeyPointSurf::display(const vpImage<unsigned char> &Icurrent, unsigned int size, const vpColor &color)
584 {
585 // matchedPointsCurrentImageList.front();
586 //
587 // vpImagePoint ipCur;
588 //
589  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++)
590  {
591  vpDisplay::displayCross (Icurrent, currentImagePointsList[i], size, color);
592  }
593 }
594 
595 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
596 
615 vp_deprecated vpList<int*>* vpKeyPointSurf::matchPoint(vpList<float*> descriptorList, vpList<int> laplacianList)
616 {
617  vpList<int*>* pairPoints = new vpList<int*>;
618 
619  if(descriptorList.nb != laplacianList.nb){
620  vpTRACE("Error, the two lists have different number of element");
621  return pairPoints;
622  }
623 
624  CvSeqReader reader;
625  cvStartReadSeq( ref_descriptors, &reader );
626 
627  descriptorList.front();
628  pairPoints->front();
629  laplacianList.front();
630  int indexList = 0;
631  while(!descriptorList.outside()){
632  float* descriptor = descriptorList.value();
633 
634  int nearest_neighbor = naiveNearestNeighbor( descriptor, laplacianList.value(), ref_keypoints, ref_descriptors);
635 
636  if(nearest_neighbor >= 0){
637  int* tab;
638  tab = new int[2];
639  tab[0] = nearest_neighbor;
640  tab[1] = indexList;
641  pairPoints->addRight(tab);
642  }
643  indexList++;
644  descriptorList.next();
645  laplacianList.next();
646  }
647 
648  return pairPoints;
649 }
650 #endif
651 
652 std::list<int*>* vpKeyPointSurf::matchPoint(std::list<float*> descriptorList, std::list<int> laplacianList)
653 {
654  std::list<int*>* pairPoints = new std::list<int*>;
655 
656  if(descriptorList.size() != laplacianList.size()){
657  vpTRACE("Error, the two lists have different number of element");
658  return pairPoints;
659  }
660 
661  CvSeqReader reader;
662  cvStartReadSeq( ref_descriptors, &reader );
663 
664  std::list<float*>::const_iterator descriptorListIter = descriptorList.begin();
665  std::list<int>::const_iterator laplacianListIter = laplacianList.begin();
666  descriptorList.front();
667  int indexList = 0;
668  while(descriptorListIter != descriptorList.end()){
669  float* descriptor = *descriptorListIter;
670 
671  int nearest_neighbor = naiveNearestNeighbor( descriptor, *laplacianListIter, ref_keypoints, ref_descriptors);
672 
673  if(nearest_neighbor >= 0){
674  int* tab;
675  tab = new int[2];
676  tab[0] = nearest_neighbor;
677  tab[1] = indexList;
678  pairPoints->push_back(tab);
679  }
680  indexList++;
681  ++descriptorListIter;
682  ++laplacianListIter;
683  }
684 
685  return pairPoints;
686 }
687 
694 {
695  if (index >= static_cast<int>(referenceImagePointsList.size()) || index < 0){
696  vpTRACE("Index of the reference point out of range");
697  throw(vpException(vpException::fatalError,"Index of the refrence point out of range"));
698  }
699 
700  float* descriptor = NULL;
701 
702  CvSeqReader reader;
703  cvStartReadSeq( ref_descriptors, &reader );
704 
705  for(int j = 0; j < ref_descriptors->total; j++ ){
706  if(j== index){
707  descriptor = (float*)reader.ptr;
708  break;
709  }
710  CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
711  }
712 
713  return descriptor;
714 }
715 
722 {
723  if (index >= static_cast<int>(referenceImagePointsList.size()) || index < 0){
724  vpTRACE("Index of the reference point out of range");
725  throw(vpException(vpException::fatalError,"Index of the refrence point out of range"));
726  }
727 
728  CvSeqReader reader;
729  cvStartReadSeq( ref_keypoints, &reader );
730 
731  int laplacian = 0;/* normally only -1, 0, +1 are possible */
732 
733  for(int j = 0; j < ref_keypoints->total; j++ ){
734  if(j== index){
735  const CvSURFPoint* kp = (const CvSURFPoint*)reader.ptr;
736  laplacian = kp->laplacian;
737  break;
738  }
739  CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
740  }
741 
742  return laplacian;
743 }
744 
752 void vpKeyPointSurf::getDescriptorParamReferencePoint (const int index, int& size, float& dir)
753 {
754  if (index >= static_cast<int>(referenceImagePointsList.size()) || index < 0){
755  vpTRACE("Index of the reference point out of range");
756  throw(vpException(vpException::fatalError,"Index of the refrence point out of range"));
757  }
758 
759  CvSeqReader reader;
760  cvStartReadSeq( ref_keypoints, &reader );
761 
762  for(int j = 0; j < ref_keypoints->total; j++ ){
763  if(j== index){
764  const CvSURFPoint* kp = (const CvSURFPoint*)reader.ptr;
765  size = kp->size;
766  dir = kp->dir;
767  break;
768  }
769  CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
770  }
771 }
772 
773 
774 #endif
775 
776 
777 /*
778  * Local variables:
779  * c-basic-offset: 4
780  * End:
781  */
782 
void set_j(const double j)
Definition: vpImagePoint.h:156
class that defines what is a Keypoint. This class provides all the basic elements to implement classe...
double getTop() const
Definition: vpRect.h:169
void getDescriptorParamReferencePoint(const int index, int &size, float &dir)
double get_i() const
Definition: vpImagePoint.h:181
bool outside(void) const
Test if the current element is outside the list (on the virtual element)
Definition: vpList.h:431
unsigned int getWidth() const
Definition: vpImage.h:154
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
#define vpTRACE
Definition: vpDebug.h:401
Provide simple list management.
Definition: vpList.h:112
Type * bitmap
points toward the bitmap
Definition: vpImage.h:115
Class to define colors available for display functionnalities.
Definition: vpColor.h:123
int getLaplacianReferencePoint(const int index)
void set_i(const double i)
Definition: vpImagePoint.h:145
unsigned int matchPoint(const vpImage< unsigned char > &I)
double getHeight() const
Definition: vpRect.h:150
void display(const vpImage< unsigned char > &Iref, const vpImage< unsigned char > &Icurrent, unsigned int size=3)
static const vpColor green
Definition: vpColor.h:168
double get_j() const
Definition: vpImagePoint.h:192
void next(void)
position the current element on the next one
Definition: vpList.h:275
static const vpColor red
Definition: vpColor.h:165
double getWidth() const
Definition: vpRect.h:188
unsigned int nb
Definition: vpList.h:118
void front(void)
Position the current element on the first element of the list.
Definition: vpList.h:386
float * getDescriptorReferencePoint(const int index)
type & value(void)
return the value of the current element
Definition: vpList.h:303
bool _reference_computed
flag to indicate if the reference has been built.
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void addRight(const type &el)
add a new element in the list, at the right of the current one
Definition: vpList.h:480
std::vector< vpImagePoint > referenceImagePointsList
unsigned int buildReference(const vpImage< unsigned char > &I)
static void createSubImage(const vpImage< Type > &I, unsigned int i_sub, unsigned int j_sub, unsigned int nrow_sub, unsigned int ncol_sub, vpImage< Type > &S)
Definition: vpImageTools.h:129
std::vector< unsigned int > matchedReferencePoints
unsigned int getHeight() const
Definition: vpImage.h:145
Defines a rectangle in the plane.
Definition: vpRect.h:82
std::vector< vpImagePoint > currentImagePointsList
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
double getLeft() const
Definition: vpRect.h:156
virtual ~vpKeyPointSurf()