1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Key point Surf.
33  *
34  * Authors:
35  * Nicolas Melchior
36  *
37  *****************************************************************************/
38 
39 #include <visp3/vision/vpKeyPointSurf.h>
40 
41 #if defined(VISP_HAVE_OPENCV_NONFREE) && (VISP_HAVE_OPENCV_VERSION < 0x030000)
42 
43 #include <visp3/core/vpDebug.h>
44 #include <visp3/core/vpDisplay.h>
45 #include <visp3/core/vpImageConvert.h>
46 #include <visp3/core/vpImageTools.h>
47 
48 #include <ctype.h>
49 #include <list>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <vector>
53 
54 double compareSURFDescriptors(const float *d1, const float *d2, double best, int length);
55 int naiveNearestNeighbor(const float *vec, int laplacian, const CvSeq *model_keypoints, const CvSeq *model_descriptors);
56 int naiveNearestNeighbor(const float *vec, const CvSeq *ref_keypoints, const CvSeq *ref_descriptors);
57 void findPairs(const CvSeq *objectKeypoints, const CvSeq *objectDescriptors, const CvSeq *imageKeypoints,
58                const CvSeq *imageDescriptors, std::vector<int> &ptpairs);
59 
60 // Compare two surf descriptors.
compareSURFDescriptors(const float * d1,const float * d2,double best,int length)61 double compareSURFDescriptors(const float *d1, const float *d2, double best, int length)
62 {
63   double total_cost = 0;
64   int i;
65   assert(length % 4 == 0);
66   for (i = 0; i < length; i += 4) {
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 // Find for a point candidate the most similar point in the reference point
79 // list.
naiveNearestNeighbor(const float * vec,int laplacian,const CvSeq * model_keypoints,const CvSeq * model_descriptors)80 int naiveNearestNeighbor(const float *vec, int laplacian, const CvSeq *model_keypoints, const CvSeq *model_descriptors)
81 {
82   int length = (int)(model_descriptors->elem_size / (int)sizeof(float));
83   int i, neighbor = -1;
84   double d, dist1 = 1e6, dist2 = 1e6;
85   CvSeqReader reader, kreader;
86   cvStartReadSeq(model_keypoints, &kreader, 0);
87   cvStartReadSeq(model_descriptors, &reader, 0);
88 
89   for (i = 0; i < model_descriptors->total; i++) {
90     const CvSURFPoint *kp = (const CvSURFPoint *)kreader.ptr;
91     const float *mvec = (const float *)reader.ptr;
92     CV_NEXT_SEQ_ELEM(kreader.seq->elem_size, kreader);
93     CV_NEXT_SEQ_ELEM(reader.seq->elem_size, reader);
94     if (laplacian != kp->laplacian)
95       continue;
96     d = compareSURFDescriptors(vec, mvec, dist2, length);
97     if (d < dist1) {
98       dist2 = dist1;
99       dist1 = d;
100       neighbor = i;
101     } else if (d < dist2)
102       dist2 = d;
103   }
104   if (dist1 < 0.6 * dist2)
105     return neighbor;
106   return -1;
107 }
108 
109 // Find for a point candidate the most similar point in the reference point
110 // list.
naiveNearestNeighbor(const float * vec,const CvSeq * ref_keypoints,const CvSeq * ref_descriptors)111 int naiveNearestNeighbor(const float *vec, const CvSeq *ref_keypoints, const CvSeq *ref_descriptors)
112 {
113   int length = (int)(ref_descriptors->elem_size / (int)sizeof(float));
114   int i, neighbor = -1;
115   double dist1 = 1e6, dist2 = 1e6;
116   CvSeqReader reader, kreader;
117   cvStartReadSeq(ref_keypoints, &kreader, 0);
118   cvStartReadSeq(ref_descriptors, &reader, 0);
119 
120   for (i = 0; i < ref_descriptors->total; i++) {
121     const float *mvec = (const float *)reader.ptr;
122     CV_NEXT_SEQ_ELEM(kreader.seq->elem_size, kreader);
123     CV_NEXT_SEQ_ELEM(reader.seq->elem_size, reader);
124     double d = compareSURFDescriptors(vec, mvec, dist2, length);
125     if (d < dist1) {
126       dist2 = dist1;
127       dist1 = d;
128       neighbor = i;
129     } else if (d < dist2)
130       dist2 = d;
131   }
132   if (dist1 < 0.6 * dist2)
133     return neighbor;
134   return -1;
135 }
136 
137 // Find all the matched points
findPairs(const CvSeq * objectKeypoints,const CvSeq * objectDescriptors,const CvSeq * imageKeypoints,const CvSeq * imageDescriptors,std::vector<int> & ptpairs)138 void findPairs(const CvSeq *objectKeypoints, const CvSeq *objectDescriptors, const CvSeq *imageKeypoints,
139                const CvSeq *imageDescriptors, std::vector<int> &ptpairs)
140 {
141   int i;
142   CvSeqReader reader, kreader;
143   cvStartReadSeq(objectKeypoints, &kreader);
144   cvStartReadSeq(objectDescriptors, &reader);
145   ptpairs.clear();
146 
147   for (i = 0; i < objectDescriptors->total; i++) {
148     const CvSURFPoint *kp = (const CvSURFPoint *)kreader.ptr;
149     const float *descriptor = (const float *)reader.ptr;
150     CV_NEXT_SEQ_ELEM(kreader.seq->elem_size, kreader);
151     CV_NEXT_SEQ_ELEM(reader.seq->elem_size, reader);
152     int nearest_neighbor = naiveNearestNeighbor(descriptor, kp->laplacian, imageKeypoints, imageDescriptors);
153     if (nearest_neighbor >= 0) {
154       ptpairs.push_back(i);
155       ptpairs.push_back(nearest_neighbor);
156     }
157   }
158 }
159 
160 /*!
161 
162   Basic constructor. It sets by default the hessian threshold to 500
163   (a good default value is between 300 and 500) and the descriptor
164   type to extended.
165 
166 */
vpKeyPointSurf()167 vpKeyPointSurf::vpKeyPointSurf()
168   : vpBasicKeyPoint(), storage(NULL), params(), storage_cur(NULL), image_keypoints(NULL), image_descriptors(NULL),
169     ref_keypoints(NULL), ref_descriptors(NULL), hessianThreshold(500), descriptorType(extendedDescriptor)
170 {
171   init();
172 }
173 
174 /*!
175   Initialize any OpenCV parameters.
176 */
init()177 void vpKeyPointSurf::init()
178 {
179 #if (VISP_HAVE_OPENCV_VERSION >= 0x020400) // Require opencv >= 2.4.0
180   cv::initModule_nonfree();
181 #endif
182 
183   storage = cvCreateMemStorage(0);
184   params = cvSURFParams(hessianThreshold, descriptorType);
185 }
186 
187 /*!
188   Basic Destructor
189 
190 */
~vpKeyPointSurf()191 vpKeyPointSurf::~vpKeyPointSurf()
192 {
193   cvReleaseMemStorage(&storage);
194   if (storage_cur != NULL) {
195     cvReleaseMemStorage(&storage_cur);
196   }
197 }
198 
199 /*!
200 
201   Build the list of reference points. The computation of the points is
202   made all over the image I.
203 
204   \param I : The gray scaled image where the reference points are computed.
205 
206   \return the number of reference points.
207 */
buildReference(const vpImage<unsigned char> & I)208 unsigned int vpKeyPointSurf::buildReference(const vpImage<unsigned char> &I)
209 {
210   IplImage *model = NULL;
211 
212   if ((I.getWidth() % 8) == 0) {
213     int height = (int)I.getHeight();
214     int width = (int)I.getWidth();
215     CvSize size = cvSize(width, height);
216     model = cvCreateImageHeader(size, IPL_DEPTH_8U, 1);
217     model->imageData = (char *)I.bitmap;
218   } else {
219     vpImageConvert::convert(I, model);
220   }
221 
222   cvExtractSURF(model, 0, &ref_keypoints, &ref_descriptors, storage, params);
223 
224   unsigned int nbPoints = (unsigned int)ref_keypoints->total;
225 
226   referenceImagePointsList.resize(nbPoints);
227 
228   for (unsigned int i = 0; i < nbPoints; i++) {
229     CvSURFPoint *r1 = (CvSURFPoint *)cvGetSeqElem(ref_keypoints, (int)i);
230 
231     referenceImagePointsList[i].set_i(r1->pt.y);
232     referenceImagePointsList[i].set_j(r1->pt.x);
233   }
234 
235   if ((I.getWidth() % 8) == 0) {
236     model->imageData = NULL;
237     cvReleaseImageHeader(&model);
238   } else {
239     cvReleaseImage(&model);
240   }
241 
242   _reference_computed = true;
243   return nbPoints;
244 }
245 
246 /*!
247 
248   Build the list of reference points. The computation of the points is
249   made only on a part of the image. This part is a rectangle defined
250   by its top left corner, its height and its width. The parameters of
251   this rectangle must be given in pixel.
252 
253   \param I : The gray scaled image where the reference points are computed.
254 
255   \param iP : The top left corner of the rectangle.
256 
257   \param height : height of the rectangle (in pixel).
258 
259   \param width : width of the rectangle (in pixel).
260 
261   \return the number of reference points.
262 */
buildReference(const vpImage<unsigned char> & I,const vpImagePoint & iP,unsigned int height,unsigned int width)263 unsigned int vpKeyPointSurf::buildReference(const vpImage<unsigned char> &I, const vpImagePoint &iP,
264                                             unsigned int height, unsigned int width)
265 {
266   if ((iP.get_i() + height) >= I.getHeight() || (iP.get_j() + width) >= I.getWidth()) {
267     vpTRACE("Bad size for the subimage");
268     throw(vpException(vpImageException::notInTheImage, "Bad size for the subimage"));
269   }
270 
271   vpImage<unsigned char> subImage;
272 
273   vpImageTools::crop(I, (unsigned int)iP.get_i(), (unsigned int)iP.get_j(), height, width, subImage);
274 
275   unsigned int nbRefPoint = this->buildReference(subImage);
276 
277   for (unsigned int k = 0; k < nbRefPoint; k++) {
278     (referenceImagePointsList[k]).set_i((referenceImagePointsList[k]).get_i() + iP.get_i());
279     (referenceImagePointsList[k]).set_j((referenceImagePointsList[k]).get_j() + iP.get_j());
280   }
281   return (nbRefPoint);
282 }
283 
284 /*!
285 
286   Build the list of reference points. The computation of the points is
287   made only on a part of the image. This part is a rectangle. The
288   parameters of this rectangle must be given in pixel.
289 
290   \param I : The gray scaled image where the reference points are computed.
291 
292   \param rectangle : The rectangle which defines the interesting part
293   of the image.
294 
295   \return the number of reference points.
296 */
buildReference(const vpImage<unsigned char> & I,const vpRect & rectangle)297 unsigned int vpKeyPointSurf::buildReference(const vpImage<unsigned char> &I, const vpRect &rectangle)
298 {
299   vpImagePoint iP;
300   iP.set_i(rectangle.getTop());
301   iP.set_j(rectangle.getLeft());
302   return (this->buildReference(I, iP, (unsigned int)rectangle.getHeight(), (unsigned int)rectangle.getWidth()));
303 }
304 
305 /*!
306 
307   Computes the SURF points in the current image I and try to matched
308   them with the points in the reference list. Only the matched points
309   are stored.
310 
311   \param I : The gray scaled image where the points are computed.
312 
313   \return the number of point which have been matched.
314 */
matchPoint(const vpImage<unsigned char> & I)315 unsigned int vpKeyPointSurf::matchPoint(const vpImage<unsigned char> &I)
316 {
317   IplImage *currentImage = NULL;
318 
319   if ((I.getWidth() % 8) == 0) {
320     int height = (int)I.getHeight();
321     int width = (int)I.getWidth();
322     CvSize size = cvSize(width, height);
323     currentImage = cvCreateImageHeader(size, IPL_DEPTH_8U, 1);
324     currentImage->imageData = (char *)I.bitmap;
325   } else {
326     vpImageConvert::convert(I, currentImage);
327   }
328 
329   /* we release the memory storage for the current points (it has to be kept
330       allocated for the get descriptor points, ...) */
331   if (storage_cur != NULL) {
332     cvReleaseMemStorage(&storage_cur);
333     storage_cur = NULL;
334   }
335   storage_cur = cvCreateMemStorage(0);
336 
337   cvExtractSURF(currentImage, 0, &image_keypoints, &image_descriptors, storage_cur, params);
338 
339   CvSeqReader reader, kreader;
340   cvStartReadSeq(ref_keypoints, &kreader);
341   cvStartReadSeq(ref_descriptors, &reader);
342 
343   std::list<int> indexImagePair;
344   std::list<int> indexReferencePair;
345 
346   unsigned int nbrPair = 0;
347 
348   for (int i = 0; i < ref_descriptors->total; i++) {
349     const CvSURFPoint *kp = (const CvSURFPoint *)kreader.ptr;
350     const float *descriptor = (const float *)reader.ptr;
351     CV_NEXT_SEQ_ELEM(kreader.seq->elem_size, kreader);
352     CV_NEXT_SEQ_ELEM(reader.seq->elem_size, reader);
353     int nearest_neighbor = naiveNearestNeighbor(descriptor, kp->laplacian, image_keypoints, image_descriptors);
354     if (nearest_neighbor >= 0) {
355       indexReferencePair.push_back(i);
356       indexImagePair.push_back(nearest_neighbor);
357       nbrPair++;
358     }
359   }
360 
361   std::list<int>::const_iterator indexImagePairIter = indexImagePair.begin();
362   std::list<int>::const_iterator indexReferencePairIter = indexReferencePair.begin();
363 
364   matchedReferencePoints.resize(0);
365 
366   if (nbrPair == 0)
367     return (0);
368 
369   currentImagePointsList.resize(nbrPair);
370   matchedReferencePoints.resize(nbrPair);
371 
372   for (unsigned int i = 0; i < nbrPair; i++) {
373     int index = *indexImagePairIter;
374 
375     CvSURFPoint *r1 = (CvSURFPoint *)cvGetSeqElem(image_keypoints, index);
376 
377     currentImagePointsList[i].set_i(r1->pt.y);
378     currentImagePointsList[i].set_j(r1->pt.x);
379 
380     matchedReferencePoints[i] = (unsigned int)*indexReferencePairIter;
381 
382     ++indexImagePairIter;
383     ++indexReferencePairIter;
384   }
385 
386   if ((I.getWidth() % 8) == 0) {
387     currentImage->imageData = NULL;
388     cvReleaseImageHeader(&currentImage);
389   } else {
390     cvReleaseImage(&currentImage);
391   }
392 
393   return nbrPair;
394 }
395 
396 /*!
397 
398   Computes the SURF points in only a part of the current image I and
399   try to matched them with the points in the reference list. The part
400   of the image is a rectangle defined by its top left corner, its
401   height and its width. The parameters of this rectangle must be given
402   in pixel. Only the matched points are stored.
403 
404   \param I : The gray scaled image where the points are computed.
405 
406   \param iP : The top left corner of the rectangle.
407 
408   \param height : height of the rectangle (in pixel).
409 
410   \param width : width of the rectangle (in pixel).
411 
412   \return the number of point which have been matched.
413 */
matchPoint(const vpImage<unsigned char> & I,const vpImagePoint & iP,unsigned int height,unsigned int width)414 unsigned int vpKeyPointSurf::matchPoint(const vpImage<unsigned char> &I, const vpImagePoint &iP,
415                                         unsigned int height, unsigned int width)
416 {
417   if ((iP.get_i() + height) >= I.getHeight() || (iP.get_j() + width) >= I.getWidth()) {
418     vpTRACE("Bad size for the subimage");
419     throw(vpException(vpImageException::notInTheImage, "Bad size for the subimage"));
420   }
421 
422   vpImage<unsigned char> subImage;
423 
424   vpImageTools::crop(I, (unsigned int)iP.get_i(), (unsigned int)iP.get_j(), height, width, subImage);
425 
426   unsigned int nbMatchedPoint = this->matchPoint(subImage);
427 
428   for (unsigned int k = 0; k < nbMatchedPoint; k++) {
429     (currentImagePointsList[k]).set_i((currentImagePointsList[k]).get_i() + iP.get_i());
430     (currentImagePointsList[k]).set_j((currentImagePointsList[k]).get_j() + iP.get_j());
431   }
432 
433   return (nbMatchedPoint);
434 }
435 
436 /*!
437 
438   Computes the SURF points in only a part of the current image I and
439   try to matched them with the points in the reference list. The part
440   of the image is a rectangle. The parameters of this rectangle must
441   be given in pixel. Only the matched points are stored.
442 
443   \param I : The gray scaled image where the points are computed.
444 
445   \param rectangle : The rectangle which defines the interesting part
446   of the image.
447 
448   \return the number of point which have been matched.
449 */
matchPoint(const vpImage<unsigned char> & I,const vpRect & rectangle)450 unsigned int vpKeyPointSurf::matchPoint(const vpImage<unsigned char> &I, const vpRect &rectangle)
451 {
452   vpImagePoint iP;
453   iP.set_i(rectangle.getTop());
454   iP.set_j(rectangle.getLeft());
455   return (this->matchPoint(I, iP, (unsigned int)rectangle.getHeight(), (unsigned int)rectangle.getWidth()));
456 }
457 
458 /*!
459 
460   This function displays the matched reference points and the matched
461   points computed in the current image. The reference points are
462   displayed in the image Ireference and the matched points coming from
463   the current image are displayed in the image Icurrent. It is
464   possible to set Ireference and Icurrent with the same image when
465   calling the method.
466 
467   \param Ireference : The image where the matched reference points are
468   displayed.
469 
470   \param Icurrent : The image where the matched points computed in the
471   current image are displayed.
472 
473   \param size : Size in pixels of the cross that is used to display matched
474   points.
475 
476 */
display(const vpImage<unsigned char> & Ireference,const vpImage<unsigned char> & Icurrent,unsigned int size)477 void vpKeyPointSurf::display(const vpImage<unsigned char> &Ireference, const vpImage<unsigned char> &Icurrent,
478                              unsigned int size)
479 {
480   //  matchedPointsCurrentImageList.front();
481   //  matchedPointsReferenceImageList.front();
482 
483   //   if (matchedPointsCurrentImageList.nbElements()
484   //       != matchedPointsReferenceImageList.nbElements())
485   //   {
486   //     vpTRACE("Numbers of points mismatch");
487   //     throw(vpException(vpException::fatalError,"Numbers of points
488   //     mismatch"));
489   //   }
490 
491   for (unsigned int i = 0; i < matchedReferencePoints.size(); i++) {
492     vpDisplay::displayCross(Ireference, referenceImagePointsList[matchedReferencePoints[i]], size, vpColor::red);
493     vpDisplay::displayCross(Icurrent, currentImagePointsList[i], size, vpColor::green);
494     //       matchedPointsReferenceImageList.next();
495     //       matchedPointsCurrentImageList.next();
496   }
497 }
498 
499 /*!
500 
501   This function displays only the matched points computed in the
502   current image. They are displayed in the image Icurrent.
503 
504   \param Icurrent : The image where the matched points computed in the
505   current image are displayed.
506 
507   \param size : Size in pixels of the cross that is used to display matched
508   points.
509 
510   \param color : Color used to display the matched points.
511 */
display(const vpImage<unsigned char> & Icurrent,unsigned int size,const vpColor & color)512 void vpKeyPointSurf::display(const vpImage<unsigned char> &Icurrent, unsigned int size, const vpColor &color)
513 {
514   //   matchedPointsCurrentImageList.front();
515   //
516   //   vpImagePoint ipCur;
517   //
518   for (unsigned int i = 0; i < matchedReferencePoints.size(); i++) {
519     vpDisplay::displayCross(Icurrent, currentImagePointsList[i], size, color);
520   }
521 }
522 
matchPoint(std::list<float * > descriptorList,std::list<int> laplacianList)523 std::list<int *> *vpKeyPointSurf::matchPoint(std::list<float *> descriptorList, std::list<int> laplacianList)
524 {
525   std::list<int *> *pairPoints = new std::list<int *>;
526 
527   if (descriptorList.size() != laplacianList.size()) {
528     vpTRACE("Error, the two lists have different number of element");
529     return pairPoints;
530   }
531 
532   CvSeqReader reader;
533   cvStartReadSeq(ref_descriptors, &reader);
534 
535   std::list<float *>::const_iterator descriptorListIter = descriptorList.begin();
536   std::list<int>::const_iterator laplacianListIter = laplacianList.begin();
537   descriptorList.front();
538   int indexList = 0;
539   while (descriptorListIter != descriptorList.end()) {
540     float *descriptor = *descriptorListIter;
541 
542     int nearest_neighbor = naiveNearestNeighbor(descriptor, *laplacianListIter, ref_keypoints, ref_descriptors);
543 
544     if (nearest_neighbor >= 0) {
545       int *tab;
546       tab = new int[2];
547       tab[0] = nearest_neighbor;
548       tab[1] = indexList;
549       pairPoints->push_back(tab);
550     }
551     indexList++;
552     ++descriptorListIter;
553     ++laplacianListIter;
554   }
555 
556   return pairPoints;
557 }
558 
559 /*!
560   Get the descriptor of the nth reference point.
561 
562  \param index : The index of the desired reference point. The index must be
563  between 0 and the number of reference points - 1.
564 */
getDescriptorReferencePoint(int index)565 float *vpKeyPointSurf::getDescriptorReferencePoint(int index)
566 {
567   if (index >= static_cast<int>(referenceImagePointsList.size()) || index < 0) {
568     vpTRACE("Index of the reference point out of range");
569     throw(vpException(vpException::fatalError, "Index of the reference point out of range"));
570   }
571 
572   float *descriptor = NULL;
573 
574   CvSeqReader reader;
575   cvStartReadSeq(ref_descriptors, &reader);
576 
577   for (int j = 0; j < ref_descriptors->total; j++) {
578     if (j == index) {
579       descriptor = (float *)reader.ptr;
580       break;
581     }
582     CV_NEXT_SEQ_ELEM(reader.seq->elem_size, reader);
583   }
584 
585   return descriptor;
586 }
587 
588 /*!
589   Get the laplacian of the nth reference point.
590 
591  \param index : The index of the desired reference point. The index must be
592  between 0 and the number of reference points - 1.
593 */
getLaplacianReferencePoint(int index)594 int vpKeyPointSurf::getLaplacianReferencePoint(int index)
595 {
596   if (index >= static_cast<int>(referenceImagePointsList.size()) || index < 0) {
597     vpTRACE("Index of the reference point out of range");
598     throw(vpException(vpException::fatalError, "Index of the reference point out of range"));
599   }
600 
601   CvSeqReader reader;
602   cvStartReadSeq(ref_keypoints, &reader);
603 
604   int laplacian = 0; /* normally only -1, 0, +1 are possible */
605 
606   for (int j = 0; j < ref_keypoints->total; j++) {
607     if (j == index) {
608       const CvSURFPoint *kp = (const CvSURFPoint *)reader.ptr;
609       laplacian = kp->laplacian;
610       break;
611     }
612     CV_NEXT_SEQ_ELEM(reader.seq->elem_size, reader);
613   }
614 
615   return laplacian;
616 }
617 
618 /*!
619   Get the parameters of the descriptor of the nth reference point.
620 
621  \param index : The index of the desired reference point. The index must be
622  between 0 and the number of reference points - 1. \param size : The size of
623  the point used to compute the descriptor. \param dir : The orientation of the
624  descriptor (in degree).
625 */
getDescriptorParamReferencePoint(int index,int & size,float & dir)626 void vpKeyPointSurf::getDescriptorParamReferencePoint(int index, int &size, float &dir)
627 {
628   if (index >= static_cast<int>(referenceImagePointsList.size()) || index < 0) {
629     vpTRACE("Index of the reference point out of range");
630     throw(vpException(vpException::fatalError, "Index of the reference point out of range"));
631   }
632 
633   CvSeqReader reader;
634   cvStartReadSeq(ref_keypoints, &reader);
635 
636   for (int j = 0; j < ref_keypoints->total; j++) {
637     if (j == index) {
638       const CvSURFPoint *kp = (const CvSURFPoint *)reader.ptr;
639       size = kp->size;
640       dir = kp->dir;
641       break;
642     }
643     CV_NEXT_SEQ_ELEM(reader.seq->elem_size, reader);
644   }
645 }
646 
647 #elif !defined(VISP_BUILD_SHARED_LIBS)
648 // Work arround to avoid warning: libvisp_vision.a(vpKeyPointSurf.cpp.o) has
649 // no symbols
dummy_vpKeyPointSurf()650 void dummy_vpKeyPointSurf(){};
651 #endif
652