Visual Servoing Platform  version 3.6.1 under development (2024-05-28)
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/vpConfig.h>
48 #include <visp3/core/vpException.h>
49 #include <visp3/core/vpHistogram.h>
50 #include <visp3/core/vpImage.h>
51 #include <visp3/core/vpImageConvert.h>
52 #include <visp3/core/vpImageException.h>
53 #include <visp3/core/vpMath.h>
54 #include <visp3/core/vpMatrix.h>
55 #include <visp3/core/vpRGBa.h>
56 
57 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
58 #include <opencv2/imgproc/imgproc.hpp>
59 #include <opencv2/imgproc/imgproc_c.h>
60 #endif
61 
69 class VISP_EXPORT vpImageFilter
70 {
71 public:
73  typedef enum vpCannyBackendType
74  {
75  CANNY_OPENCV_BACKEND = 0,
76  CANNY_VISP_BACKEND = 1,
77  CANNY_COUNT_BACKEND = 2
78  } vpCannyBackendType;
79 
80  static std::string vpCannyBackendTypeList(const std::string &pref = "<", const std::string &sep = " , ",
81  const std::string &suf = ">");
82 
83  static std::string vpCannyBackendTypeToString(const vpCannyBackendType &type);
84 
85  static vpCannyBackendType vpCannyBackendTypeFromString(const std::string &name);
86 
89  {
90  CANNY_GBLUR_SOBEL_FILTERING = 0,
91  CANNY_GBLUR_SCHARR_FILTERING = 1,
92  CANNY_COUNT_FILTERING = 2
93  } vpCannyFilteringAndGradientType;
94 
95  static std::string vpGetCannyFiltAndGradTypes(const std::string &pref = "<", const std::string &sep = " , ",
96  const std::string &suf = ">");
97 
98  static std::string vpCannyFiltAndGradTypeToStr(const vpCannyFilteringAndGradientType &type);
99 
100  static vpCannyFilteringAndGradientType vpCannyFiltAndGradTypeFromStr(const std::string &name);
101 
102  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
103  const float &thresholdCanny, const unsigned int &apertureSobel);
104 
105  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
106  const float &lowerThresholdCanny, const float &higherThresholdCanny,
107  const unsigned int &apertureSobel);
108 
109  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
110  const float &lowerThresholdCanny, const float &higherThresholdCanny,
111  const unsigned int &apertureSobel, const float &gaussianStdev, const float &lowerThresholdRatio,
112  const float &upperThresholdRatio, const bool &normalizeGradients,
113  const vpCannyBackendType &cannyBackend, const vpCannyFilteringAndGradientType &cannyFilteringSteps,
114  const vpImage<bool> *p_mask = nullptr);
115 
116 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
117  static float computeCannyThreshold(const cv::Mat &cv_I, const cv::Mat *p_cv_dIx, const cv::Mat *p_cv_dIy,
118  float &lowerThresh, const unsigned int &gaussianKernelSize = 5,
119  const float &gaussianStdev = 2.f, const unsigned int &apertureGradient = 3,
120  const float &lowerThresholdRatio = 0.6, const float &upperThresholdRatio = 0.8,
121  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
122 
123  static void computePartialDerivatives(const cv::Mat &cv_I,
124  cv::Mat &cv_dIx, cv::Mat &cv_dIy,
125  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
126  const unsigned int &gaussianKernelSize = 5, const float &gaussianStdev = 2.f,
127  const unsigned int &apertureGradient = 3,
128  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
129 #endif
130 
151  template <typename ImageType, typename FilterType>
152  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
154  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
155  const unsigned int &gaussianKernelSize = 5, const FilterType &gaussianStdev = 2.f,
156  const unsigned int &apertureGradient = 3,
157  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
158  const vpCannyBackendType &backend = CANNY_VISP_BACKEND,
159  const vpImage<bool> *p_mask = nullptr)
160  {
161  if (backend == CANNY_OPENCV_BACKEND) {
162 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
163  cv::Mat cv_I, cv_dIx, cv_dIy;
164  vpImageConvert::convert(I, cv_I);
165  computePartialDerivatives(cv_I, cv_dIx, cv_dIy, computeDx, computeDy, normalize, gaussianKernelSize,
166  static_cast<float>(gaussianStdev), apertureGradient, filteringType);
167  if (computeDx) {
168  vpImageConvert::convert(cv_dIx, dIx);
169  }
170  if (computeDy) {
171  vpImageConvert::convert(cv_dIy, dIy);
172  }
173 #else
174  throw(vpException(vpException::badValue, "You need to compile ViSP with OpenCV to use CANNY_OPENCV_BACKEND"));
175 #endif
176  }
177  else {
178  if ((filteringType == CANNY_GBLUR_SCHARR_FILTERING) || (filteringType == CANNY_GBLUR_SOBEL_FILTERING)) {
179  dIx.resize(I.getHeight(), I.getWidth());
180  dIy.resize(I.getHeight(), I.getWidth());
181 
182  // Computing the Gaussian blur + gradients of the image
183  vpImage<FilterType> Iblur;
184  vpImageFilter::gaussianBlur(I, Iblur, gaussianKernelSize, gaussianStdev, true, p_mask);
185 
186  vpArray2D<FilterType> gradientFilterX(apertureGradient, apertureGradient); // Gradient filter along the X-axis
187  vpArray2D<FilterType> gradientFilterY(apertureGradient, apertureGradient); // Gradient filter along the Y-axis
188 
189 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
190  // Helper to apply the scale to the raw values of the filters
191  auto scaleFilter = [](vpArray2D<FilterType> &filter, const float &scale) {
192  const unsigned int nbRows = filter.getRows();
193  const unsigned int nbCols = filter.getCols();
194  for (unsigned int r = 0; r < nbRows; ++r) {
195  for (unsigned int c = 0; c < nbCols; ++c) {
196  filter[r][c] = filter[r][c] * scale;
197  }
198  }
199  };
200 #endif
201 
202  // Scales to apply to the filters to get a normalized gradient filter that gives a gradient
203  // between 0 and 255 for an vpImage<uchar>
204  float scaleX = 1.f;
205  float scaleY = 1.f;
206 
207  if (filteringType == CANNY_GBLUR_SOBEL_FILTERING) {
208  if (computeDx) {
209  scaleX = static_cast<float>(vpImageFilter::getSobelKernelX(gradientFilterX.data, (apertureGradient - 1) / 2));
210  }
211  if (computeDy) {
212  scaleY = static_cast<float>(vpImageFilter::getSobelKernelY(gradientFilterY.data, (apertureGradient - 1) / 2));
213  }
214  }
215  else if (filteringType == CANNY_GBLUR_SCHARR_FILTERING) {
216  if (computeDx) {
217  scaleX = static_cast<float>(vpImageFilter::getScharrKernelX(gradientFilterX.data, (apertureGradient - 1) / 2));
218  }
219  if (computeDy) {
220  scaleY = static_cast<float>(vpImageFilter::getScharrKernelY(gradientFilterY.data, (apertureGradient - 1) / 2));
221  }
222  }
223 
224  // Scale the gradient filters to have a normalized gradient filter
225  if (normalize) {
226  if (computeDx) {
227  scaleFilter(gradientFilterX, scaleX);
228  }
229  if (computeDy) {
230  scaleFilter(gradientFilterY, scaleY);
231  }
232  }
233 
234  // Apply the gradient filters to get the gradients
235  if (computeDx) {
236  vpImageFilter::filter(Iblur, dIx, gradientFilterX, true, p_mask);
237  }
238 
239  if (computeDy) {
240  vpImageFilter::filter(Iblur, dIy, gradientFilterY, true, p_mask);
241  }
242  }
243  else {
244  std::string errMsg = "[vpImageFilter::computePartialDerivatives] Filtering + gradient method \"";
245  errMsg += vpCannyFiltAndGradTypeToStr(filteringType);
246  errMsg += "\" is not implemented yet\n";
248  }
249  }
250  }
251 
252 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
253  template <typename FilterType>
254  inline static void computePartialDerivatives(const vpImage<vpRGBa> &I,
256  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
257  const unsigned int &gaussianKernelSize = 5, const FilterType &gaussianStdev = 2.f,
258  const unsigned int &apertureGradient = 3,
259  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
260  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr) = delete;
261 
262  template <typename ImageType>
263  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
265  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
266  const unsigned int &gaussianKernelSize = 5, const unsigned char &gaussianStdev = 2.f,
267  const unsigned int &apertureGradient = 3,
268  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
269  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr) = delete;
270 
271  template <typename ImageType>
272  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
273  vpImage<vpRGBa> &dIx, vpImage<vpRGBa> &dIy,
274  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
275  const unsigned int gaussianKernelSize = 5, const vpRGBa gaussianStdev = vpRGBa(),
276  const unsigned int apertureGradient = 3,
277  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
278  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr) = delete;
279 #else
280  template <typename FilterType>
281  inline static void computePartialDerivatives(const vpImage<vpRGBa> &I,
283  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
284  const unsigned int &gaussianKernelSize = 5, const FilterType &gaussianStdev = 2.f,
285  const unsigned int &apertureGradient = 3,
286  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
287  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr);
288 
289  template <typename ImageType>
290  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
292  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
293  const unsigned int &gaussianKernelSize = 5, const unsigned char &gaussianStdev = 2.f,
294  const unsigned int &apertureGradient = 3,
295  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
296  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr);
297 
298  template <typename ImageType>
299  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
300  vpImage<vpRGBa> &dIx, vpImage<vpRGBa> &dIy,
301  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
302  const unsigned int gaussianKernelSize = 5, const vpRGBa gaussianStdev = vpRGBa(),
303  const unsigned int apertureGradient = 3,
304  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
305  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr);
306 #endif
307 
328  template<typename OutType>
329  inline static float computeCannyThreshold(const vpImage<unsigned char> &I, float &lowerThresh,
330  const vpImage<OutType> *p_dIx = nullptr, const vpImage<OutType> *p_dIy = nullptr,
331  const unsigned int &gaussianKernelSize = 5,
332  const OutType &gaussianStdev = 2.f, const unsigned int &apertureGradient = 3,
333  const float &lowerThresholdRatio = 0.6, const float &upperThresholdRatio = 0.8,
334  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
335  const vpImage<bool> *p_mask = nullptr)
336  {
337  const unsigned int w = I.getWidth();
338  const unsigned int h = I.getHeight();
339 
340  vpImage<unsigned char> dI(h, w);
341  vpImage<OutType> dIx(h, w), dIy(h, w);
342  if ((p_dIx != nullptr) && (p_dIy != nullptr)) {
343  dIx = *p_dIx;
344  dIy = *p_dIy;
345  }
346  else {
347  computePartialDerivatives(I, dIx, dIy, true, true, true, gaussianKernelSize, gaussianStdev,
348  apertureGradient, filteringType, vpImageFilter::CANNY_VISP_BACKEND, p_mask);
349  }
350 
351  // Computing the absolute gradient of the image G = |dIx| + |dIy|
352  for (unsigned int r = 0; r < h; ++r) {
353  for (unsigned int c = 0; c < w; ++c) {
354  // We have to compute the value for each pixel if we don't have a mask or for
355  // pixels for which the mask is true otherwise
356  bool computeVal = checkBooleanMask(p_mask, r, c);
357 
358  if (computeVal) {
359  float dx = static_cast<float>(dIx[r][c]);
360  float dy = static_cast<float>(dIy[r][c]);
361  float gradient = std::abs(dx) + std::abs(dy);
362  float gradientClamped = std::min<float>(gradient, static_cast<float>(std::numeric_limits<unsigned char>::max()));
363  dI[r][c] = static_cast<unsigned char>(gradientClamped);
364  }
365  }
366  }
367 
368  // Compute the histogram
369  vpHistogram hist;
370  hist.setMask(p_mask);
371  const unsigned int nbBins = 256;
372  hist.calculate(dI, nbBins);
373  float totalNbPixels = static_cast<float>(hist.getTotal());
374  float accu = 0;
375  float t = upperThresholdRatio * totalNbPixels;
376  float bon = 0;
377  for (unsigned int i = 0; i < nbBins; ++i) {
378  float tf = static_cast<float>(hist[i]);
379  accu = accu + tf;
380  if (accu > t) {
381  bon = static_cast<float>(i);
382  break;
383  }
384  }
385  float upperThresh = std::max<float>(bon, 1.f);
386  lowerThresh = lowerThresholdRatio * bon;
387  return upperThresh;
388  }
389 
397  template <class ImageType> static double derivativeFilterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c)
398  {
399  return ((2047.0 * static_cast<double>(I[r][c + 1] - I[r][c - 1])) + (913.0 * static_cast<double>(I[r][c + 2] - I[r][c - 2])) +
400  (112.0 * static_cast<double>(I[r][c + 3] - I[r][c - 3]))) / 8418.0;
401  }
402 
410  template <class ImageType> static double derivativeFilterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c)
411  {
412  return ((2047.0 * static_cast<double>(I[r + 1][c] - I[r - 1][c])) + (913.0 * static_cast<double>(I[r + 2][c] - I[r - 2][c])) +
413  (112.0 * static_cast<double>(I[r + 3][c] - I[r - 3][c]))) / 8418.0;
414  }
415 
429  template <class ImageType, typename FilterType>
430  static FilterType derivativeFilterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
431  {
432  const unsigned int stop = (size - 1) / 2;
433  unsigned int i;
434  FilterType result;
435 
436  result = 0;
437 
438  for (i = 1; i <= stop; ++i) {
439  result += filter[i] * static_cast<FilterType>(I[r][c + i] - I[r][c - i]);
440  }
441  return result;
442  }
443 
457  template <class ImageType, typename FilterType>
458  static FilterType derivativeFilterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
459  {
460  const unsigned int stop = (size - 1) / 2;
461  unsigned int i;
462  FilterType result;
463 
464  result = 0;
465 
466  for (i = 1; i <= stop; ++i) {
467  result += filter[i] * static_cast<FilterType>(I[r + i][c] - I[r - i][c]);
468  }
469  return result;
470  }
471 
501  template <typename ImageType, typename FilterType>
502  static void filter(const vpImage<ImageType> &I, vpImage<FilterType> &If, const vpArray2D<FilterType> &M, bool convolve = false,
503  const vpImage<bool> *p_mask = nullptr)
504  {
505  const unsigned int size_y = M.getRows(), size_x = M.getCols();
506  const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
507 
508  const unsigned int inputHeight = I.getHeight(), inputWidth = I.getWidth();
509  If.resize(inputHeight, inputWidth, 0.0);
510 
511  if (convolve) {
512  const unsigned int stopHeight = inputHeight - half_size_y;
513  const unsigned int stopWidth = inputWidth - half_size_x;
514  for (unsigned int i = half_size_y; i < stopHeight; ++i) {
515  for (unsigned int j = half_size_x; j < stopWidth; ++j) {
516  // We have to compute the value for each pixel if we don't have a mask or for
517  // pixels for which the mask is true otherwise
518  bool computeVal = checkBooleanMask(p_mask, i, j);
519  if (computeVal) {
520  FilterType conv = 0;
521 
522  for (unsigned int a = 0; a < size_y; ++a) {
523  for (unsigned int b = 0; b < size_x; ++b) {
524  FilterType val = static_cast<FilterType>(I[(i + half_size_y) - a][(j + half_size_x) - b]); // Convolution
525  conv += M[a][b] * val;
526  }
527  }
528  If[i][j] = conv;
529  }
530  }
531  }
532  }
533  else {
534  const unsigned int stopHeight = inputHeight - half_size_y;
535  const unsigned int stopWidth = inputWidth - half_size_x;
536  for (unsigned int i = half_size_y; i < stopHeight; ++i) {
537  for (unsigned int j = half_size_x; j < stopWidth; ++j) {
538  // We have to compute the value for each pixel if we don't have a mask or for
539  // pixels for which the mask is true otherwise
540  bool computeVal = checkBooleanMask(p_mask, i, j);
541  if (computeVal) {
542  FilterType corr = 0;
543 
544  for (unsigned int a = 0; a < size_y; ++a) {
545  for (unsigned int b = 0; b < size_x; ++b) {
546  FilterType val = static_cast<FilterType>(I[(i - half_size_y) + a][(j - half_size_x) + b]); // Correlation
547  corr += M[a][b] * val;
548  }
549  }
550  If[i][j] = corr;
551  }
552  }
553  }
554  }
555  }
556 
557 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
558  template <typename FilterType>
559  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &If, const vpArray2D<FilterType> &M, bool convolve = false) = delete;
560 #else
561  template <typename FilterType>
562  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &If, const vpArray2D<FilterType> &M, bool convolve = false);
563 #endif
564 
578  template <typename ImageType, typename FilterType>
580  bool convolve = false, const vpImage<bool> *p_mask = nullptr)
581  {
582  const unsigned int size = M.getRows();
583  const unsigned int half_size = size / 2;
584  const unsigned int height = I.getHeight(), width = I.getWidth();
585  const unsigned int stopV = height - half_size;
586  const unsigned int stopU = width - half_size;
587 
588  Iu.resize(height, width, 0.0);
589  Iv.resize(height, width, 0.0);
590 
591  if (convolve) {
592  for (unsigned int v = half_size; v < stopV; ++v) {
593  for (unsigned int u = half_size; u < stopU; ++u) {
594  // We have to compute the value for each pixel if we don't have a mask or for
595  // pixels for which the mask is true otherwise
596  bool computeVal = checkBooleanMask(p_mask, v, u);
597  if (computeVal) {
598  FilterType conv_u = 0;
599  FilterType conv_v = 0;
600 
601  for (unsigned int a = 0; a < size; ++a) {
602  for (unsigned int b = 0; b < size; ++b) {
603  FilterType val = static_cast<FilterType>(I[(v + half_size) - a][(u + half_size) - b]); // Convolution
604  conv_u += M[a][b] * val;
605  conv_v += M[b][a] * val;
606  }
607  }
608  Iu[v][u] = conv_u;
609  Iv[v][u] = conv_v;
610  }
611  }
612  }
613  }
614  else {
615  for (unsigned int v = half_size; v < stopV; ++v) {
616  for (unsigned int u = half_size; u < stopU; ++u) {
617  // We have to compute the value for each pixel if we don't have a mask or for
618  // pixels for which the mask is true otherwise
619  bool computeVal = checkBooleanMask(p_mask, v, u);
620 
621  if (computeVal) {
622  FilterType conv_u = 0;
623  FilterType conv_v = 0;
624 
625  for (unsigned int a = 0; a < size; ++a) {
626  for (unsigned int b = 0; b < size; ++b) {
627  FilterType val = static_cast<FilterType>(I[(v - half_size) + a][(u - half_size) + b]); // Correlation
628  conv_u += M[a][b] * val;
629  conv_v += M[b][a] * val;
630  }
631  }
632  Iu[v][u] = conv_u;
633  Iv[v][u] = conv_v;
634  }
635  }
636  }
637  }
638  }
639 
640 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
641  template<typename FilterType>
642  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &Iu, vpImage<FilterType> &Iv, const vpArray2D<FilterType> &M, bool convolve) = delete;
643 
644  template<typename ImageType>
645  static void filter(const vpImage<ImageType> &I, vpImage<ImageType> &Iu, vpImage<ImageType> &Iv, const vpArray2D<vpRGBa> &M, bool convolve) = delete;
646 #else
647  template<typename FilterType>
648  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &Iu, vpImage<FilterType> &Iv, const vpArray2D<FilterType> &M, bool convolve);
649 
650  template<typename ImageType>
651  static void filter(const vpImage<ImageType> &I, vpImage<ImageType> &Iu, vpImage<ImageType> &Iv, const vpArray2D<vpRGBa> &M, bool convolve);
652 #endif
653 
654  static void sepFilter(const vpImage<unsigned char> &I, vpImage<double> &If, const vpColVector &kernelH, const vpColVector &kernelV);
655 
665  template <typename ImageType, typename FilterType>
666  static void filter(const vpImage<ImageType> &I, vpImage<FilterType> &GI, const FilterType *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr)
667  {
669  filterX<ImageType, FilterType>(I, GIx, filter, size, p_mask);
670  filterY<FilterType, FilterType>(GIx, GI, filter, size, p_mask);
671  GIx.destroy();
672  }
673 
674  static inline unsigned char filterGaussXPyramidal(const vpImage<unsigned char> &I, unsigned int i, unsigned int j)
675  {
676  return static_cast<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.);
677  }
678  static inline unsigned char filterGaussYPyramidal(const vpImage<unsigned char> &I, unsigned int i, unsigned int j)
679  {
680  return static_cast<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.);
681  }
682 
683  template <typename ImageType, typename FilterType>
684  static void filterX(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *filter, unsigned int size,
685  const vpImage<bool> *p_mask = nullptr)
686  {
687  const unsigned int height = I.getHeight();
688  const unsigned int width = I.getWidth();
689  const unsigned int stop1J = (size - 1) / 2;
690  const unsigned int stop2J = width - ((size - 1) / 2);
691  resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
692 
693  for (unsigned int i = 0; i < height; ++i) {
694  for (unsigned int j = 0; j < stop1J; ++j) {
695  // We have to compute the value for each pixel if we don't have a mask or for
696  // pixels for which the mask is true otherwise
697  bool computeVal = checkBooleanMask(p_mask, i, j);
698  if (computeVal) {
699  dIx[i][j] = vpImageFilter::filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
700  }
701  }
702  for (unsigned int j = stop1J; j < stop2J; ++j) {
703  // We have to compute the value for each pixel if we don't have a mask or for
704  // pixels for which the mask is true otherwise
705  bool computeVal = checkBooleanMask(p_mask, i, j);
706  if (computeVal) {
707  dIx[i][j] = vpImageFilter::filterX<ImageType, FilterType>(I, i, j, filter, size);
708  }
709  }
710  for (unsigned int j = stop2J; j < width; ++j) {
711  // We have to compute the value for each pixel if we don't have a mask or for
712  // pixels for which the mask is true otherwise
713  bool computeVal = checkBooleanMask(p_mask, i, j);
714  if (computeVal) {
715  dIx[i][j] = vpImageFilter::filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
716  }
717  }
718  }
719  }
720 
721  static void filterX(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr);
722 
723 #ifdef DOXYGEN_SHOULD_SKIP_THIS
724  static void filterXR(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
725  static void filterXG(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
726  static void filterXB(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
727 #endif
728 
729  template<typename ImageType, typename FilterType>
730  static inline FilterType filterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
731  {
732  const unsigned int stop = (size - 1) / 2;
733  FilterType result = static_cast<FilterType>(0.);
734 
735  for (unsigned int i = 1; i <= stop; ++i) {
736  result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
737  }
738  return result + (filter[0] * static_cast<FilterType>(I[r][c]));
739  }
740 
741 #ifndef DOXYGEN_SHOULD_SKIP_THIS
742  static inline double filterXR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
743  {
744  const unsigned int stop = (size - 1) / 2;
745  double result = 0.;
746  for (unsigned int i = 1; i <= stop; ++i) {
747  result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
748  }
749  return result + (filter[0] * static_cast<double>(I[r][c].R));
750  }
751 
752  static inline double filterXG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
753  {
754  const unsigned int stop = (size - 1) / 2;
755  double result = 0.;
756 
757  for (unsigned int i = 1; i <= stop; ++i) {
758  result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
759  }
760  return result + (filter[0] * static_cast<double>(I[r][c].G));
761  }
762 
763  static inline double filterXB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
764  {
765  const unsigned int stop = (size - 1) / 2;
766  double result = 0.;
767 
768  for (unsigned int i = 1; i <= stop; ++i) {
769  result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
770  }
771  return result + (filter[0] * static_cast<double>(I[r][c].B));
772  }
773 
774  template <typename ImageType, typename FilterType>
775  static inline FilterType filterXLeftBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
776  const FilterType *filter, unsigned int size)
777  {
778  const unsigned int stop = (size - 1) / 2;
779  FilterType result = static_cast<FilterType>(0.);
780 
781  for (unsigned int i = 1; i <= stop; ++i) {
782  if (c > i) {
783  result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
784  }
785  else {
786  result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][i - c]);
787  }
788  }
789  return result + (filter[0] * static_cast<FilterType>(I[r][c]));
790  }
791 
792  static inline double filterXLeftBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
793  const double *filter, unsigned int size)
794  {
795  const unsigned int stop = (size - 1) / 2;
796  double result = 0.;
797 
798  for (unsigned int i = 1; i <= stop; ++i) {
799  if (c > i) {
800  result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
801  }
802  else {
803  result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][i - c].R);
804  }
805  }
806  return result + (filter[0] * static_cast<double>(I[r][c].R));
807  }
808 
809  static inline double filterXLeftBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
810  const double *filter, unsigned int size)
811  {
812  const unsigned int stop = (size - 1) / 2;
813  double result = 0.;
814 
815  for (unsigned int i = 1; i <= stop; ++i) {
816  if (c > i) {
817  result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
818  }
819  else {
820  result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][i - c].G);
821  }
822  }
823  return result + (filter[0] * static_cast<double>(I[r][c].G));
824  }
825 
826  static inline double filterXLeftBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
827  const double *filter, unsigned int size)
828  {
829  const unsigned int stop = (size - 1) / 2;
830  double result = 0.;
831 
832  for (unsigned int i = 1; i <= stop; ++i) {
833  if (c > i) {
834  result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
835  }
836  else {
837  result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][i - c].B);
838  }
839  }
840  return result + (filter[0] * static_cast<double>(I[r][c].B));
841  }
842 
843  template <typename ImageType, typename FilterType>
844  static inline FilterType filterXRightBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
845  const FilterType *filter, unsigned int size)
846  {
847  const unsigned int stop = (size - 1) / 2;
848  const unsigned int width = I.getWidth();
849  FilterType result = static_cast<FilterType>(0.);
850 
851  for (unsigned int i = 1; i <= stop; ++i) {
852  if ((c + i) < width) {
853  result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
854  }
855  else {
856  result += filter[i] * static_cast<FilterType>(I[r][((2 * width) - c) - i - 1] + I[r][c - i]);
857  }
858  }
859  return result + (filter[0] * static_cast<FilterType>(I[r][c]));
860  }
861 
862  static inline double filterXRightBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
863  const double *filter, unsigned int size)
864  {
865  const unsigned int stop = (size - 1) / 2;
866  const unsigned int width = I.getWidth();
867  double result = 0.;
868 
869  for (unsigned int i = 1; i <= stop; ++i) {
870  if ((c + i) < width) {
871  result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
872  }
873  else {
874  result += filter[i] * static_cast<double>(I[r][((2 * width) - c) - i - 1].R + I[r][c - i].R);
875  }
876  }
877  return result + (filter[0] * static_cast<double>(I[r][c].R));
878  }
879 
880  static inline double filterXRightBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
881  const double *filter, unsigned int size)
882  {
883  const unsigned int stop = (size - 1) / 2;
884  const unsigned int width = I.getWidth();
885  double result = 0.;
886 
887  for (unsigned int i = 1; i <= stop; ++i) {
888  if ((c + i) < width) {
889  result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
890  }
891  else {
892  result += filter[i] * static_cast<double>(I[r][((2 * width) - c) - i - 1].G + I[r][c - i].G);
893  }
894  }
895  return result + (filter[0] * static_cast<double>(I[r][c].G));
896  }
897 
898  static inline double filterXRightBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
899  const double *filter, unsigned int size)
900  {
901  const unsigned int stop = (size - 1) / 2;
902  const unsigned int width = I.getWidth();
903  double result = 0.;
904 
905  for (unsigned int i = 1; i <= stop; ++i) {
906  if ((c + i) < width) {
907  result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
908  }
909  else {
910  result += filter[i] * static_cast<double>(I[r][(2 * width) - c - i - 1].B + I[r][c - i].B);
911  }
912  }
913  return result + (filter[0] * static_cast<double>(I[r][c].B));
914  }
915 #endif
916 
917 
918  static void filterY(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr);
919 
920 #ifndef DOXYGEN_SHOULD_SKIP_THIS
921  static void filterYR(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
922  static void filterYG(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
923  static void filterYB(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
924 #endif
925 
926  template<typename ImageType, typename FilterType>
927  static void filterY(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *filter, unsigned int size,
928  const vpImage<bool> *p_mask = nullptr)
929  {
930  const unsigned int height = I.getHeight(), width = I.getWidth();
931  const unsigned int stop1I = (size - 1) / 2;
932  const unsigned int stop2I = height - ((size - 1) / 2);
933  resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
934 
935  for (unsigned int i = 0; i < stop1I; ++i) {
936  for (unsigned int j = 0; j < width; ++j) {
937  // We have to compute the value for each pixel if we don't have a mask or for
938  // pixels for which the mask is true otherwise
939  bool computeVal = checkBooleanMask(p_mask, i, j);
940  if (computeVal) {
941  dIy[i][j] = vpImageFilter::filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
942  }
943  }
944  }
945  for (unsigned int i = stop1I; i < stop2I; ++i) {
946  for (unsigned int j = 0; j < width; ++j) {
947  // We have to compute the value for each pixel if we don't have a mask or for
948  // pixels for which the mask is true otherwise
949  bool computeVal = checkBooleanMask(p_mask, i, j);
950  if (computeVal) {
951  dIy[i][j] = vpImageFilter::filterY<ImageType, FilterType>(I, i, j, filter, size);
952  }
953  }
954  }
955  for (unsigned int i = stop2I; i < height; ++i) {
956  for (unsigned int j = 0; j < width; ++j) {
957  // We have to compute the value for each pixel if we don't have a mask or for
958  // pixels for which the mask is true otherwise
959  bool computeVal = checkBooleanMask(p_mask, i, j);
960  if (computeVal) {
961  dIy[i][j] = vpImageFilter::filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
962  }
963  }
964  }
965  }
966 
967  template<typename ImageType, typename FilterType>
968  static inline FilterType filterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
969  {
970  const unsigned int stop = (size - 1) / 2;
971  FilterType result = static_cast<FilterType>(0.);
972 
973  for (unsigned int i = 1; i <= stop; ++i) {
974  result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
975  }
976  return result + (filter[0] * static_cast<FilterType>(I[r][c]));
977  }
978 #ifndef DOXYGEN_SHOULD_SKIP_THIS
979  static inline double filterYR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
980  {
981  const unsigned int stop = (size - 1) / 2;
982  double result = 0.;
983 
984  for (unsigned int i = 1; i <= stop; ++i) {
985  result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
986  }
987  return result + (filter[0] * static_cast<double>(I[r][c].R));
988  }
989  static inline double filterYG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
990  {
991  const unsigned int stop = (size - 1) / 2;
992  double result = 0.;
993 
994  for (unsigned int i = 1; i <= stop; ++i) {
995  result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
996  }
997  return result + (filter[0] * static_cast<double>(I[r][c].G));
998  }
999 
1000  static inline double filterYB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1001  {
1002  const unsigned int stop = (size - 1) / 2;
1003  double result = 0.;
1004 
1005  for (unsigned int i = 1; i <= stop; ++i) {
1006  result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
1007  }
1008  return result + (filter[0] * static_cast<double>(I[r][c].B));
1009  }
1010 
1011  template<typename ImageType, typename FilterType>
1012  static inline FilterType filterYTopBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
1013  const FilterType *filter, unsigned int size)
1014  {
1015  const unsigned int stop = (size - 1) / 2;
1016  FilterType result = static_cast<FilterType>(0.);
1017 
1018  for (unsigned int i = 1; i <= stop; ++i) {
1019  if (r > i) {
1020  result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
1021  }
1022  else {
1023  result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[i - r][c]);
1024  }
1025  }
1026  return result + (filter[0] * static_cast<FilterType>(I[r][c]));
1027  }
1028 
1029  double static inline filterYTopBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1030  {
1031  const unsigned int stop = (size - 1) / 2;
1032  double result = 0.;
1033 
1034  for (unsigned int i = 1; i <= stop; ++i) {
1035  if (r > i) {
1036  result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
1037  }
1038  else {
1039  result += filter[i] * static_cast<double>(I[r + i][c].R + I[i - r][c].R);
1040  }
1041  }
1042  return result + (filter[0] * static_cast<double>(I[r][c].R));
1043  }
1044 
1045  double static inline filterYTopBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1046  {
1047  const unsigned int stop = (size - 1) / 2;
1048  double result = 0.;
1049 
1050  for (unsigned int i = 1; i <= stop; ++i) {
1051  if (r > i) {
1052  result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
1053  }
1054  else {
1055  result += filter[i] * static_cast<double>(I[r + i][c].G + I[i - r][c].G);
1056  }
1057  }
1058  return result + (filter[0] * static_cast<double>(I[r][c].G));
1059  }
1060 
1061  double static inline filterYTopBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1062  {
1063  const unsigned int stop = (size - 1) / 2;
1064  double result = 0.;
1065 
1066  for (unsigned int i = 1; i <= stop; ++i) {
1067  if (r > i) {
1068  result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
1069  }
1070  else {
1071  result += filter[i] * static_cast<double>(I[r + i][c].B + I[i - r][c].B);
1072  }
1073  }
1074  return result + (filter[0] * static_cast<double>(I[r][c].B));
1075  }
1076 
1077  template<typename ImageType, typename FilterType>
1078  static inline FilterType filterYBottomBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
1079  const FilterType *filter, unsigned int size)
1080  {
1081  const unsigned int height = I.getHeight();
1082  const unsigned int stop = (size - 1) / 2;
1083  FilterType result = static_cast<FilterType>(0.);
1084 
1085  for (unsigned int i = 1; i <= stop; ++i) {
1086  if ((r + i) < height) {
1087  result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
1088  }
1089  else {
1090  result += filter[i] * static_cast<FilterType>(I[((2 * height) - r) - i - 1][c] + I[r - i][c]);
1091  }
1092  }
1093  return result + (filter[0] * static_cast<FilterType>(I[r][c]));
1094  }
1095 
1096  double static inline filterYBottomBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
1097  const double *filter, unsigned int size)
1098  {
1099  const unsigned int height = I.getHeight();
1100  const unsigned int stop = (size - 1) / 2;
1101  double result = 0.;
1102 
1103  for (unsigned int i = 1; i <= stop; ++i) {
1104  if ((r + i) < height) {
1105  result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
1106  }
1107  else {
1108  result += filter[i] * static_cast<double>(I[((2 * height) - r) - i - 1][c].R + I[r - i][c].R);
1109  }
1110  }
1111  return result + (filter[0] * static_cast<double>(I[r][c].R));
1112  }
1113 
1114  double static inline filterYBottomBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
1115  const double *filter, unsigned int size)
1116  {
1117  const unsigned int height = I.getHeight();
1118  const unsigned int stop = (size - 1) / 2;
1119  double result = 0.;
1120 
1121  for (unsigned int i = 1; i <= stop; ++i) {
1122  if ((r + i) < height) {
1123  result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
1124  }
1125  else {
1126  result += filter[i] * static_cast<double>(I[((2 * height) - r) - i - 1][c].G + I[r - i][c].G);
1127  }
1128  }
1129  return result + (filter[0] * static_cast<double>(I[r][c].G));
1130  }
1131 
1132  double static inline filterYBottomBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
1133  const double *filter, unsigned int size)
1134  {
1135  const unsigned int height = I.getHeight();
1136  const unsigned int stop = (size - 1) / 2;
1137  double result = 0.;
1138 
1139  for (unsigned int i = 1; i <= stop; ++i) {
1140  if ((r + i) < height) {
1141  result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
1142  }
1143  else {
1144  result += filter[i] * static_cast<double>(I[((2 * height) - r) - i - 1][c].B + I[r - i][c].B);
1145  }
1146  }
1147  return result + (filter[0] * static_cast<double>(I[r][c].B));
1148  }
1149 #endif
1150 
1151 
1165  template <typename ImageType, typename FilterType>
1166  static void gaussianBlur(const vpImage<ImageType> &I, vpImage<FilterType> &GI, unsigned int size = 7, FilterType sigma = 0., bool normalize = true,
1167  const vpImage<bool> *p_mask = nullptr)
1168  {
1169  FilterType *fg = new FilterType[(size + 1) / 2];
1170  vpImageFilter::getGaussianKernel<FilterType>(fg, size, sigma, normalize);
1171  vpImage<FilterType> GIx;
1172  vpImageFilter::filterX<ImageType, FilterType>(I, GIx, fg, size, p_mask);
1173  vpImageFilter::filterY<FilterType, FilterType>(GIx, GI, fg, size, p_mask);
1174  GIx.destroy();
1175  delete[] fg;
1176  }
1177 
1178  static void gaussianBlur(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &GI, unsigned int size = 7, double sigma = 0., bool normalize = true,
1179  const vpImage<bool> *p_mask = nullptr);
1180 
1188  template <class T> static double gaussianFilter(const vpImage<T> &fr, unsigned int r, unsigned int c)
1189  {
1190  return ((15.0 * fr[r][c]) +
1191  (12.0 * (fr[r - 1][c] + fr[r][c - 1] + fr[r + 1][c] + fr[r][c + 1])) +
1192  (9.0 * (fr[r - 1][c - 1] + fr[r + 1][c - 1] + fr[r - 1][c + 1] + fr[r + 1][c + 1])) +
1193  (5.0 * (fr[r - 2][c] + fr[r][c - 2] + fr[r + 2][c] + fr[r][c + 2])) +
1194  (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] +
1195  fr[r + 2][c + 1] + fr[r - 1][c + 2] + fr[r + 1][c + 2])) +
1196  (2.0 * (fr[r - 2][c - 2] + fr[r + 2][c - 2] + fr[r - 2][c + 2] + fr[r + 2][c + 2]))) / 159.0;
1197  }
1198  // Gaussian pyramid operation
1199  static void getGaussPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1200  static void getGaussXPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1201  static void getGaussYPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1202 
1219  template<typename FilterType>
1220  static void getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma = 0., bool normalize = true)
1221  {
1222  if ((size % 2) != 1) {
1223  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
1224  }
1225 
1226  if (sigma <= 0) {
1227  sigma = static_cast<FilterType>((size - 1) / 6.0);
1228  }
1229 
1230  int middle = (static_cast<int>(size) - 1) / 2;
1231  FilterType sigma2 = static_cast<FilterType>(vpMath::sqr(sigma));
1232  FilterType coef1 = static_cast<FilterType>(1. / (sigma * sqrt(2. * M_PI)));
1233  FilterType v_2_sigma2 = static_cast<FilterType>(2. * sigma2);
1234  for (int i = 0; i <= middle; ++i) {
1235  filter[i] = coef1 * static_cast<FilterType>(exp(-(i * i) / v_2_sigma2));
1236  }
1237  if (normalize) {
1238  // renormalization
1239  FilterType sum = 0;
1240  for (int i = 1; i <= middle; ++i) {
1241  sum += 2 * filter[i];
1242  }
1243  sum += filter[0];
1244 
1245  for (int i = 0; i <= middle; ++i) {
1246  filter[i] = filter[i] / sum;
1247  }
1248  }
1249  }
1250 
1265  template <typename FilterType>
1266  static void getGaussianDerivativeKernel(FilterType *filter, unsigned int size, FilterType sigma = 0., bool normalize = true)
1267  {
1268  if ((size % 2) != 1) {
1269  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
1270  }
1271 
1272  if (sigma <= 0) {
1273  sigma = static_cast<FilterType>((size - 1) / 6.0);
1274  }
1275 
1276  int middle = (static_cast<int>(size) - 1) / 2;
1277  FilterType sigma2 = static_cast<FilterType>(vpMath::sqr(sigma));
1278  FilterType coef_1 = static_cast<FilterType>(1. / (sigma * sqrt(2. * M_PI)));
1279  FilterType coef_1_over_2 = coef_1 / static_cast<FilterType>(2.);
1280  FilterType v_2_coef_1 = static_cast<FilterType>(2.) * coef_1;
1281  FilterType v_2_sigma2 = static_cast<FilterType>(2. * sigma2);
1282  filter[0] = 0.;
1283  for (int i = 1; i <= middle; ++i) {
1284  filter[i] = -coef_1_over_2 * (static_cast<FilterType>(exp(-((i + 1) * (i + 1)) / v_2_sigma2)) - static_cast<FilterType>(exp(-((i - 1) * (i - 1)) / v_2_sigma2)));
1285  }
1286 
1287  if (normalize) {
1288  FilterType sum = 0;
1289  for (int i = 1; i <= middle; ++i) {
1290  sum += v_2_coef_1 * static_cast<FilterType>(exp(-(i * i) / v_2_sigma2));
1291  }
1292  sum += coef_1;
1293 
1294  for (int i = 1; i <= middle; ++i) {
1295  filter[i] = filter[i] / sum;
1296  }
1297  }
1298  }
1299 
1300  // Gradient along X
1301  template<typename FilterType>
1302  static void getGradX(const vpImage<unsigned char> &I, vpImage<FilterType> &dIx, const vpImage<bool> *p_mask = nullptr)
1303  {
1304  const unsigned int height = I.getHeight(), width = I.getWidth();
1305  const unsigned int stopJ = width - 3;
1306  resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1307 
1308  for (unsigned int i = 0; i < height; ++i) {
1309  for (unsigned int j = 0; j < 3; ++j) {
1310  // If a mask is used, the image is already initialized with 0s
1311  bool computeVal = (p_mask == nullptr);
1312  if (computeVal) {
1313  dIx[i][j] = static_cast<FilterType>(0);
1314  }
1315  }
1316  for (unsigned int j = 3; j < stopJ; ++j) {
1317  // We have to compute the value for each pixel if we don't have a mask or for
1318  // pixels for which the mask is true otherwise
1319  bool computeVal = checkBooleanMask(p_mask, i, j);
1320  if (computeVal) {
1321  dIx[i][j] = static_cast<FilterType>(vpImageFilter::derivativeFilterX(I, i, j));
1322  }
1323  }
1324  for (unsigned int j = stopJ; j < width; ++j) {
1325  // If a mask is used, the image is already initialized with 0s
1326  bool computeVal = (p_mask == nullptr);
1327  if (computeVal) {
1328  dIx[i][j] = static_cast<FilterType>(0);
1329  }
1330  }
1331  }
1332  }
1333 
1334  template <typename ImageType, typename FilterType>
1335  static void getGradX(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr)
1336  {
1337  const unsigned int height = I.getHeight(), width = I.getWidth();
1338  const unsigned int stop1J = (size - 1) / 2;
1339  const unsigned int stop2J = width - ((size - 1) / 2);
1340  resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1341 
1342  for (unsigned int i = 0; i < height; ++i) {
1343  for (unsigned int j = 0; j < stop1J; ++j) {
1344  // If a mask is used, the image is already initialized with 0s
1345  bool computeVal = (p_mask == nullptr);
1346  if (computeVal) {
1347  dIx[i][j] = static_cast<FilterType>(0);
1348  }
1349  }
1350  for (unsigned int j = stop1J; j < stop2J; ++j) {
1351  // We have to compute the value for each pixel if we don't have a mask or for
1352  // pixels for which the mask is true otherwise
1353  bool computeVal = checkBooleanMask(p_mask, i, j);
1354  if (computeVal) {
1355  dIx[i][j] = vpImageFilter::derivativeFilterX<ImageType, FilterType>(I, i, j, filter, size);
1356  }
1357  }
1358  for (unsigned int j = stop2J; j < width; ++j) {
1359  // If a mask is used, the image is already initialized with 0s
1360  bool computeVal = (p_mask == nullptr);
1361  if (computeVal) {
1362  dIx[i][j] = static_cast<FilterType>(0);
1363  }
1364  }
1365  }
1366  }
1367 
1379  template <typename ImageType, typename FilterType>
1380  static void getGradXGauss2D(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *gaussianKernel,
1381  const FilterType *gaussianDerivativeKernel, unsigned int size, const vpImage<bool> *p_mask = nullptr)
1382  {
1383  vpImage<FilterType> GIy;
1384  vpImageFilter::filterY<ImageType, FilterType>(I, GIy, gaussianKernel, size, p_mask);
1385  vpImageFilter::getGradX<FilterType, FilterType>(GIy, dIx, gaussianDerivativeKernel, size, p_mask);
1386  }
1387 
1388  // Gradient along Y
1389  template <typename FilterType>
1390  static void getGradY(const vpImage<unsigned char> &I, vpImage<FilterType> &dIy, const vpImage<bool> *p_mask = nullptr)
1391  {
1392  const unsigned int height = I.getHeight(), width = I.getWidth();
1393  const unsigned int stopI = height - 3;
1394  resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1395 
1396  for (unsigned int i = 0; i < 3; ++i) {
1397  for (unsigned int j = 0; j < width; ++j) {
1398  // We have to compute the value for each pixel if we don't have a mask or for
1399  // pixels for which the mask is true otherwise
1400  bool computeVal = checkBooleanMask(p_mask, i, j);
1401  if (computeVal) {
1402  dIy[i][j] = static_cast<FilterType>(0);
1403  }
1404  }
1405  }
1406  for (unsigned int i = 3; i < stopI; ++i) {
1407  for (unsigned int j = 0; j < width; ++j) {
1408  // We have to compute the value for each pixel if we don't have a mask or for
1409  // pixels for which the mask is true otherwise
1410  bool computeVal = checkBooleanMask(p_mask, i, j);
1411  if (computeVal) {
1412  dIy[i][j] = static_cast<FilterType>(vpImageFilter::derivativeFilterY(I, i, j));
1413  }
1414  }
1415  }
1416  for (unsigned int i = stopI; i < height; ++i) {
1417  for (unsigned int j = 0; j < width; ++j) {
1418  // We have to compute the value for each pixel if we don't have a mask or for
1419  // pixels for which the mask is true otherwise
1420  bool computeVal = checkBooleanMask(p_mask, i, j);
1421  if (computeVal) {
1422  dIy[i][j] = static_cast<FilterType>(0);
1423  }
1424  }
1425  }
1426  }
1427 
1428  template <typename ImageType, typename FilterType>
1429  static void getGradY(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr)
1430  {
1431  const unsigned int height = I.getHeight(), width = I.getWidth();
1432  const unsigned int stop1I = (size - 1) / 2;
1433  const unsigned int stop2I = height - ((size - 1) / 2);
1434  resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1435 
1436  for (unsigned int i = 0; i < stop1I; ++i) {
1437  for (unsigned int j = 0; j < width; ++j) {
1438  // We have to compute the value for each pixel if we don't have a mask or for
1439  // pixels for which the mask is true otherwise
1440  bool computeVal = checkBooleanMask(p_mask, i, j);
1441  if (computeVal) {
1442  dIy[i][j] = static_cast<FilterType>(0);
1443  }
1444  }
1445  }
1446  for (unsigned int i = stop1I; i < stop2I; ++i) {
1447  for (unsigned int j = 0; j < width; ++j) {
1448  // We have to compute the value for each pixel if we don't have a mask or for
1449  // pixels for which the mask is true otherwise
1450  bool computeVal = checkBooleanMask(p_mask, i, j);
1451  if (computeVal) {
1452  dIy[i][j] = vpImageFilter::derivativeFilterY<ImageType, FilterType>(I, i, j, filter, size);
1453  }
1454  }
1455  }
1456  for (unsigned int i = stop2I; i < height; ++i) {
1457  for (unsigned int j = 0; j < width; ++j) {
1458  // We have to compute the value for each pixel if we don't have a mask or for
1459  // pixels for which the mask is true otherwise
1460  bool computeVal = checkBooleanMask(p_mask, i, j);
1461  if (computeVal) {
1462  dIy[i][j] = static_cast<FilterType>(0);
1463  }
1464  }
1465  }
1466  }
1467 
1479  template <typename ImageType, typename FilterType>
1480  static void getGradYGauss2D(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *gaussianKernel,
1481  const FilterType *gaussianDerivativeKernel, unsigned int size, const vpImage<bool> *p_mask = nullptr)
1482  {
1483  vpImage<FilterType> GIx;
1484  vpImageFilter::filterX<ImageType, FilterType>(I, GIx, gaussianKernel, size, p_mask);
1485  vpImageFilter::getGradY<FilterType, FilterType>(GIx, dIy, gaussianDerivativeKernel, size, p_mask);
1486  }
1487 
1495  template <typename FilterType>
1496  inline static FilterType getScharrKernelX(FilterType *filter, unsigned int size)
1497  {
1498  if (size != 1) {
1499  // Size = 1 => kernel_size = 2*1 + 1 = 3
1500  std::stringstream errMsg;
1501  errMsg << "Cannot get Scharr kernel of size " << ((size * 2) + 1) << " != 3";
1502  throw vpException(vpException::dimensionError, errMsg.str());
1503  }
1504 
1505  vpArray2D<FilterType> ScharrY((size * 2) + 1, (size * 2) + 1);
1506  FilterType norm = getScharrKernelY<FilterType>(ScharrY.data, size);
1507  memcpy(filter, ScharrY.t().data, ScharrY.getRows() * ScharrY.getCols() * sizeof(FilterType));
1508  return norm;
1509  }
1510 
1518  template <typename FilterType>
1519  inline static FilterType getScharrKernelY(FilterType *filter, unsigned int size)
1520  {
1521  // Scharr kernel pre-computed for the usual size
1522  static const FilterType ScharrY3x3[9] = { -3.0, -10.0, -3.0, 0.0, 0.0, 0.0, 3.0, 10.0, 3.0 };
1523 
1524  if (size != 1) {
1525  // Size = 1 => kernel_size = 2*1 + 1 = 3
1526  std::stringstream errMsg;
1527  errMsg << "Cannot get Scharr kernel of size " << ((size * 2) + 1) << " != 3";
1528  throw vpException(vpException::dimensionError, errMsg.str());
1529  }
1530 
1531  const unsigned int kernel_size = (size * 2) + 1;
1532  if (kernel_size == 3) {
1533  memcpy(filter, ScharrY3x3, kernel_size * kernel_size * sizeof(FilterType));
1534  return static_cast<FilterType>(1.0 / 32.0);
1535  }
1536 
1537  return static_cast<FilterType>(0.);
1538  }
1539 
1547  template <typename FilterType>
1548  inline static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
1549  {
1550  if (size == 0) {
1551  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
1552  }
1553  if (size > 20) {
1554  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
1555  }
1556 
1557  vpArray2D<FilterType> SobelY((size * 2) + 1, (size * 2) + 1);
1558  FilterType norm = getSobelKernelY<FilterType>(SobelY.data, size);
1559  memcpy(filter, SobelY.t().data, SobelY.getRows() * SobelY.getCols() * sizeof(FilterType));
1560  return norm;
1561  }
1562 
1570  template <typename FilterType>
1571  inline static FilterType getSobelKernelY(FilterType *filter, unsigned int size)
1572  {
1573  // Sobel kernel pre-computed for the usual size
1574  static const FilterType SobelY3x3[9] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 };
1575  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,
1576  0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0 };
1577  static const FilterType SobelY7x7[49] = { -1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
1578  -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
1579  5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1 };
1580  const vpArray2D<FilterType> smoothingKernel(3, 3);
1581  smoothingKernel[0][0] = 1.0;
1582  smoothingKernel[0][1] = 2.0;
1583  smoothingKernel[0][2] = 1.0;
1584  smoothingKernel[1][0] = 2.0;
1585  smoothingKernel[1][1] = 4.0;
1586  smoothingKernel[1][2] = 2.0;
1587  smoothingKernel[2][0] = 1.0;
1588  smoothingKernel[2][1] = 2.0;
1589  smoothingKernel[2][2] = 1.0;
1590 
1591  if (size == 0) {
1592  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
1593  }
1594  if (size > 20) {
1595  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
1596  }
1597 
1598  const unsigned int kernel_size = (size * 2) + 1;
1599  FilterType scale = static_cast<FilterType>(1. / 8.); // Scale to normalize Sobel3x3
1600  if (kernel_size == 3) {
1601  memcpy(filter, SobelY3x3, kernel_size * kernel_size * sizeof(FilterType));
1602  return scale;
1603  }
1604  scale *= static_cast<FilterType>(1. / 16.); // Sobel5x5 is the convolution of smoothingKernel, which needs 1/16 scale factor, with Sobel3x3
1605  if (kernel_size == 5) {
1606  memcpy(filter, SobelY5x5, kernel_size * kernel_size * sizeof(FilterType));
1607  return scale;
1608  }
1609  scale *= static_cast<FilterType>(1. / 16.); // Sobel7x7 is the convolution of smoothingKernel, which needs 1/16 scale factor, with Sobel5x5
1610  if (kernel_size == 7) {
1611  memcpy(filter, SobelY7x7, kernel_size * kernel_size * sizeof(FilterType));
1612  return scale;
1613  }
1614 
1615  vpArray2D<FilterType> sobelY(7, 7);
1616  memcpy(sobelY.data, SobelY7x7, sobelY.getRows() * sobelY.getCols() * sizeof(FilterType));
1617  for (unsigned int i = 4; i <= size; ++i) {
1618  sobelY = vpArray2D<FilterType>::conv2(sobelY, smoothingKernel, "full");
1619  // Sobel(N+1)x(N+1) is the convolution of smoothingKernel, which needs 1/16 scale factor, with SobelNxN
1620  scale *= static_cast<FilterType>(1. / 16.);
1621  }
1622 
1623  memcpy(filter, sobelY.data, sobelY.getRows() * sobelY.getCols() * sizeof(FilterType));
1624 
1625  return scale;
1626  }
1627 
1628 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
1629  static float median(const cv::Mat &cv_I);
1630  static float median(const vpImage<unsigned char> &Isrc);
1631  static std::vector<float> median(const vpImage<vpRGBa> &Isrc);
1632 #endif
1633 
1634 private:
1645  template<typename ImageType>
1646  static void resizeAndInitializeIfNeeded(const vpImage<bool> *p_mask, const unsigned int height, const unsigned int width, vpImage<ImageType> &I)
1647  {
1648  if (p_mask == nullptr) {
1649  // Just need to resize the output image, values will be computed and overwrite what is inside the image
1650  I.resize(height, width);
1651  }
1652  else {
1653  // Need to reset the image because some points will not be computed
1654  I.resize(height, width, static_cast<ImageType>(0));
1655  }
1656  }
1657 
1667  static bool checkBooleanMask(const vpImage<bool> *p_mask, const unsigned int &r, const unsigned int &c)
1668  {
1669  bool computeVal = true;
1670 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
1671  if (p_mask != nullptr)
1672 #else
1673  if (p_mask != NULL)
1674 #endif
1675  {
1676  computeVal = (*p_mask)[r][c];
1677  }
1678  return computeVal;
1679  }
1680 
1681 // Note that on ubuntu 12.04 __cplusplus is equal to 1 that's why in the next line we consider __cplusplus <= 199711L
1682 // and not __cplusplus == 199711L
1683 #if ((__cplusplus <= 199711L) || (defined(_MSVC_LANG) && (_MSVC_LANG == 199711L))) // Check if cxx98
1684  // Helper to apply the scale to the raw values of the filters
1685  template <typename FilterType>
1686  static void scaleFilter(vpArray2D<FilterType> &filter, const float &scale)
1687  {
1688  const unsigned int nbRows = filter.getRows();
1689  const unsigned int nbCols = filter.getCols();
1690  for (unsigned int r = 0; r < nbRows; ++r) {
1691  for (unsigned int c = 0; c < nbCols; ++c) {
1692  filter[r][c] = filter[r][c] * scale;
1693  }
1694  }
1695 }
1696 #endif
1697 
1698 };
1699 
1700 #endif
Implementation of a generic 2D array used as base class for matrices and vectors.
Definition: vpArray2D.h:126
unsigned int getCols() const
Definition: vpArray2D.h:329
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:139
static vpArray2D< Type > conv2(const vpArray2D< Type > &M, const vpArray2D< Type > &kernel, const std::string &mode)
Definition: vpArray2D.h:1152
vpArray2D< Type > t() const
Compute the transpose of the array.
Definition: vpArray2D.h:1141
unsigned int getRows() const
Definition: vpArray2D.h:339
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:72
@ dimensionError
Bad dimension.
Definition: vpException.h:70
@ notImplementedError
Not implemented.
Definition: vpException.h:68
Class to compute a gray level image histogram.
Definition: vpHistogram.h:108
unsigned int getTotal()
Get the total number of pixels in the input image.
Definition: vpHistogram.h:310
void calculate(const vpImage< unsigned char > &I, unsigned int nbins=256, unsigned int nbThreads=1)
void setMask(const vpImage< bool > *p_mask)
Set a mask to ignore pixels for which the mask is false.
Definition: vpHistogram.h:248
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:70
static void filterY(const vpImage< ImageType > &I, vpImage< FilterType > &dIy, const FilterType *filter, unsigned int size, const vpImage< bool > *p_mask=nullptr)
static unsigned char filterGaussXPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static void getGradY(const vpImage< ImageType > &I, vpImage< FilterType > &dIy, const FilterType *filter, unsigned int size, const vpImage< bool > *p_mask=nullptr)
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 void getGradX(const vpImage< unsigned char > &I, vpImage< FilterType > &dIx, const vpImage< bool > *p_mask=nullptr)
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, const vpImage< bool > *p_mask=nullptr)
Compute the upper Canny edge filter threshold, using Gaussian blur + Sobel or + Scharr operators to c...
static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
static void getGradXGauss2D(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, const FilterType *gaussianKernel, const FilterType *gaussianDerivativeKernel, unsigned int size, const vpImage< bool > *p_mask=nullptr)
static void filterXB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, 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 filter(const vpImage< ImageType > &I, vpImage< ImageType > &Iu, vpImage< ImageType > &Iv, const vpArray2D< vpRGBa > &M, bool convolve)=delete
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:89
static void getGaussianDerivativeKernel(FilterType *filter, unsigned int size, FilterType sigma=0., bool normalize=true)
static void gaussianBlur(const vpImage< ImageType > &I, vpImage< FilterType > &GI, unsigned int size=7, FilterType sigma=0., bool normalize=true, const vpImage< bool > *p_mask=nullptr)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &If, const vpArray2D< FilterType > &M, bool convolve=false, const vpImage< bool > *p_mask=nullptr)
vpCannyBackendType
Canny filter backends for the edge detection operations.
Definition: vpImageFilter.h:74
@ CANNY_VISP_BACKEND
Use ViSP.
Definition: vpImageFilter.h:76
static void getGradX(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, const FilterType *filter, unsigned int size, const vpImage< bool > *p_mask=nullptr)
static FilterType derivativeFilterY(const vpImage< ImageType > &I, unsigned int r, unsigned int c, 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, const vpImage< bool > *p_mask=nullptr)=delete
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, const vpImage< bool > *p_mask=nullptr)=delete
static void getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma=0., bool normalize=true)
static FilterType getScharrKernelY(FilterType *filter, unsigned int size)
static FilterType getSobelKernelY(FilterType *filter, unsigned int size)
static void getGradYGauss2D(const vpImage< ImageType > &I, vpImage< FilterType > &dIy, const FilterType *gaussianKernel, const FilterType *gaussianDerivativeKernel, unsigned int size, const vpImage< bool > *p_mask=nullptr)
static FilterType getScharrKernelX(FilterType *filter, unsigned int size)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &GI, const FilterType *filter, unsigned int size, const vpImage< bool > *p_mask=nullptr)
static void filterXG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void getGradY(const vpImage< unsigned char > &I, vpImage< FilterType > &dIy, const vpImage< bool > *p_mask=nullptr)
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, const vpImage< bool > *p_mask=nullptr)=delete
static void filterX(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, const FilterType *filter, unsigned int size, const vpImage< bool > *p_mask=nullptr)
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, const vpImage< bool > *p_mask=nullptr)
Compute the partial derivatives (i.e. horizontal and vertical gradients) of the input image.
static unsigned char filterGaussYPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &Iu, vpImage< FilterType > &Iv, const vpArray2D< FilterType > &M, bool convolve=false, const vpImage< bool > *p_mask=nullptr)
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)
void destroy()
Destructor : Memory de-allocation.
Definition: vpImage.h:827
unsigned int getWidth() const
Definition: vpImage.h:245
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:798
unsigned int getHeight() const
Definition: vpImage.h:184
static double sqr(double x)
Definition: vpMath.h:201
Definition: vpRGBa.h:61