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,
261 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
262 const vpCannyBackendType &backend = CANNY_VISP_BACKEND,
const vpImage<bool> *p_mask =
nullptr) =
delete;
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,
270 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
271 const vpCannyBackendType &backend = CANNY_VISP_BACKEND,
const vpImage<bool> *p_mask =
nullptr) =
delete;
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,
279 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
280 const vpCannyBackendType &backend = CANNY_VISP_BACKEND,
const vpImage<bool> *p_mask =
nullptr) =
delete;
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;
573 template <
typename FilterType>
577 const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
580 for (
unsigned int a = 0; a < size_y; ++a) {
581 for (
unsigned int b = 0; b < size_x; ++b) {
582 FilterType val =
static_cast<FilterType
>(I[row - half_size_y + a][col - half_size_x + b]);
583 corr += M[a][b] * val;
589 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
590 template <
typename FilterType>
593 template <
typename FilterType>
610 template <
typename ImageType,
typename FilterType>
612 bool convolve =
false,
const vpImage<bool> *p_mask =
nullptr)
614 const unsigned int size = M.
getRows();
615 const unsigned int half_size = size / 2;
617 const unsigned int stopV = height - half_size;
618 const unsigned int stopU = width - half_size;
620 Iu.
resize(height, width, 0.0);
621 Iv.
resize(height, width, 0.0);
624 for (
unsigned int v = half_size; v < stopV; ++v) {
625 for (
unsigned int u = half_size; u < stopU; ++u) {
628 bool computeVal = checkBooleanMask(p_mask, v, u);
630 FilterType conv_u = 0;
631 FilterType conv_v = 0;
633 for (
unsigned int a = 0; a < size; ++a) {
634 for (
unsigned int b = 0; b < size; ++b) {
635 FilterType val =
static_cast<FilterType
>(I[(v + half_size) - a][(u + half_size) - b]);
636 conv_u += M[a][b] * val;
637 conv_v += M[b][a] * val;
647 for (
unsigned int v = half_size; v < stopV; ++v) {
648 for (
unsigned int u = half_size; u < stopU; ++u) {
651 bool computeVal = checkBooleanMask(p_mask, v, u);
654 FilterType conv_u = 0;
655 FilterType conv_v = 0;
657 for (
unsigned int a = 0; a < size; ++a) {
658 for (
unsigned int b = 0; b < size; ++b) {
659 FilterType val =
static_cast<FilterType
>(I[(v - half_size) + a][(u - half_size) + b]);
660 conv_u += M[a][b] * val;
661 conv_v += M[b][a] * val;
672 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
673 template<
typename FilterType>
676 template<
typename ImageType>
679 template<
typename FilterType>
682 template<
typename ImageType>
697 template <
typename ImageType,
typename FilterType>
701 filterX<ImageType, FilterType>(I, GIx, filter, size, p_mask);
702 filterY<FilterType, FilterType>(GIx, GI, filter, size, p_mask);
709 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.);
714 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.);
717 template <
typename ImageType,
typename FilterType>
721 const unsigned int height = I.
getHeight();
722 const unsigned int width = I.
getWidth();
723 const unsigned int stop1J = (size - 1) / 2;
724 const unsigned int stop2J = width - ((size - 1) / 2);
725 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
727 for (
unsigned int i = 0; i < height; ++i) {
728 for (
unsigned int j = 0; j < stop1J; ++j) {
731 bool computeVal = checkBooleanMask(p_mask, i, j);
733 dIx[i][j] = vpImageFilter::filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
736 for (
unsigned int j = stop1J; j < stop2J; ++j) {
739 bool computeVal = checkBooleanMask(p_mask, i, j);
741 dIx[i][j] = vpImageFilter::filterX<ImageType, FilterType>(I, i, j, filter, size);
744 for (
unsigned int j = stop2J; j < width; ++j) {
747 bool computeVal = checkBooleanMask(p_mask, i, j);
749 dIx[i][j] = vpImageFilter::filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
757 template<
typename ImageType,
typename FilterType>
758 static inline FilterType
filterX(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
760 const unsigned int stop = (size - 1) / 2;
761 FilterType result =
static_cast<FilterType
>(0.);
763 for (
unsigned int i = 1; i <= stop; ++i) {
764 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
766 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
769 #ifndef DOXYGEN_SHOULD_SKIP_THIS
774 static double filterXR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
775 static double filterXG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
776 static double filterXB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
778 static double filterXLeftBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
779 static double filterXLeftBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
780 static double filterXLeftBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
781 static double filterXRightBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
782 static double filterXRightBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
783 static double filterXRightBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
785 template <
typename ImageType,
typename FilterType>
786 static inline FilterType filterXLeftBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
787 const FilterType *filter,
unsigned int size)
789 const unsigned int stop = (size - 1) / 2;
790 FilterType result =
static_cast<FilterType
>(0.);
792 for (
unsigned int i = 1; i <= stop; ++i) {
794 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
797 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][i - c]);
800 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
803 template <
typename ImageType,
typename FilterType>
804 static inline FilterType filterXRightBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
805 const FilterType *filter,
unsigned int size)
807 const unsigned int stop = (size - 1) / 2;
808 const unsigned int width = I.
getWidth();
809 FilterType result =
static_cast<FilterType
>(0.);
810 const unsigned int twice = 2;
812 for (
unsigned int i = 1; i <= stop; ++i) {
813 if ((c + i) < width) {
814 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
817 result += filter[i] *
static_cast<FilterType
>(I[r][((twice * width) - c) - i - 1] + I[r][c - i]);
820 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
826 template<
typename ImageType,
typename FilterType>
831 const unsigned int stop1I = (size - 1) / 2;
832 const unsigned int stop2I = height - ((size - 1) / 2);
833 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
835 for (
unsigned int i = 0; i < stop1I; ++i) {
836 for (
unsigned int j = 0; j < width; ++j) {
839 bool computeVal = checkBooleanMask(p_mask, i, j);
841 dIy[i][j] = vpImageFilter::filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
845 for (
unsigned int i = stop1I; i < stop2I; ++i) {
846 for (
unsigned int j = 0; j < width; ++j) {
849 bool computeVal = checkBooleanMask(p_mask, i, j);
851 dIy[i][j] = vpImageFilter::filterY<ImageType, FilterType>(I, i, j, filter, size);
855 for (
unsigned int i = stop2I; i < height; ++i) {
856 for (
unsigned int j = 0; j < width; ++j) {
859 bool computeVal = checkBooleanMask(p_mask, i, j);
861 dIy[i][j] = vpImageFilter::filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
867 template<
typename ImageType,
typename FilterType>
868 static inline FilterType
filterY(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
870 const unsigned int stop = (size - 1) / 2;
871 FilterType result =
static_cast<FilterType
>(0.);
873 for (
unsigned int i = 1; i <= stop; ++i) {
874 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
876 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
878 #ifndef DOXYGEN_SHOULD_SKIP_THIS
883 static double filterYR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
884 static double filterYG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
885 static double filterYB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
887 static double filterYTopBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
888 static double filterYTopBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
889 static double filterYTopBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
890 static double filterYBottomBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
891 static double filterYBottomBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
892 static double filterYBottomBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
894 template<
typename ImageType,
typename FilterType>
895 static inline FilterType filterYTopBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
896 const FilterType *filter,
unsigned int size)
898 const unsigned int stop = (size - 1) / 2;
899 FilterType result =
static_cast<FilterType
>(0.);
901 for (
unsigned int i = 1; i <= stop; ++i) {
903 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
906 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[i - r][c]);
909 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
912 template<
typename ImageType,
typename FilterType>
913 static inline FilterType filterYBottomBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
914 const FilterType *filter,
unsigned int size)
916 const unsigned int height = I.
getHeight();
917 const unsigned int stop = (size - 1) / 2;
918 FilterType result =
static_cast<FilterType
>(0.);
919 const unsigned int twiceHeight = 2 * height;
920 for (
unsigned int i = 1; i <= stop; ++i) {
921 if ((r + i) < height) {
922 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
925 result += filter[i] *
static_cast<FilterType
>(I[(twiceHeight - r) - i - 1][c] + I[r - i][c]);
928 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
946 template <
typename ImageType,
typename FilterType>
950 FilterType *fg =
new FilterType[(size + 1) / 2];
951 vpImageFilter::getGaussianKernel<FilterType>(fg, size, sigma, normalize);
953 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, fg, size, p_mask);
954 vpImageFilter::filterY<FilterType, FilterType>(GIx, GI, fg, size, p_mask);
972 return ((15.0 * fr[r][c]) +
973 (12.0 * (fr[r - 1][c] + fr[r][c - 1] + fr[r + 1][c] + fr[r][c + 1])) +
974 (9.0 * (fr[r - 1][c - 1] + fr[r + 1][c - 1] + fr[r - 1][c + 1] + fr[r + 1][c + 1])) +
975 (5.0 * (fr[r - val2][c] + fr[r][c - val2] + fr[r + val2][c] + fr[r][c + val2])) +
976 (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] +
977 fr[r + val2][c + 1] + fr[r - 1][c + val2] + fr[r + 1][c + val2])) +
978 (2.0 * (fr[r - val2][c - val2] + fr[r + val2][c - val2] + fr[r - val2][c + val2] + fr[r + val2][c + val2]))) / 159.0;
1001 template<
typename FilterType>
1002 static void getGaussianKernel(FilterType *filter,
unsigned int size, FilterType sigma = 0.,
bool normalize =
true)
1004 const unsigned int mod2 = 2;
1005 if ((size % mod2) != 1) {
1010 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1013 int middle = (
static_cast<int>(size) - 1) / 2;
1014 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(sigma));
1015 FilterType coef1 =
static_cast<FilterType
>(1. / (sigma * sqrt(2. * M_PI)));
1016 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. * sigma2);
1017 for (
int i = 0; i <= middle; ++i) {
1018 filter[i] = coef1 *
static_cast<FilterType
>(exp(-(i * i) / v_2_sigma2));
1023 const unsigned int val2 = 2U;
1024 for (
int i = 1; i <= middle; ++i) {
1025 sum += val2 * filter[i];
1029 for (
int i = 0; i <= middle; ++i) {
1030 filter[i] = filter[i] / sum;
1049 template <
typename FilterType>
1052 const unsigned int mod2 = 2;
1053 if ((size % mod2) != 1) {
1058 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1062 int middle = (
static_cast<int>(size) - 1) / half;
1063 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(sigma));
1064 FilterType coef_1 =
static_cast<FilterType
>(1. / (sigma * sqrt(2. * M_PI)));
1065 FilterType coef_1_over_2 = coef_1 /
static_cast<FilterType
>(2.);
1066 FilterType v_2_coef_1 =
static_cast<FilterType
>(2.) * coef_1;
1067 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. * sigma2);
1069 for (
int i = 1; i <= middle; ++i) {
1070 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)));
1075 for (
int i = 1; i <= middle; ++i) {
1076 sum += v_2_coef_1 *
static_cast<FilterType
>(exp(-(i * i) / v_2_sigma2));
1080 for (
int i = 1; i <= middle; ++i) {
1081 filter[i] = filter[i] / sum;
1087 template<
typename FilterType>
1091 const unsigned int stopJ = width - 3;
1092 const unsigned int val_3 = 3;
1093 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1095 for (
unsigned int i = 0; i < height; ++i) {
1096 for (
unsigned int j = 0; j < val_3; ++j) {
1098 bool computeVal = (p_mask ==
nullptr);
1100 dIx[i][j] =
static_cast<FilterType
>(0);
1103 for (
unsigned int j = 3; j < stopJ; ++j) {
1106 bool computeVal = checkBooleanMask(p_mask, i, j);
1111 for (
unsigned int j = stopJ; j < width; ++j) {
1113 bool computeVal = (p_mask ==
nullptr);
1115 dIx[i][j] =
static_cast<FilterType
>(0);
1121 template <
typename ImageType,
typename FilterType>
1125 const unsigned int stop1J = (size - 1) / 2;
1126 const unsigned int stop2J = width - ((size - 1) / 2);
1127 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1129 for (
unsigned int i = 0; i < height; ++i) {
1130 for (
unsigned int j = 0; j < stop1J; ++j) {
1132 bool computeVal = (p_mask ==
nullptr);
1134 dIx[i][j] =
static_cast<FilterType
>(0);
1137 for (
unsigned int j = stop1J; j < stop2J; ++j) {
1140 bool computeVal = checkBooleanMask(p_mask, i, j);
1142 dIx[i][j] = vpImageFilter::derivativeFilterX<ImageType, FilterType>(I, i, j, filter, size);
1145 for (
unsigned int j = stop2J; j < width; ++j) {
1147 bool computeVal = (p_mask ==
nullptr);
1149 dIx[i][j] =
static_cast<FilterType
>(0);
1166 template <
typename ImageType,
typename FilterType>
1168 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
1171 vpImageFilter::filterY<ImageType, FilterType>(I, GIy, gaussianKernel, size, p_mask);
1172 vpImageFilter::getGradX<FilterType, FilterType>(GIy, dIx, gaussianDerivativeKernel, size, p_mask);
1176 template <
typename FilterType>
1180 const unsigned int stopI = height - 3;
1181 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1182 const unsigned int val_3 = 3;
1183 for (
unsigned int i = 0; i < val_3; ++i) {
1184 for (
unsigned int j = 0; j < width; ++j) {
1187 bool computeVal = checkBooleanMask(p_mask, i, j);
1189 dIy[i][j] =
static_cast<FilterType
>(0);
1193 for (
unsigned int i = 3; i < stopI; ++i) {
1194 for (
unsigned int j = 0; j < width; ++j) {
1197 bool computeVal = checkBooleanMask(p_mask, i, j);
1203 for (
unsigned int i = stopI; i < height; ++i) {
1204 for (
unsigned int j = 0; j < width; ++j) {
1207 bool computeVal = checkBooleanMask(p_mask, i, j);
1209 dIy[i][j] =
static_cast<FilterType
>(0);
1215 template <
typename ImageType,
typename FilterType>
1219 const unsigned int stop1I = (size - 1) / 2;
1220 const unsigned int stop2I = height - ((size - 1) / 2);
1221 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1223 for (
unsigned int i = 0; i < stop1I; ++i) {
1224 for (
unsigned int j = 0; j < width; ++j) {
1227 bool computeVal = checkBooleanMask(p_mask, i, j);
1229 dIy[i][j] =
static_cast<FilterType
>(0);
1233 for (
unsigned int i = stop1I; i < stop2I; ++i) {
1234 for (
unsigned int j = 0; j < width; ++j) {
1237 bool computeVal = checkBooleanMask(p_mask, i, j);
1239 dIy[i][j] = vpImageFilter::derivativeFilterY<ImageType, FilterType>(I, i, j, filter, size);
1243 for (
unsigned int i = stop2I; i < height; ++i) {
1244 for (
unsigned int j = 0; j < width; ++j) {
1247 bool computeVal = checkBooleanMask(p_mask, i, j);
1249 dIy[i][j] =
static_cast<FilterType
>(0);
1266 template <
typename ImageType,
typename FilterType>
1268 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
1271 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, gaussianKernel, size, p_mask);
1272 vpImageFilter::getGradY<FilterType, FilterType>(GIx, dIy, gaussianDerivativeKernel, size, p_mask);
1282 template <
typename FilterType>
1285 const unsigned int actualKernelSize = (size * 2) + 1;
1288 std::stringstream errMsg;
1289 errMsg <<
"Cannot get Scharr kernel of size " << actualKernelSize <<
" != 3";
1294 FilterType norm = getScharrKernelY<FilterType>(ScharrY.
data, size);
1295 memcpy(filter, ScharrY.
t().data, ScharrY.
getRows() * ScharrY.
getCols() *
sizeof(FilterType));
1306 template <
typename FilterType>
1310 static const FilterType ScharrY3x3[9] = { -3.0, -10.0, -3.0, 0.0, 0.0, 0.0, 3.0, 10.0, 3.0 };
1314 std::stringstream errMsg;
1315 errMsg <<
"Cannot get Scharr kernel of size " << ((size * 2) + 1) <<
" != 3";
1319 const unsigned int kernel_size = (size * 2) + 1;
1320 const unsigned int kernel3 = 3;
1321 if (kernel_size == kernel3) {
1322 memcpy(filter, ScharrY3x3, kernel_size * kernel_size *
sizeof(FilterType));
1323 return static_cast<FilterType
>(1.0 / 32.0);
1326 return static_cast<FilterType
>(0.);
1336 template <
typename FilterType>
1339 const unsigned int maxSize = 20;
1343 if (size > maxSize) {
1347 const unsigned int kernel_size = (size * 2) + 1;
1349 FilterType norm = getSobelKernelY<FilterType>(SobelY.
data, size);
1350 memcpy(filter, SobelY.
t().data, SobelY.
getRows() * SobelY.
getCols() *
sizeof(FilterType));
1361 template <
typename FilterType>
1365 static const FilterType SobelY3x3[9] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 };
1366 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,
1367 0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0 };
1368 static const FilterType SobelY7x7[49] = { -1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
1369 -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
1370 5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1 };
1372 const unsigned int index_0 = 0;
1373 const unsigned int index_1 = 1;
1374 const unsigned int index_2 = 2;
1375 smoothingKernel[index_0][index_0] = 1.0;
1376 smoothingKernel[index_0][index_1] = 2.0;
1377 smoothingKernel[index_0][index_2] = 1.0;
1378 smoothingKernel[index_1][index_0] = 2.0;
1379 smoothingKernel[index_1][index_1] = 4.0;
1380 smoothingKernel[index_1][index_2] = 2.0;
1381 smoothingKernel[index_2][index_0] = 1.0;
1382 smoothingKernel[index_2][index_1] = 2.0;
1383 smoothingKernel[index_2][index_2] = 1.0;
1385 const unsigned int maxSize = 20;
1389 if (size > maxSize) {
1393 const unsigned int kernel_size = (size * 2) + 1;
1394 FilterType scale =
static_cast<FilterType
>(1. / 8.);
1395 const unsigned int kernel3 = 3, kernel5 = 5, kernel7 = 7;
1396 if (kernel_size == kernel3) {
1397 memcpy(filter, SobelY3x3, kernel_size * kernel_size *
sizeof(FilterType));
1400 scale *=
static_cast<FilterType
>(1. / 16.);
1401 if (kernel_size == kernel5) {
1402 memcpy(filter, SobelY5x5, kernel_size * kernel_size *
sizeof(FilterType));
1405 scale *=
static_cast<FilterType
>(1. / 16.);
1406 if (kernel_size == kernel7) {
1407 memcpy(filter, SobelY7x7, kernel_size * kernel_size *
sizeof(FilterType));
1412 memcpy(sobelY.
data, SobelY7x7, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
1413 for (
unsigned int i = 4; i <= size; ++i) {
1416 scale *=
static_cast<FilterType
>(1. / 16.);
1419 memcpy(filter, sobelY.
data, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
1424 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
1425 static float median(
const cv::Mat &cv_I);
1441 template<
typename ImageType>
1444 if (p_mask ==
nullptr) {
1450 I.
resize(height, width,
static_cast<ImageType
>(0));
1463 static bool checkBooleanMask(
const vpImage<bool> *p_mask,
const unsigned int &r,
const unsigned int &c)
1465 bool computeVal =
true;
1466 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
1467 if (p_mask !=
nullptr)
1472 computeVal = (*p_mask)[r][c];
1479 #if ((__cplusplus <= 199711L) || (defined(_MSVC_LANG) && (_MSVC_LANG == 199711L)))
1481 template <
typename FilterType>
1484 const unsigned int nbRows = filter.
getRows();
1485 const unsigned int nbCols = filter.
getCols();
1486 for (
unsigned int r = 0; r < nbRows; ++r) {
1487 for (
unsigned int c = 0; c < nbCols; ++c) {
1488 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 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 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 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 filter(const vpImage< FilterType > &I, const vpArray2D< FilterType > &M, unsigned int row, unsigned int col)
Apply a filter at a given image location.
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 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.
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)