Visual Servoing Platform  version 3.2.0 under development (2019-01-22)
vpImageFilter.cpp
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  * Various image tools, convolution, ...
33  *
34  * Authors:
35  * Eric Marchand
36  *
37  *****************************************************************************/
38 
39 #include <visp3/core/vpImageConvert.h>
40 #include <visp3/core/vpImageFilter.h>
41 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020408)
42 #include <opencv2/imgproc/imgproc.hpp>
43 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020101)
44 #include <opencv2/imgproc/imgproc_c.h>
45 #elif defined(VISP_HAVE_OPENCV)
46 #include <cv.h>
47 #endif
48 
76 void vpImageFilter::filter(const vpImage<unsigned char> &I, vpImage<double> &If, const vpMatrix &M, const bool convolve)
77 {
78  unsigned int size_y = M.getRows(), size_x = M.getCols();
79  unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
80 
81  If.resize(I.getHeight(), I.getWidth(), 0.0);
82 
83  if (convolve) {
84  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
85  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
86  double conv = 0;
87 
88  for (unsigned int a = 0; a < size_y; a++) {
89  for (unsigned int b = 0; b < size_x; b++) {
90  double val = I[i + half_size_y - a][j + half_size_x - b]; // Convolution
91  conv += M[a][b] * val;
92  }
93  }
94  If[i][j] = conv;
95  }
96  }
97  } else {
98  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
99  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
100  double corr = 0;
101 
102  for (unsigned int a = 0; a < size_y; a++) {
103  for (unsigned int b = 0; b < size_x; b++) {
104  double val = I[i - half_size_y + a][j - half_size_x + b]; // Correlation
105  corr += M[a][b] * val;
106  }
107  }
108  If[i][j] = corr;
109  }
110  }
111  }
112 }
113 
127  const bool convolve)
128 {
129  unsigned int size = M.getRows();
130  unsigned int half_size = size / 2;
131 
132  Iu.resize(I.getHeight(), I.getWidth(), 0.0);
133  Iv.resize(I.getHeight(), I.getWidth(), 0.0);
134 
135  if (convolve) {
136  for (unsigned int v = half_size; v < I.getHeight() - half_size; v++) {
137  for (unsigned int u = half_size; u < I.getWidth() - half_size; u++) {
138  double conv_u = 0;
139  double conv_v = 0;
140 
141  for (unsigned int a = 0; a < size; a++) {
142  for (unsigned int b = 0; b < size; b++) {
143  double val = I[v + half_size - a][u + half_size - b]; // Convolution
144  conv_u += M[a][b] * val;
145  conv_v += M[b][a] * val;
146  }
147  }
148  Iu[v][u] = conv_u;
149  Iv[v][u] = conv_v;
150  }
151  }
152  } else {
153  for (unsigned int v = half_size; v < I.getHeight() - half_size; v++) {
154  for (unsigned int u = half_size; u < I.getWidth() - half_size; u++) {
155  double conv_u = 0;
156  double conv_v = 0;
157 
158  for (unsigned int a = 0; a < size; a++) {
159  for (unsigned int b = 0; b < size; b++) {
160  double val = I[v - half_size + a][u - half_size + b]; // Correlation
161  conv_u += M[a][b] * val;
162  conv_v += M[b][a] * val;
163  }
164  }
165  Iu[v][u] = conv_u;
166  Iv[v][u] = conv_v;
167  }
168  }
169  }
170 }
171 
225  const vpColVector &kernelV)
226 {
227  unsigned int size = kernelH.size();
228  unsigned int half_size = size / 2;
229 
230  If.resize(I.getHeight(), I.getWidth(), 0.0);
231  vpImage<double> I_filter(I.getHeight(), I.getWidth(), 0.0);
232 
233  for (unsigned int i = 0; i < I.getHeight(); i++) {
234  for (unsigned int j = half_size; j < I.getWidth() - half_size; j++) {
235  double conv = 0.0;
236  for (unsigned int a = 0; a < kernelH.size(); a++) {
237  conv += kernelH[a] * I[i][j + half_size - a];
238  }
239 
240  I_filter[i][j] = conv;
241  }
242  }
243 
244  for (unsigned int i = half_size; i < I.getHeight() - half_size; i++) {
245  for (unsigned int j = 0; j < I.getWidth(); j++) {
246  double conv = 0.0;
247  for (unsigned int a = 0; a < kernelV.size(); a++) {
248  conv += kernelV[a] * I_filter[i + half_size - a][j];
249  }
250 
251  If[i][j] = conv;
252  }
253  }
254 }
255 
256 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020100)
257 
298  const unsigned int gaussianFilterSize, const double thresholdCanny,
299  const unsigned int apertureSobel)
300 {
301 #if (VISP_HAVE_OPENCV_VERSION < 0x020408)
302  IplImage *img_ipl = NULL;
303  vpImageConvert::convert(Isrc, img_ipl);
304  IplImage *edges_ipl;
305  edges_ipl = cvCreateImage(cvSize(img_ipl->width, img_ipl->height), img_ipl->depth, img_ipl->nChannels);
306 
307  cvSmooth(img_ipl, img_ipl, CV_GAUSSIAN, (int)gaussianFilterSize, (int)gaussianFilterSize, 0, 0);
308  cvCanny(img_ipl, edges_ipl, thresholdCanny, thresholdCanny, (int)apertureSobel);
309 
310  vpImageConvert::convert(edges_ipl, Ires);
311  cvReleaseImage(&img_ipl);
312  cvReleaseImage(&edges_ipl);
313 #else
314  cv::Mat img_cvmat, edges_cvmat;
315  vpImageConvert::convert(Isrc, img_cvmat);
316  cv::GaussianBlur(img_cvmat, img_cvmat, cv::Size((int)gaussianFilterSize, (int)gaussianFilterSize), 0, 0);
317  cv::Canny(img_cvmat, edges_cvmat, thresholdCanny, thresholdCanny, (int)apertureSobel);
318  vpImageConvert::convert(edges_cvmat, Ires);
319 #endif
320 }
321 #endif
322 
327  unsigned int size)
328 {
329  vpImage<double> GIx;
330  filterX(I, GIx, filter, size);
331  filterY(GIx, GI, filter, size);
332  GIx.destroy();
333 }
334 
338 void vpImageFilter::filter(const vpImage<double> &I, vpImage<double> &GI, const double *filter, unsigned int size)
339 {
340  vpImage<double> GIx;
341  filterX(I, GIx, filter, size);
342  filterY(GIx, GI, filter, size);
343  GIx.destroy();
344 }
345 
347  unsigned int size)
348 {
349  dIx.resize(I.getHeight(), I.getWidth());
350  for (unsigned int i = 0; i < I.getHeight(); i++) {
351  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
352  dIx[i][j] = vpImageFilter::filterXLeftBorder(I, i, j, filter, size);
353  // dIx[i][j]=0;
354  }
355  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
356  dIx[i][j] = vpImageFilter::filterX(I, i, j, filter, size);
357  }
358  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
359  dIx[i][j] = vpImageFilter::filterXRightBorder(I, i, j, filter, size);
360  // dIx[i][j]=0;
361  }
362  }
363 }
364 void vpImageFilter::filterX(const vpImage<double> &I, vpImage<double> &dIx, const double *filter, unsigned int size)
365 {
366  dIx.resize(I.getHeight(), I.getWidth());
367  for (unsigned int i = 0; i < I.getHeight(); i++) {
368  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
369  dIx[i][j] = vpImageFilter::filterXLeftBorder(I, i, j, filter, size);
370  // dIx[i][j]=0;
371  }
372  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
373  dIx[i][j] = vpImageFilter::filterX(I, i, j, filter, size);
374  }
375  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
376  dIx[i][j] = vpImageFilter::filterXRightBorder(I, i, j, filter, size);
377  // dIx[i][j]=0;
378  }
379  }
380 }
382  unsigned int size)
383 {
384  dIy.resize(I.getHeight(), I.getWidth());
385  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
386  for (unsigned int j = 0; j < I.getWidth(); j++) {
387  dIy[i][j] = vpImageFilter::filterYTopBorder(I, i, j, filter, size);
388  }
389  }
390  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
391  for (unsigned int j = 0; j < I.getWidth(); j++) {
392  dIy[i][j] = vpImageFilter::filterY(I, i, j, filter, size);
393  }
394  }
395  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
396  for (unsigned int j = 0; j < I.getWidth(); j++) {
397  dIy[i][j] = vpImageFilter::filterYBottomBorder(I, i, j, filter, size);
398  }
399  }
400 }
401 void vpImageFilter::filterY(const vpImage<double> &I, vpImage<double> &dIy, const double *filter, unsigned int size)
402 {
403  dIy.resize(I.getHeight(), I.getWidth());
404  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
405  for (unsigned int j = 0; j < I.getWidth(); j++) {
406  dIy[i][j] = vpImageFilter::filterYTopBorder(I, i, j, filter, size);
407  }
408  }
409  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
410  for (unsigned int j = 0; j < I.getWidth(); j++) {
411  dIy[i][j] = vpImageFilter::filterY(I, i, j, filter, size);
412  }
413  }
414  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
415  for (unsigned int j = 0; j < I.getWidth(); j++) {
416  dIy[i][j] = vpImageFilter::filterYBottomBorder(I, i, j, filter, size);
417  }
418  }
419 }
420 
432 void vpImageFilter::gaussianBlur(const vpImage<unsigned char> &I, vpImage<double> &GI, unsigned int size, double sigma,
433  bool normalize)
434 {
435  double *fg = new double[(size + 1) / 2];
436  vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
437  vpImage<double> GIx;
438  vpImageFilter::filterX(I, GIx, fg, size);
439  vpImageFilter::filterY(GIx, GI, fg, size);
440  GIx.destroy();
441  delete[] fg;
442 }
443 
455 void vpImageFilter::gaussianBlur(const vpImage<double> &I, vpImage<double> &GI, unsigned int size, double sigma,
456  bool normalize)
457 {
458  double *fg = new double[(size + 1) / 2];
459  vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
460  vpImage<double> GIx;
461  vpImageFilter::filterX(I, GIx, fg, size);
462  vpImageFilter::filterY(GIx, GI, fg, size);
463  GIx.destroy();
464  delete[] fg;
465 }
466 
478 void vpImageFilter::getGaussianKernel(double *filter, unsigned int size, double sigma, bool normalize)
479 {
480  if (size % 2 != 1)
481  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
482 
483  if (sigma <= 0)
484  sigma = (size - 1) / 6.0;
485 
486  int middle = (int)(size - 1) / 2;
487  double sigma2 = vpMath::sqr(sigma);
488  for (int i = 0; i <= middle; i++) {
489  filter[i] = (1. / (sigma * sqrt(2. * M_PI))) * exp(-(i * i) / (2. * sigma2));
490  }
491  if (normalize) {
492  // renormalization
493  double sum = 0;
494  for (int i = 1; i <= middle; i++) {
495  sum += 2 * filter[i];
496  }
497  sum += filter[0];
498 
499  for (int i = 0; i <= middle; i++) {
500  filter[i] = filter[i] / sum;
501  }
502  }
503 }
504 
517 void vpImageFilter::getGaussianDerivativeKernel(double *filter, unsigned int size, double sigma, bool normalize)
518 {
519  if (size % 2 != 1)
520  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
521 
522  if (sigma <= 0)
523  sigma = (size - 1) / 6.0;
524 
525  int middle = (int)(size - 1) / 2;
526  double sigma2 = vpMath::sqr(sigma);
527  filter[0] = 0.;
528  for (int i = 1; i <= middle; i++) {
529  filter[i] = -(1. / (sigma * sqrt(2. * M_PI))) *
530  (exp(-((i + 1) * (i + 1)) / (2. * sigma2)) - exp(-((i - 1) * (i - 1)) / (2. * sigma2))) / 2.;
531  }
532 
533  if (normalize) {
534  double sum = 0;
535  for (int i = 1; i <= middle; i++) {
536  sum += 2. * (1. / (sigma * sqrt(2. * M_PI))) * exp(-(i * i) / (2. * sigma2));
537  }
538  sum += (1. / (sigma * sqrt(2. * M_PI)));
539 
540  for (int i = 1; i <= middle; i++) {
541  filter[i] = filter[i] / sum;
542  }
543  }
544 }
545 
547 {
548  dIx.resize(I.getHeight(), I.getWidth());
549  // dIx=0;
550  for (unsigned int i = 0; i < I.getHeight(); i++) {
551  for (unsigned int j = 0; j < 3; j++) {
552  dIx[i][j] = 0;
553  }
554  for (unsigned int j = 3; j < I.getWidth() - 3; j++) {
555  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j);
556  }
557  for (unsigned int j = I.getWidth() - 3; j < I.getWidth(); j++) {
558  dIx[i][j] = 0;
559  }
560  }
561 }
562 
564 {
565  dIy.resize(I.getHeight(), I.getWidth());
566  // dIy=0;
567  for (unsigned int i = 0; i < 3; i++) {
568  for (unsigned int j = 0; j < I.getWidth(); j++) {
569  dIy[i][j] = 0;
570  }
571  }
572  for (unsigned int i = 3; i < I.getHeight() - 3; i++) {
573  for (unsigned int j = 0; j < I.getWidth(); j++) {
574  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j);
575  }
576  }
577  for (unsigned int i = I.getHeight() - 3; i < I.getHeight(); i++) {
578  for (unsigned int j = 0; j < I.getWidth(); j++) {
579  dIy[i][j] = 0;
580  }
581  }
582 }
583 
585  unsigned int size)
586 {
587  dIx.resize(I.getHeight(), I.getWidth());
588  //#pragma omp parallel for
589  for (unsigned int i = 0; i < I.getHeight(); i++) {
590  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
591  dIx[i][j] = 0;
592  }
593  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
594  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j, filter, size);
595  }
596  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
597  dIx[i][j] = 0;
598  }
599  }
600 }
601 void vpImageFilter::getGradX(const vpImage<double> &I, vpImage<double> &dIx, const double *filter, unsigned int size)
602 {
603  dIx.resize(I.getHeight(), I.getWidth());
604  // dIx=0;
605  for (unsigned int i = 0; i < I.getHeight(); i++) {
606  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
607  dIx[i][j] = 0;
608  }
609  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
610  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j, filter, size);
611  }
612  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
613  dIx[i][j] = 0;
614  }
615  }
616 }
617 
619  unsigned int size)
620 {
621  dIy.resize(I.getHeight(), I.getWidth());
622  //#pragma omp parallel for
623  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
624  for (unsigned int j = 0; j < I.getWidth(); j++) {
625  dIy[i][j] = 0;
626  }
627  }
628  //#pragma omp parallel for
629  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
630  for (unsigned int j = 0; j < I.getWidth(); j++) {
631  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j, filter, size);
632  }
633  }
634  //#pragma omp parallel for
635  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
636  for (unsigned int j = 0; j < I.getWidth(); j++) {
637  dIy[i][j] = 0;
638  }
639  }
640 }
641 
642 void vpImageFilter::getGradY(const vpImage<double> &I, vpImage<double> &dIy, const double *filter, unsigned int size)
643 {
644  dIy.resize(I.getHeight(), I.getWidth());
645  // dIy=0;
646  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
647  for (unsigned int j = 0; j < I.getWidth(); j++) {
648  dIy[i][j] = 0;
649  }
650  }
651  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
652  for (unsigned int j = 0; j < I.getWidth(); j++) {
653  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j, filter, size);
654  }
655  }
656  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
657  for (unsigned int j = 0; j < I.getWidth(); j++) {
658  dIy[i][j] = 0;
659  }
660  }
661 }
662 
673 void vpImageFilter::getGradXGauss2D(const vpImage<unsigned char> &I, vpImage<double> &dIx, const double *gaussianKernel,
674  const double *gaussianDerivativeKernel, unsigned int size)
675 {
676  vpImage<double> GIy;
677  vpImageFilter::filterY(I, GIy, gaussianKernel, size);
678  vpImageFilter::getGradX(GIy, dIx, gaussianDerivativeKernel, size);
679 }
680 
691 void vpImageFilter::getGradYGauss2D(const vpImage<unsigned char> &I, vpImage<double> &dIy, const double *gaussianKernel,
692  const double *gaussianDerivativeKernel, unsigned int size)
693 {
694  vpImage<double> GIx;
695  vpImageFilter::filterX(I, GIx, gaussianKernel, size);
696  vpImageFilter::getGradY(GIx, dIy, gaussianDerivativeKernel, size);
697 }
698 
699 // operation pour pyramide gaussienne
701 {
703 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x030000)
704  cv::Mat imgsrc, imgdest;
705  vpImageConvert::convert(I, imgsrc);
706  cv::pyrDown(imgsrc, imgdest, cv::Size((int)I.getWidth() / 2, (int)I.getHeight() / 2));
707  vpImageConvert::convert(imgdest, GI);
708 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020408)
709  cv::Mat imgsrc, imgdest;
710  vpImageConvert::convert(I, imgsrc);
711  cv::pyrDown(imgsrc, imgdest, cvSize((int)I.getWidth() / 2, (int)I.getHeight() / 2));
712  vpImageConvert::convert(imgdest, GI);
713 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020100)
714  IplImage *imgsrc = NULL; // cvCreateImage(cvGetSize(imgign), IPL_DEPTH_8U, 1);
715  IplImage *imgdest = NULL; // cvCreateImage(cvGetSize(imgign), IPL_DEPTH_8U, 1);
716  imgsrc = cvCreateImage(cvSize((int)I.getWidth(), (int)I.getHeight()), IPL_DEPTH_8U, 1);
717  imgdest = cvCreateImage(cvSize((int)I.getWidth() / 2, (int)I.getHeight() / 2), IPL_DEPTH_8U, 1);
718  vpImageConvert::convert(I, imgsrc);
719  cvPyrDown(imgsrc, imgdest);
720  vpImageConvert::convert(imgdest, GI);
721 
722  cvReleaseImage(&imgsrc);
723  cvReleaseImage(&imgdest);
724 // vpImage<unsigned char> sGI;sGI=GI;
725 
726 #else
729 #endif
730 }
731 
733 {
734 #if 0
735  GI.resize(I.getHeight(),(int)((I.getWidth()+1.)/2.)) ;
736  for (unsigned int i=0 ; i < I.getHeight() ; i++)
737  {
738  GI[i][0]=I[i][0];
739  for (unsigned int j=1 ; j < ((I.getWidth()+1.)/2.)-1 ; j++)
740  {
741  GI[i][j]=vpImageFilter::filterGaussXPyramidal(I,i,2*j);
742  }
743  GI[i][(int)((I.getWidth()+1.)/2.)-1]=I[i][2*((int)((I.getWidth()+1.)/2.)-1)];
744  }
745 #else
746  unsigned int w = I.getWidth() / 2;
747 
748  GI.resize(I.getHeight(), w);
749  for (unsigned int i = 0; i < I.getHeight(); i++) {
750  GI[i][0] = I[i][0];
751  for (unsigned int j = 1; j < w - 1; j++) {
752  GI[i][j] = vpImageFilter::filterGaussXPyramidal(I, i, 2 * j);
753  }
754  GI[i][w - 1] = I[i][2 * w - 1];
755  }
756 
757 #endif
758 }
760 {
761 
762 #ifdef ORIG
763  GI.resize((int)((I.getHeight() + 1.) / 2.), I.getWidth());
764  for (unsigned int j = 0; j < I.getWidth(); j++) {
765  GI[0][j] = I[0][j];
766  for (unsigned int i = 1; i < ((I.getHeight() + 1.) / 2.) - 1; i++) {
767  GI[i][j] = vpImageFilter::filterGaussYPyramidal(I, 2 * i, j);
768  }
769  GI[(int)((I.getHeight() + 1.) / 2.) - 1][j] = I[2 * ((int)((I.getHeight() + 1.) / 2.) - 1)][j];
770  }
771 
772 #else
773  unsigned int h = I.getHeight() / 2;
774 
775  GI.resize(h, I.getWidth());
776  for (unsigned int j = 0; j < I.getWidth(); j++) {
777  GI[0][j] = I[0][j];
778  for (unsigned int i = 1; i < h - 1; i++) {
779  GI[i][j] = vpImageFilter::filterGaussYPyramidal(I, 2 * i, j);
780  }
781  GI[h - 1][j] = I[2 * h - 1][j];
782  }
783 #endif
784 }
785 
793 double vpImageFilter::getSobelKernelX(double *filter, unsigned int size)
794 {
795  if (size == 0)
796  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
797  if (size > 20)
798  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
799 
800  vpMatrix SobelY(size*2+1, size*2+1);
801  double norm = getSobelKernelY(SobelY.data, size);
802  memcpy(filter, SobelY.t().data, SobelY.getRows()*SobelY.getCols()*sizeof(double));
803  return norm;
804 }
805 
813 double vpImageFilter::getSobelKernelY(double *filter, unsigned int size)
814 {
815  //Sobel kernel pre-computed for the usual size
816  static const double SobelY3x3[9] = {-1.0, -2.0, -1.0,
817  0.0, 0.0, 0.0,
818  1.0, 2.0, 1.0};
819  static const double SobelY5x5[25] = {-1.0, -4.0, -6.0, -4.0, -1.0,
820  -2.0, -8.0, -12.0, -8.0, -2.0,
821  0.0, 0.0, 0.0, 0.0, 0.0,
822  2.0, 8.0, 12.0, 8.0, 2.0,
823  1.0, 4.0, 6.0, 4.0, 1.0};
824  static const double SobelY7x7[49] = {-1, -6, -15, -20, -15, -6, -1,
825  -4, -24, -60, -80, -60, -24, -4,
826  -5, -30, -75, -100, -75, -30, -5,
827  0, 0, 0, 0, 0, 0, 0,
828  5, 30, 75, 100, 75, 30, 5,
829  4, 24, 60, 80, 60, 24, 4,
830  1, 6, 15, 20, 15, 6, 1};
831  static const vpMatrix smoothingKernel(3,3);
832  smoothingKernel[0][0] = 1.0; smoothingKernel[0][1] = 2.0; smoothingKernel[0][2] = 1.0;
833  smoothingKernel[1][0] = 2.0; smoothingKernel[1][1] = 4.0; smoothingKernel[1][2] = 2.0;
834  smoothingKernel[2][0] = 1.0; smoothingKernel[2][1] = 2.0; smoothingKernel[2][2] = 1.0;
835 
836  if (size == 0)
837  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
838  if (size > 20)
839  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
840 
841  const unsigned int kernel_size = size*2+1;
842  if (kernel_size == 3) {
843  memcpy(filter, SobelY3x3, kernel_size*kernel_size*sizeof(double));
844  return 1/8.0;
845  }
846  if (kernel_size == 5) {
847  memcpy(filter, SobelY5x5, kernel_size*kernel_size*sizeof(double));
848  return 1/16.0;
849  }
850  if (kernel_size == 7) {
851  memcpy(filter, SobelY7x7, kernel_size*kernel_size*sizeof(double));
852  return 1/16.0;
853  }
854 
855  vpMatrix sobelY(7,7);
856  memcpy(sobelY.data, SobelY7x7, sobelY.getRows()*sobelY.getCols()*sizeof(double));
857  for (unsigned int i = 4; i <= size; i++) {
858  sobelY = vpMatrix::conv2(sobelY, smoothingKernel, "full");
859  }
860 
861  memcpy(filter, sobelY.data, sobelY.getRows()*sobelY.getCols()*sizeof(double));
862 
863  return 1/16.0;
864 }
static double getSobelKernelY(double *filter, unsigned int size)
static void getGaussPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:104
static double filterXLeftBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static vpMatrix conv2(const vpMatrix &M, const vpMatrix &kernel, const std::string &mode="full")
Definition: vpMatrix.cpp:5164
unsigned int getWidth() const
Definition: vpImage.h:239
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static void getGradX(const vpImage< unsigned char > &I, vpImage< double > &dIx)
static void getGaussYPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
static void getGradY(const vpImage< unsigned char > &I, vpImage< double > &dIy)
static double derivativeFilterY(const vpImage< T > &I, const unsigned int r, const unsigned int c)
Definition: vpImageFilter.h:95
static void sepFilter(const vpImage< unsigned char > &I, vpImage< double > &If, const vpColVector &kernelH, const vpColVector &kernelV)
static void getGaussianKernel(double *filter, unsigned int size, double sigma=0., bool normalize=true)
error that can be emited by ViSP classes.
Definition: vpException.h:71
static unsigned char filterGaussYPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:84
static void getGradYGauss2D(const vpImage< unsigned char > &I, vpImage< double > &dIy, const double *gaussianKernel, const double *gaussianDerivativeKernel, unsigned int size)
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:158
unsigned int getCols() const
Definition: vpArray2D.h:146
Error that can be emited by the vpImage class and its derivates.
static void getGradXGauss2D(const vpImage< unsigned char > &I, vpImage< double > &dIx, const double *gaussianKernel, const double *gaussianDerivativeKernel, unsigned int size)
static void filterY(const vpImage< unsigned char > &I, vpImage< double > &dIx, const double *filter, unsigned int size)
static void getGaussXPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
static double sqr(double x)
Definition: vpMath.h:108
static void gaussianBlur(const vpImage< unsigned char > &I, vpImage< double > &GI, unsigned int size=7, double sigma=0., bool normalize=true)
static double filterYTopBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterXRightBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:866
unsigned int getRows() const
Definition: vpArray2D.h:156
void destroy()
Destructor : Memory de-allocation.
Definition: vpImage.h:895
vpMatrix t() const
Definition: vpMatrix.cpp:375
static void filterX(const vpImage< unsigned char > &I, vpImage< double > &dIx, const double *filter, unsigned int size)
static void getGaussianDerivativeKernel(double *filter, unsigned int size, double sigma=0., bool normalize=true)
static double filterYBottomBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
static unsigned char filterGaussXPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
unsigned int getHeight() const
Definition: vpImage.h:178
static void filter(const vpImage< double > &I, vpImage< double > &Iu, vpImage< double > &Iv, const vpMatrix &M, const bool convolve=false)
static double getSobelKernelX(double *filter, unsigned int size)
static void canny(const vpImage< unsigned char > &I, vpImage< unsigned char > &Ic, const unsigned int gaussianFilterSize, const double thresholdCanny, const unsigned int apertureSobel)
static double derivativeFilterX(const vpImage< T > &I, const unsigned int r, const unsigned int c)
Definition: vpImageFilter.h:81