39 #ifndef VP_IMAGE_FILTER_H
40 #define VP_IMAGE_FILTER_H
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>
57 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
58 #include <opencv2/imgproc/imgproc.hpp>
59 #include <opencv2/imgproc/imgproc_c.h>
76 CANNY_OPENCV_BACKEND = 0,
77 CANNY_VISP_BACKEND = 1,
78 CANNY_COUNT_BACKEND = 2
81 static std::string vpCannyBackendTypeList(
const std::string &pref =
"<",
const std::string &sep =
" , ",
82 const std::string &suf =
">");
84 static std::string vpCannyBackendTypeToString(
const vpCannyBackendType &type);
86 static vpCannyBackendType vpCannyBackendTypeFromString(
const std::string &name);
91 CANNY_GBLUR_SOBEL_FILTERING = 0,
92 CANNY_GBLUR_SCHARR_FILTERING = 1,
93 CANNY_COUNT_FILTERING = 2
94 } vpCannyFilteringAndGradientType;
96 static std::string vpGetCannyFiltAndGradTypes(
const std::string &pref =
"<",
const std::string &sep =
" , ",
97 const std::string &suf =
">");
99 static std::string vpCannyFiltAndGradTypeToStr(
const vpCannyFilteringAndGradientType &type);
101 static vpCannyFilteringAndGradientType vpCannyFiltAndGradTypeFromStr(
const std::string &name);
104 const float &thresholdCanny,
const unsigned int &apertureSobel);
107 const float &lowerThresholdCanny,
const float &higherThresholdCanny,
108 const unsigned int &apertureSobel);
111 const float &lowerThresholdCanny,
const float &higherThresholdCanny,
112 const unsigned int &apertureSobel,
const float &gaussianStdev,
const float &lowerThresholdRatio,
113 const float &upperThresholdRatio,
const bool &normalizeGradients,
114 const vpCannyBackendType &cannyBackend,
const vpCannyFilteringAndGradientType &cannyFilteringSteps,
117 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
118 static float computeCannyThreshold(
const cv::Mat &cv_I,
const cv::Mat *p_cv_dIx,
const cv::Mat *p_cv_dIy,
119 float &lowerThresh,
const unsigned int &gaussianKernelSize = 5,
120 const float &gaussianStdev = 2.f,
const unsigned int &apertureGradient = 3,
121 const float &lowerThresholdRatio = 0.6,
const float &upperThresholdRatio = 0.8,
122 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
124 static void computePartialDerivatives(
const cv::Mat &cv_I,
125 cv::Mat &cv_dIx, cv::Mat &cv_dIy,
126 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
127 const unsigned int &gaussianKernelSize = 5,
const float &gaussianStdev = 2.f,
128 const unsigned int &apertureGradient = 3,
129 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
152 template <
typename ImageType,
typename FilterType>
155 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
156 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
157 const unsigned int &apertureGradient = 3,
162 if (backend == CANNY_OPENCV_BACKEND) {
163 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
164 cv::Mat cv_I, cv_dIx, cv_dIy;
166 computePartialDerivatives(cv_I, cv_dIx, cv_dIy, computeDx, computeDy, normalize, gaussianKernelSize,
167 static_cast<float>(gaussianStdev), apertureGradient, filteringType);
179 if ((filteringType == CANNY_GBLUR_SCHARR_FILTERING) || (filteringType == CANNY_GBLUR_SOBEL_FILTERING)) {
190 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
193 const unsigned int nbRows = filter.
getRows();
194 const unsigned int nbCols = filter.
getCols();
195 for (
unsigned int r = 0; r < nbRows; ++r) {
196 for (
unsigned int c = 0; c < nbCols; ++c) {
197 filter[r][c] = filter[r][c] * scale;
207 const unsigned int val2 = 2U;
209 if (filteringType == CANNY_GBLUR_SOBEL_FILTERING) {
217 else if (filteringType == CANNY_GBLUR_SCHARR_FILTERING) {
229 scaleFilter(gradientFilterX, scaleX);
232 scaleFilter(gradientFilterY, scaleY);
246 std::string errMsg =
"[vpImageFilter::computePartialDerivatives] Filtering + gradient method \"";
247 errMsg += vpCannyFiltAndGradTypeToStr(filteringType);
248 errMsg +=
"\" is not implemented yet\n";
254 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
255 template <
typename FilterType>
258 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
259 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
260 const unsigned int &apertureGradient = 3,
264 template <
typename ImageType>
267 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
268 const unsigned int &gaussianKernelSize = 5,
const unsigned char &gaussianStdev = 2.f,
269 const unsigned int &apertureGradient = 3,
273 template <
typename ImageType>
276 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
277 const unsigned int gaussianKernelSize = 5,
const vpRGBa gaussianStdev =
vpRGBa(),
278 const unsigned int apertureGradient = 3,
282 template <
typename FilterType>
285 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
286 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
287 const unsigned int &apertureGradient = 3,
291 template <
typename ImageType>
294 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
295 const unsigned int &gaussianKernelSize = 5,
const unsigned char &gaussianStdev = 2.f,
296 const unsigned int &apertureGradient = 3,
300 template <
typename ImageType>
303 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
304 const unsigned int gaussianKernelSize = 5,
const vpRGBa gaussianStdev =
vpRGBa(),
305 const unsigned int apertureGradient = 3,
330 template<
typename OutType>
333 const unsigned int &gaussianKernelSize = 5,
334 const OutType &gaussianStdev = 2.f,
const unsigned int &apertureGradient = 3,
335 const float &lowerThresholdRatio = 0.6,
const float &upperThresholdRatio = 0.8,
339 const unsigned int w = I.
getWidth();
344 if ((p_dIx !=
nullptr) && (p_dIy !=
nullptr)) {
349 computePartialDerivatives(I, dIx, dIy,
true,
true,
true, gaussianKernelSize, gaussianStdev,
354 for (
unsigned int r = 0; r < h; ++r) {
355 for (
unsigned int c = 0; c < w; ++c) {
358 bool computeVal = checkBooleanMask(p_mask, r, c);
361 float dx =
static_cast<float>(dIx[r][c]);
362 float dy =
static_cast<float>(dIy[r][c]);
363 float gradient = std::abs(dx) + std::abs(dy);
364 float gradientClamped = std::min<float>(gradient,
static_cast<float>(std::numeric_limits<unsigned char>::max()));
365 dI[r][c] =
static_cast<unsigned char>(gradientClamped);
373 const unsigned int nbBins = 256;
375 float totalNbPixels =
static_cast<float>(hist.
getTotal());
377 float t = upperThresholdRatio * totalNbPixels;
380 bool notFound =
true;
381 while ((i < nbBins) && notFound) {
382 float tf =
static_cast<float>(hist[i]);
385 bon =
static_cast<float>(i);
390 float upperThresh = std::max<float>(bon, 1.f);
391 lowerThresh = lowerThresholdRatio * bon;
404 const int val1 = 1, val2 = 2, val3 = 3;
405 return ((2047.0 *
static_cast<double>(I[r][c + val1] - I[r][c - val1])) + (913.0 *
static_cast<double>(I[r][c + val2] - I[r][c - val2])) +
406 (112.0 *
static_cast<double>(I[r][c + val3] - I[r][c - val3]))) / 8418.0;
418 const int val1 = 1, val2 = 2, val3 = 3;
419 return ((2047.0 *
static_cast<double>(I[r + val1][c] - I[r - val1][c])) + (913.0 *
static_cast<double>(I[r + val2][c] - I[r - val2][c])) +
420 (112.0 *
static_cast<double>(I[r + val3][c] - I[r - val3][c]))) / 8418.0;
436 template <
class ImageType,
typename FilterType>
439 const unsigned int stop = (size - 1) / 2;
445 for (i = 1; i <= stop; ++i) {
446 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] - I[r][c - i]);
464 template <
class ImageType,
typename FilterType>
467 const unsigned int stop = (size - 1) / 2;
473 for (i = 1; i <= stop; ++i) {
474 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] - I[r - i][c]);
508 template <
typename ImageType,
typename FilterType>
513 const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
516 If.
resize(inputHeight, inputWidth, 0.0);
519 const unsigned int stopHeight = inputHeight - half_size_y;
520 const unsigned int stopWidth = inputWidth - half_size_x;
521 for (
unsigned int i = half_size_y; i < stopHeight; ++i) {
522 for (
unsigned int j = half_size_x; j < stopWidth; ++j) {
525 bool computeVal = checkBooleanMask(p_mask, i, j);
529 for (
unsigned int a = 0; a < size_y; ++a) {
530 for (
unsigned int b = 0; b < size_x; ++b) {
531 FilterType val =
static_cast<FilterType
>(I[(i + half_size_y) - a][(j + half_size_x) - b]);
532 conv += M[a][b] * val;
541 const unsigned int stopHeight = inputHeight - half_size_y;
542 const unsigned int stopWidth = inputWidth - half_size_x;
543 for (
unsigned int i = half_size_y; i < stopHeight; ++i) {
544 for (
unsigned int j = half_size_x; j < stopWidth; ++j) {
547 bool computeVal = checkBooleanMask(p_mask, i, j);
551 for (
unsigned int a = 0; a < size_y; ++a) {
552 for (
unsigned int b = 0; b < size_x; ++b) {
553 FilterType val =
static_cast<FilterType
>(I[(i - half_size_y) + a][(j - half_size_x) + b]);
554 corr += M[a][b] * val;
564 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
565 template <
typename FilterType>
568 template <
typename FilterType>
585 template <
typename ImageType,
typename FilterType>
587 bool convolve =
false,
const vpImage<bool> *p_mask =
nullptr)
589 const unsigned int size = M.
getRows();
590 const unsigned int half_size = size / 2;
592 const unsigned int stopV = height - half_size;
593 const unsigned int stopU = width - half_size;
595 Iu.
resize(height, width, 0.0);
596 Iv.
resize(height, width, 0.0);
599 for (
unsigned int v = half_size; v < stopV; ++v) {
600 for (
unsigned int u = half_size; u < stopU; ++u) {
603 bool computeVal = checkBooleanMask(p_mask, v, u);
605 FilterType conv_u = 0;
606 FilterType conv_v = 0;
608 for (
unsigned int a = 0; a < size; ++a) {
609 for (
unsigned int b = 0; b < size; ++b) {
610 FilterType val =
static_cast<FilterType
>(I[(v + half_size) - a][(u + half_size) - b]);
611 conv_u += M[a][b] * val;
612 conv_v += M[b][a] * val;
622 for (
unsigned int v = half_size; v < stopV; ++v) {
623 for (
unsigned int u = half_size; u < stopU; ++u) {
626 bool computeVal = checkBooleanMask(p_mask, v, u);
629 FilterType conv_u = 0;
630 FilterType conv_v = 0;
632 for (
unsigned int a = 0; a < size; ++a) {
633 for (
unsigned int b = 0; b < size; ++b) {
634 FilterType val =
static_cast<FilterType
>(I[(v - half_size) + a][(u - half_size) + b]);
635 conv_u += M[a][b] * val;
636 conv_v += M[b][a] * val;
647 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
648 template<
typename FilterType>
651 template<
typename ImageType>
654 template<
typename FilterType>
657 template<
typename ImageType>
672 template <
typename ImageType,
typename FilterType>
676 filterX<ImageType, FilterType>(I, GIx, filter, size, p_mask);
677 filterY<FilterType, FilterType>(GIx, GI, filter, size, p_mask);
684 return static_cast<unsigned char>(((1. * I[i][j - val2]) + (4. * I[i][j - 1]) + (6. * I[i][j]) + (4. * I[i][j + 1]) + (1. * I[i][j + val2])) / 16.);
689 return static_cast<unsigned char>(((1. * I[i - val2][j]) + (4. * I[i - 1][j]) + (6. * I[i][j]) + (4. * I[i + 1][j]) + (1. * I[i + val2][j])) / 16.);
692 template <
typename ImageType,
typename FilterType>
696 const unsigned int height = I.
getHeight();
697 const unsigned int width = I.
getWidth();
698 const unsigned int stop1J = (size - 1) / 2;
699 const unsigned int stop2J = width - ((size - 1) / 2);
700 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
702 for (
unsigned int i = 0; i < height; ++i) {
703 for (
unsigned int j = 0; j < stop1J; ++j) {
706 bool computeVal = checkBooleanMask(p_mask, i, j);
708 dIx[i][j] = vpImageFilter::filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
711 for (
unsigned int j = stop1J; j < stop2J; ++j) {
714 bool computeVal = checkBooleanMask(p_mask, i, j);
716 dIx[i][j] = vpImageFilter::filterX<ImageType, FilterType>(I, i, j, filter, size);
719 for (
unsigned int j = stop2J; j < width; ++j) {
722 bool computeVal = checkBooleanMask(p_mask, i, j);
724 dIx[i][j] = vpImageFilter::filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
732 template<
typename ImageType,
typename FilterType>
733 static inline FilterType
filterX(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
735 const unsigned int stop = (size - 1) / 2;
736 FilterType result =
static_cast<FilterType
>(0.);
738 for (
unsigned int i = 1; i <= stop; ++i) {
739 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
741 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
744 #ifndef DOXYGEN_SHOULD_SKIP_THIS
749 static double filterXR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
750 static double filterXG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
751 static double filterXB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
753 static double filterXLeftBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
754 static double filterXLeftBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
755 static double filterXLeftBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
756 static double filterXRightBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
757 static double filterXRightBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
758 static double filterXRightBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
760 template <
typename ImageType,
typename FilterType>
761 static inline FilterType filterXLeftBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
762 const FilterType *filter,
unsigned int size)
764 const unsigned int stop = (size - 1) / 2;
765 FilterType result =
static_cast<FilterType
>(0.);
767 for (
unsigned int i = 1; i <= stop; ++i) {
769 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
772 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][i - c]);
775 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
778 template <
typename ImageType,
typename FilterType>
779 static inline FilterType filterXRightBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
780 const FilterType *filter,
unsigned int size)
782 const unsigned int stop = (size - 1) / 2;
783 const unsigned int width = I.
getWidth();
784 FilterType result =
static_cast<FilterType
>(0.);
785 const unsigned int twice = 2;
787 for (
unsigned int i = 1; i <= stop; ++i) {
788 if ((c + i) < width) {
789 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
792 result += filter[i] *
static_cast<FilterType
>(I[r][((twice * width) - c) - i - 1] + I[r][c - i]);
795 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
801 template<
typename ImageType,
typename FilterType>
806 const unsigned int stop1I = (size - 1) / 2;
807 const unsigned int stop2I = height - ((size - 1) / 2);
808 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
810 for (
unsigned int i = 0; i < stop1I; ++i) {
811 for (
unsigned int j = 0; j < width; ++j) {
814 bool computeVal = checkBooleanMask(p_mask, i, j);
816 dIy[i][j] = vpImageFilter::filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
820 for (
unsigned int i = stop1I; i < stop2I; ++i) {
821 for (
unsigned int j = 0; j < width; ++j) {
824 bool computeVal = checkBooleanMask(p_mask, i, j);
826 dIy[i][j] = vpImageFilter::filterY<ImageType, FilterType>(I, i, j, filter, size);
830 for (
unsigned int i = stop2I; i < height; ++i) {
831 for (
unsigned int j = 0; j < width; ++j) {
834 bool computeVal = checkBooleanMask(p_mask, i, j);
836 dIy[i][j] = vpImageFilter::filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
842 template<
typename ImageType,
typename FilterType>
843 static inline FilterType
filterY(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
845 const unsigned int stop = (size - 1) / 2;
846 FilterType result =
static_cast<FilterType
>(0.);
848 for (
unsigned int i = 1; i <= stop; ++i) {
849 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
851 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
853 #ifndef DOXYGEN_SHOULD_SKIP_THIS
858 static double filterYR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
859 static double filterYG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
860 static double filterYB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
862 static double filterYTopBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
863 static double filterYTopBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
864 static double filterYTopBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
865 static double filterYBottomBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
866 static double filterYBottomBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
867 static double filterYBottomBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
869 template<
typename ImageType,
typename FilterType>
870 static inline FilterType filterYTopBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
871 const FilterType *filter,
unsigned int size)
873 const unsigned int stop = (size - 1) / 2;
874 FilterType result =
static_cast<FilterType
>(0.);
876 for (
unsigned int i = 1; i <= stop; ++i) {
878 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
881 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[i - r][c]);
884 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
887 template<
typename ImageType,
typename FilterType>
888 static inline FilterType filterYBottomBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
889 const FilterType *filter,
unsigned int size)
891 const unsigned int height = I.
getHeight();
892 const unsigned int stop = (size - 1) / 2;
893 FilterType result =
static_cast<FilterType
>(0.);
894 const unsigned int twiceHeight = 2 * height;
895 for (
unsigned int i = 1; i <= stop; ++i) {
896 if ((r + i) < height) {
897 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
900 result += filter[i] *
static_cast<FilterType
>(I[(twiceHeight - r) - i - 1][c] + I[r - i][c]);
903 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
921 template <
typename ImageType,
typename FilterType>
925 FilterType *fg =
new FilterType[(size + 1) / 2];
926 vpImageFilter::getGaussianKernel<FilterType>(fg, size, sigma, normalize);
928 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, fg, size, p_mask);
929 vpImageFilter::filterY<FilterType, FilterType>(GIx, GI, fg, size, p_mask);
947 return ((15.0 * fr[r][c]) +
948 (12.0 * (fr[r - 1][c] + fr[r][c - 1] + fr[r + 1][c] + fr[r][c + 1])) +
949 (9.0 * (fr[r - 1][c - 1] + fr[r + 1][c - 1] + fr[r - 1][c + 1] + fr[r + 1][c + 1])) +
950 (5.0 * (fr[r - val2][c] + fr[r][c - val2] + fr[r + val2][c] + fr[r][c + val2])) +
951 (4.0 * (fr[r - val2][c + 1] + fr[r - val2][c - 1] + fr[r - 1][c - val2] + fr[r + 1][c - val2] + fr[r + val2][c - 1] +
952 fr[r + val2][c + 1] + fr[r - 1][c + val2] + fr[r + 1][c + val2])) +
953 (2.0 * (fr[r - val2][c - val2] + fr[r + val2][c - val2] + fr[r - val2][c + val2] + fr[r + val2][c + val2]))) / 159.0;
976 template<
typename FilterType>
977 static void getGaussianKernel(FilterType *filter,
unsigned int size, FilterType sigma = 0.,
bool normalize =
true)
979 const unsigned int mod2 = 2;
980 if ((size % mod2) != 1) {
985 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
988 int middle = (
static_cast<int>(size) - 1) / 2;
989 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(sigma));
990 FilterType coef1 =
static_cast<FilterType
>(1. / (sigma * sqrt(2. * M_PI)));
991 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. * sigma2);
992 for (
int i = 0; i <= middle; ++i) {
993 filter[i] = coef1 *
static_cast<FilterType
>(exp(-(i * i) / v_2_sigma2));
998 const unsigned int val2 = 2U;
999 for (
int i = 1; i <= middle; ++i) {
1000 sum += val2 * filter[i];
1004 for (
int i = 0; i <= middle; ++i) {
1005 filter[i] = filter[i] / sum;
1024 template <
typename FilterType>
1027 const unsigned int mod2 = 2;
1028 if ((size % mod2) != 1) {
1033 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1037 int middle = (
static_cast<int>(size) - 1) / half;
1038 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(sigma));
1039 FilterType coef_1 =
static_cast<FilterType
>(1. / (sigma * sqrt(2. * M_PI)));
1040 FilterType coef_1_over_2 = coef_1 /
static_cast<FilterType
>(2.);
1041 FilterType v_2_coef_1 =
static_cast<FilterType
>(2.) * coef_1;
1042 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. * sigma2);
1044 for (
int i = 1; i <= middle; ++i) {
1045 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)));
1050 for (
int i = 1; i <= middle; ++i) {
1051 sum += v_2_coef_1 *
static_cast<FilterType
>(exp(-(i * i) / v_2_sigma2));
1055 for (
int i = 1; i <= middle; ++i) {
1056 filter[i] = filter[i] / sum;
1062 template<
typename FilterType>
1066 const unsigned int stopJ = width - 3;
1067 const unsigned int val_3 = 3;
1068 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1070 for (
unsigned int i = 0; i < height; ++i) {
1071 for (
unsigned int j = 0; j < val_3; ++j) {
1073 bool computeVal = (p_mask ==
nullptr);
1075 dIx[i][j] =
static_cast<FilterType
>(0);
1078 for (
unsigned int j = 3; j < stopJ; ++j) {
1081 bool computeVal = checkBooleanMask(p_mask, i, j);
1086 for (
unsigned int j = stopJ; j < width; ++j) {
1088 bool computeVal = (p_mask ==
nullptr);
1090 dIx[i][j] =
static_cast<FilterType
>(0);
1096 template <
typename ImageType,
typename FilterType>
1100 const unsigned int stop1J = (size - 1) / 2;
1101 const unsigned int stop2J = width - ((size - 1) / 2);
1102 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1104 for (
unsigned int i = 0; i < height; ++i) {
1105 for (
unsigned int j = 0; j < stop1J; ++j) {
1107 bool computeVal = (p_mask ==
nullptr);
1109 dIx[i][j] =
static_cast<FilterType
>(0);
1112 for (
unsigned int j = stop1J; j < stop2J; ++j) {
1115 bool computeVal = checkBooleanMask(p_mask, i, j);
1117 dIx[i][j] = vpImageFilter::derivativeFilterX<ImageType, FilterType>(I, i, j, filter, size);
1120 for (
unsigned int j = stop2J; j < width; ++j) {
1122 bool computeVal = (p_mask ==
nullptr);
1124 dIx[i][j] =
static_cast<FilterType
>(0);
1141 template <
typename ImageType,
typename FilterType>
1143 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
1146 vpImageFilter::filterY<ImageType, FilterType>(I, GIy, gaussianKernel, size, p_mask);
1147 vpImageFilter::getGradX<FilterType, FilterType>(GIy, dIx, gaussianDerivativeKernel, size, p_mask);
1151 template <
typename FilterType>
1155 const unsigned int stopI = height - 3;
1156 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1157 const unsigned int val_3 = 3;
1158 for (
unsigned int i = 0; i < val_3; ++i) {
1159 for (
unsigned int j = 0; j < width; ++j) {
1162 bool computeVal = checkBooleanMask(p_mask, i, j);
1164 dIy[i][j] =
static_cast<FilterType
>(0);
1168 for (
unsigned int i = 3; i < stopI; ++i) {
1169 for (
unsigned int j = 0; j < width; ++j) {
1172 bool computeVal = checkBooleanMask(p_mask, i, j);
1178 for (
unsigned int i = stopI; i < height; ++i) {
1179 for (
unsigned int j = 0; j < width; ++j) {
1182 bool computeVal = checkBooleanMask(p_mask, i, j);
1184 dIy[i][j] =
static_cast<FilterType
>(0);
1190 template <
typename ImageType,
typename FilterType>
1194 const unsigned int stop1I = (size - 1) / 2;
1195 const unsigned int stop2I = height - ((size - 1) / 2);
1196 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1198 for (
unsigned int i = 0; i < stop1I; ++i) {
1199 for (
unsigned int j = 0; j < width; ++j) {
1202 bool computeVal = checkBooleanMask(p_mask, i, j);
1204 dIy[i][j] =
static_cast<FilterType
>(0);
1208 for (
unsigned int i = stop1I; i < stop2I; ++i) {
1209 for (
unsigned int j = 0; j < width; ++j) {
1212 bool computeVal = checkBooleanMask(p_mask, i, j);
1214 dIy[i][j] = vpImageFilter::derivativeFilterY<ImageType, FilterType>(I, i, j, filter, size);
1218 for (
unsigned int i = stop2I; i < height; ++i) {
1219 for (
unsigned int j = 0; j < width; ++j) {
1222 bool computeVal = checkBooleanMask(p_mask, i, j);
1224 dIy[i][j] =
static_cast<FilterType
>(0);
1241 template <
typename ImageType,
typename FilterType>
1243 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
1246 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, gaussianKernel, size, p_mask);
1247 vpImageFilter::getGradY<FilterType, FilterType>(GIx, dIy, gaussianDerivativeKernel, size, p_mask);
1257 template <
typename FilterType>
1260 const unsigned int actualKernelSize = (size * 2) + 1;
1263 std::stringstream errMsg;
1264 errMsg <<
"Cannot get Scharr kernel of size " << actualKernelSize <<
" != 3";
1269 FilterType norm = getScharrKernelY<FilterType>(ScharrY.
data, size);
1270 memcpy(filter, ScharrY.
t().data, ScharrY.
getRows() * ScharrY.
getCols() *
sizeof(FilterType));
1281 template <
typename FilterType>
1285 static const FilterType ScharrY3x3[9] = { -3.0, -10.0, -3.0, 0.0, 0.0, 0.0, 3.0, 10.0, 3.0 };
1289 std::stringstream errMsg;
1290 errMsg <<
"Cannot get Scharr kernel of size " << ((size * 2) + 1) <<
" != 3";
1294 const unsigned int kernel_size = (size * 2) + 1;
1295 const unsigned int kernel3 = 3;
1296 if (kernel_size == kernel3) {
1297 memcpy(filter, ScharrY3x3, kernel_size * kernel_size *
sizeof(FilterType));
1298 return static_cast<FilterType
>(1.0 / 32.0);
1301 return static_cast<FilterType
>(0.);
1311 template <
typename FilterType>
1314 const unsigned int maxSize = 20;
1318 if (size > maxSize) {
1322 const unsigned int kernel_size = (size * 2) + 1;
1324 FilterType norm = getSobelKernelY<FilterType>(SobelY.
data, size);
1325 memcpy(filter, SobelY.
t().data, SobelY.
getRows() * SobelY.
getCols() *
sizeof(FilterType));
1336 template <
typename FilterType>
1340 static const FilterType SobelY3x3[9] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 };
1341 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,
1342 0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0 };
1343 static const FilterType SobelY7x7[49] = { -1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
1344 -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
1345 5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1 };
1347 const unsigned int index_0 = 0;
1348 const unsigned int index_1 = 1;
1349 const unsigned int index_2 = 2;
1350 smoothingKernel[index_0][index_0] = 1.0;
1351 smoothingKernel[index_0][index_1] = 2.0;
1352 smoothingKernel[index_0][index_2] = 1.0;
1353 smoothingKernel[index_1][index_0] = 2.0;
1354 smoothingKernel[index_1][index_1] = 4.0;
1355 smoothingKernel[index_1][index_2] = 2.0;
1356 smoothingKernel[index_2][index_0] = 1.0;
1357 smoothingKernel[index_2][index_1] = 2.0;
1358 smoothingKernel[index_2][index_2] = 1.0;
1360 const unsigned int maxSize = 20;
1364 if (size > maxSize) {
1368 const unsigned int kernel_size = (size * 2) + 1;
1369 FilterType scale =
static_cast<FilterType
>(1. / 8.);
1370 const unsigned int kernel3 = 3, kernel5 = 5, kernel7 = 7;
1371 if (kernel_size == kernel3) {
1372 memcpy(filter, SobelY3x3, kernel_size * kernel_size *
sizeof(FilterType));
1375 scale *=
static_cast<FilterType
>(1. / 16.);
1376 if (kernel_size == kernel5) {
1377 memcpy(filter, SobelY5x5, kernel_size * kernel_size *
sizeof(FilterType));
1380 scale *=
static_cast<FilterType
>(1. / 16.);
1381 if (kernel_size == kernel7) {
1382 memcpy(filter, SobelY7x7, kernel_size * kernel_size *
sizeof(FilterType));
1387 memcpy(sobelY.
data, SobelY7x7, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
1388 for (
unsigned int i = 4; i <= size; ++i) {
1391 scale *=
static_cast<FilterType
>(1. / 16.);
1394 memcpy(filter, sobelY.
data, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
1399 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
1400 static float median(
const cv::Mat &cv_I);
1416 template<
typename ImageType>
1419 if (p_mask ==
nullptr) {
1425 I.
resize(height, width,
static_cast<ImageType
>(0));
1438 static bool checkBooleanMask(
const vpImage<bool> *p_mask,
const unsigned int &r,
const unsigned int &c)
1440 bool computeVal =
true;
1441 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
1442 if (p_mask !=
nullptr)
1447 computeVal = (*p_mask)[r][c];
1454 #if ((__cplusplus <= 199711L) || (defined(_MSVC_LANG) && (_MSVC_LANG == 199711L)))
1456 template <
typename FilterType>
1459 const unsigned int nbRows = filter.
getRows();
1460 const unsigned int nbCols = filter.
getCols();
1461 for (
unsigned int r = 0; r < nbRows; ++r) {
1462 for (
unsigned int c = 0; c < nbCols; ++c) {
1463 filter[r][c] = filter[r][c] * scale;
Implementation of a generic 2D array used as base class for matrices and vectors.
unsigned int getCols() const
Type * data
Address of the first element of the data array.
static vpArray2D< Type > conv2(const vpArray2D< Type > &M, const vpArray2D< Type > &kernel, const std::string &mode)
vpArray2D< Type > t() const
Compute the transpose of the array.
unsigned int getRows() const
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.
@ dimensionError
Bad dimension.
@ notImplementedError
Not implemented.
Class to compute a gray level image histogram.
unsigned int getTotal()
Get the total number of pixels in the input image.
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.
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...
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 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.
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 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 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 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.
unsigned int getWidth() const
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
unsigned int getHeight() const
static double sqr(double x)