Visual Servoing Platform  version 3.6.1 under development (2023-12-02)
vpImageFilter.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Various image tools, convolution, ...
32  */
33 
34 #ifndef _vpImageFilter_h_
35 #define _vpImageFilter_h_
36 
42 #include <fstream>
43 #include <iostream>
44 #include <math.h>
45 #include <string.h>
46 
47 #include <visp3/core/vpException.h>
48 #include <visp3/core/vpHistogram.h>
49 #include <visp3/core/vpImage.h>
50 #include <visp3/core/vpImageConvert.h>
51 #include <visp3/core/vpImageException.h>
52 #include <visp3/core/vpMath.h>
53 #include <visp3/core/vpMatrix.h>
54 #include <visp3/core/vpRGBa.h>
55 
56 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
57 #include <opencv2/imgproc/imgproc.hpp>
58 #include <opencv2/imgproc/imgproc_c.h>
59 #endif
60 
68 class VISP_EXPORT vpImageFilter
69 {
70 public:
72  typedef enum vpCannyBackendType
73  {
74  CANNY_OPENCV_BACKEND = 0,
75  CANNY_VISP_BACKEND = 1,
76  CANNY_COUNT_BACKEND = 2
77  } vpCannyBackendType;
78 
79  static std::string vpCannyBackendTypeList(const std::string &pref = "<", const std::string &sep = " , ",
80  const std::string &suf = ">");
81 
82  static std::string vpCannyBackendTypeToString(const vpCannyBackendType &type);
83 
84  static vpCannyBackendType vpCannyBackendTypeFromString(const std::string &name);
85 
88  {
89  CANNY_GBLUR_SOBEL_FILTERING = 0,
90  CANNY_GBLUR_SCHARR_FILTERING = 1,
91  CANNY_COUNT_FILTERING = 2
92  } vpCannyFilteringAndGradientType;
93 
94  static std::string vpCannyFilteringAndGradientTypeList(const std::string &pref = "<", const std::string &sep = " , ",
95  const std::string &suf = ">");
96 
97  static std::string vpCannyFilteringAndGradientTypeToString(const vpCannyFilteringAndGradientType &type);
98 
99  static vpCannyFilteringAndGradientType vpCannyFilteringAndGradientTypeFromString(const std::string &name);
100 
101  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
102  const float &thresholdCanny, const unsigned int &apertureSobel);
103 
104  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
105  const float &lowerThresholdCanny, const float &higherThresholdCanny,
106  const unsigned int &apertureSobel);
107 
108  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
109  const float &lowerThresholdCanny, const float &higherThresholdCanny,
110  const unsigned int &apertureSobel, const float &gaussianStdev, const float &lowerThresholdRatio,
111  const float &upperThresholdRatio, const bool &normalizeGradients,
112  const vpCannyBackendType &cannyBackend, const vpCannyFilteringAndGradientType &cannyFilteringSteps);
113 
114 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
115  static float computeCannyThreshold(const cv::Mat &cv_I, const cv::Mat *p_cv_dIx, const cv::Mat *p_cv_dIy,
116  float &lowerThresh, const unsigned int &gaussianKernelSize = 5,
117  const float &gaussianStdev = 2.f, const unsigned int &apertureGradient = 3,
118  const float &lowerThresholdRatio = 0.6, const float &upperThresholdRatio = 0.8,
119  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
120 
121  static void computePartialDerivatives(const cv::Mat &cv_I,
122  cv::Mat &cv_dIx, cv::Mat &cv_dIy,
123  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
124  const unsigned int &gaussianKernelSize = 5, const float &gaussianStdev = 2.f,
125  const unsigned int &apertureGradient = 3,
126  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
127 #endif
128 
148  template <typename ImageType, typename FilterType>
149  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
151  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
152  const unsigned int &gaussianKernelSize = 5, const FilterType &gaussianStdev = 2.f,
153  const unsigned int &apertureGradient = 3,
154  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
155  const vpCannyBackendType &backend = CANNY_VISP_BACKEND)
156  {
157  if (backend == CANNY_OPENCV_BACKEND) {
158 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
159  cv::Mat cv_I, cv_dIx, cv_dIy;
160  vpImageConvert::convert(I, cv_I);
161  computePartialDerivatives(cv_I, cv_dIx, cv_dIy, computeDx, computeDy, normalize, gaussianKernelSize,
162  gaussianStdev, apertureGradient, filteringType);
163  if (computeDx) {
164  vpImageConvert::convert(cv_dIx, dIx);
165  }
166  if (computeDy) {
167  vpImageConvert::convert(cv_dIy, dIy);
168  }
169 #else
170  throw(vpException(vpException::badValue, "You need to compile ViSP with OpenCV to use CANNY_OPENCV_BACKEND"));
171 #endif
172  }
173  else {
174  if (filteringType == CANNY_GBLUR_SCHARR_FILTERING || filteringType == CANNY_GBLUR_SOBEL_FILTERING) {
175  dIx.resize(I.getHeight(), I.getWidth());
176  dIy.resize(I.getHeight(), I.getWidth());
177 
178  // Computing the Gaussian blur + gradients of the image
179  vpImage<FilterType> Iblur;
180  vpImageFilter::gaussianBlur(I, Iblur, gaussianKernelSize, gaussianStdev);
181 
182  vpArray2D<FilterType> gradientFilterX(apertureGradient, apertureGradient); // Gradient filter along the X-axis
183  vpArray2D<FilterType> gradientFilterY(apertureGradient, apertureGradient); // Gradient filter along the Y-axis
184 
185  // Helper to apply the scale to the raw values of the filters
186  auto scaleFilter = [](vpArray2D<FilterType> &filter, const float &scale) {
187  for (unsigned int r = 0; r < filter.getRows(); r++) {
188  for (unsigned int c = 0; c < filter.getCols(); c++) {
189  filter[r][c] = filter[r][c] * scale;
190  }
191  }};
192 
193  // Scales to apply to the filters to get a normalized gradient filter that gives a gradient
194  // between 0 and 255 for an vpImage<uchar>
195  float scaleX = 1.f;
196  float scaleY = 1.f;
197 
198  if (filteringType == CANNY_GBLUR_SOBEL_FILTERING) {
199  if (computeDx) {
200  scaleX = vpImageFilter::getSobelKernelX(gradientFilterX.data, (apertureGradient - 1)/2);
201  }
202  if (computeDy) {
203  scaleY = vpImageFilter::getSobelKernelY(gradientFilterY.data, (apertureGradient - 1)/2);
204  }
205  }
206  else if (filteringType == CANNY_GBLUR_SCHARR_FILTERING) {
207  if (computeDx) {
208  scaleX = vpImageFilter::getScharrKernelX(gradientFilterX.data, (apertureGradient - 1)/2);
209  }
210  if (computeDy) {
211  scaleY = vpImageFilter::getScharrKernelY(gradientFilterY.data, (apertureGradient - 1)/2);
212  }
213  }
214 
215  // Scale the gradient filters to have a normalized gradient filter
216  if (normalize) {
217  if (computeDx) {
218  scaleFilter(gradientFilterX, scaleX);
219  }
220  if (computeDy) {
221  scaleFilter(gradientFilterY, scaleY);
222  }
223  }
224 
225  // Apply the gradient filters to get the gradients
226  if (computeDx) {
227  vpImageFilter::filter(Iblur, dIx, gradientFilterX);
228  }
229 
230  if (computeDy) {
231  vpImageFilter::filter(Iblur, dIy, gradientFilterY);
232  }
233  }
234  else {
235  std::string errMsg = "[vpImageFilter::computePartialDerivatives] Filtering + gradient method \"";
236  errMsg += vpCannyFilteringAndGradientTypeToString(filteringType);
237  errMsg += "\" is not implemented yet\n";
239  }
240  }
241  }
242 
243  template <typename FilterType>
244  inline static void computePartialDerivatives(const vpImage<vpRGBa> &I,
246  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
247  const unsigned int &gaussianKernelSize = 5, const FilterType &gaussianStdev = 2.f,
248  const unsigned int &apertureGradient = 3,
249  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
250  const vpCannyBackendType &backend = CANNY_VISP_BACKEND) = delete;
251 
252  template <typename ImageType>
253  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
255  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
256  const unsigned int &gaussianKernelSize = 5, const unsigned char &gaussianStdev = 2.f,
257  const unsigned int &apertureGradient = 3,
258  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
259  const vpCannyBackendType &backend = CANNY_VISP_BACKEND) = delete;
260 
261  template <typename ImageType>
262  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
263  vpImage<vpRGBa> &dIx, vpImage<vpRGBa> &dIy,
264  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
265  const unsigned int gaussianKernelSize = 5, const vpRGBa gaussianStdev = vpRGBa(),
266  const unsigned int apertureGradient = 3,
267  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
268  const vpCannyBackendType &backend = CANNY_VISP_BACKEND) = delete;
269 
289  template<typename OutType>
290  inline static float computeCannyThreshold(const vpImage<unsigned char> &I, float &lowerThresh,
291  const vpImage<OutType> *p_dIx = nullptr, const vpImage<OutType> *p_dIy = nullptr,
292  const unsigned int &gaussianKernelSize = 5,
293  const OutType &gaussianStdev = 2.f, const unsigned int &apertureGradient = 3,
294  const float &lowerThresholdRatio = 0.6, const float &upperThresholdRatio = 0.8,
295  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING)
296  {
297  double w = I.getWidth();
298  double h = I.getHeight();
299 
300  vpImage<unsigned char> dI(h, w);
301  vpImage<OutType> dIx(h, w), dIy(h, w);
302  if (p_dIx != nullptr && p_dIy != nullptr) {
303  dIx = *p_dIx;
304  dIy = *p_dIy;
305  }
306  else {
307  computePartialDerivatives(I, dIx, dIy, true, true, true, gaussianKernelSize, gaussianStdev,
308  apertureGradient, filteringType);
309  }
310 
311  // Computing the absolute gradient of the image G = |dIx| + |dIy|
312  for (unsigned int r = 0; r < h; r++) {
313  for (unsigned int c = 0; c < w; c++) {
314  float dx = (float)dIx[r][c];
315  float dy = (float)dIy[r][c];
316  float gradient = std::abs(dx) + std::abs(dy);
317  float gradientClamped = std::min(gradient, (float)std::numeric_limits<unsigned char>::max());
318  dI[r][c] = gradientClamped;
319  }
320  }
321 
322  // Compute the histogram
323  vpHistogram hist;
324  const unsigned int nbBins = 256;
325  hist.calculate(dI, nbBins);
326  float accu = 0;
327  float t = (float)(upperThresholdRatio * w * h);
328  float bon = 0;
329  for (unsigned int i = 0; i < nbBins; i++) {
330  float tf = hist[i];
331  accu = accu + tf;
332  if (accu > t) {
333  bon = (float)i;
334  break;
335  }
336  }
337  float upperThresh = std::max(bon, 1.f);
338  lowerThresh = lowerThresholdRatio * bon;
339  return upperThresh;
340  }
341 
349  template <class ImageType> static double derivativeFilterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c)
350  {
351  return (2047.0 * (I[r][c + 1] - I[r][c - 1]) + 913.0 * (I[r][c + 2] - I[r][c - 2]) +
352  112.0 * (I[r][c + 3] - I[r][c - 3])) / 8418.0;
353  }
354 
362  template <class ImageType> static double derivativeFilterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c)
363  {
364  return (2047.0 * (I[r + 1][c] - I[r - 1][c]) + 913.0 * (I[r + 2][c] - I[r - 2][c]) +
365  112.0 * (I[r + 3][c] - I[r - 3][c])) / 8418.0;
366  }
367 
381  template <class ImageType, typename FilterType>
382  static FilterType derivativeFilterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
383  {
384  unsigned int i;
385  FilterType result;
386 
387  result = 0;
388 
389  for (i = 1; i <= (size - 1) / 2; i++) {
390  result += filter[i] * (I[r][c + i] - I[r][c - i]);
391  }
392  return result;
393  }
394 
408  template <class ImageType, typename FilterType>
409  static FilterType derivativeFilterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
410  {
411  unsigned int i;
412  FilterType result;
413 
414  result = 0;
415 
416  for (i = 1; i <= (size - 1) / 2; i++) {
417  result += filter[i] * (I[r + i][c] - I[r - i][c]);
418  }
419  return result;
420  }
421 
450  template <typename ImageType, typename FilterType>
451  static void filter(const vpImage<ImageType> &I, vpImage<FilterType> &If, const vpArray2D<FilterType> &M, bool convolve = false)
452  {
453  unsigned int size_y = M.getRows(), size_x = M.getCols();
454  unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
455 
456  If.resize(I.getHeight(), I.getWidth(), 0.0);
457 
458  if (convolve) {
459  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
460  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
461  FilterType conv = 0;
462 
463  for (unsigned int a = 0; a < size_y; a++) {
464  for (unsigned int b = 0; b < size_x; b++) {
465  FilterType val = I[i + half_size_y - a][j + half_size_x - b]; // Convolution
466  conv += M[a][b] * val;
467  }
468  }
469  If[i][j] = conv;
470  }
471  }
472  }
473  else {
474  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
475  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
476  FilterType corr = 0;
477 
478  for (unsigned int a = 0; a < size_y; a++) {
479  for (unsigned int b = 0; b < size_x; b++) {
480  FilterType val = I[i - half_size_y + a][j - half_size_x + b]; // Correlation
481  corr += M[a][b] * val;
482  }
483  }
484  If[i][j] = corr;
485  }
486  }
487  }
488  }
489 
490  template <typename FilterType>
491  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &If, const vpArray2D<FilterType> &M, bool convolve = false) = delete;
492 
505  template <typename ImageType, typename FilterType>
507  bool convolve = false)
508  {
509  unsigned int size = M.getRows();
510  unsigned int half_size = size / 2;
511 
512  Iu.resize(I.getHeight(), I.getWidth(), 0.0);
513  Iv.resize(I.getHeight(), I.getWidth(), 0.0);
514 
515  if (convolve) {
516  for (unsigned int v = half_size; v < I.getHeight() - half_size; v++) {
517  for (unsigned int u = half_size; u < I.getWidth() - half_size; u++) {
518  FilterType conv_u = 0;
519  FilterType conv_v = 0;
520 
521  for (unsigned int a = 0; a < size; a++) {
522  for (unsigned int b = 0; b < size; b++) {
523  FilterType val = I[v + half_size - a][u + half_size - b]; // Convolution
524  conv_u += M[a][b] * val;
525  conv_v += M[b][a] * val;
526  }
527  }
528  Iu[v][u] = conv_u;
529  Iv[v][u] = conv_v;
530  }
531  }
532  }
533  else {
534  for (unsigned int v = half_size; v < I.getHeight() - half_size; v++) {
535  for (unsigned int u = half_size; u < I.getWidth() - half_size; u++) {
536  FilterType conv_u = 0;
537  FilterType conv_v = 0;
538 
539  for (unsigned int a = 0; a < size; a++) {
540  for (unsigned int b = 0; b < size; b++) {
541  FilterType val = I[v - half_size + a][u - half_size + b]; // Correlation
542  conv_u += M[a][b] * val;
543  conv_v += M[b][a] * val;
544  }
545  }
546  Iu[v][u] = conv_u;
547  Iv[v][u] = conv_v;
548  }
549  }
550  }
551  }
552 
553  template<typename FilterType>
554  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &Iu, vpImage<FilterType> &Iv, const vpArray2D<FilterType> &M, bool convolve) = delete;
555 
556  template<typename ImageType>
557  static void filter(const vpImage<ImageType> &I, vpImage<ImageType> &Iu, vpImage<ImageType> &Iv, const vpArray2D<vpRGBa> &M, bool convolve) = delete;
558 
559  static void sepFilter(const vpImage<unsigned char> &I, vpImage<double> &If, const vpColVector &kernelH, const vpColVector &kernelV);
560 
569  template <typename ImageType, typename FilterType>
570  static void filter(const vpImage<ImageType> &I, vpImage<FilterType> &GI, const FilterType *filter, unsigned int size)
571  {
573  filterX<ImageType, FilterType>(I, GIx, filter, size);
574  filterY<FilterType, FilterType>(GIx, GI, filter, size);
575  GIx.destroy();
576  }
577 
578  static inline unsigned char filterGaussXPyramidal(const vpImage<unsigned char> &I, unsigned int i, unsigned int j)
579  {
580  return (unsigned char)((1. * I[i][j - 2] + 4. * I[i][j - 1] + 6. * I[i][j] + 4. * I[i][j + 1] + 1. * I[i][j + 2]) / 16.);
581  }
582  static inline unsigned char filterGaussYPyramidal(const vpImage<unsigned char> &I, unsigned int i, unsigned int j)
583  {
584  return (unsigned char)((1. * I[i - 2][j] + 4. * I[i - 1][j] + 6. * I[i][j] + 4. * I[i + 1][j] + 1. * I[i + 2][j]) / 16.);
585  }
586 
587  template <typename ImageType, typename FilterType>
588  static void filterX(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *filter, unsigned int size)
589  {
590  dIx.resize(I.getHeight(), I.getWidth());
591  for (unsigned int i = 0; i < I.getHeight(); i++) {
592  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
593  dIx[i][j] = vpImageFilter::filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
594  }
595  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
596  dIx[i][j] = vpImageFilter::filterX<ImageType, FilterType>(I, i, j, filter, size);
597  }
598  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
599  dIx[i][j] = vpImageFilter::filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
600  }
601  }
602  }
603 
604  static void filterX(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
605  static void filterXR(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
606  static void filterXG(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
607  static void filterXB(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
608 
609  template<typename ImageType, typename FilterType>
610  static inline FilterType filterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
611  {
612  FilterType result;
613 
614  result = 0;
615 
616  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
617  result += filter[i] * (I[r][c + i] + I[r][c - i]);
618  }
619  return result + filter[0] * I[r][c];
620  }
621 
622  static inline double filterXR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
623  {
624  double result;
625 
626  result = 0;
627 
628  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
629  result += filter[i] * (I[r][c + i].R + I[r][c - i].R);
630  }
631  return result + filter[0] * I[r][c].R;
632  }
633 
634  static inline double filterXG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
635  {
636  double result;
637 
638  result = 0;
639 
640  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
641  result += filter[i] * (I[r][c + i].G + I[r][c - i].G);
642  }
643  return result + filter[0] * I[r][c].G;
644  }
645 
646  static inline double filterXB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
647  {
648  double result;
649 
650  result = 0;
651 
652  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
653  result += filter[i] * (I[r][c + i].B + I[r][c - i].B);
654  }
655  return result + filter[0] * I[r][c].B;
656  }
657 
658  template <typename ImageType, typename FilterType>
659  static inline FilterType filterXLeftBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
660  const FilterType *filter, unsigned int size)
661  {
662  FilterType result;
663 
664  result = 0;
665 
666  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
667  if (c > i)
668  result += filter[i] * (I[r][c + i] + I[r][c - i]);
669  else
670  result += filter[i] * (I[r][c + i] + I[r][i - c]);
671  }
672  return result + filter[0] * I[r][c];
673  }
674 
675  static inline double filterXLeftBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
676  const double *filter, unsigned int size)
677  {
678  double result;
679 
680  result = 0;
681 
682  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
683  if (c > i)
684  result += filter[i] * (I[r][c + i].R + I[r][c - i].R);
685  else
686  result += filter[i] * (I[r][c + i].R + I[r][i - c].R);
687  }
688  return result + filter[0] * I[r][c].R;
689  }
690 
691  static inline double filterXLeftBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
692  const double *filter, unsigned int size)
693  {
694  double result;
695 
696  result = 0;
697 
698  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
699  if (c > i)
700  result += filter[i] * (I[r][c + i].G + I[r][c - i].G);
701  else
702  result += filter[i] * (I[r][c + i].G + I[r][i - c].G);
703  }
704  return result + filter[0] * I[r][c].G;
705  }
706 
707  static inline double filterXLeftBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
708  const double *filter, unsigned int size)
709  {
710  double result;
711 
712  result = 0;
713 
714  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
715  if (c > i)
716  result += filter[i] * (I[r][c + i].B + I[r][c - i].B);
717  else
718  result += filter[i] * (I[r][c + i].B + I[r][i - c].B);
719  }
720  return result + filter[0] * I[r][c].B;
721  }
722 
723  template <typename ImageType, typename FilterType>
724  static inline FilterType filterXRightBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
725  const FilterType *filter, unsigned int size)
726  {
727  FilterType result;
728 
729  result = 0;
730 
731  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
732  if (c + i < I.getWidth())
733  result += filter[i] * (I[r][c + i] + I[r][c - i]);
734  else
735  result += filter[i] * (I[r][2 * I.getWidth() - c - i - 1] + I[r][c - i]);
736  }
737  return result + filter[0] * I[r][c];
738  }
739 
740  static inline double filterXRightBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
741  const double *filter, unsigned int size)
742  {
743  double result;
744 
745  result = 0;
746 
747  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
748  if (c + i < I.getWidth())
749  result += filter[i] * (I[r][c + i].R + I[r][c - i].R);
750  else
751  result += filter[i] * (I[r][2 * I.getWidth() - c - i - 1].R + I[r][c - i].R);
752  }
753  return result + filter[0] * I[r][c].R;
754  }
755 
756  static inline double filterXRightBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
757  const double *filter, unsigned int size)
758  {
759  double result;
760 
761  result = 0;
762 
763  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
764  if (c + i < I.getWidth())
765  result += filter[i] * (I[r][c + i].G + I[r][c - i].G);
766  else
767  result += filter[i] * (I[r][2 * I.getWidth() - c - i - 1].G + I[r][c - i].G);
768  }
769  return result + filter[0] * I[r][c].G;
770  }
771 
772  static inline double filterXRightBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
773  const double *filter, unsigned int size)
774  {
775  double result;
776 
777  result = 0;
778 
779  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
780  if (c + i < I.getWidth())
781  result += filter[i] * (I[r][c + i].B + I[r][c - i].B);
782  else
783  result += filter[i] * (I[r][2 * I.getWidth() - c - i - 1].B + I[r][c - i].B);
784  }
785  return result + filter[0] * I[r][c].B;
786  }
787 
788  static void filterY(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
789  static void filterYR(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
790  static void filterYG(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
791  static void filterYB(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
792 
793  template<typename ImageType, typename FilterType>
794  static void filterY(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *filter, unsigned int size)
795  {
796  dIy.resize(I.getHeight(), I.getWidth());
797  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
798  for (unsigned int j = 0; j < I.getWidth(); j++) {
799  dIy[i][j] = vpImageFilter::filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
800  }
801  }
802  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
803  for (unsigned int j = 0; j < I.getWidth(); j++) {
804  dIy[i][j] = vpImageFilter::filterY<ImageType, FilterType>(I, i, j, filter, size);
805  }
806  }
807  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
808  for (unsigned int j = 0; j < I.getWidth(); j++) {
809  dIy[i][j] = vpImageFilter::filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
810  }
811  }
812  }
813 
814  template<typename ImageType, typename FilterType>
815  static inline FilterType filterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
816  {
817  FilterType result;
818 
819  result = 0;
820 
821  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
822  result += filter[i] * (I[r + i][c] + I[r - i][c]);
823  }
824  return result + filter[0] * I[r][c];
825  }
826 
827  static inline double filterYR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
828  {
829  double result;
830 
831  result = 0;
832 
833  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
834  result += filter[i] * (I[r + i][c].R + I[r - i][c].R);
835  }
836  return result + filter[0] * I[r][c].R;
837  }
838  static inline double filterYG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
839  {
840  double result;
841 
842  result = 0;
843 
844  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
845  result += filter[i] * (I[r + i][c].G + I[r - i][c].G);
846  }
847  return result + filter[0] * I[r][c].G;
848  }
849 
850  static inline double filterYB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
851  {
852  double result;
853 
854  result = 0;
855 
856  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
857  result += filter[i] * (I[r + i][c].B + I[r - i][c].B);
858  }
859  return result + filter[0] * I[r][c].B;
860  }
861 
862  template<typename ImageType, typename FilterType>
863  static inline FilterType filterYTopBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
864  const FilterType *filter, unsigned int size)
865  {
866  FilterType result;
867 
868  result = 0;
869 
870  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
871  if (r > i)
872  result += filter[i] * (I[r + i][c] + I[r - i][c]);
873  else
874  result += filter[i] * (I[r + i][c] + I[i - r][c]);
875  }
876  return result + filter[0] * I[r][c];
877  }
878 
879  double static inline filterYTopBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
880  {
881  double result;
882 
883  result = 0;
884 
885  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
886  if (r > i)
887  result += filter[i] * (I[r + i][c].R + I[r - i][c].R);
888  else
889  result += filter[i] * (I[r + i][c].R + I[i - r][c].R);
890  }
891  return result + filter[0] * I[r][c].R;
892  }
893 
894  double static inline filterYTopBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
895  {
896  double result;
897 
898  result = 0;
899 
900  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
901  if (r > i)
902  result += filter[i] * (I[r + i][c].G + I[r - i][c].G);
903  else
904  result += filter[i] * (I[r + i][c].G + I[i - r][c].G);
905  }
906  return result + filter[0] * I[r][c].G;
907  }
908 
909  double static inline filterYTopBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
910  {
911  double result;
912 
913  result = 0;
914 
915  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
916  if (r > i)
917  result += filter[i] * (I[r + i][c].B + I[r - i][c].B);
918  else
919  result += filter[i] * (I[r + i][c].B + I[i - r][c].B);
920  }
921  return result + filter[0] * I[r][c].B;
922  }
923 
924  template<typename ImageType, typename FilterType>
925  static inline FilterType filterYBottomBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
926  const FilterType *filter, unsigned int size)
927  {
928  FilterType result;
929 
930  result = 0;
931 
932  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
933  if (r + i < I.getHeight())
934  result += filter[i] * (I[r + i][c] + I[r - i][c]);
935  else
936  result += filter[i] * (I[2 * I.getHeight() - r - i - 1][c] + I[r - i][c]);
937  }
938  return result + filter[0] * I[r][c];
939  }
940 
941  double static inline filterYBottomBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
942  const double *filter, unsigned int size)
943  {
944  double result;
945 
946  result = 0;
947 
948  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
949  if (r + i < I.getHeight())
950  result += filter[i] * (I[r + i][c].R + I[r - i][c].R);
951  else
952  result += filter[i] * (I[2 * I.getHeight() - r - i - 1][c].R + I[r - i][c].R);
953  }
954  return result + filter[0] * I[r][c].R;
955  }
956 
957  double static inline filterYBottomBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
958  const double *filter, unsigned int size)
959  {
960  double result;
961 
962  result = 0;
963 
964  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
965  if (r + i < I.getHeight())
966  result += filter[i] * (I[r + i][c].G + I[r - i][c].G);
967  else
968  result += filter[i] * (I[2 * I.getHeight() - r - i - 1][c].G + I[r - i][c].G);
969  }
970  return result + filter[0] * I[r][c].G;
971  }
972 
973  double static inline filterYBottomBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
974  const double *filter, unsigned int size)
975  {
976  double result;
977 
978  result = 0;
979 
980  for (unsigned int i = 1; i <= (size - 1) / 2; i++) {
981  if (r + i < I.getHeight())
982  result += filter[i] * (I[r + i][c].B + I[r - i][c].B);
983  else
984  result += filter[i] * (I[2 * I.getHeight() - r - i - 1][c].B + I[r - i][c].B);
985  }
986  return result + filter[0] * I[r][c].B;
987  }
988 
1001  template <typename ImageType, typename FilterType>
1002  static void gaussianBlur(const vpImage<ImageType> &I, vpImage<FilterType> &GI, unsigned int size = 7, FilterType sigma = 0., bool normalize = true)
1003  {
1004  FilterType *fg = new FilterType[(size + 1) / 2];
1005  vpImageFilter::getGaussianKernel<FilterType>(fg, size, sigma, normalize);
1006  vpImage<FilterType> GIx;
1007  vpImageFilter::filterX<ImageType, FilterType>(I, GIx, fg, size);
1008  vpImageFilter::filterY<FilterType, FilterType>(GIx, GI, fg, size);
1009  GIx.destroy();
1010  delete[] fg;
1011  }
1012 
1013  static void gaussianBlur(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &GI, unsigned int size = 7, double sigma = 0., bool normalize = true);
1014 
1022  template <class T> static double gaussianFilter(const vpImage<T> &fr, unsigned int r, unsigned int c)
1023  {
1024  return (15.0 * fr[r][c] + 12.0 * (fr[r - 1][c] + fr[r][c - 1] + fr[r + 1][c] + fr[r][c + 1]) +
1025  9.0 * (fr[r - 1][c - 1] + fr[r + 1][c - 1] + fr[r - 1][c + 1] + fr[r + 1][c + 1]) +
1026  5.0 * (fr[r - 2][c] + fr[r][c - 2] + fr[r + 2][c] + fr[r][c + 2]) +
1027  4.0 * (fr[r - 2][c + 1] + fr[r - 2][c - 1] + fr[r - 1][c - 2] + fr[r + 1][c - 2] + fr[r + 2][c - 1] +
1028  fr[r + 2][c + 1] + fr[r - 1][c + 2] + fr[r + 1][c + 2]) +
1029  2.0 * (fr[r - 2][c - 2] + fr[r + 2][c - 2] + fr[r - 2][c + 2] + fr[r + 2][c + 2])) / 159.0;
1030  }
1031  // Gaussian pyramid operation
1032  static void getGaussPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1033  static void getGaussXPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1034  static void getGaussYPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1035 
1052  template<typename FilterType>
1053  static void getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma = 0., bool normalize = true)
1054  {
1055  if (size % 2 != 1)
1056  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
1057 
1058  if (sigma <= 0)
1059  sigma = static_cast<FilterType>((size - 1) / 6.0);
1060 
1061  int middle = (int)(size - 1) / 2;
1062  FilterType sigma2 = static_cast<FilterType>(vpMath::sqr(sigma));
1063  FilterType coef1 = static_cast<FilterType>(1. / (sigma * sqrt(2. * M_PI)));
1064  FilterType _2_sigma2 = static_cast<FilterType>(2. * sigma2);
1065  for (int i = 0; i <= middle; i++) {
1066  filter[i] = coef1 * exp(-(i * i) / _2_sigma2);
1067  }
1068  if (normalize) {
1069  // renormalization
1070  FilterType sum = 0;
1071  for (int i = 1; i <= middle; i++) {
1072  sum += 2 * filter[i];
1073  }
1074  sum += filter[0];
1075 
1076  for (int i = 0; i <= middle; i++) {
1077  filter[i] = filter[i] / sum;
1078  }
1079  }
1080  }
1081 
1096  template <typename FilterType>
1097  static void getGaussianDerivativeKernel(FilterType *filter, unsigned int size, FilterType sigma = 0., bool normalize = true)
1098  {
1099  if (size % 2 != 1)
1100  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
1101 
1102  if (sigma <= 0)
1103  sigma = static_cast<FilterType>((size - 1) / 6.0);
1104 
1105  int middle = (int)(size - 1) / 2;
1106  FilterType sigma2 = static_cast<FilterType>(vpMath::sqr(sigma));
1107  FilterType coef_1 = static_cast<FilterType>(1. / (sigma * sqrt(2. * M_PI)));
1108  FilterType coef_1_over_2 = coef_1 / static_cast<FilterType>(2.);
1109  FilterType _2_coef_1 = static_cast<FilterType>(2.) * coef_1;
1110  FilterType _2_sigma2 = static_cast<FilterType>(2. * sigma2);
1111  filter[0] = 0.;
1112  for (int i = 1; i <= middle; i++) {
1113  filter[i] = -coef_1_over_2 * (static_cast<FilterType>(exp(-((i + 1) * (i + 1)) / _2_sigma2)) - static_cast<FilterType>(exp(-((i - 1) * (i - 1)) / _2_sigma2)));
1114  }
1115 
1116  if (normalize) {
1117  FilterType sum = 0;
1118  for (int i = 1; i <= middle; i++) {
1119  sum += _2_coef_1 * static_cast<FilterType>(exp(-(i * i) / _2_sigma2));
1120  }
1121  sum += coef_1;
1122 
1123  for (int i = 1; i <= middle; i++) {
1124  filter[i] = filter[i] / sum;
1125  }
1126  }
1127  }
1128 
1129  // Gradient along X
1130  template<typename FilterType>
1132  {
1133  dIx.resize(I.getHeight(), I.getWidth());
1134  // dIx=0;
1135  for (unsigned int i = 0; i < I.getHeight(); i++) {
1136  for (unsigned int j = 0; j < 3; j++) {
1137  dIx[i][j] = 0;
1138  }
1139  for (unsigned int j = 3; j < I.getWidth() - 3; j++) {
1140  dIx[i][j] = vpImageFilter::derivativeFilterX(I, i, j);
1141  }
1142  for (unsigned int j = I.getWidth() - 3; j < I.getWidth(); j++) {
1143  dIx[i][j] = 0;
1144  }
1145  }
1146  }
1147 
1148  template <typename ImageType, typename FilterType>
1149  static void getGradX(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *filter, unsigned int size)
1150  {
1151  dIx.resize(I.getHeight(), I.getWidth());
1152  for (unsigned int i = 0; i < I.getHeight(); i++) {
1153  for (unsigned int j = 0; j < (size - 1) / 2; j++) {
1154  dIx[i][j] = 0;
1155  }
1156  for (unsigned int j = (size - 1) / 2; j < I.getWidth() - (size - 1) / 2; j++) {
1157  dIx[i][j] = vpImageFilter::derivativeFilterX<ImageType, FilterType>(I, i, j, filter, size);
1158  }
1159  for (unsigned int j = I.getWidth() - (size - 1) / 2; j < I.getWidth(); j++) {
1160  dIx[i][j] = 0;
1161  }
1162  }
1163  }
1164 
1175  template <typename ImageType, typename FilterType>
1176  static void getGradXGauss2D(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *gaussianKernel,
1177  const FilterType *gaussianDerivativeKernel, unsigned int size)
1178  {
1179  vpImage<FilterType> GIy;
1180  vpImageFilter::filterY<ImageType, FilterType>(I, GIy, gaussianKernel, size);
1181  vpImageFilter::getGradX<FilterType, FilterType>(GIy, dIx, gaussianDerivativeKernel, size);
1182  }
1183 
1184  // Gradient along Y
1185  template <typename FilterType>
1187  {
1188  dIy.resize(I.getHeight(), I.getWidth());
1189  for (unsigned int i = 0; i < 3; i++) {
1190  for (unsigned int j = 0; j < I.getWidth(); j++) {
1191  dIy[i][j] = 0;
1192  }
1193  }
1194  for (unsigned int i = 3; i < I.getHeight() - 3; i++) {
1195  for (unsigned int j = 0; j < I.getWidth(); j++) {
1196  dIy[i][j] = vpImageFilter::derivativeFilterY(I, i, j);
1197  }
1198  }
1199  for (unsigned int i = I.getHeight() - 3; i < I.getHeight(); i++) {
1200  for (unsigned int j = 0; j < I.getWidth(); j++) {
1201  dIy[i][j] = 0;
1202  }
1203  }
1204  }
1205 
1206  template <typename ImageType, typename FilterType>
1207  static void getGradY(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *filter, unsigned int size)
1208  {
1209  dIy.resize(I.getHeight(), I.getWidth());
1210  for (unsigned int i = 0; i < (size - 1) / 2; i++) {
1211  for (unsigned int j = 0; j < I.getWidth(); j++) {
1212  dIy[i][j] = 0;
1213  }
1214  }
1215  for (unsigned int i = (size - 1) / 2; i < I.getHeight() - (size - 1) / 2; i++) {
1216  for (unsigned int j = 0; j < I.getWidth(); j++) {
1217  dIy[i][j] = vpImageFilter::derivativeFilterY<ImageType, FilterType>(I, i, j, filter, size);
1218  }
1219  }
1220  for (unsigned int i = I.getHeight() - (size - 1) / 2; i < I.getHeight(); i++) {
1221  for (unsigned int j = 0; j < I.getWidth(); j++) {
1222  dIy[i][j] = 0;
1223  }
1224  }
1225  }
1226 
1237  template <typename ImageType, typename FilterType>
1238  static void getGradYGauss2D(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *gaussianKernel,
1239  const FilterType *gaussianDerivativeKernel, unsigned int size)
1240  {
1241  vpImage<FilterType> GIx;
1242  vpImageFilter::filterX<ImageType, FilterType>(I, GIx, gaussianKernel, size);
1243  vpImageFilter::getGradY<FilterType, FilterType>(GIx, dIy, gaussianDerivativeKernel, size);
1244  }
1245 
1253  template <typename FilterType>
1254  inline static FilterType getScharrKernelX(FilterType *filter, unsigned int size)
1255  {
1256  if (size != 1) {
1257  // Size = 1 => kernel_size = 2*1 + 1 = 3
1258  std::string errMsg = "Cannot get Scharr kernel of size " + std::to_string(size * 2 + 1) + " != 3";
1260  }
1261 
1262  vpArray2D<FilterType> ScharrY(size * 2 + 1, size * 2 + 1);
1263  FilterType norm = getScharrKernelY<FilterType>(ScharrY.data, size);
1264  memcpy(filter, ScharrY.t().data, ScharrY.getRows() * ScharrY.getCols() * sizeof(FilterType));
1265  return norm;
1266  }
1267 
1275  template <typename FilterType>
1276  inline static FilterType getScharrKernelY(FilterType *filter, unsigned int size)
1277  {
1278  // Scharr kernel pre-computed for the usual size
1279  static const FilterType ScharrY3x3[9] = { -3.0, -10.0, -3.0, 0.0, 0.0, 0.0, 3.0, 10.0, 3.0 };
1280 
1281  if (size != 1) {
1282  // Size = 1 => kernel_size = 2*1 + 1 = 3
1283  std::string errMsg = "Cannot get Scharr kernel of size " + std::to_string(size * 2 + 1) + " != 3";
1285  }
1286 
1287  const unsigned int kernel_size = size * 2 + 1;
1288  if (kernel_size == 3) {
1289  memcpy(filter, ScharrY3x3, kernel_size * kernel_size * sizeof(FilterType));
1290  return 1 / 32.0;
1291  }
1292 
1293  return 0.;
1294  }
1295 
1303  template <typename FilterType>
1304  inline static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
1305  {
1306  if (size == 0)
1307  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
1308  if (size > 20)
1309  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
1310 
1311  vpArray2D<FilterType> SobelY(size * 2 + 1, size * 2 + 1);
1312  FilterType norm = getSobelKernelY<FilterType>(SobelY.data, size);
1313  memcpy(filter, SobelY.t().data, SobelY.getRows() * SobelY.getCols() * sizeof(FilterType));
1314  return norm;
1315  }
1316 
1324  template <typename FilterType>
1325  inline static FilterType getSobelKernelY(FilterType *filter, unsigned int size)
1326  {
1327  // Sobel kernel pre-computed for the usual size
1328  static const FilterType SobelY3x3[9] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 };
1329  static const FilterType SobelY5x5[25] = { -1.0, -4.0, -6.0, -4.0, -1.0, -2.0, -8.0, -12.0, -8.0, -2.0, 0.0, 0.0, 0.0,
1330  0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0 };
1331  static const FilterType SobelY7x7[49] = { -1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
1332  -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
1333  5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1 };
1334  const vpArray2D<FilterType> smoothingKernel(3, 3);
1335  smoothingKernel[0][0] = 1.0;
1336  smoothingKernel[0][1] = 2.0;
1337  smoothingKernel[0][2] = 1.0;
1338  smoothingKernel[1][0] = 2.0;
1339  smoothingKernel[1][1] = 4.0;
1340  smoothingKernel[1][2] = 2.0;
1341  smoothingKernel[2][0] = 1.0;
1342  smoothingKernel[2][1] = 2.0;
1343  smoothingKernel[2][2] = 1.0;
1344 
1345  if (size == 0)
1346  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
1347  if (size > 20)
1348  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
1349 
1350  const unsigned int kernel_size = size * 2 + 1;
1351  double scale = (1. / 8.); // Scale to normalize Sobel3x3
1352  if (kernel_size == 3) {
1353  memcpy(filter, SobelY3x3, kernel_size * kernel_size * sizeof(FilterType));
1354  return scale;
1355  }
1356  scale *= 1./ 16.; // Sobel5x5 is the convolution of smoothingKernel, which needs 1/16 scale factor, with Sobel3x3
1357  if (kernel_size == 5) {
1358  memcpy(filter, SobelY5x5, kernel_size * kernel_size * sizeof(FilterType));
1359  return scale;
1360  }
1361  scale *= 1./ 16.; // Sobel7x7 is the convolution of smoothingKernel, which needs 1/16 scale factor, with Sobel5x5
1362  if (kernel_size == 7) {
1363  memcpy(filter, SobelY7x7, kernel_size * kernel_size * sizeof(FilterType));
1364  return scale;
1365  }
1366 
1367  vpArray2D<FilterType> sobelY(7, 7);
1368  memcpy(sobelY.data, SobelY7x7, sobelY.getRows() * sobelY.getCols() * sizeof(FilterType));
1369  for (unsigned int i = 4; i <= size; i++) {
1370  sobelY = vpArray2D<FilterType>::conv2(sobelY, smoothingKernel, "full");
1371  // Sobel(N+1)x(N+1) is the convolution of smoothingKernel, which needs 1/16 scale factor, with SobelNxN
1372  scale *= 1./ 16.;
1373  }
1374 
1375  memcpy(filter, sobelY.data, sobelY.getRows() * sobelY.getCols() * sizeof(FilterType));
1376 
1377  return scale;
1378  }
1379 
1380 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
1381  static float median(const cv::Mat &cv_I);
1382  static float median(const vpImage<unsigned char> &Isrc);
1383  static std::vector<float> median(const vpImage<vpRGBa> &Isrc);
1384 #endif
1385 };
1386 
1387 #endif
Implementation of a generic 2D array used as base class for matrices and vectors.
Definition: vpArray2D.h:125
unsigned int getCols() const
Definition: vpArray2D.h:257
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:138
static vpArray2D< Type > conv2(const vpArray2D< Type > &M, const vpArray2D< Type > &kernel, const std::string &mode)
Definition: vpArray2D.h:1045
vpArray2D< Type > t() const
Compute the transpose of the array.
Definition: vpArray2D.h:1034
unsigned int getRows() const
Definition: vpArray2D.h:267
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:85
@ dimensionError
Bad dimension.
Definition: vpException.h:83
@ notImplementedError
Not implemented.
Definition: vpException.h:81
Class to compute a gray level image histogram.
Definition: vpHistogram.h:108
void calculate(const vpImage< unsigned char > &I, unsigned int nbins=256, unsigned int nbThreads=1)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Error that can be emitted by the vpImage class and its derivatives.
@ incorrectInitializationError
Wrong image initialization.
Various image filter, convolution, etc...
Definition: vpImageFilter.h:69
static unsigned char filterGaussXPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static FilterType filterX(const vpImage< ImageType > &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
static double derivativeFilterX(const vpImage< ImageType > &I, unsigned int r, unsigned int c)
static double filterXG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static FilterType filterYBottomBorder(const vpImage< ImageType > &I, unsigned int r, unsigned int c, const FilterType *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 filterYB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterYBottomBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void getGradYGauss2D(const vpImage< ImageType > &I, vpImage< FilterType > &dIy, const FilterType *gaussianKernel, const FilterType *gaussianDerivativeKernel, unsigned int size)
static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
static double filterXRightBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &If, const vpArray2D< FilterType > &M, bool convolve=false)
static double filterYBottomBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterYTopBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterXB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterYR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static FilterType filterY(const vpImage< ImageType > &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
static void getGradXGauss2D(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, const FilterType *gaussianKernel, const FilterType *gaussianDerivativeKernel, unsigned int size)
static FilterType filterYTopBorder(const vpImage< ImageType > &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
static double filterXLeftBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterYR(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void computePartialDerivatives(const vpImage< ImageType > &I, vpImage< vpRGBa > &dIx, vpImage< vpRGBa > &dIy, const bool &computeDx=true, const bool &computeDy=true, const bool &normalize=true, const unsigned int gaussianKernelSize=5, const vpRGBa gaussianStdev=vpRGBa(), const unsigned int apertureGradient=3, const vpCannyFilteringAndGradientType &filteringType=CANNY_GBLUR_SOBEL_FILTERING, const vpCannyBackendType &backend=CANNY_VISP_BACKEND)=delete
static void computePartialDerivatives(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, vpImage< FilterType > &dIy, const bool &computeDx=true, const bool &computeDy=true, const bool &normalize=true, const unsigned int &gaussianKernelSize=5, const FilterType &gaussianStdev=2.f, const unsigned int &apertureGradient=3, const vpCannyFilteringAndGradientType &filteringType=CANNY_GBLUR_SOBEL_FILTERING, const vpCannyBackendType &backend=CANNY_VISP_BACKEND)
Compute the partial derivatives (i.e. horizontal and vertical gradients) of the input image.
static double filterXB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filter(const vpImage< ImageType > &I, vpImage< ImageType > &Iu, vpImage< ImageType > &Iv, const vpArray2D< vpRGBa > &M, bool convolve)=delete
static double filterXR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filter(const vpImage< vpRGBa > &I, vpImage< FilterType > &Iu, vpImage< FilterType > &Iv, const vpArray2D< FilterType > &M, bool convolve)=delete
vpCannyFilteringAndGradientType
Canny filter and gradient operators to apply on the image before the edge detection stage.
Definition: vpImageFilter.h:88
static void getGaussianDerivativeKernel(FilterType *filter, unsigned int size, FilterType sigma=0., bool normalize=true)
static float computeCannyThreshold(const vpImage< unsigned char > &I, float &lowerThresh, const vpImage< OutType > *p_dIx=nullptr, const vpImage< OutType > *p_dIy=nullptr, const unsigned int &gaussianKernelSize=5, const OutType &gaussianStdev=2.f, const unsigned int &apertureGradient=3, const float &lowerThresholdRatio=0.6, const float &upperThresholdRatio=0.8, const vpCannyFilteringAndGradientType &filteringType=CANNY_GBLUR_SOBEL_FILTERING)
Compute the upper Canny edge filter threshold, using Gaussian blur + Sobel or + Scharr operators to c...
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &GI, const FilterType *filter, unsigned int size)
vpCannyBackendType
Canny filter backends for the edge detection operations.
Definition: vpImageFilter.h:73
static double filterXLeftBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static FilterType filterXRightBorder(const vpImage< ImageType > &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
static FilterType derivativeFilterY(const vpImage< ImageType > &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
static double filterXLeftBorderG(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 void getGradX(const vpImage< unsigned char > &I, vpImage< FilterType > &dIx)
static void filterXR(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double derivativeFilterY(const vpImage< ImageType > &I, unsigned int r, unsigned int c)
static void computePartialDerivatives(const vpImage< ImageType > &I, vpImage< unsigned char > &dIx, vpImage< unsigned char > &dIy, const bool &computeDx=true, const bool &computeDy=true, const bool &normalize=true, const unsigned int &gaussianKernelSize=5, const unsigned char &gaussianStdev=2.f, const unsigned int &apertureGradient=3, const vpCannyFilteringAndGradientType &filteringType=CANNY_GBLUR_SOBEL_FILTERING, const vpCannyBackendType &backend=CANNY_VISP_BACKEND)=delete
static void getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma=0., bool normalize=true)
static double filterYTopBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void getGradX(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, const FilterType *filter, unsigned int size)
static void computePartialDerivatives(const vpImage< vpRGBa > &I, vpImage< FilterType > &dIx, vpImage< FilterType > &dIy, const bool &computeDx=true, const bool &computeDy=true, const bool &normalize=true, const unsigned int &gaussianKernelSize=5, const FilterType &gaussianStdev=2.f, const unsigned int &apertureGradient=3, const vpCannyFilteringAndGradientType &filteringType=CANNY_GBLUR_SOBEL_FILTERING, const vpCannyBackendType &backend=CANNY_VISP_BACKEND)=delete
static void filterYG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static FilterType getScharrKernelY(FilterType *filter, unsigned int size)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &Iu, vpImage< FilterType > &Iv, const vpArray2D< FilterType > &M, bool convolve=false)
static FilterType filterXLeftBorder(const vpImage< ImageType > &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
static double filterXRightBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterX(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, const FilterType *filter, unsigned int size)
static FilterType getSobelKernelY(FilterType *filter, unsigned int size)
static void getGradY(const vpImage< ImageType > &I, vpImage< FilterType > &dIy, const FilterType *filter, unsigned int size)
static FilterType getScharrKernelX(FilterType *filter, unsigned int size)
static void filterXG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterYG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterY(const vpImage< ImageType > &I, vpImage< FilterType > &dIy, const FilterType *filter, unsigned int size)
static double filterYBottomBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterYB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static unsigned char filterGaussYPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static void gaussianBlur(const vpImage< ImageType > &I, vpImage< FilterType > &GI, unsigned int size=7, FilterType sigma=0., bool normalize=true)
static double gaussianFilter(const vpImage< T > &fr, unsigned int r, unsigned int c)
static void filter(const vpImage< vpRGBa > &I, vpImage< FilterType > &If, const vpArray2D< FilterType > &M, bool convolve=false)=delete
static FilterType derivativeFilterX(const vpImage< ImageType > &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
static void getGradY(const vpImage< unsigned char > &I, vpImage< FilterType > &dIy)
void destroy()
Destructor : Memory de-allocation.
Definition: vpImage.h:822
unsigned int getWidth() const
Definition: vpImage.h:240
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:793
unsigned int getHeight() const
Definition: vpImage.h:182
static double sqr(double x)
Definition: vpMath.h:201
Definition: vpRGBa.h:61