Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
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 #include <visp3/core/vpRGBa.h>
42 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020408)
43 #include <opencv2/imgproc/imgproc.hpp>
44 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020101)
45 #include <opencv2/imgproc/imgproc_c.h>
46 #elif defined(VISP_HAVE_OPENCV)
47 #include <cv.h>
48 #endif
49 
77 void vpImageFilter::filter(const vpImage<unsigned char> &I, vpImage<double> &If, const vpMatrix &M, bool convolve)
78 {
79  unsigned int size_y = M.getRows(), size_x = M.getCols();
80  unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
81 
82  If.resize(I.getHeight(), I.getWidth(), 0.0);
83 
84  if (convolve) {
85  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
86  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
87  double conv = 0;
88 
89  for (unsigned int a = 0; a < size_y; a++) {
90  for (unsigned int b = 0; b < size_x; b++) {
91  double val = I[i + half_size_y - a][j + half_size_x - b]; // Convolution
92  conv += M[a][b] * val;
93  }
94  }
95  If[i][j] = conv;
96  }
97  }
98  } else {
99  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
100  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
101  double corr = 0;
102 
103  for (unsigned int a = 0; a < size_y; a++) {
104  for (unsigned int b = 0; b < size_x; b++) {
105  double val = I[i - half_size_y + a][j - half_size_x + b]; // Correlation
106  corr += M[a][b] * val;
107  }
108  }
109  If[i][j] = corr;
110  }
111  }
112  }
113 }
114 
128  bool convolve)
129 {
130  unsigned int size = M.getRows();
131  unsigned int half_size = size / 2;
132 
133  Iu.resize(I.getHeight(), I.getWidth(), 0.0);
134  Iv.resize(I.getHeight(), I.getWidth(), 0.0);
135 
136  if (convolve) {
137  for (unsigned int v = half_size; v < I.getHeight() - half_size; v++) {
138  for (unsigned int u = half_size; u < I.getWidth() - half_size; u++) {
139  double conv_u = 0;
140  double conv_v = 0;
141 
142  for (unsigned int a = 0; a < size; a++) {
143  for (unsigned int b = 0; b < size; b++) {
144  double val = I[v + half_size - a][u + half_size - b]; // Convolution
145  conv_u += M[a][b] * val;
146  conv_v += M[b][a] * val;
147  }
148  }
149  Iu[v][u] = conv_u;
150  Iv[v][u] = conv_v;
151  }
152  }
153  } else {
154  for (unsigned int v = half_size; v < I.getHeight() - half_size; v++) {
155  for (unsigned int u = half_size; u < I.getWidth() - half_size; u++) {
156  double conv_u = 0;
157  double conv_v = 0;
158 
159  for (unsigned int a = 0; a < size; a++) {
160  for (unsigned int b = 0; b < size; b++) {
161  double val = I[v - half_size + a][u - half_size + b]; // Correlation
162  conv_u += M[a][b] * val;
163  conv_v += M[b][a] * val;
164  }
165  }
166  Iu[v][u] = conv_u;
167  Iv[v][u] = conv_v;
168  }
169  }
170  }
171 }
172 
226  const vpColVector &kernelV)
227 {
228  unsigned int size = kernelH.size();
229  unsigned int half_size = size / 2;
230 
231  If.resize(I.getHeight(), I.getWidth(), 0.0);
232  vpImage<double> I_filter(I.getHeight(), I.getWidth(), 0.0);
233 
234  for (unsigned int i = 0; i < I.getHeight(); i++) {
235  for (unsigned int j = half_size; j < I.getWidth() - half_size; j++) {
236  double conv = 0.0;
237  for (unsigned int a = 0; a < kernelH.size(); a++) {
238  conv += kernelH[a] * I[i][j + half_size - a];
239  }
240 
241  I_filter[i][j] = conv;
242  }
243  }
244 
245  for (unsigned int i = half_size; i < I.getHeight() - half_size; i++) {
246  for (unsigned int j = 0; j < I.getWidth(); j++) {
247  double conv = 0.0;
248  for (unsigned int a = 0; a < kernelV.size(); a++) {
249  conv += kernelV[a] * I_filter[i + half_size - a][j];
250  }
251 
252  If[i][j] = conv;
253  }
254  }
255 }
256 
257 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020100)
258 
299  unsigned int gaussianFilterSize, double thresholdCanny,
300  unsigned int apertureSobel)
301 {
302 #if (VISP_HAVE_OPENCV_VERSION < 0x020408)
303  IplImage *img_ipl = NULL;
304  vpImageConvert::convert(Isrc, img_ipl);
305  IplImage *edges_ipl;
306  edges_ipl = cvCreateImage(cvSize(img_ipl->width, img_ipl->height), img_ipl->depth, img_ipl->nChannels);
307 
308  cvSmooth(img_ipl, img_ipl, CV_GAUSSIAN, (int)gaussianFilterSize, (int)gaussianFilterSize, 0, 0);
309  cvCanny(img_ipl, edges_ipl, thresholdCanny, thresholdCanny, (int)apertureSobel);
310 
311  vpImageConvert::convert(edges_ipl, Ires);
312  cvReleaseImage(&img_ipl);
313  cvReleaseImage(&edges_ipl);
314 #else
315  cv::Mat img_cvmat, edges_cvmat;
316  vpImageConvert::convert(Isrc, img_cvmat);
317  cv::GaussianBlur(img_cvmat, img_cvmat, cv::Size((int)gaussianFilterSize, (int)gaussianFilterSize), 0, 0);
318  cv::Canny(img_cvmat, edges_cvmat, thresholdCanny, thresholdCanny, (int)apertureSobel);
319  vpImageConvert::convert(edges_cvmat, Ires);
320 #endif
321 }
322 #endif
323 
328  unsigned int size)
329 {
330  vpImage<double> GIx;
331  filterX(I, GIx, filter, size);
332  filterY(GIx, GI, filter, size);
333  GIx.destroy();
334 }
335 
339 void vpImageFilter::filter(const vpImage<double> &I, vpImage<double> &GI, const double *filter, unsigned int size)
340 {
341  vpImage<double> GIx;
342  filterX(I, GIx, filter, size);
343  filterY(GIx, GI, filter, size);
344  GIx.destroy();
345 }
346 
348  unsigned int size)
349 {
350  dIx.resize(I.getHeight(), I.getWidth());
351  for (unsigned int i = 0; i < I.getHeight(); i++) {
352  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
353  dIx[i][j] = vpImageFilter::filterXLeftBorder(I, i, j, filter, size);
354  // dIx[i][j]=0;
355  }
356  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
357  dIx[i][j] = vpImageFilter::filterX(I, i, j, filter, size);
358  }
359  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
360  dIx[i][j] = vpImageFilter::filterXRightBorder(I, i, j, filter, size);
361  // dIx[i][j]=0;
362  }
363  }
364 }
366  unsigned int size)
367 {
368  dIx.resize(I.getHeight(), I.getWidth());
369  for (unsigned int i = 0; i < I.getHeight(); i++) {
370  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
371  dIx[i][j].R = static_cast<unsigned char>(vpImageFilter::filterXLeftBorderR(I, i, j, filter, size));
372  dIx[i][j].G = static_cast<unsigned char>(vpImageFilter::filterXLeftBorderG(I, i, j, filter, size));
373  dIx[i][j].B = static_cast<unsigned char>(vpImageFilter::filterXLeftBorderB(I, i, j, filter, size));
374  }
375  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
376  dIx[i][j].R = static_cast<unsigned char>(vpImageFilter::filterXR(I, i, j, filter, size));
377  dIx[i][j].G = static_cast<unsigned char>(vpImageFilter::filterXG(I, i, j, filter, size));
378  dIx[i][j].B = static_cast<unsigned char>(vpImageFilter::filterXB(I, i, j, filter, size));
379  }
380  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
381  dIx[i][j].R = static_cast<unsigned char>(vpImageFilter::filterXRightBorderR(I, i, j, filter, size));
382  dIx[i][j].G = static_cast<unsigned char>(vpImageFilter::filterXRightBorderG(I, i, j, filter, size));
383  dIx[i][j].B = static_cast<unsigned char>(vpImageFilter::filterXRightBorderB(I, i, j, filter, size));
384  }
385  }
386 }
387 void vpImageFilter::filterX(const vpImage<double> &I, vpImage<double> &dIx, const double *filter, unsigned int size)
388 {
389  dIx.resize(I.getHeight(), I.getWidth());
390  for (unsigned int i = 0; i < I.getHeight(); i++) {
391  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
392  dIx[i][j] = vpImageFilter::filterXLeftBorder(I, i, j, filter, size);
393  // dIx[i][j]=0;
394  }
395  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
396  dIx[i][j] = vpImageFilter::filterX(I, i, j, filter, size);
397  }
398  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
399  dIx[i][j] = vpImageFilter::filterXRightBorder(I, i, j, filter, size);
400  // dIx[i][j]=0;
401  }
402  }
403 }
405  unsigned int size)
406 {
407  dIy.resize(I.getHeight(), I.getWidth());
408  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
409  for (unsigned int j = 0; j < I.getWidth(); j++) {
410  dIy[i][j] = vpImageFilter::filterYTopBorder(I, i, j, filter, size);
411  }
412  }
413  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
414  for (unsigned int j = 0; j < I.getWidth(); j++) {
415  dIy[i][j] = vpImageFilter::filterY(I, i, j, filter, size);
416  }
417  }
418  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
419  for (unsigned int j = 0; j < I.getWidth(); j++) {
420  dIy[i][j] = vpImageFilter::filterYBottomBorder(I, i, j, filter, size);
421  }
422  }
423 }
425  unsigned int size)
426 {
427  dIy.resize(I.getHeight(), I.getWidth());
428  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
429  for (unsigned int j = 0; j < I.getWidth(); j++) {
430  dIy[i][j].R = static_cast<unsigned char>(vpImageFilter::filterYTopBorderR(I, i, j, filter, size));
431  dIy[i][j].G = static_cast<unsigned char>(vpImageFilter::filterYTopBorderG(I, i, j, filter, size));
432  dIy[i][j].B = static_cast<unsigned char>(vpImageFilter::filterYTopBorderB(I, i, j, filter, size));
433  }
434  }
435  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
436  for (unsigned int j = 0; j < I.getWidth(); j++) {
437  dIy[i][j].R = static_cast<unsigned char>(vpImageFilter::filterYR(I, i, j, filter, size));
438  dIy[i][j].G = static_cast<unsigned char>(vpImageFilter::filterYG(I, i, j, filter, size));
439  dIy[i][j].B = static_cast<unsigned char>(vpImageFilter::filterYB(I, i, j, filter, size));
440  }
441  }
442  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
443  for (unsigned int j = 0; j < I.getWidth(); j++) {
444  dIy[i][j].R = static_cast<unsigned char>(vpImageFilter::filterYBottomBorderR(I, i, j, filter, size));
445  dIy[i][j].G = static_cast<unsigned char>(vpImageFilter::filterYBottomBorderG(I, i, j, filter, size));
446  dIy[i][j].B = static_cast<unsigned char>(vpImageFilter::filterYBottomBorderB(I, i, j, filter, size));
447  }
448  }
449 }
450 void vpImageFilter::filterY(const vpImage<double> &I, vpImage<double> &dIy, const double *filter, unsigned int size)
451 {
452  dIy.resize(I.getHeight(), I.getWidth());
453  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
454  for (unsigned int j = 0; j < I.getWidth(); j++) {
455  dIy[i][j] = vpImageFilter::filterYTopBorder(I, i, j, filter, size);
456  }
457  }
458  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
459  for (unsigned int j = 0; j < I.getWidth(); j++) {
460  dIy[i][j] = vpImageFilter::filterY(I, i, j, filter, size);
461  }
462  }
463  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
464  for (unsigned int j = 0; j < I.getWidth(); j++) {
465  dIy[i][j] = vpImageFilter::filterYBottomBorder(I, i, j, filter, size);
466  }
467  }
468 }
469 
482 void vpImageFilter::gaussianBlur(const vpImage<unsigned char> &I, vpImage<double> &GI, unsigned int size, double sigma,
483  bool normalize)
484 {
485  double *fg = new double[(size + 1) / 2];
486  vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
487  vpImage<double> GIx;
488  vpImageFilter::filterX(I, GIx, fg, size);
489  vpImageFilter::filterY(GIx, GI, fg, size);
490  GIx.destroy();
491  delete[] fg;
492 }
493 
505 void vpImageFilter::gaussianBlur(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &GI, unsigned int size, double sigma,
506  bool normalize)
507 {
508  double *fg = new double[(size + 1) / 2];
509  vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
510  vpImage<vpRGBa> GIx;
511  vpImageFilter::filterX(I, GIx, fg, size);
512  vpImageFilter::filterY(GIx, GI, fg, size);
513  GIx.destroy();
514  delete[] fg;
515 }
516 
528 void vpImageFilter::gaussianBlur(const vpImage<double> &I, vpImage<double> &GI, unsigned int size, double sigma,
529  bool normalize)
530 {
531  double *fg = new double[(size + 1) / 2];
532  vpImageFilter::getGaussianKernel(fg, size, sigma, normalize);
533  vpImage<double> GIx;
534  vpImageFilter::filterX(I, GIx, fg, size);
535  vpImageFilter::filterY(GIx, GI, fg, size);
536  GIx.destroy();
537  delete[] fg;
538 }
539 
555 void vpImageFilter::getGaussianKernel(double *filter, unsigned int size, double sigma, bool normalize)
556 {
557  if (size % 2 != 1)
558  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
559 
560  if (sigma <= 0)
561  sigma = (size - 1) / 6.0;
562 
563  int middle = (int)(size - 1) / 2;
564  double sigma2 = vpMath::sqr(sigma);
565  for (int i = 0; i <= middle; i++) {
566  filter[i] = (1. / (sigma * sqrt(2. * M_PI))) * exp(-(i * i) / (2. * sigma2));
567  }
568  if (normalize) {
569  // renormalization
570  double sum = 0;
571  for (int i = 1; i <= middle; i++) {
572  sum += 2 * filter[i];
573  }
574  sum += filter[0];
575 
576  for (int i = 0; i <= middle; i++) {
577  filter[i] = filter[i] / sum;
578  }
579  }
580 }
581 
595 void vpImageFilter::getGaussianDerivativeKernel(double *filter, unsigned int size, double sigma, bool normalize)
596 {
597  if (size % 2 != 1)
598  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
599 
600  if (sigma <= 0)
601  sigma = (size - 1) / 6.0;
602 
603  int middle = (int)(size - 1) / 2;
604  double sigma2 = vpMath::sqr(sigma);
605  filter[0] = 0.;
606  for (int i = 1; i <= middle; i++) {
607  filter[i] = -(1. / (sigma * sqrt(2. * M_PI))) *
608  (exp(-((i + 1) * (i + 1)) / (2. * sigma2)) - exp(-((i - 1) * (i - 1)) / (2. * sigma2))) / 2.;
609  }
610 
611  if (normalize) {
612  double sum = 0;
613  for (int i = 1; i <= middle; i++) {
614  sum += 2. * (1. / (sigma * sqrt(2. * M_PI))) * exp(-(i * i) / (2. * sigma2));
615  }
616  sum += (1. / (sigma * sqrt(2. * M_PI)));
617 
618  for (int i = 1; i <= middle; i++) {
619  filter[i] = filter[i] / sum;
620  }
621  }
622 }
623 
625 {
626  dIx.resize(I.getHeight(), I.getWidth());
627  // dIx=0;
628  for (unsigned int i = 0; i < I.getHeight(); i++) {
629  for (unsigned int j = 0; j < 3; j++) {
630  dIx[i][j] = 0;
631  }
632  for (unsigned int j = 3; j < I.getWidth() - 3; j++) {
633  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j);
634  }
635  for (unsigned int j = I.getWidth() - 3; j < I.getWidth(); j++) {
636  dIx[i][j] = 0;
637  }
638  }
639 }
640 
642 {
643  dIy.resize(I.getHeight(), I.getWidth());
644  // dIy=0;
645  for (unsigned int i = 0; i < 3; i++) {
646  for (unsigned int j = 0; j < I.getWidth(); j++) {
647  dIy[i][j] = 0;
648  }
649  }
650  for (unsigned int i = 3; i < I.getHeight() - 3; i++) {
651  for (unsigned int j = 0; j < I.getWidth(); j++) {
652  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j);
653  }
654  }
655  for (unsigned int i = I.getHeight() - 3; i < I.getHeight(); i++) {
656  for (unsigned int j = 0; j < I.getWidth(); j++) {
657  dIy[i][j] = 0;
658  }
659  }
660 }
661 
663  unsigned int size)
664 {
665  dIx.resize(I.getHeight(), I.getWidth());
666  //#pragma omp parallel for
667  for (unsigned int i = 0; i < I.getHeight(); i++) {
668  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
669  dIx[i][j] = 0;
670  }
671  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
672  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j, filter, size);
673  }
674  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
675  dIx[i][j] = 0;
676  }
677  }
678 }
679 void vpImageFilter::getGradX(const vpImage<double> &I, vpImage<double> &dIx, const double *filter, unsigned int size)
680 {
681  dIx.resize(I.getHeight(), I.getWidth());
682  // dIx=0;
683  for (unsigned int i = 0; i < I.getHeight(); i++) {
684  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
685  dIx[i][j] = 0;
686  }
687  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
688  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j, filter, size);
689  }
690  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
691  dIx[i][j] = 0;
692  }
693  }
694 }
695 
697  unsigned int size)
698 {
699  dIy.resize(I.getHeight(), I.getWidth());
700  //#pragma omp parallel for
701  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
702  for (unsigned int j = 0; j < I.getWidth(); j++) {
703  dIy[i][j] = 0;
704  }
705  }
706  //#pragma omp parallel for
707  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
708  for (unsigned int j = 0; j < I.getWidth(); j++) {
709  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j, filter, size);
710  }
711  }
712  //#pragma omp parallel for
713  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
714  for (unsigned int j = 0; j < I.getWidth(); j++) {
715  dIy[i][j] = 0;
716  }
717  }
718 }
719 
720 void vpImageFilter::getGradY(const vpImage<double> &I, vpImage<double> &dIy, const double *filter, unsigned int size)
721 {
722  dIy.resize(I.getHeight(), I.getWidth());
723  // dIy=0;
724  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
725  for (unsigned int j = 0; j < I.getWidth(); j++) {
726  dIy[i][j] = 0;
727  }
728  }
729  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
730  for (unsigned int j = 0; j < I.getWidth(); j++) {
731  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j, filter, size);
732  }
733  }
734  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
735  for (unsigned int j = 0; j < I.getWidth(); j++) {
736  dIy[i][j] = 0;
737  }
738  }
739 }
740 
750 void vpImageFilter::getGradXGauss2D(const vpImage<unsigned char> &I, vpImage<double> &dIx, const double *gaussianKernel,
751  const double *gaussianDerivativeKernel, unsigned int size)
752 {
753  vpImage<double> GIy;
754  vpImageFilter::filterY(I, GIy, gaussianKernel, size);
755  vpImageFilter::getGradX(GIy, dIx, gaussianDerivativeKernel, size);
756 }
757 
767 void vpImageFilter::getGradYGauss2D(const vpImage<unsigned char> &I, vpImage<double> &dIy, const double *gaussianKernel,
768  const double *gaussianDerivativeKernel, unsigned int size)
769 {
770  vpImage<double> GIx;
771  vpImageFilter::filterX(I, GIx, gaussianKernel, size);
772  vpImageFilter::getGradY(GIx, dIy, gaussianDerivativeKernel, size);
773 }
774 
775 // operation pour pyramide gaussienne
777 {
779 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x030000)
780  cv::Mat imgsrc, imgdest;
781  vpImageConvert::convert(I, imgsrc);
782  cv::pyrDown(imgsrc, imgdest, cv::Size((int)I.getWidth() / 2, (int)I.getHeight() / 2));
783  vpImageConvert::convert(imgdest, GI);
784 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020408)
785  cv::Mat imgsrc, imgdest;
786  vpImageConvert::convert(I, imgsrc);
787  cv::pyrDown(imgsrc, imgdest, cvSize((int)I.getWidth() / 2, (int)I.getHeight() / 2));
788  vpImageConvert::convert(imgdest, GI);
789 #elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020100)
790  IplImage *imgsrc = NULL; // cvCreateImage(cvGetSize(imgign), IPL_DEPTH_8U, 1);
791  IplImage *imgdest = NULL; // cvCreateImage(cvGetSize(imgign), IPL_DEPTH_8U, 1);
792  imgsrc = cvCreateImage(cvSize((int)I.getWidth(), (int)I.getHeight()), IPL_DEPTH_8U, 1);
793  imgdest = cvCreateImage(cvSize((int)I.getWidth() / 2, (int)I.getHeight() / 2), IPL_DEPTH_8U, 1);
794  vpImageConvert::convert(I, imgsrc);
795  cvPyrDown(imgsrc, imgdest);
796  vpImageConvert::convert(imgdest, GI);
797 
798  cvReleaseImage(&imgsrc);
799  cvReleaseImage(&imgdest);
800 // vpImage<unsigned char> sGI;sGI=GI;
801 
802 #else
805 #endif
806 }
807 
809 {
810 #if 0
811  GI.resize(I.getHeight(),(int)((I.getWidth()+1.)/2.)) ;
812  for (unsigned int i=0 ; i < I.getHeight() ; i++)
813  {
814  GI[i][0]=I[i][0];
815  for (unsigned int j=1 ; j < ((I.getWidth()+1.)/2.)-1 ; j++)
816  {
817  GI[i][j]=vpImageFilter::filterGaussXPyramidal(I,i,2*j);
818  }
819  GI[i][(int)((I.getWidth()+1.)/2.)-1]=I[i][2*((int)((I.getWidth()+1.)/2.)-1)];
820  }
821 #else
822  unsigned int w = I.getWidth() / 2;
823 
824  GI.resize(I.getHeight(), w);
825  for (unsigned int i = 0; i < I.getHeight(); i++) {
826  GI[i][0] = I[i][0];
827  for (unsigned int j = 1; j < w - 1; j++) {
828  GI[i][j] = vpImageFilter::filterGaussXPyramidal(I, i, 2 * j);
829  }
830  GI[i][w - 1] = I[i][2 * w - 1];
831  }
832 
833 #endif
834 }
836 {
837 
838 #ifdef ORIG
839  GI.resize((int)((I.getHeight() + 1.) / 2.), I.getWidth());
840  for (unsigned int j = 0; j < I.getWidth(); j++) {
841  GI[0][j] = I[0][j];
842  for (unsigned int i = 1; i < ((I.getHeight() + 1.) / 2.) - 1; i++) {
843  GI[i][j] = vpImageFilter::filterGaussYPyramidal(I, 2 * i, j);
844  }
845  GI[(int)((I.getHeight() + 1.) / 2.) - 1][j] = I[2 * ((int)((I.getHeight() + 1.) / 2.) - 1)][j];
846  }
847 
848 #else
849  unsigned int h = I.getHeight() / 2;
850 
851  GI.resize(h, I.getWidth());
852  for (unsigned int j = 0; j < I.getWidth(); j++) {
853  GI[0][j] = I[0][j];
854  for (unsigned int i = 1; i < h - 1; i++) {
855  GI[i][j] = vpImageFilter::filterGaussYPyramidal(I, 2 * i, j);
856  }
857  GI[h - 1][j] = I[2 * h - 1][j];
858  }
859 #endif
860 }
861 
869 double vpImageFilter::getSobelKernelX(double *filter, unsigned int size)
870 {
871  if (size == 0)
872  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
873  if (size > 20)
874  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
875 
876  vpMatrix SobelY(size*2+1, size*2+1);
877  double norm = getSobelKernelY(SobelY.data, size);
878  memcpy(filter, SobelY.t().data, SobelY.getRows()*SobelY.getCols()*sizeof(double));
879  return norm;
880 }
881 
889 double vpImageFilter::getSobelKernelY(double *filter, unsigned int size)
890 {
891  //Sobel kernel pre-computed for the usual size
892  static const double SobelY3x3[9] = {-1.0, -2.0, -1.0,
893  0.0, 0.0, 0.0,
894  1.0, 2.0, 1.0};
895  static const double SobelY5x5[25] = {-1.0, -4.0, -6.0, -4.0, -1.0,
896  -2.0, -8.0, -12.0, -8.0, -2.0,
897  0.0, 0.0, 0.0, 0.0, 0.0,
898  2.0, 8.0, 12.0, 8.0, 2.0,
899  1.0, 4.0, 6.0, 4.0, 1.0};
900  static const double SobelY7x7[49] = {-1, -6, -15, -20, -15, -6, -1,
901  -4, -24, -60, -80, -60, -24, -4,
902  -5, -30, -75, -100, -75, -30, -5,
903  0, 0, 0, 0, 0, 0, 0,
904  5, 30, 75, 100, 75, 30, 5,
905  4, 24, 60, 80, 60, 24, 4,
906  1, 6, 15, 20, 15, 6, 1};
907  static const vpMatrix smoothingKernel(3,3);
908  smoothingKernel[0][0] = 1.0; smoothingKernel[0][1] = 2.0; smoothingKernel[0][2] = 1.0;
909  smoothingKernel[1][0] = 2.0; smoothingKernel[1][1] = 4.0; smoothingKernel[1][2] = 2.0;
910  smoothingKernel[2][0] = 1.0; smoothingKernel[2][1] = 2.0; smoothingKernel[2][2] = 1.0;
911 
912  if (size == 0)
913  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
914  if (size > 20)
915  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
916 
917  const unsigned int kernel_size = size*2+1;
918  if (kernel_size == 3) {
919  memcpy(filter, SobelY3x3, kernel_size*kernel_size*sizeof(double));
920  return 1/8.0;
921  }
922  if (kernel_size == 5) {
923  memcpy(filter, SobelY5x5, kernel_size*kernel_size*sizeof(double));
924  return 1/16.0;
925  }
926  if (kernel_size == 7) {
927  memcpy(filter, SobelY7x7, kernel_size*kernel_size*sizeof(double));
928  return 1/16.0;
929  }
930 
931  vpMatrix sobelY(7,7);
932  memcpy(sobelY.data, SobelY7x7, sobelY.getRows()*sobelY.getCols()*sizeof(double));
933  for (unsigned int i = 4; i <= size; i++) {
934  sobelY = vpMatrix::conv2(sobelY, smoothingKernel, "full");
935  }
936 
937  memcpy(filter, sobelY.data, sobelY.getRows()*sobelY.getCols()*sizeof(double));
938 
939  return 1/16.0;
940 }
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:153
static double filterXLeftBorder(const vpImage< unsigned char > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterXR(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterYTopBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterYG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterYBottomBorderG(const vpImage< vpRGBa > &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:6810
static void filterXB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double derivativeFilterX(const vpImage< T > &I, unsigned int r, unsigned int c)
Definition: vpImageFilter.h:82
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
static void getGradX(const vpImage< unsigned char > &I, vpImage< double > &dIx)
static void filterYB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void getGaussYPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
static void getGradY(const vpImage< unsigned char > &I, vpImage< double > &dIy)
static void sepFilter(const vpImage< unsigned char > &I, vpImage< double > &If, const vpColVector &kernelH, const vpColVector &kernelV)
static double derivativeFilterY(const vpImage< T > &I, unsigned int r, unsigned int c)
Definition: vpImageFilter.h:96
static double filterYBottomBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
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)
unsigned int getRows() const
Definition: vpArray2D.h:289
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:145
static void getGradYGauss2D(const vpImage< unsigned char > &I, vpImage< double > &dIy, const double *gaussianKernel, const double *gaussianDerivativeKernel, unsigned int size)
static double filterXLeftBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:291
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 double filterYTopBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
unsigned int getCols() const
Definition: vpArray2D.h:279
vpMatrix t() const
Definition: vpMatrix.cpp:464
static double filterYTopBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, 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:116
static double filterXRightBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void canny(const vpImage< unsigned char > &I, vpImage< unsigned char > &Ic, unsigned int gaussianFilterSize, double thresholdCanny, unsigned int apertureSobel)
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)
static double filterXLeftBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
void destroy()
Destructor : Memory de-allocation.
Definition: vpImage.h:829
static double filterXRightBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filter(const vpImage< double > &I, vpImage< double > &Iu, vpImage< double > &Iv, const vpMatrix &M, bool convolve=false)
static void filterXG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
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 void filterYR(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
unsigned int getHeight() const
Definition: vpImage.h:188
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:130
static unsigned char filterGaussXPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static double filterXLeftBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterXRightBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double getSobelKernelX(double *filter, unsigned int size)
unsigned int getWidth() const
Definition: vpImage.h:246
static double filterYBottomBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)