Visual Servoing Platform  version 3.6.1 under development (2024-04-25)
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 private:
82  template<typename ImageType>
83  static void resizeAndInitializeIfNeeded(const vpImage<bool> *p_mask, const unsigned int height, const unsigned int width, vpImage<ImageType> &I)
84  {
85  if (p_mask == nullptr) {
86  // Just need to resize the output image, values will be computed and overwrite what is inside the image
87  I.resize(height, width);
88  }
89  else {
90  // Need to reset the image because some points will not be computed
91  I.resize(height, width, static_cast<ImageType>(0));
92  }
93  }
94 
104  static bool checkBooleanMask(const vpImage<bool> *p_mask, const unsigned int &r, const unsigned int &c)
105  {
106  bool computeVal = true;
107 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
108  if (p_mask != nullptr)
109 #else
110  if (p_mask != NULL)
111 #endif
112  {
113  computeVal = (*p_mask)[r][c];
114  }
115  return computeVal;
116  }
117 
118 // Note that on ubuntu 12.04 __cplusplus is equal to 1 that's why in the next line we consider __cplusplus <= 199711L
119 // and not __cplusplus == 199711L
120 #if ((__cplusplus <= 199711L) || (defined(_MSVC_LANG) && (_MSVC_LANG == 199711L))) // Check if cxx98
121  // Helper to apply the scale to the raw values of the filters
122  template <typename FilterType>
123  static void scaleFilter(vpArray2D<FilterType> &filter, const float &scale)
124  {
125  const unsigned int nbRows = filter.getRows();
126  const unsigned int nbCols = filter.getCols();
127  for (unsigned int r = 0; r < nbRows; ++r) {
128  for (unsigned int c = 0; c < nbCols; ++c) {
129  filter[r][c] = filter[r][c] * scale;
130  }
131  }
132  }
133 #endif
134 
135 public:
137  typedef enum vpCannyBackendType
138  {
139  CANNY_OPENCV_BACKEND = 0,
140  CANNY_VISP_BACKEND = 1,
141  CANNY_COUNT_BACKEND = 2
142  } vpCannyBackendType;
143 
144  static std::string vpCannyBackendTypeList(const std::string &pref = "<", const std::string &sep = " , ",
145  const std::string &suf = ">");
146 
147  static std::string vpCannyBackendTypeToString(const vpCannyBackendType &type);
148 
149  static vpCannyBackendType vpCannyBackendTypeFromString(const std::string &name);
150 
153  {
154  CANNY_GBLUR_SOBEL_FILTERING = 0,
155  CANNY_GBLUR_SCHARR_FILTERING = 1,
156  CANNY_COUNT_FILTERING = 2
157  } vpCannyFilteringAndGradientType;
158 
159  static std::string vpCannyFilteringAndGradientTypeList(const std::string &pref = "<", const std::string &sep = " , ",
160  const std::string &suf = ">");
161 
162  static std::string vpCannyFilteringAndGradientTypeToString(const vpCannyFilteringAndGradientType &type);
163 
164  static vpCannyFilteringAndGradientType vpCannyFilteringAndGradientTypeFromString(const std::string &name);
165 
166  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
167  const float &thresholdCanny, const unsigned int &apertureSobel);
168 
169  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
170  const float &lowerThresholdCanny, const float &higherThresholdCanny,
171  const unsigned int &apertureSobel);
172 
173  static void canny(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ic, const unsigned int &gaussianFilterSize,
174  const float &lowerThresholdCanny, const float &higherThresholdCanny,
175  const unsigned int &apertureSobel, const float &gaussianStdev, const float &lowerThresholdRatio,
176  const float &upperThresholdRatio, const bool &normalizeGradients,
177  const vpCannyBackendType &cannyBackend, const vpCannyFilteringAndGradientType &cannyFilteringSteps,
178  const vpImage<bool> *p_mask = nullptr);
179 
180 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
181  static float computeCannyThreshold(const cv::Mat &cv_I, const cv::Mat *p_cv_dIx, const cv::Mat *p_cv_dIy,
182  float &lowerThresh, const unsigned int &gaussianKernelSize = 5,
183  const float &gaussianStdev = 2.f, const unsigned int &apertureGradient = 3,
184  const float &lowerThresholdRatio = 0.6, const float &upperThresholdRatio = 0.8,
185  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
186 
187  static void computePartialDerivatives(const cv::Mat &cv_I,
188  cv::Mat &cv_dIx, cv::Mat &cv_dIy,
189  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
190  const unsigned int &gaussianKernelSize = 5, const float &gaussianStdev = 2.f,
191  const unsigned int &apertureGradient = 3,
192  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
193 #endif
194 
215  template <typename ImageType, typename FilterType>
216  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
218  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
219  const unsigned int &gaussianKernelSize = 5, const FilterType &gaussianStdev = 2.f,
220  const unsigned int &apertureGradient = 3,
221  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
222  const vpCannyBackendType &backend = CANNY_VISP_BACKEND,
223  const vpImage<bool> *p_mask = nullptr)
224  {
225  if (backend == CANNY_OPENCV_BACKEND) {
226 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
227  cv::Mat cv_I, cv_dIx, cv_dIy;
228  vpImageConvert::convert(I, cv_I);
229  computePartialDerivatives(cv_I, cv_dIx, cv_dIy, computeDx, computeDy, normalize, gaussianKernelSize,
230  static_cast<float>(gaussianStdev), apertureGradient, filteringType);
231  if (computeDx) {
232  vpImageConvert::convert(cv_dIx, dIx);
233  }
234  if (computeDy) {
235  vpImageConvert::convert(cv_dIy, dIy);
236  }
237 #else
238  throw(vpException(vpException::badValue, "You need to compile ViSP with OpenCV to use CANNY_OPENCV_BACKEND"));
239 #endif
240  }
241  else {
242  if ((filteringType == CANNY_GBLUR_SCHARR_FILTERING) || (filteringType == CANNY_GBLUR_SOBEL_FILTERING)) {
243  dIx.resize(I.getHeight(), I.getWidth());
244  dIy.resize(I.getHeight(), I.getWidth());
245 
246  // Computing the Gaussian blur + gradients of the image
247  vpImage<FilterType> Iblur;
248  vpImageFilter::gaussianBlur(I, Iblur, gaussianKernelSize, gaussianStdev, true, p_mask);
249 
250  vpArray2D<FilterType> gradientFilterX(apertureGradient, apertureGradient); // Gradient filter along the X-axis
251  vpArray2D<FilterType> gradientFilterY(apertureGradient, apertureGradient); // Gradient filter along the Y-axis
252 
253 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
254  // Helper to apply the scale to the raw values of the filters
255  auto scaleFilter = [](vpArray2D<FilterType> &filter, const float &scale) {
256  const unsigned int nbRows = filter.getRows();
257  const unsigned int nbCols = filter.getCols();
258  for (unsigned int r = 0; r < nbRows; ++r) {
259  for (unsigned int c = 0; c < nbCols; ++c) {
260  filter[r][c] = filter[r][c] * scale;
261  }
262  }};
263 #endif
264 
265  // Scales to apply to the filters to get a normalized gradient filter that gives a gradient
266  // between 0 and 255 for an vpImage<uchar>
267  float scaleX = 1.f;
268  float scaleY = 1.f;
269 
270  if (filteringType == CANNY_GBLUR_SOBEL_FILTERING) {
271  if (computeDx) {
272  scaleX = static_cast<float>(vpImageFilter::getSobelKernelX(gradientFilterX.data, (apertureGradient - 1) / 2));
273  }
274  if (computeDy) {
275  scaleY = static_cast<float>(vpImageFilter::getSobelKernelY(gradientFilterY.data, (apertureGradient - 1) / 2));
276  }
277  }
278  else if (filteringType == CANNY_GBLUR_SCHARR_FILTERING) {
279  if (computeDx) {
280  scaleX = static_cast<float>(vpImageFilter::getScharrKernelX(gradientFilterX.data, (apertureGradient - 1) / 2));
281  }
282  if (computeDy) {
283  scaleY = static_cast<float>(vpImageFilter::getScharrKernelY(gradientFilterY.data, (apertureGradient - 1) / 2));
284  }
285  }
286 
287  // Scale the gradient filters to have a normalized gradient filter
288  if (normalize) {
289  if (computeDx) {
290  scaleFilter(gradientFilterX, scaleX);
291  }
292  if (computeDy) {
293  scaleFilter(gradientFilterY, scaleY);
294  }
295  }
296 
297  // Apply the gradient filters to get the gradients
298  if (computeDx) {
299  vpImageFilter::filter(Iblur, dIx, gradientFilterX, true, p_mask);
300  }
301 
302  if (computeDy) {
303  vpImageFilter::filter(Iblur, dIy, gradientFilterY, true, p_mask);
304  }
305  }
306  else {
307  std::string errMsg = "[vpImageFilter::computePartialDerivatives] Filtering + gradient method \"";
308  errMsg += vpCannyFilteringAndGradientTypeToString(filteringType);
309  errMsg += "\" is not implemented yet\n";
311  }
312  }
313  }
314 
315 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
316  template <typename FilterType>
317  inline static void computePartialDerivatives(const vpImage<vpRGBa> &I,
319  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
320  const unsigned int &gaussianKernelSize = 5, const FilterType &gaussianStdev = 2.f,
321  const unsigned int &apertureGradient = 3,
322  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
323  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr) = delete;
324 
325  template <typename ImageType>
326  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
328  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
329  const unsigned int &gaussianKernelSize = 5, const unsigned char &gaussianStdev = 2.f,
330  const unsigned int &apertureGradient = 3,
331  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
332  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr) = delete;
333 
334  template <typename ImageType>
335  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
336  vpImage<vpRGBa> &dIx, vpImage<vpRGBa> &dIy,
337  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
338  const unsigned int gaussianKernelSize = 5, const vpRGBa gaussianStdev = vpRGBa(),
339  const unsigned int apertureGradient = 3,
340  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
341  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr) = delete;
342 #else
343  template <typename FilterType>
344  inline static void computePartialDerivatives(const vpImage<vpRGBa> &I,
346  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
347  const unsigned int &gaussianKernelSize = 5, const FilterType &gaussianStdev = 2.f,
348  const unsigned int &apertureGradient = 3,
349  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
350  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr);
351 
352  template <typename ImageType>
353  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
355  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
356  const unsigned int &gaussianKernelSize = 5, const unsigned char &gaussianStdev = 2.f,
357  const unsigned int &apertureGradient = 3,
358  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
359  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr);
360 
361  template <typename ImageType>
362  inline static void computePartialDerivatives(const vpImage<ImageType> &I,
363  vpImage<vpRGBa> &dIx, vpImage<vpRGBa> &dIy,
364  const bool &computeDx = true, const bool &computeDy = true, const bool &normalize = true,
365  const unsigned int gaussianKernelSize = 5, const vpRGBa gaussianStdev = vpRGBa(),
366  const unsigned int apertureGradient = 3,
367  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
368  const vpCannyBackendType &backend = CANNY_VISP_BACKEND, const vpImage<bool> *p_mask = nullptr);
369 #endif
370 
391  template<typename OutType>
392  inline static float computeCannyThreshold(const vpImage<unsigned char> &I, float &lowerThresh,
393  const vpImage<OutType> *p_dIx = nullptr, const vpImage<OutType> *p_dIy = nullptr,
394  const unsigned int &gaussianKernelSize = 5,
395  const OutType &gaussianStdev = 2.f, const unsigned int &apertureGradient = 3,
396  const float &lowerThresholdRatio = 0.6, const float &upperThresholdRatio = 0.8,
397  const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
398  const vpImage<bool> *p_mask = nullptr)
399  {
400  const unsigned int w = I.getWidth();
401  const unsigned int h = I.getHeight();
402 
403  vpImage<unsigned char> dI(h, w);
404  vpImage<OutType> dIx(h, w), dIy(h, w);
405  if ((p_dIx != nullptr) && (p_dIy != nullptr)) {
406  dIx = *p_dIx;
407  dIy = *p_dIy;
408  }
409  else {
410  computePartialDerivatives(I, dIx, dIy, true, true, true, gaussianKernelSize, gaussianStdev,
411  apertureGradient, filteringType, vpImageFilter::CANNY_VISP_BACKEND, p_mask);
412  }
413 
414  // Computing the absolute gradient of the image G = |dIx| + |dIy|
415  for (unsigned int r = 0; r < h; ++r) {
416  for (unsigned int c = 0; c < w; ++c) {
417  // We have to compute the value for each pixel if we don't have a mask or for
418  // pixels for which the mask is true otherwise
419  bool computeVal = checkBooleanMask(p_mask, r, c);
420 
421  if (computeVal) {
422  float dx = static_cast<float>(dIx[r][c]);
423  float dy = static_cast<float>(dIy[r][c]);
424  float gradient = std::abs(dx) + std::abs(dy);
425  float gradientClamped = std::min<float>(gradient, static_cast<float>(std::numeric_limits<unsigned char>::max()));
426  dI[r][c] = static_cast<unsigned char>(gradientClamped);
427  }
428  }
429  }
430 
431  // Compute the histogram
432  vpHistogram hist;
433  hist.setMask(p_mask);
434  const unsigned int nbBins = 256;
435  hist.calculate(dI, nbBins);
436  float totalNbPixels = static_cast<float>(hist.getTotal());
437  float accu = 0;
438  float t = upperThresholdRatio * totalNbPixels;
439  float bon = 0;
440  for (unsigned int i = 0; i < nbBins; ++i) {
441  float tf = static_cast<float>(hist[i]);
442  accu = accu + tf;
443  if (accu > t) {
444  bon = (float)i;
445  break;
446  }
447  }
448  float upperThresh = std::max<float>(bon, 1.f);
449  lowerThresh = lowerThresholdRatio * bon;
450  return upperThresh;
451  }
452 
460  template <class ImageType> static double derivativeFilterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c)
461  {
462  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]) +
463  112.0 * static_cast<double>(I[r][c + 3] - I[r][c - 3])) / 8418.0;
464  }
465 
473  template <class ImageType> static double derivativeFilterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c)
474  {
475  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]) +
476  112.0 * static_cast<double>(I[r + 3][c] - I[r - 3][c])) / 8418.0;
477  }
478 
492  template <class ImageType, typename FilterType>
493  static FilterType derivativeFilterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
494  {
495  const unsigned int stop = (size - 1) / 2;
496  unsigned int i;
497  FilterType result;
498 
499  result = 0;
500 
501  for (i = 1; i <= stop; ++i) {
502  result += filter[i] * static_cast<FilterType>(I[r][c + i] - I[r][c - i]);
503  }
504  return result;
505  }
506 
520  template <class ImageType, typename FilterType>
521  static FilterType derivativeFilterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
522  {
523  const unsigned int stop = (size - 1) / 2;
524  unsigned int i;
525  FilterType result;
526 
527  result = 0;
528 
529  for (i = 1; i <= stop; ++i) {
530  result += filter[i] * static_cast<FilterType>(I[r + i][c] - I[r - i][c]);
531  }
532  return result;
533  }
534 
564  template <typename ImageType, typename FilterType>
565  static void filter(const vpImage<ImageType> &I, vpImage<FilterType> &If, const vpArray2D<FilterType> &M, bool convolve = false,
566  const vpImage<bool> *p_mask = nullptr)
567  {
568  const unsigned int size_y = M.getRows(), size_x = M.getCols();
569  const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
570 
571  const unsigned int inputHeight = I.getHeight(), inputWidth = I.getWidth();
572  If.resize(inputHeight, inputWidth, 0.0);
573 
574  if (convolve) {
575  const unsigned int stopHeight = inputHeight - half_size_y;
576  const unsigned int stopWidth = inputWidth - half_size_x;
577  for (unsigned int i = half_size_y; i < stopHeight; ++i) {
578  for (unsigned int j = half_size_x; j < stopWidth; ++j) {
579  // We have to compute the value for each pixel if we don't have a mask or for
580  // pixels for which the mask is true otherwise
581  bool computeVal = checkBooleanMask(p_mask, i, j);
582  if (computeVal) {
583  FilterType conv = 0;
584 
585  for (unsigned int a = 0; a < size_y; ++a) {
586  for (unsigned int b = 0; b < size_x; ++b) {
587  FilterType val = static_cast<FilterType>(I[i + half_size_y - a][j + half_size_x - b]); // Convolution
588  conv += M[a][b] * val;
589  }
590  }
591  If[i][j] = conv;
592  }
593  }
594  }
595  }
596  else {
597  const unsigned int stopHeight = inputHeight - half_size_y;
598  const unsigned int stopWidth = inputWidth - half_size_x;
599  for (unsigned int i = half_size_y; i < stopHeight; ++i) {
600  for (unsigned int j = half_size_x; j < stopWidth; ++j) {
601  // We have to compute the value for each pixel if we don't have a mask or for
602  // pixels for which the mask is true otherwise
603  bool computeVal = checkBooleanMask(p_mask, i, j);
604  if (computeVal) {
605  FilterType corr = 0;
606 
607  for (unsigned int a = 0; a < size_y; ++a) {
608  for (unsigned int b = 0; b < size_x; ++b) {
609  FilterType val = static_cast<FilterType>(I[i - half_size_y + a][j - half_size_x + b]); // Correlation
610  corr += M[a][b] * val;
611  }
612  }
613  If[i][j] = corr;
614  }
615  }
616  }
617  }
618  }
619 
620 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
621  template <typename FilterType>
622  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &If, const vpArray2D<FilterType> &M, bool convolve = false) = delete;
623 #else
624  template <typename FilterType>
625  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &If, const vpArray2D<FilterType> &M, bool convolve = false);
626 #endif
627 
641  template <typename ImageType, typename FilterType>
643  bool convolve = false, const vpImage<bool> *p_mask = nullptr)
644  {
645  const unsigned int size = M.getRows();
646  const unsigned int half_size = size / 2;
647  const unsigned int height = I.getHeight(), width = I.getWidth();
648  const unsigned int stopV = height - half_size;
649  const unsigned int stopU = width - half_size;
650 
651  Iu.resize(height, width, 0.0);
652  Iv.resize(height, width, 0.0);
653 
654  if (convolve) {
655  for (unsigned int v = half_size; v < stopV; ++v) {
656  for (unsigned int u = half_size; u < stopU; ++u) {
657  // We have to compute the value for each pixel if we don't have a mask or for
658  // pixels for which the mask is true otherwise
659  bool computeVal = checkBooleanMask(p_mask, v, u);
660  if (computeVal) {
661  FilterType conv_u = 0;
662  FilterType conv_v = 0;
663 
664  for (unsigned int a = 0; a < size; ++a) {
665  for (unsigned int b = 0; b < size; ++b) {
666  FilterType val = static_cast<FilterType>(I[v + half_size - a][u + half_size - b]); // Convolution
667  conv_u += M[a][b] * val;
668  conv_v += M[b][a] * val;
669  }
670  }
671  Iu[v][u] = conv_u;
672  Iv[v][u] = conv_v;
673  }
674  }
675  }
676  }
677  else {
678  for (unsigned int v = half_size; v < stopV; ++v) {
679  for (unsigned int u = half_size; u < stopU; ++u) {
680  // We have to compute the value for each pixel if we don't have a mask or for
681  // pixels for which the mask is true otherwise
682  bool computeVal = checkBooleanMask(p_mask, v, u);
683 
684  if (computeVal) {
685  FilterType conv_u = 0;
686  FilterType conv_v = 0;
687 
688  for (unsigned int a = 0; a < size; ++a) {
689  for (unsigned int b = 0; b < size; ++b) {
690  FilterType val = static_cast<FilterType>(I[v - half_size + a][u - half_size + b]); // Correlation
691  conv_u += M[a][b] * val;
692  conv_v += M[b][a] * val;
693  }
694  }
695  Iu[v][u] = conv_u;
696  Iv[v][u] = conv_v;
697  }
698  }
699  }
700  }
701  }
702 
703 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))) // Check if cxx11 or higher
704  template<typename FilterType>
705  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &Iu, vpImage<FilterType> &Iv, const vpArray2D<FilterType> &M, bool convolve) = delete;
706 
707  template<typename ImageType>
708  static void filter(const vpImage<ImageType> &I, vpImage<ImageType> &Iu, vpImage<ImageType> &Iv, const vpArray2D<vpRGBa> &M, bool convolve) = delete;
709 #else
710  template<typename FilterType>
711  static void filter(const vpImage<vpRGBa> &I, vpImage<FilterType> &Iu, vpImage<FilterType> &Iv, const vpArray2D<FilterType> &M, bool convolve);
712 
713  template<typename ImageType>
714  static void filter(const vpImage<ImageType> &I, vpImage<ImageType> &Iu, vpImage<ImageType> &Iv, const vpArray2D<vpRGBa> &M, bool convolve);
715 #endif
716 
717  static void sepFilter(const vpImage<unsigned char> &I, vpImage<double> &If, const vpColVector &kernelH, const vpColVector &kernelV);
718 
728  template <typename ImageType, typename FilterType>
729  static void filter(const vpImage<ImageType> &I, vpImage<FilterType> &GI, const FilterType *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr)
730  {
732  filterX<ImageType, FilterType>(I, GIx, filter, size, p_mask);
733  filterY<FilterType, FilterType>(GIx, GI, filter, size, p_mask);
734  GIx.destroy();
735  }
736 
737  static inline unsigned char filterGaussXPyramidal(const vpImage<unsigned char> &I, unsigned int i, unsigned int j)
738  {
739  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.);
740  }
741  static inline unsigned char filterGaussYPyramidal(const vpImage<unsigned char> &I, unsigned int i, unsigned int j)
742  {
743  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.);
744  }
745 
746  template <typename ImageType, typename FilterType>
747  static void filterX(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *filter, unsigned int size,
748  const vpImage<bool> *p_mask = nullptr)
749  {
750  const unsigned int height = I.getHeight();
751  const unsigned int width = I.getWidth();
752  const unsigned int stop1J = (size - 1) / 2;
753  const unsigned int stop2J = width - (size - 1) / 2;
754  resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
755 
756  for (unsigned int i = 0; i < height; ++i) {
757  for (unsigned int j = 0; j < stop1J; ++j) {
758  // We have to compute the value for each pixel if we don't have a mask or for
759  // pixels for which the mask is true otherwise
760  bool computeVal = checkBooleanMask(p_mask, i, j);
761  if (computeVal) {
762  dIx[i][j] = vpImageFilter::filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
763  }
764  }
765  for (unsigned int j = stop1J; j < stop2J; ++j) {
766  // We have to compute the value for each pixel if we don't have a mask or for
767  // pixels for which the mask is true otherwise
768  bool computeVal = checkBooleanMask(p_mask, i, j);
769  if (computeVal) {
770  dIx[i][j] = vpImageFilter::filterX<ImageType, FilterType>(I, i, j, filter, size);
771  }
772  }
773  for (unsigned int j = stop2J; j < width; ++j) {
774  // We have to compute the value for each pixel if we don't have a mask or for
775  // pixels for which the mask is true otherwise
776  bool computeVal = checkBooleanMask(p_mask, i, j);
777  if (computeVal) {
778  dIx[i][j] = vpImageFilter::filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
779  }
780  }
781  }
782  }
783 
784  static void filterX(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr);
785 
786 #ifdef DOXYGEN_SHOULD_SKIP_THIS
787  static void filterXR(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
788  static void filterXG(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
789  static void filterXB(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
790 #endif
791 
792  template<typename ImageType, typename FilterType>
793  static inline FilterType filterX(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
794  {
795  const unsigned int stop = (size - 1) / 2;
796  FilterType result = static_cast<FilterType>(0.);
797 
798  for (unsigned int i = 1; i <= stop; ++i) {
799  result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
800  }
801  return result + filter[0] * static_cast<FilterType>(I[r][c]);
802  }
803 
804 #ifndef DOXYGEN_SHOULD_SKIP_THIS
805  static inline double filterXR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
806  {
807  const unsigned int stop = (size - 1) / 2;
808  double result = 0.;
809  for (unsigned int i = 1; i <= stop; ++i) {
810  result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
811  }
812  return result + filter[0] * static_cast<double>(I[r][c].R);
813  }
814 
815  static inline double filterXG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
816  {
817  const unsigned int stop = (size - 1) / 2;
818  double result = 0.;
819 
820  for (unsigned int i = 1; i <= stop; ++i) {
821  result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
822  }
823  return result + filter[0] * static_cast<double>(I[r][c].G);
824  }
825 
826  static inline double filterXB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
827  {
828  const unsigned int stop = (size - 1) / 2;
829  double result = 0.;
830 
831  for (unsigned int i = 1; i <= stop; ++i) {
832  result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
833  }
834  return result + filter[0] * static_cast<double>(I[r][c].B);
835  }
836 
837  template <typename ImageType, typename FilterType>
838  static inline FilterType filterXLeftBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
839  const FilterType *filter, unsigned int size)
840  {
841  const unsigned int stop = (size - 1) / 2;
842  FilterType result = static_cast<FilterType>(0.);
843 
844  for (unsigned int i = 1; i <= stop; ++i) {
845  if (c > i) {
846  result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
847  }
848  else {
849  result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][i - c]);
850  }
851  }
852  return result + filter[0] * static_cast<FilterType>(I[r][c]);
853  }
854 
855  static inline double filterXLeftBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
856  const double *filter, unsigned int size)
857  {
858  const unsigned int stop = (size - 1) / 2;
859  double result = 0.;
860 
861  for (unsigned int i = 1; i <= stop; ++i) {
862  if (c > i) {
863  result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
864  }
865  else {
866  result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][i - c].R);
867  }
868  }
869  return result + filter[0] * static_cast<double>(I[r][c].R);
870  }
871 
872  static inline double filterXLeftBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
873  const double *filter, unsigned int size)
874  {
875  const unsigned int stop = (size - 1) / 2;
876  double result = 0.;
877 
878  for (unsigned int i = 1; i <= stop; ++i) {
879  if (c > i) {
880  result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
881  }
882  else {
883  result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][i - c].G);
884  }
885  }
886  return result + filter[0] * static_cast<double>(I[r][c].G);
887  }
888 
889  static inline double filterXLeftBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
890  const double *filter, unsigned int size)
891  {
892  const unsigned int stop = (size - 1) / 2;
893  double result = 0.;
894 
895  for (unsigned int i = 1; i <= stop; ++i) {
896  if (c > i) {
897  result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
898  }
899  else {
900  result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][i - c].B);
901  }
902  }
903  return result + filter[0] * static_cast<double>(I[r][c].B);
904  }
905 
906  template <typename ImageType, typename FilterType>
907  static inline FilterType filterXRightBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
908  const FilterType *filter, unsigned int size)
909  {
910  const unsigned int stop = (size - 1) / 2;
911  const unsigned int width = I.getWidth();
912  FilterType result = static_cast<FilterType>(0.);
913 
914  for (unsigned int i = 1; i <= stop; ++i) {
915  if ((c + i) < width) {
916  result += filter[i] * static_cast<FilterType>(I[r][c + i] + I[r][c - i]);
917  }
918  else {
919  result += filter[i] * static_cast<FilterType>(I[r][2 * width - c - i - 1] + I[r][c - i]);
920  }
921  }
922  return result + filter[0] * static_cast<FilterType>(I[r][c]);
923  }
924 
925  static inline double filterXRightBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
926  const double *filter, unsigned int size)
927  {
928  const unsigned int stop = (size - 1) / 2;
929  const unsigned int width = I.getWidth();
930  double result = 0.;
931 
932  for (unsigned int i = 1; i <= stop; ++i) {
933  if ((c + i) < width) {
934  result += filter[i] * static_cast<double>(I[r][c + i].R + I[r][c - i].R);
935  }
936  else {
937  result += filter[i] * static_cast<double>(I[r][2 * width - c - i - 1].R + I[r][c - i].R);
938  }
939  }
940  return result + filter[0] * static_cast<double>(I[r][c].R);
941  }
942 
943  static inline double filterXRightBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
944  const double *filter, unsigned int size)
945  {
946  const unsigned int stop = (size - 1) / 2;
947  const unsigned int width = I.getWidth();
948  double result = 0.;
949 
950  for (unsigned int i = 1; i <= stop; ++i) {
951  if ((c + i) < width) {
952  result += filter[i] * static_cast<double>(I[r][c + i].G + I[r][c - i].G);
953  }
954  else {
955  result += filter[i] * static_cast<double>(I[r][2 * width - c - i - 1].G + I[r][c - i].G);
956  }
957  }
958  return result + filter[0] * static_cast<double>(I[r][c].G);
959  }
960 
961  static inline double filterXRightBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
962  const double *filter, unsigned int size)
963  {
964  const unsigned int stop = (size - 1) / 2;
965  const unsigned int width = I.getWidth();
966  double result = 0.;
967 
968  for (unsigned int i = 1; i <= stop; ++i) {
969  if ((c + i) < width) {
970  result += filter[i] * static_cast<double>(I[r][c + i].B + I[r][c - i].B);
971  }
972  else {
973  result += filter[i] * static_cast<double>(I[r][2 * width - c - i - 1].B + I[r][c - i].B);
974  }
975  }
976  return result + filter[0] * static_cast<double>(I[r][c].B);
977  }
978 #endif
979 
980 
981  static void filterY(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr);
982 
983 #ifndef DOXYGEN_SHOULD_SKIP_THIS
984  static void filterYR(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
985  static void filterYG(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
986  static void filterYB(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx, const double *filter, unsigned int size);
987 #endif
988 
989  template<typename ImageType, typename FilterType>
990  static void filterY(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *filter, unsigned int size,
991  const vpImage<bool> *p_mask = nullptr)
992  {
993  const unsigned int height = I.getHeight(), width = I.getWidth();
994  const unsigned int stop1I = (size - 1) / 2;
995  const unsigned int stop2I = height - (size - 1) / 2;
996  resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
997 
998  for (unsigned int i = 0; i < stop1I; ++i) {
999  for (unsigned int j = 0; j < width; ++j) {
1000  // We have to compute the value for each pixel if we don't have a mask or for
1001  // pixels for which the mask is true otherwise
1002  bool computeVal = checkBooleanMask(p_mask, i, j);
1003  if (computeVal) {
1004  dIy[i][j] = vpImageFilter::filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
1005  }
1006  }
1007  }
1008  for (unsigned int i = stop1I; i < stop2I; ++i) {
1009  for (unsigned int j = 0; j < width; ++j) {
1010  // We have to compute the value for each pixel if we don't have a mask or for
1011  // pixels for which the mask is true otherwise
1012  bool computeVal = checkBooleanMask(p_mask, i, j);
1013  if (computeVal) {
1014  dIy[i][j] = vpImageFilter::filterY<ImageType, FilterType>(I, i, j, filter, size);
1015  }
1016  }
1017  }
1018  for (unsigned int i = stop2I; i < height; ++i) {
1019  for (unsigned int j = 0; j < width; ++j) {
1020  // We have to compute the value for each pixel if we don't have a mask or for
1021  // pixels for which the mask is true otherwise
1022  bool computeVal = checkBooleanMask(p_mask, i, j);
1023  if (computeVal) {
1024  dIy[i][j] = vpImageFilter::filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
1025  }
1026  }
1027  }
1028  }
1029 
1030  template<typename ImageType, typename FilterType>
1031  static inline FilterType filterY(const vpImage<ImageType> &I, unsigned int r, unsigned int c, const FilterType *filter, unsigned int size)
1032  {
1033  const unsigned int stop = (size - 1) / 2;
1034  FilterType result = static_cast<FilterType>(0.);
1035 
1036  for (unsigned int i = 1; i <= stop; ++i) {
1037  result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
1038  }
1039  return result + filter[0] * static_cast<FilterType>(I[r][c]);
1040  }
1041 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1042  static inline double filterYR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1043  {
1044  const unsigned int stop = (size - 1) / 2;
1045  double result = 0.;
1046 
1047  for (unsigned int i = 1; i <= stop; ++i) {
1048  result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
1049  }
1050  return result + filter[0] * static_cast<double>(I[r][c].R);
1051  }
1052  static inline double filterYG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1053  {
1054  const unsigned int stop = (size - 1) / 2;
1055  double result = 0.;
1056 
1057  for (unsigned int i = 1; i <= stop; ++i) {
1058  result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
1059  }
1060  return result + filter[0] * static_cast<double>(I[r][c].G);
1061  }
1062 
1063  static inline double filterYB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1064  {
1065  const unsigned int stop = (size - 1) / 2;
1066  double result = 0.;
1067 
1068  for (unsigned int i = 1; i <= stop; ++i) {
1069  result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
1070  }
1071  return result + filter[0] * static_cast<double>(I[r][c].B);
1072  }
1073 
1074  template<typename ImageType, typename FilterType>
1075  static inline FilterType filterYTopBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
1076  const FilterType *filter, unsigned int size)
1077  {
1078  const unsigned int stop = (size - 1) / 2;
1079  FilterType result = static_cast<FilterType>(0.);
1080 
1081  for (unsigned int i = 1; i <= stop; ++i) {
1082  if (r > i) {
1083  result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
1084  }
1085  else {
1086  result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[i - r][c]);
1087  }
1088  }
1089  return result + filter[0] * static_cast<FilterType>(I[r][c]);
1090  }
1091 
1092  double static inline filterYTopBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1093  {
1094  const unsigned int stop = (size - 1) / 2;
1095  double result = 0.;
1096 
1097  for (unsigned int i = 1; i <= stop; ++i) {
1098  if (r > i) {
1099  result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
1100  }
1101  else {
1102  result += filter[i] * static_cast<double>(I[r + i][c].R + I[i - r][c].R);
1103  }
1104  }
1105  return result + filter[0] * static_cast<double>(I[r][c].R);
1106  }
1107 
1108  double static inline filterYTopBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1109  {
1110  const unsigned int stop = (size - 1) / 2;
1111  double result = 0.;
1112 
1113  for (unsigned int i = 1; i <= stop; ++i) {
1114  if (r > i) {
1115  result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
1116  }
1117  else {
1118  result += filter[i] * static_cast<double>(I[r + i][c].G + I[i - r][c].G);
1119  }
1120  }
1121  return result + filter[0] * static_cast<double>(I[r][c].G);
1122  }
1123 
1124  double static inline filterYTopBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
1125  {
1126  const unsigned int stop = (size - 1) / 2;
1127  double result = 0.;
1128 
1129  for (unsigned int i = 1; i <= stop; ++i) {
1130  if (r > i) {
1131  result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
1132  }
1133  else {
1134  result += filter[i] * static_cast<double>(I[r + i][c].B + I[i - r][c].B);
1135  }
1136  }
1137  return result + filter[0] * static_cast<double>(I[r][c].B);
1138  }
1139 
1140  template<typename ImageType, typename FilterType>
1141  static inline FilterType filterYBottomBorder(const vpImage<ImageType> &I, unsigned int r, unsigned int c,
1142  const FilterType *filter, unsigned int size)
1143  {
1144  const unsigned int height = I.getHeight();
1145  const unsigned int stop = (size - 1) / 2;
1146  FilterType result = static_cast<FilterType>(0.);
1147 
1148  for (unsigned int i = 1; i <= stop; ++i) {
1149  if ((r + i) < height) {
1150  result += filter[i] * static_cast<FilterType>(I[r + i][c] + I[r - i][c]);
1151  }
1152  else {
1153  result += filter[i] * static_cast<FilterType>(I[2 * height - r - i - 1][c] + I[r - i][c]);
1154  }
1155  }
1156  return result + filter[0] * static_cast<FilterType>(I[r][c]);
1157  }
1158 
1159  double static inline filterYBottomBorderR(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
1160  const double *filter, unsigned int size)
1161  {
1162  const unsigned int height = I.getHeight();
1163  const unsigned int stop = (size - 1) / 2;
1164  double result = 0.;
1165 
1166  for (unsigned int i = 1; i <= stop; ++i) {
1167  if ((r + i) < height) {
1168  result += filter[i] * static_cast<double>(I[r + i][c].R + I[r - i][c].R);
1169  }
1170  else {
1171  result += filter[i] * static_cast<double>(I[2 * height - r - i - 1][c].R + I[r - i][c].R);
1172  }
1173  }
1174  return result + filter[0] * static_cast<double>(I[r][c].R);
1175  }
1176 
1177  double static inline filterYBottomBorderG(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
1178  const double *filter, unsigned int size)
1179  {
1180  const unsigned int height = I.getHeight();
1181  const unsigned int stop = (size - 1) / 2;
1182  double result = 0.;
1183 
1184  for (unsigned int i = 1; i <= stop; ++i) {
1185  if ((r + i) < height) {
1186  result += filter[i] * static_cast<double>(I[r + i][c].G + I[r - i][c].G);
1187  }
1188  else {
1189  result += filter[i] * static_cast<double>(I[2 * height - r - i - 1][c].G + I[r - i][c].G);
1190  }
1191  }
1192  return result + filter[0] * static_cast<double>(I[r][c].G);
1193  }
1194 
1195  double static inline filterYBottomBorderB(const vpImage<vpRGBa> &I, unsigned int r, unsigned int c,
1196  const double *filter, unsigned int size)
1197  {
1198  const unsigned int height = I.getHeight();
1199  const unsigned int stop = (size - 1) / 2;
1200  double result = 0.;
1201 
1202  for (unsigned int i = 1; i <= stop; ++i) {
1203  if ((r + i) < height) {
1204  result += filter[i] * static_cast<double>(I[r + i][c].B + I[r - i][c].B);
1205  }
1206  else {
1207  result += filter[i] * static_cast<double>(I[2 * height - r - i - 1][c].B + I[r - i][c].B);
1208  }
1209  }
1210  return result + filter[0] * static_cast<double>(I[r][c].B);
1211  }
1212 #endif
1213 
1214 
1228  template <typename ImageType, typename FilterType>
1229  static void gaussianBlur(const vpImage<ImageType> &I, vpImage<FilterType> &GI, unsigned int size = 7, FilterType sigma = 0., bool normalize = true,
1230  const vpImage<bool> *p_mask = nullptr)
1231  {
1232  FilterType *fg = new FilterType[(size + 1) / 2];
1233  vpImageFilter::getGaussianKernel<FilterType>(fg, size, sigma, normalize);
1234  vpImage<FilterType> GIx;
1235  vpImageFilter::filterX<ImageType, FilterType>(I, GIx, fg, size, p_mask);
1236  vpImageFilter::filterY<FilterType, FilterType>(GIx, GI, fg, size, p_mask);
1237  GIx.destroy();
1238  delete[] fg;
1239  }
1240 
1241  static void gaussianBlur(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &GI, unsigned int size = 7, double sigma = 0., bool normalize = true,
1242  const vpImage<bool> *p_mask = nullptr);
1243 
1251  template <class T> static double gaussianFilter(const vpImage<T> &fr, unsigned int r, unsigned int c)
1252  {
1253  return (15.0 * fr[r][c] + 12.0 * (fr[r - 1][c] + fr[r][c - 1] + fr[r + 1][c] + fr[r][c + 1]) +
1254  9.0 * (fr[r - 1][c - 1] + fr[r + 1][c - 1] + fr[r - 1][c + 1] + fr[r + 1][c + 1]) +
1255  5.0 * (fr[r - 2][c] + fr[r][c - 2] + fr[r + 2][c] + fr[r][c + 2]) +
1256  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] +
1257  fr[r + 2][c + 1] + fr[r - 1][c + 2] + fr[r + 1][c + 2]) +
1258  2.0 * (fr[r - 2][c - 2] + fr[r + 2][c - 2] + fr[r - 2][c + 2] + fr[r + 2][c + 2])) / 159.0;
1259  }
1260  // Gaussian pyramid operation
1261  static void getGaussPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1262  static void getGaussXPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1263  static void getGaussYPyramidal(const vpImage<unsigned char> &I, vpImage<unsigned char> &GI);
1264 
1281  template<typename FilterType>
1282  static void getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma = 0., bool normalize = true)
1283  {
1284  if ((size % 2) != 1) {
1285  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
1286  }
1287 
1288  if (sigma <= 0) {
1289  sigma = static_cast<FilterType>((size - 1) / 6.0);
1290  }
1291 
1292  int middle = (static_cast<int>(size) - 1) / 2;
1293  FilterType sigma2 = static_cast<FilterType>(vpMath::sqr(sigma));
1294  FilterType coef1 = static_cast<FilterType>(1. / (sigma * sqrt(2. * M_PI)));
1295  FilterType _2_sigma2 = static_cast<FilterType>(2. * sigma2);
1296  for (int i = 0; i <= middle; ++i) {
1297  filter[i] = coef1 * static_cast<FilterType>(exp(-(i * i) / _2_sigma2));
1298  }
1299  if (normalize) {
1300  // renormalization
1301  FilterType sum = 0;
1302  for (int i = 1; i <= middle; ++i) {
1303  sum += 2 * filter[i];
1304  }
1305  sum += filter[0];
1306 
1307  for (int i = 0; i <= middle; ++i) {
1308  filter[i] = filter[i] / sum;
1309  }
1310  }
1311  }
1312 
1327  template <typename FilterType>
1328  static void getGaussianDerivativeKernel(FilterType *filter, unsigned int size, FilterType sigma = 0., bool normalize = true)
1329  {
1330  if ((size % 2) != 1) {
1331  throw(vpImageException(vpImageException::incorrectInitializationError, "Bad Gaussian filter size"));
1332  }
1333 
1334  if (sigma <= 0) {
1335  sigma = static_cast<FilterType>((size - 1) / 6.0);
1336  }
1337 
1338  int middle = (static_cast<int>(size) - 1) / 2;
1339  FilterType sigma2 = static_cast<FilterType>(vpMath::sqr(sigma));
1340  FilterType coef_1 = static_cast<FilterType>(1. / (sigma * sqrt(2. * M_PI)));
1341  FilterType coef_1_over_2 = coef_1 / static_cast<FilterType>(2.);
1342  FilterType _2_coef_1 = static_cast<FilterType>(2.) * coef_1;
1343  FilterType _2_sigma2 = static_cast<FilterType>(2. * sigma2);
1344  filter[0] = 0.;
1345  for (int i = 1; i <= middle; ++i) {
1346  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)));
1347  }
1348 
1349  if (normalize) {
1350  FilterType sum = 0;
1351  for (int i = 1; i <= middle; ++i) {
1352  sum += _2_coef_1 * static_cast<FilterType>(exp(-(i * i) / _2_sigma2));
1353  }
1354  sum += coef_1;
1355 
1356  for (int i = 1; i <= middle; ++i) {
1357  filter[i] = filter[i] / sum;
1358  }
1359  }
1360  }
1361 
1362  // Gradient along X
1363  template<typename FilterType>
1364  static void getGradX(const vpImage<unsigned char> &I, vpImage<FilterType> &dIx, const vpImage<bool> *p_mask = nullptr)
1365  {
1366  const unsigned int height = I.getHeight(), width = I.getWidth();
1367  const unsigned int stopJ = width - 3;
1368  resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1369 
1370  for (unsigned int i = 0; i < height; ++i) {
1371  for (unsigned int j = 0; j < 3; ++j) {
1372  // If a mask is used, the image is already initialized with 0s
1373  bool computeVal = (p_mask == nullptr);
1374  if (computeVal) {
1375  dIx[i][j] = static_cast<FilterType>(0);
1376  }
1377  }
1378  for (unsigned int j = 3; j < stopJ; ++j) {
1379  // We have to compute the value for each pixel if we don't have a mask or for
1380  // pixels for which the mask is true otherwise
1381  bool computeVal = checkBooleanMask(p_mask, i, j);
1382  if (computeVal) {
1383  dIx[i][j] = static_cast<FilterType>(vpImageFilter::derivativeFilterX(I, i, j));
1384  }
1385  }
1386  for (unsigned int j = stopJ; j < width; ++j) {
1387  // If a mask is used, the image is already initialized with 0s
1388  bool computeVal = (p_mask == nullptr);
1389  if (computeVal) {
1390  dIx[i][j] = static_cast<FilterType>(0);
1391  }
1392  }
1393  }
1394  }
1395 
1396  template <typename ImageType, typename FilterType>
1397  static void getGradX(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr)
1398  {
1399  const unsigned int height = I.getHeight(), width = I.getWidth();
1400  const unsigned int stop1J = (size - 1) / 2;
1401  const unsigned int stop2J = width - (size - 1) / 2;
1402  resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1403 
1404  for (unsigned int i = 0; i < height; ++i) {
1405  for (unsigned int j = 0; j < stop1J; ++j) {
1406  // If a mask is used, the image is already initialized with 0s
1407  bool computeVal = (p_mask == nullptr);
1408  if (computeVal) {
1409  dIx[i][j] = static_cast<FilterType>(0);
1410  }
1411  }
1412  for (unsigned int j = stop1J; j < stop2J; ++j) {
1413  // We have to compute the value for each pixel if we don't have a mask or for
1414  // pixels for which the mask is true otherwise
1415  bool computeVal = checkBooleanMask(p_mask, i, j);
1416  if (computeVal) {
1417  dIx[i][j] = vpImageFilter::derivativeFilterX<ImageType, FilterType>(I, i, j, filter, size);
1418  }
1419  }
1420  for (unsigned int j = stop2J; j < width; ++j) {
1421  // If a mask is used, the image is already initialized with 0s
1422  bool computeVal = (p_mask == nullptr);
1423  if (computeVal) {
1424  dIx[i][j] = static_cast<FilterType>(0);
1425  }
1426  }
1427  }
1428  }
1429 
1441  template <typename ImageType, typename FilterType>
1442  static void getGradXGauss2D(const vpImage<ImageType> &I, vpImage<FilterType> &dIx, const FilterType *gaussianKernel,
1443  const FilterType *gaussianDerivativeKernel, unsigned int size, const vpImage<bool> *p_mask = nullptr)
1444  {
1445  vpImage<FilterType> GIy;
1446  vpImageFilter::filterY<ImageType, FilterType>(I, GIy, gaussianKernel, size, p_mask);
1447  vpImageFilter::getGradX<FilterType, FilterType>(GIy, dIx, gaussianDerivativeKernel, size, p_mask);
1448  }
1449 
1450  // Gradient along Y
1451  template <typename FilterType>
1452  static void getGradY(const vpImage<unsigned char> &I, vpImage<FilterType> &dIy, const vpImage<bool> *p_mask = nullptr)
1453  {
1454  const unsigned int height = I.getHeight(), width = I.getWidth();
1455  const unsigned int stopI = height - 3;
1456  resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1457 
1458  for (unsigned int i = 0; i < 3; ++i) {
1459  for (unsigned int j = 0; j < width; ++j) {
1460  // We have to compute the value for each pixel if we don't have a mask or for
1461  // pixels for which the mask is true otherwise
1462  bool computeVal = checkBooleanMask(p_mask, i, j);
1463  if (computeVal) {
1464  dIy[i][j] = static_cast<FilterType>(0);
1465  }
1466  }
1467  }
1468  for (unsigned int i = 3; i < stopI; ++i) {
1469  for (unsigned int j = 0; j < width; ++j) {
1470  // We have to compute the value for each pixel if we don't have a mask or for
1471  // pixels for which the mask is true otherwise
1472  bool computeVal = checkBooleanMask(p_mask, i, j);
1473  if (computeVal) {
1474  dIy[i][j] = static_cast<FilterType>(vpImageFilter::derivativeFilterY(I, i, j));
1475  }
1476  }
1477  }
1478  for (unsigned int i = stopI; i < height; ++i) {
1479  for (unsigned int j = 0; j < width; ++j) {
1480  // We have to compute the value for each pixel if we don't have a mask or for
1481  // pixels for which the mask is true otherwise
1482  bool computeVal = checkBooleanMask(p_mask, i, j);
1483  if (computeVal) {
1484  dIy[i][j] = static_cast<FilterType>(0);
1485  }
1486  }
1487  }
1488  }
1489 
1490  template <typename ImageType, typename FilterType>
1491  static void getGradY(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *filter, unsigned int size, const vpImage<bool> *p_mask = nullptr)
1492  {
1493  const unsigned int height = I.getHeight(), width = I.getWidth();
1494  const unsigned int stop1I = (size - 1) / 2;
1495  const unsigned int stop2I = height - (size - 1) / 2;
1496  resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1497 
1498  for (unsigned int i = 0; i < stop1I; ++i) {
1499  for (unsigned int j = 0; j < width; ++j) {
1500  // We have to compute the value for each pixel if we don't have a mask or for
1501  // pixels for which the mask is true otherwise
1502  bool computeVal = checkBooleanMask(p_mask, i, j);
1503  if (computeVal) {
1504  dIy[i][j] = static_cast<FilterType>(0);
1505  }
1506  }
1507  }
1508  for (unsigned int i = stop1I; i < stop2I; ++i) {
1509  for (unsigned int j = 0; j < width; ++j) {
1510  // We have to compute the value for each pixel if we don't have a mask or for
1511  // pixels for which the mask is true otherwise
1512  bool computeVal = checkBooleanMask(p_mask, i, j);
1513  if (computeVal) {
1514  dIy[i][j] = vpImageFilter::derivativeFilterY<ImageType, FilterType>(I, i, j, filter, size);
1515  }
1516  }
1517  }
1518  for (unsigned int i = stop2I; i < height; ++i) {
1519  for (unsigned int j = 0; j < width; ++j) {
1520  // We have to compute the value for each pixel if we don't have a mask or for
1521  // pixels for which the mask is true otherwise
1522  bool computeVal = checkBooleanMask(p_mask, i, j);
1523  if (computeVal) {
1524  dIy[i][j] = static_cast<FilterType>(0);
1525  }
1526  }
1527  }
1528  }
1529 
1541  template <typename ImageType, typename FilterType>
1542  static void getGradYGauss2D(const vpImage<ImageType> &I, vpImage<FilterType> &dIy, const FilterType *gaussianKernel,
1543  const FilterType *gaussianDerivativeKernel, unsigned int size, const vpImage<bool> *p_mask = nullptr)
1544  {
1545  vpImage<FilterType> GIx;
1546  vpImageFilter::filterX<ImageType, FilterType>(I, GIx, gaussianKernel, size, p_mask);
1547  vpImageFilter::getGradY<FilterType, FilterType>(GIx, dIy, gaussianDerivativeKernel, size, p_mask);
1548  }
1549 
1557  template <typename FilterType>
1558  inline static FilterType getScharrKernelX(FilterType *filter, unsigned int size)
1559  {
1560  if (size != 1) {
1561  // Size = 1 => kernel_size = 2*1 + 1 = 3
1562  std::stringstream errMsg;
1563  errMsg << "Cannot get Scharr kernel of size " << size * 2 + 1 << " != 3";
1564  throw vpException(vpException::dimensionError, errMsg.str());
1565  }
1566 
1567  vpArray2D<FilterType> ScharrY(size * 2 + 1, size * 2 + 1);
1568  FilterType norm = getScharrKernelY<FilterType>(ScharrY.data, size);
1569  memcpy(filter, ScharrY.t().data, ScharrY.getRows() * ScharrY.getCols() * sizeof(FilterType));
1570  return norm;
1571  }
1572 
1580  template <typename FilterType>
1581  inline static FilterType getScharrKernelY(FilterType *filter, unsigned int size)
1582  {
1583  // Scharr kernel pre-computed for the usual size
1584  static const FilterType ScharrY3x3[9] = { -3.0, -10.0, -3.0, 0.0, 0.0, 0.0, 3.0, 10.0, 3.0 };
1585 
1586  if (size != 1) {
1587  // Size = 1 => kernel_size = 2*1 + 1 = 3
1588  std::stringstream errMsg;
1589  errMsg << "Cannot get Scharr kernel of size " << size * 2 + 1 << " != 3";
1590  throw vpException(vpException::dimensionError, errMsg.str());
1591  }
1592 
1593  const unsigned int kernel_size = size * 2 + 1;
1594  if (kernel_size == 3) {
1595  memcpy(filter, ScharrY3x3, kernel_size * kernel_size * sizeof(FilterType));
1596  return static_cast<FilterType>(1.0 / 32.0);
1597  }
1598 
1599  return static_cast<FilterType>(0.);
1600  }
1601 
1609  template <typename FilterType>
1610  inline static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
1611  {
1612  if (size == 0) {
1613  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
1614  }
1615  if (size > 20) {
1616  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
1617  }
1618 
1619  vpArray2D<FilterType> SobelY(size * 2 + 1, size * 2 + 1);
1620  FilterType norm = getSobelKernelY<FilterType>(SobelY.data, size);
1621  memcpy(filter, SobelY.t().data, SobelY.getRows() * SobelY.getCols() * sizeof(FilterType));
1622  return norm;
1623  }
1624 
1632  template <typename FilterType>
1633  inline static FilterType getSobelKernelY(FilterType *filter, unsigned int size)
1634  {
1635  // Sobel kernel pre-computed for the usual size
1636  static const FilterType SobelY3x3[9] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 };
1637  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,
1638  0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0 };
1639  static const FilterType SobelY7x7[49] = { -1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
1640  -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
1641  5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1 };
1642  const vpArray2D<FilterType> smoothingKernel(3, 3);
1643  smoothingKernel[0][0] = 1.0;
1644  smoothingKernel[0][1] = 2.0;
1645  smoothingKernel[0][2] = 1.0;
1646  smoothingKernel[1][0] = 2.0;
1647  smoothingKernel[1][1] = 4.0;
1648  smoothingKernel[1][2] = 2.0;
1649  smoothingKernel[2][0] = 1.0;
1650  smoothingKernel[2][1] = 2.0;
1651  smoothingKernel[2][2] = 1.0;
1652 
1653  if (size == 0) {
1654  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size 0!");
1655  }
1656  if (size > 20) {
1657  throw vpException(vpException::dimensionError, "Cannot get Sobel kernel of size > 20!");
1658  }
1659 
1660  const unsigned int kernel_size = size * 2 + 1;
1661  FilterType scale = static_cast<FilterType>(1. / 8.); // Scale to normalize Sobel3x3
1662  if (kernel_size == 3) {
1663  memcpy(filter, SobelY3x3, kernel_size * kernel_size * sizeof(FilterType));
1664  return scale;
1665  }
1666  scale *= static_cast<FilterType>(1. / 16.); // Sobel5x5 is the convolution of smoothingKernel, which needs 1/16 scale factor, with Sobel3x3
1667  if (kernel_size == 5) {
1668  memcpy(filter, SobelY5x5, kernel_size * kernel_size * sizeof(FilterType));
1669  return scale;
1670  }
1671  scale *= static_cast<FilterType>(1. / 16.); // Sobel7x7 is the convolution of smoothingKernel, which needs 1/16 scale factor, with Sobel5x5
1672  if (kernel_size == 7) {
1673  memcpy(filter, SobelY7x7, kernel_size * kernel_size * sizeof(FilterType));
1674  return scale;
1675  }
1676 
1677  vpArray2D<FilterType> sobelY(7, 7);
1678  memcpy(sobelY.data, SobelY7x7, sobelY.getRows() * sobelY.getCols() * sizeof(FilterType));
1679  for (unsigned int i = 4; i <= size; ++i) {
1680  sobelY = vpArray2D<FilterType>::conv2(sobelY, smoothingKernel, "full");
1681  // Sobel(N+1)x(N+1) is the convolution of smoothingKernel, which needs 1/16 scale factor, with SobelNxN
1682  scale *= static_cast<FilterType>(1. / 16.);
1683  }
1684 
1685  memcpy(filter, sobelY.data, sobelY.getRows() * sobelY.getCols() * sizeof(FilterType));
1686 
1687  return scale;
1688  }
1689 
1690 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
1691  static float median(const cv::Mat &cv_I);
1692  static float median(const vpImage<unsigned char> &Isrc);
1693  static std::vector<float> median(const vpImage<vpRGBa> &Isrc);
1694 #endif
1695 };
1696 
1697 #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:327
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:1143
vpArray2D< Type > t() const
Compute the transpose of the array.
Definition: vpArray2D.h:1132
unsigned int getRows() const
Definition: vpArray2D.h:337
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
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 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)
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)
vpCannyFilteringAndGradientType
Canny filter and gradient operators to apply on the image before the edge detection stage.
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.
@ CANNY_VISP_BACKEND
Use ViSP.
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 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 getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma=0., bool normalize=true)
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)
static FilterType getScharrKernelY(FilterType *filter, unsigned int size)
static void filter(const vpImage< vpRGBa > &I, vpImage< FilterType > &If, const vpArray2D< FilterType > &M, bool convolve=false)
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)
static FilterType getSobelKernelY(FilterType *filter, unsigned int size)
static void filter(const vpImage< vpRGBa > &I, vpImage< FilterType > &Iu, vpImage< FilterType > &Iv, const vpArray2D< FilterType > &M, bool convolve)
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 filter(const vpImage< ImageType > &I, vpImage< ImageType > &Iu, vpImage< ImageType > &Iv, const vpArray2D< vpRGBa > &M, bool convolve)
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 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:812
unsigned int getWidth() const
Definition: vpImage.h:245
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:783
unsigned int getHeight() const
Definition: vpImage.h:184
static double sqr(double x)
Definition: vpMath.h:201
Definition: vpRGBa.h:61