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.6f,
const float &upperThresholdRatio = 0.8f,
339 const unsigned int w = I.
getWidth();
342 if ((lowerThresholdRatio <= 0.f) || (lowerThresholdRatio >= 1.f)) {
343 std::stringstream errMsg;
344 errMsg <<
"Lower ratio (" << lowerThresholdRatio <<
") " << (lowerThresholdRatio < 0.f ?
"should be greater than 0 !" :
"should be lower than 1 !");
348 if ((upperThresholdRatio <= 0.f) || (upperThresholdRatio >= 1.f)) {
349 std::stringstream errMsg;
350 errMsg <<
"Upper ratio (" << upperThresholdRatio <<
") " << (upperThresholdRatio < 0.f ?
"should be greater than 0 !" :
"should be lower than 1 !");
354 if (lowerThresholdRatio >= upperThresholdRatio) {
355 std::stringstream errMsg;
356 errMsg <<
"Lower ratio (" << lowerThresholdRatio <<
") should be lower than the upper ratio (" << upperThresholdRatio <<
")";
362 if ((p_dIx !=
nullptr) && (p_dIy !=
nullptr)) {
367 computePartialDerivatives(I, dIx, dIy,
true,
true,
true, gaussianKernelSize, gaussianStdev,
372 for (
unsigned int r = 0; r < h; ++r) {
373 for (
unsigned int c = 0; c < w; ++c) {
376 bool computeVal = checkBooleanMask(p_mask, r, c);
379 float dx =
static_cast<float>(dIx[r][c]);
380 float dy =
static_cast<float>(dIy[r][c]);
381 float gradient = std::abs(dx) + std::abs(dy);
382 float gradientClamped = std::min<float>(gradient,
static_cast<float>(std::numeric_limits<unsigned char>::max()));
383 dI[r][c] =
static_cast<unsigned char>(gradientClamped);
391 const unsigned int nbBins = 256;
393 float totalNbPixels =
static_cast<float>(hist.
getTotal());
395 float t = upperThresholdRatio * totalNbPixels;
398 bool notFound =
true;
399 while ((i < nbBins) && notFound) {
400 float tf =
static_cast<float>(hist[i]);
403 bon =
static_cast<float>(i);
409 std::stringstream errMsg;
410 errMsg <<
"Could not find a bin for which " << upperThresholdRatio * 100.f <<
" percents of the pixels had a gradient lower than the upper threshold.";
413 float upperThresh = std::max<float>(bon, 1.f);
414 lowerThresh = lowerThresholdRatio * bon;
415 lowerThresh = std::max<float>(lowerThresh, std::numeric_limits<float>::epsilon());
428 const int val1 = 1, val2 = 2, val3 = 3;
429 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])) +
430 (112.0 *
static_cast<double>(I[r][c + val3] - I[r][c - val3]))) / 8418.0;
442 const int val1 = 1, val2 = 2, val3 = 3;
443 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])) +
444 (112.0 *
static_cast<double>(I[r + val3][c] - I[r - val3][c]))) / 8418.0;
460 template <
class ImageType,
typename FilterType>
463 const unsigned int stop = (size - 1) / 2;
469 for (i = 1; i <= stop; ++i) {
470 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] - I[r][c - i]);
488 template <
class ImageType,
typename FilterType>
491 const unsigned int stop = (size - 1) / 2;
497 for (i = 1; i <= stop; ++i) {
498 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] - I[r - i][c]);
532 template <
typename ImageType,
typename FilterType>
537 const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
540 If.
resize(inputHeight, inputWidth, 0.0);
543 const unsigned int stopHeight = inputHeight - half_size_y;
544 const unsigned int stopWidth = inputWidth - half_size_x;
545 for (
unsigned int i = half_size_y; i < stopHeight; ++i) {
546 for (
unsigned int j = half_size_x; j < stopWidth; ++j) {
549 bool computeVal = checkBooleanMask(p_mask, i, j);
553 for (
unsigned int a = 0; a < size_y; ++a) {
554 for (
unsigned int b = 0; b < size_x; ++b) {
555 FilterType val =
static_cast<FilterType
>(I[(i + half_size_y) - a][(j + half_size_x) - b]);
556 conv += M[a][b] * val;
565 const unsigned int stopHeight = inputHeight - half_size_y;
566 const unsigned int stopWidth = inputWidth - half_size_x;
567 for (
unsigned int i = half_size_y; i < stopHeight; ++i) {
568 for (
unsigned int j = half_size_x; j < stopWidth; ++j) {
571 bool computeVal = checkBooleanMask(p_mask, i, j);
575 for (
unsigned int a = 0; a < size_y; ++a) {
576 for (
unsigned int b = 0; b < size_x; ++b) {
577 FilterType val =
static_cast<FilterType
>(I[(i - half_size_y) + a][(j - half_size_x) + b]);
578 corr += M[a][b] * val;
597 template <
typename FilterType>
601 const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
604 for (
unsigned int a = 0; a < size_y; ++a) {
605 for (
unsigned int b = 0; b < size_x; ++b) {
606 FilterType val =
static_cast<FilterType
>(I[row - half_size_y + a][col - half_size_x + b]);
607 corr += M[a][b] * val;
613 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
614 template <
typename FilterType>
617 template <
typename FilterType>
634 template <
typename ImageType,
typename FilterType>
636 bool convolve =
false,
const vpImage<bool> *p_mask =
nullptr)
638 const unsigned int size = M.
getRows();
639 const unsigned int half_size = size / 2;
641 const unsigned int stopV = height - half_size;
642 const unsigned int stopU = width - half_size;
644 Iu.
resize(height, width, 0.0);
645 Iv.
resize(height, width, 0.0);
648 for (
unsigned int v = half_size; v < stopV; ++v) {
649 for (
unsigned int u = half_size; u < stopU; ++u) {
652 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;
671 for (
unsigned int v = half_size; v < stopV; ++v) {
672 for (
unsigned int u = half_size; u < stopU; ++u) {
675 bool computeVal = checkBooleanMask(p_mask, v, u);
678 FilterType conv_u = 0;
679 FilterType conv_v = 0;
681 for (
unsigned int a = 0; a < size; ++a) {
682 for (
unsigned int b = 0; b < size; ++b) {
683 FilterType val =
static_cast<FilterType
>(I[(v - half_size) + a][(u - half_size) + b]);
684 conv_u += M[a][b] * val;
685 conv_v += M[b][a] * val;
696 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
697 template<
typename FilterType>
700 template<
typename ImageType>
703 template<
typename FilterType>
706 template<
typename ImageType>
721 template <
typename ImageType,
typename FilterType>
725 filterX<ImageType, FilterType>(I, GIx, filter, size, p_mask);
726 filterY<FilterType, FilterType>(GIx, GI, filter, size, p_mask);
733 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.);
738 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.);
741 template <
typename ImageType,
typename FilterType>
745 const unsigned int height = I.
getHeight();
746 const unsigned int width = I.
getWidth();
747 const unsigned int stop1J = (size - 1) / 2;
748 const unsigned int stop2J = width - ((size - 1) / 2);
749 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
751 for (
unsigned int i = 0; i < height; ++i) {
752 for (
unsigned int j = 0; j < stop1J; ++j) {
755 bool computeVal = checkBooleanMask(p_mask, i, j);
757 dIx[i][j] = vpImageFilter::filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
760 for (
unsigned int j = stop1J; j < stop2J; ++j) {
763 bool computeVal = checkBooleanMask(p_mask, i, j);
765 dIx[i][j] = vpImageFilter::filterX<ImageType, FilterType>(I, i, j, filter, size);
768 for (
unsigned int j = stop2J; j < width; ++j) {
771 bool computeVal = checkBooleanMask(p_mask, i, j);
773 dIx[i][j] = vpImageFilter::filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
781 template<
typename ImageType,
typename FilterType>
782 static inline FilterType
filterX(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
784 const unsigned int stop = (size - 1) / 2;
785 FilterType result =
static_cast<FilterType
>(0.);
787 for (
unsigned int i = 1; i <= stop; ++i) {
788 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
790 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
793 #ifndef DOXYGEN_SHOULD_SKIP_THIS
798 static double filterXR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
799 static double filterXG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
800 static double filterXB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
802 static double filterXLeftBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
803 static double filterXLeftBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
804 static double filterXLeftBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
805 static double filterXRightBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
806 static double filterXRightBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
807 static double filterXRightBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
809 template <
typename ImageType,
typename FilterType>
810 static inline FilterType filterXLeftBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
811 const FilterType *filter,
unsigned int size)
813 const unsigned int stop = (size - 1) / 2;
814 FilterType result =
static_cast<FilterType
>(0.);
816 for (
unsigned int i = 1; i <= stop; ++i) {
818 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
821 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][i - c]);
824 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
827 template <
typename ImageType,
typename FilterType>
828 static inline FilterType filterXRightBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
829 const FilterType *filter,
unsigned int size)
831 const unsigned int stop = (size - 1) / 2;
832 const unsigned int width = I.
getWidth();
833 FilterType result =
static_cast<FilterType
>(0.);
834 const unsigned int twice = 2;
836 for (
unsigned int i = 1; i <= stop; ++i) {
837 if ((c + i) < width) {
838 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
841 result += filter[i] *
static_cast<FilterType
>(I[r][((twice * width) - c) - i - 1] + I[r][c - i]);
844 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
850 template<
typename ImageType,
typename FilterType>
855 const unsigned int stop1I = (size - 1) / 2;
856 const unsigned int stop2I = height - ((size - 1) / 2);
857 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
859 for (
unsigned int i = 0; i < stop1I; ++i) {
860 for (
unsigned int j = 0; j < width; ++j) {
863 bool computeVal = checkBooleanMask(p_mask, i, j);
865 dIy[i][j] = vpImageFilter::filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
869 for (
unsigned int i = stop1I; i < stop2I; ++i) {
870 for (
unsigned int j = 0; j < width; ++j) {
873 bool computeVal = checkBooleanMask(p_mask, i, j);
875 dIy[i][j] = vpImageFilter::filterY<ImageType, FilterType>(I, i, j, filter, size);
879 for (
unsigned int i = stop2I; i < height; ++i) {
880 for (
unsigned int j = 0; j < width; ++j) {
883 bool computeVal = checkBooleanMask(p_mask, i, j);
885 dIy[i][j] = vpImageFilter::filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
891 template<
typename ImageType,
typename FilterType>
892 static inline FilterType
filterY(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
894 const unsigned int stop = (size - 1) / 2;
895 FilterType result =
static_cast<FilterType
>(0.);
897 for (
unsigned int i = 1; i <= stop; ++i) {
898 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
900 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
902 #ifndef DOXYGEN_SHOULD_SKIP_THIS
907 static double filterYR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
908 static double filterYG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
909 static double filterYB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
911 static double filterYTopBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
912 static double filterYTopBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
913 static double filterYTopBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
914 static double filterYBottomBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
915 static double filterYBottomBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
916 static double filterYBottomBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
918 template<
typename ImageType,
typename FilterType>
919 static inline FilterType filterYTopBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
920 const FilterType *filter,
unsigned int size)
922 const unsigned int stop = (size - 1) / 2;
923 FilterType result =
static_cast<FilterType
>(0.);
925 for (
unsigned int i = 1; i <= stop; ++i) {
927 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
930 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[i - r][c]);
933 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
936 template<
typename ImageType,
typename FilterType>
937 static inline FilterType filterYBottomBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
938 const FilterType *filter,
unsigned int size)
940 const unsigned int height = I.
getHeight();
941 const unsigned int stop = (size - 1) / 2;
942 FilterType result =
static_cast<FilterType
>(0.);
943 const unsigned int twiceHeight = 2 * height;
944 for (
unsigned int i = 1; i <= stop; ++i) {
945 if ((r + i) < height) {
946 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
949 result += filter[i] *
static_cast<FilterType
>(I[(twiceHeight - r) - i - 1][c] + I[r - i][c]);
952 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
970 template <
typename ImageType,
typename FilterType>
974 FilterType *fg =
new FilterType[(size + 1) / 2];
975 vpImageFilter::getGaussianKernel<FilterType>(fg, size, sigma, normalize);
977 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, fg, size, p_mask);
978 vpImageFilter::filterY<FilterType, FilterType>(GIx, GI, fg, size, p_mask);
996 return ((15.0 * fr[r][c]) +
997 (12.0 * (fr[r - 1][c] + fr[r][c - 1] + fr[r + 1][c] + fr[r][c + 1])) +
998 (9.0 * (fr[r - 1][c - 1] + fr[r + 1][c - 1] + fr[r - 1][c + 1] + fr[r + 1][c + 1])) +
999 (5.0 * (fr[r - val2][c] + fr[r][c - val2] + fr[r + val2][c] + fr[r][c + val2])) +
1000 (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] +
1001 fr[r + val2][c + 1] + fr[r - 1][c + val2] + fr[r + 1][c + val2])) +
1002 (2.0 * (fr[r - val2][c - val2] + fr[r + val2][c - val2] + fr[r - val2][c + val2] + fr[r + val2][c + val2]))) / 159.0;
1025 template<
typename FilterType>
1026 static void getGaussianKernel(FilterType *filter,
unsigned int size, FilterType sigma = 0.,
bool normalize =
true)
1028 const unsigned int mod2 = 2;
1029 if ((size % mod2) != 1) {
1034 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1037 int middle = (
static_cast<int>(size) - 1) / 2;
1038 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(sigma));
1039 FilterType coef1 =
static_cast<FilterType
>(1. / (sigma * sqrt(2. * M_PI)));
1040 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. * sigma2);
1041 for (
int i = 0; i <= middle; ++i) {
1042 filter[i] = coef1 *
static_cast<FilterType
>(exp(-(i * i) / v_2_sigma2));
1047 const unsigned int val2 = 2U;
1048 for (
int i = 1; i <= middle; ++i) {
1049 sum += val2 * filter[i];
1053 for (
int i = 0; i <= middle; ++i) {
1054 filter[i] = filter[i] / sum;
1073 template <
typename FilterType>
1076 const unsigned int mod2 = 2;
1077 if ((size % mod2) != 1) {
1082 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1086 int middle = (
static_cast<int>(size) - 1) / half;
1087 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(sigma));
1088 FilterType coef_1 =
static_cast<FilterType
>(1. / (sigma * sqrt(2. * M_PI)));
1089 FilterType coef_1_over_2 = coef_1 /
static_cast<FilterType
>(2.);
1090 FilterType v_2_coef_1 =
static_cast<FilterType
>(2.) * coef_1;
1091 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. * sigma2);
1093 for (
int i = 1; i <= middle; ++i) {
1094 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)));
1099 for (
int i = 1; i <= middle; ++i) {
1100 sum += v_2_coef_1 *
static_cast<FilterType
>(exp(-(i * i) / v_2_sigma2));
1104 for (
int i = 1; i <= middle; ++i) {
1105 filter[i] = filter[i] / sum;
1111 template<
typename FilterType>
1115 const unsigned int stopJ = width - 3;
1116 const unsigned int val_3 = 3;
1117 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1119 for (
unsigned int i = 0; i < height; ++i) {
1120 for (
unsigned int j = 0; j < val_3; ++j) {
1122 bool computeVal = (p_mask ==
nullptr);
1124 dIx[i][j] =
static_cast<FilterType
>(0);
1127 for (
unsigned int j = 3; j < stopJ; ++j) {
1130 bool computeVal = checkBooleanMask(p_mask, i, j);
1135 for (
unsigned int j = stopJ; j < width; ++j) {
1137 bool computeVal = (p_mask ==
nullptr);
1139 dIx[i][j] =
static_cast<FilterType
>(0);
1145 template <
typename ImageType,
typename FilterType>
1149 const unsigned int stop1J = (size - 1) / 2;
1150 const unsigned int stop2J = width - ((size - 1) / 2);
1151 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1153 for (
unsigned int i = 0; i < height; ++i) {
1154 for (
unsigned int j = 0; j < stop1J; ++j) {
1156 bool computeVal = (p_mask ==
nullptr);
1158 dIx[i][j] =
static_cast<FilterType
>(0);
1161 for (
unsigned int j = stop1J; j < stop2J; ++j) {
1164 bool computeVal = checkBooleanMask(p_mask, i, j);
1166 dIx[i][j] = vpImageFilter::derivativeFilterX<ImageType, FilterType>(I, i, j, filter, size);
1169 for (
unsigned int j = stop2J; j < width; ++j) {
1171 bool computeVal = (p_mask ==
nullptr);
1173 dIx[i][j] =
static_cast<FilterType
>(0);
1190 template <
typename ImageType,
typename FilterType>
1192 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
1195 vpImageFilter::filterY<ImageType, FilterType>(I, GIy, gaussianKernel, size, p_mask);
1196 vpImageFilter::getGradX<FilterType, FilterType>(GIy, dIx, gaussianDerivativeKernel, size, p_mask);
1200 template <
typename FilterType>
1204 const unsigned int stopI = height - 3;
1205 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1206 const unsigned int val_3 = 3;
1207 for (
unsigned int i = 0; i < val_3; ++i) {
1208 for (
unsigned int j = 0; j < width; ++j) {
1211 bool computeVal = checkBooleanMask(p_mask, i, j);
1213 dIy[i][j] =
static_cast<FilterType
>(0);
1217 for (
unsigned int i = 3; i < stopI; ++i) {
1218 for (
unsigned int j = 0; j < width; ++j) {
1221 bool computeVal = checkBooleanMask(p_mask, i, j);
1227 for (
unsigned int i = stopI; i < height; ++i) {
1228 for (
unsigned int j = 0; j < width; ++j) {
1231 bool computeVal = checkBooleanMask(p_mask, i, j);
1233 dIy[i][j] =
static_cast<FilterType
>(0);
1239 template <
typename ImageType,
typename FilterType>
1243 const unsigned int stop1I = (size - 1) / 2;
1244 const unsigned int stop2I = height - ((size - 1) / 2);
1245 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1247 for (
unsigned int i = 0; i < stop1I; ++i) {
1248 for (
unsigned int j = 0; j < width; ++j) {
1251 bool computeVal = checkBooleanMask(p_mask, i, j);
1253 dIy[i][j] =
static_cast<FilterType
>(0);
1257 for (
unsigned int i = stop1I; i < stop2I; ++i) {
1258 for (
unsigned int j = 0; j < width; ++j) {
1261 bool computeVal = checkBooleanMask(p_mask, i, j);
1263 dIy[i][j] = vpImageFilter::derivativeFilterY<ImageType, FilterType>(I, i, j, filter, size);
1267 for (
unsigned int i = stop2I; i < height; ++i) {
1268 for (
unsigned int j = 0; j < width; ++j) {
1271 bool computeVal = checkBooleanMask(p_mask, i, j);
1273 dIy[i][j] =
static_cast<FilterType
>(0);
1290 template <
typename ImageType,
typename FilterType>
1292 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
1295 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, gaussianKernel, size, p_mask);
1296 vpImageFilter::getGradY<FilterType, FilterType>(GIx, dIy, gaussianDerivativeKernel, size, p_mask);
1306 template <
typename FilterType>
1309 const unsigned int actualKernelSize = (size * 2) + 1;
1312 std::stringstream errMsg;
1313 errMsg <<
"Cannot get Scharr kernel of size " << actualKernelSize <<
" != 3";
1318 FilterType norm = getScharrKernelY<FilterType>(ScharrY.
data, size);
1319 memcpy(filter, ScharrY.
t().data, ScharrY.
getRows() * ScharrY.
getCols() *
sizeof(FilterType));
1330 template <
typename FilterType>
1334 static const FilterType ScharrY3x3[9] = { -3.0, -10.0, -3.0, 0.0, 0.0, 0.0, 3.0, 10.0, 3.0 };
1338 std::stringstream errMsg;
1339 errMsg <<
"Cannot get Scharr kernel of size " << ((size * 2) + 1) <<
" != 3";
1343 const unsigned int kernel_size = (size * 2) + 1;
1344 const unsigned int kernel3 = 3;
1345 if (kernel_size == kernel3) {
1346 memcpy(filter, ScharrY3x3, kernel_size * kernel_size *
sizeof(FilterType));
1347 return static_cast<FilterType
>(1.0 / 32.0);
1350 return static_cast<FilterType
>(0.);
1360 template <
typename FilterType>
1363 const unsigned int maxSize = 20;
1367 if (size > maxSize) {
1371 const unsigned int kernel_size = (size * 2) + 1;
1373 FilterType norm = getSobelKernelY<FilterType>(SobelY.
data, size);
1374 memcpy(filter, SobelY.
t().data, SobelY.
getRows() * SobelY.
getCols() *
sizeof(FilterType));
1385 template <
typename FilterType>
1389 static const FilterType SobelY3x3[9] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 };
1390 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,
1391 0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0 };
1392 static const FilterType SobelY7x7[49] = { -1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
1393 -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
1394 5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1 };
1396 const unsigned int index_0 = 0;
1397 const unsigned int index_1 = 1;
1398 const unsigned int index_2 = 2;
1399 smoothingKernel[index_0][index_0] = 1.0;
1400 smoothingKernel[index_0][index_1] = 2.0;
1401 smoothingKernel[index_0][index_2] = 1.0;
1402 smoothingKernel[index_1][index_0] = 2.0;
1403 smoothingKernel[index_1][index_1] = 4.0;
1404 smoothingKernel[index_1][index_2] = 2.0;
1405 smoothingKernel[index_2][index_0] = 1.0;
1406 smoothingKernel[index_2][index_1] = 2.0;
1407 smoothingKernel[index_2][index_2] = 1.0;
1409 const unsigned int maxSize = 20;
1413 if (size > maxSize) {
1417 const unsigned int kernel_size = (size * 2) + 1;
1418 FilterType scale =
static_cast<FilterType
>(1. / 8.);
1419 const unsigned int kernel3 = 3, kernel5 = 5, kernel7 = 7;
1420 if (kernel_size == kernel3) {
1421 memcpy(filter, SobelY3x3, kernel_size * kernel_size *
sizeof(FilterType));
1424 scale *=
static_cast<FilterType
>(1. / 16.);
1425 if (kernel_size == kernel5) {
1426 memcpy(filter, SobelY5x5, kernel_size * kernel_size *
sizeof(FilterType));
1429 scale *=
static_cast<FilterType
>(1. / 16.);
1430 if (kernel_size == kernel7) {
1431 memcpy(filter, SobelY7x7, kernel_size * kernel_size *
sizeof(FilterType));
1436 memcpy(sobelY.
data, SobelY7x7, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
1437 for (
unsigned int i = 4; i <= size; ++i) {
1440 scale *=
static_cast<FilterType
>(1. / 16.);
1443 memcpy(filter, sobelY.
data, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
1448 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
1449 static float median(
const cv::Mat &cv_I);
1465 template<
typename ImageType>
1468 if (p_mask ==
nullptr) {
1474 I.
resize(height, width,
static_cast<ImageType
>(0));
1487 static bool checkBooleanMask(
const vpImage<bool> *p_mask,
const unsigned int &r,
const unsigned int &c)
1489 bool computeVal =
true;
1490 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
1491 if (p_mask !=
nullptr)
1496 computeVal = (*p_mask)[r][c];
1503 #if ((__cplusplus <= 199711L) || (defined(_MSVC_LANG) && (_MSVC_LANG == 199711L)))
1505 template <
typename FilterType>
1508 const unsigned int nbRows = filter.
getRows();
1509 const unsigned int nbCols = filter.
getCols();
1510 for (
unsigned int r = 0; r < nbRows; ++r) {
1511 for (
unsigned int c = 0; c < nbCols; ++c) {
1512 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 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 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.6f, const float &upperThresholdRatio=0.8f, 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 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)