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 #if (VISP_HAVE_OPENCV_VERSION < 0x050000)
60 #include <opencv2/imgproc/imgproc_c.h>
78 CANNY_OPENCV_BACKEND = 0,
79 CANNY_VISP_BACKEND = 1,
80 CANNY_COUNT_BACKEND = 2
83 static std::string vpCannyBackendTypeList(
const std::string &pref =
"<",
const std::string &sep =
" , ",
84 const std::string &suf =
">");
86 static std::string vpCannyBackendTypeToString(
const vpCannyBackendType &type);
88 static vpCannyBackendType vpCannyBackendTypeFromString(
const std::string &name);
93 CANNY_GBLUR_SOBEL_FILTERING = 0,
94 CANNY_GBLUR_SCHARR_FILTERING = 1,
95 CANNY_COUNT_FILTERING = 2
96 } vpCannyFilteringAndGradientType;
98 static std::string vpGetCannyFiltAndGradTypes(
const std::string &pref =
"<",
const std::string &sep =
" , ",
99 const std::string &suf =
">");
101 static std::string vpCannyFiltAndGradTypeToStr(
const vpCannyFilteringAndGradientType &type);
103 static vpCannyFilteringAndGradientType vpCannyFiltAndGradTypeFromStr(
const std::string &name);
106 const float &thresholdCanny,
const unsigned int &apertureSobel);
109 const float &lowerThresholdCanny,
const float &higherThresholdCanny,
110 const unsigned int &apertureSobel);
113 const float &lowerThresholdCanny,
const float &higherThresholdCanny,
114 const unsigned int &apertureSobel,
const float &gaussianStdev,
const float &lowerThresholdRatio,
115 const float &upperThresholdRatio,
const bool &normalizeGradients,
116 const vpCannyBackendType &cannyBackend,
const vpCannyFilteringAndGradientType &cannyFilteringSteps,
119 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
120 static float computeCannyThreshold(
const cv::Mat &cv_I,
const cv::Mat *p_cv_dIx,
const cv::Mat *p_cv_dIy,
121 float &lowerThresh,
const unsigned int &gaussianKernelSize = 5,
122 const float &gaussianStdev = 2.f,
const unsigned int &apertureGradient = 3,
123 const float &lowerThresholdRatio = 0.6,
const float &upperThresholdRatio = 0.8,
124 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
126 static void computePartialDerivatives(
const cv::Mat &cv_I,
127 cv::Mat &cv_dIx, cv::Mat &cv_dIy,
128 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
129 const unsigned int &gaussianKernelSize = 5,
const float &gaussianStdev = 2.f,
130 const unsigned int &apertureGradient = 3,
131 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
154 template <
typename ImageType,
typename FilterType>
157 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
158 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
159 const unsigned int &apertureGradient = 3,
164 if (backend == CANNY_OPENCV_BACKEND) {
165 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
166 cv::Mat cv_I, cv_dIx, cv_dIy;
168 computePartialDerivatives(cv_I, cv_dIx, cv_dIy, computeDx, computeDy, normalize, gaussianKernelSize,
169 static_cast<float>(gaussianStdev), apertureGradient, filteringType);
181 if ((filteringType == CANNY_GBLUR_SCHARR_FILTERING) || (filteringType == CANNY_GBLUR_SOBEL_FILTERING)) {
192 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
195 const unsigned int nbRows = filter.
getRows();
196 const unsigned int nbCols = filter.
getCols();
197 for (
unsigned int r = 0; r < nbRows; ++r) {
198 for (
unsigned int c = 0; c < nbCols; ++c) {
199 filter[r][c] = filter[r][c] * scale;
209 const unsigned int val2 = 2U;
211 if (filteringType == CANNY_GBLUR_SOBEL_FILTERING) {
219 else if (filteringType == CANNY_GBLUR_SCHARR_FILTERING) {
231 scaleFilter(gradientFilterX, scaleX);
234 scaleFilter(gradientFilterY, scaleY);
248 std::string errMsg =
"[vpImageFilter::computePartialDerivatives] Filtering + gradient method \"";
249 errMsg += vpCannyFiltAndGradTypeToStr(filteringType);
250 errMsg +=
"\" is not implemented yet\n";
256 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
257 template <
typename FilterType>
260 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
261 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
262 const unsigned int &apertureGradient = 3,
263 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
264 const vpCannyBackendType &backend = CANNY_VISP_BACKEND,
const vpImage<bool> *p_mask =
nullptr) =
delete;
266 template <
typename ImageType>
269 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
270 const unsigned int &gaussianKernelSize = 5,
const unsigned char &gaussianStdev = 2.f,
271 const unsigned int &apertureGradient = 3,
272 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
273 const vpCannyBackendType &backend = CANNY_VISP_BACKEND,
const vpImage<bool> *p_mask =
nullptr) =
delete;
275 template <
typename ImageType>
278 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
279 const unsigned int gaussianKernelSize = 5,
const vpRGBa gaussianStdev =
vpRGBa(),
280 const unsigned int apertureGradient = 3,
281 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING,
282 const vpCannyBackendType &backend = CANNY_VISP_BACKEND,
const vpImage<bool> *p_mask =
nullptr) =
delete;
284 template <
typename FilterType>
287 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
288 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
289 const unsigned int &apertureGradient = 3,
293 template <
typename ImageType>
296 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
297 const unsigned int &gaussianKernelSize = 5,
const unsigned char &gaussianStdev = 2.f,
298 const unsigned int &apertureGradient = 3,
302 template <
typename ImageType>
305 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
306 const unsigned int gaussianKernelSize = 5,
const vpRGBa gaussianStdev =
vpRGBa(),
307 const unsigned int apertureGradient = 3,
332 template<
typename OutType>
335 const unsigned int &gaussianKernelSize = 5,
336 const OutType &gaussianStdev = 2.f,
const unsigned int &apertureGradient = 3,
337 const float &lowerThresholdRatio = 0.6f,
const float &upperThresholdRatio = 0.8f,
341 const unsigned int w = I.
getWidth();
344 if ((lowerThresholdRatio <= 0.f) || (lowerThresholdRatio >= 1.f)) {
345 std::stringstream errMsg;
346 errMsg <<
"Lower ratio (" << lowerThresholdRatio <<
") " << (lowerThresholdRatio < 0.f ?
"should be greater than 0 !" :
"should be lower than 1 !");
350 if ((upperThresholdRatio <= 0.f) || (upperThresholdRatio >= 1.f)) {
351 std::stringstream errMsg;
352 errMsg <<
"Upper ratio (" << upperThresholdRatio <<
") " << (upperThresholdRatio < 0.f ?
"should be greater than 0 !" :
"should be lower than 1 !");
356 if (lowerThresholdRatio >= upperThresholdRatio) {
357 std::stringstream errMsg;
358 errMsg <<
"Lower ratio (" << lowerThresholdRatio <<
") should be lower than the upper ratio (" << upperThresholdRatio <<
")";
364 if ((p_dIx !=
nullptr) && (p_dIy !=
nullptr)) {
369 computePartialDerivatives(I, dIx, dIy,
true,
true,
true, gaussianKernelSize, gaussianStdev,
374 for (
unsigned int r = 0; r < h; ++r) {
375 for (
unsigned int c = 0; c < w; ++c) {
378 bool computeVal = checkBooleanMask(p_mask, r, c);
381 float dx =
static_cast<float>(dIx[r][c]);
382 float dy =
static_cast<float>(dIy[r][c]);
383 float gradient = std::abs(dx) + std::abs(dy);
384 float gradientClamped = std::min<float>(gradient,
static_cast<float>(std::numeric_limits<unsigned char>::max()));
385 dI[r][c] =
static_cast<unsigned char>(gradientClamped);
393 const unsigned int nbBins = 256;
395 float totalNbPixels =
static_cast<float>(hist.
getTotal());
397 float t = upperThresholdRatio * totalNbPixels;
400 bool notFound =
true;
401 while ((i < nbBins) && notFound) {
402 float tf =
static_cast<float>(hist[i]);
405 bon =
static_cast<float>(i);
411 std::stringstream errMsg;
412 errMsg <<
"Could not find a bin for which " << upperThresholdRatio * 100.f <<
" percents of the pixels had a gradient lower than the upper threshold.";
415 float upperThresh = std::max<float>(bon, 1.f);
416 lowerThresh = lowerThresholdRatio * bon;
417 lowerThresh = std::max<float>(lowerThresh, std::numeric_limits<float>::epsilon());
430 const int val1 = 1, val2 = 2, val3 = 3;
431 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])) +
432 (112.0 *
static_cast<double>(I[r][c + val3] - I[r][c - val3]))) / 8418.0;
444 const int val1 = 1, val2 = 2, val3 = 3;
445 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])) +
446 (112.0 *
static_cast<double>(I[r + val3][c] - I[r - val3][c]))) / 8418.0;
462 template <
class ImageType,
typename FilterType>
465 const unsigned int stop = (size - 1) / 2;
471 for (i = 1; i <= stop; ++i) {
472 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] - I[r][c - i]);
490 template <
class ImageType,
typename FilterType>
493 const unsigned int stop = (size - 1) / 2;
499 for (i = 1; i <= stop; ++i) {
500 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] - I[r - i][c]);
534 template <
typename ImageType,
typename FilterType>
539 const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
542 If.
resize(inputHeight, inputWidth, 0.0);
545 const unsigned int stopHeight = inputHeight - half_size_y;
546 const unsigned int stopWidth = inputWidth - half_size_x;
547 for (
unsigned int i = half_size_y; i < stopHeight; ++i) {
548 for (
unsigned int j = half_size_x; j < stopWidth; ++j) {
551 bool computeVal = checkBooleanMask(p_mask, i, j);
555 for (
unsigned int a = 0; a < size_y; ++a) {
556 for (
unsigned int b = 0; b < size_x; ++b) {
557 FilterType val =
static_cast<FilterType
>(I[(i + half_size_y) - a][(j + half_size_x) - b]);
558 conv += M[a][b] * val;
567 const unsigned int stopHeight = inputHeight - half_size_y;
568 const unsigned int stopWidth = inputWidth - half_size_x;
569 for (
unsigned int i = half_size_y; i < stopHeight; ++i) {
570 for (
unsigned int j = half_size_x; j < stopWidth; ++j) {
573 bool computeVal = checkBooleanMask(p_mask, i, j);
577 for (
unsigned int a = 0; a < size_y; ++a) {
578 for (
unsigned int b = 0; b < size_x; ++b) {
579 FilterType val =
static_cast<FilterType
>(I[(i - half_size_y) + a][(j - half_size_x) + b]);
580 corr += M[a][b] * val;
599 template <
typename FilterType>
603 const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
606 for (
unsigned int a = 0; a < size_y; ++a) {
607 for (
unsigned int b = 0; b < size_x; ++b) {
608 FilterType val =
static_cast<FilterType
>(I[row - half_size_y + a][col - half_size_x + b]);
609 corr += M[a][b] * val;
615 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
616 template <
typename FilterType>
619 template <
typename FilterType>
636 template <
typename ImageType,
typename FilterType>
638 bool convolve =
false,
const vpImage<bool> *p_mask =
nullptr)
640 const unsigned int size = M.
getRows();
641 const unsigned int half_size = size / 2;
643 const unsigned int stopV = height - half_size;
644 const unsigned int stopU = width - half_size;
646 Iu.
resize(height, width, 0.0);
647 Iv.
resize(height, width, 0.0);
650 for (
unsigned int v = half_size; v < stopV; ++v) {
651 for (
unsigned int u = half_size; u < stopU; ++u) {
654 bool computeVal = checkBooleanMask(p_mask, v, u);
656 FilterType conv_u = 0;
657 FilterType conv_v = 0;
659 for (
unsigned int a = 0; a < size; ++a) {
660 for (
unsigned int b = 0; b < size; ++b) {
661 FilterType val =
static_cast<FilterType
>(I[(v + half_size) - a][(u + half_size) - b]);
662 conv_u += M[a][b] * val;
663 conv_v += M[b][a] * val;
673 for (
unsigned int v = half_size; v < stopV; ++v) {
674 for (
unsigned int u = half_size; u < stopU; ++u) {
677 bool computeVal = checkBooleanMask(p_mask, v, u);
680 FilterType conv_u = 0;
681 FilterType conv_v = 0;
683 for (
unsigned int a = 0; a < size; ++a) {
684 for (
unsigned int b = 0; b < size; ++b) {
685 FilterType val =
static_cast<FilterType
>(I[(v - half_size) + a][(u - half_size) + b]);
686 conv_u += M[a][b] * val;
687 conv_v += M[b][a] * val;
698 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
699 template<
typename FilterType>
702 template<
typename ImageType>
705 template<
typename FilterType>
708 template<
typename ImageType>
723 template <
typename ImageType,
typename FilterType>
727 filterX<ImageType, FilterType>(I, GIx, filter, size, p_mask);
728 filterY<FilterType, FilterType>(GIx, GI, filter, size, p_mask);
735 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.);
740 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.);
743 template <
typename ImageType,
typename FilterType>
747 const unsigned int height = I.
getHeight();
748 const unsigned int width = I.
getWidth();
749 const unsigned int stop1J = (size - 1) / 2;
750 const unsigned int stop2J = width - ((size - 1) / 2);
751 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
753 for (
unsigned int i = 0; i < height; ++i) {
754 for (
unsigned int j = 0; j < stop1J; ++j) {
757 bool computeVal = checkBooleanMask(p_mask, i, j);
759 dIx[i][j] = vpImageFilter::filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
762 for (
unsigned int j = stop1J; j < stop2J; ++j) {
765 bool computeVal = checkBooleanMask(p_mask, i, j);
767 dIx[i][j] = vpImageFilter::filterX<ImageType, FilterType>(I, i, j, filter, size);
770 for (
unsigned int j = stop2J; j < width; ++j) {
773 bool computeVal = checkBooleanMask(p_mask, i, j);
775 dIx[i][j] = vpImageFilter::filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
783 template<
typename ImageType,
typename FilterType>
784 static inline FilterType
filterX(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
786 const unsigned int stop = (size - 1) / 2;
787 FilterType result =
static_cast<FilterType
>(0.);
789 for (
unsigned int i = 1; i <= stop; ++i) {
790 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
792 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
795 #ifndef DOXYGEN_SHOULD_SKIP_THIS
800 static double filterXR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
801 static double filterXG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
802 static double filterXB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
804 static double filterXLeftBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
805 static double filterXLeftBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
806 static double filterXLeftBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
807 static double filterXRightBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
808 static double filterXRightBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
809 static double filterXRightBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
811 template <
typename ImageType,
typename FilterType>
812 static inline FilterType filterXLeftBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
813 const FilterType *filter,
unsigned int size)
815 const unsigned int stop = (size - 1) / 2;
816 FilterType result =
static_cast<FilterType
>(0.);
818 for (
unsigned int i = 1; i <= stop; ++i) {
820 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
823 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][i - c]);
826 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
829 template <
typename ImageType,
typename FilterType>
830 static inline FilterType filterXRightBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
831 const FilterType *filter,
unsigned int size)
833 const unsigned int stop = (size - 1) / 2;
834 const unsigned int width = I.
getWidth();
835 FilterType result =
static_cast<FilterType
>(0.);
836 const unsigned int twice = 2;
838 for (
unsigned int i = 1; i <= stop; ++i) {
839 if ((c + i) < width) {
840 result += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
843 result += filter[i] *
static_cast<FilterType
>(I[r][((twice * width) - c) - i - 1] + I[r][c - i]);
846 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
852 template<
typename ImageType,
typename FilterType>
857 const unsigned int stop1I = (size - 1) / 2;
858 const unsigned int stop2I = height - ((size - 1) / 2);
859 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
861 for (
unsigned int i = 0; i < stop1I; ++i) {
862 for (
unsigned int j = 0; j < width; ++j) {
865 bool computeVal = checkBooleanMask(p_mask, i, j);
867 dIy[i][j] = vpImageFilter::filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
871 for (
unsigned int i = stop1I; i < stop2I; ++i) {
872 for (
unsigned int j = 0; j < width; ++j) {
875 bool computeVal = checkBooleanMask(p_mask, i, j);
877 dIy[i][j] = vpImageFilter::filterY<ImageType, FilterType>(I, i, j, filter, size);
881 for (
unsigned int i = stop2I; i < height; ++i) {
882 for (
unsigned int j = 0; j < width; ++j) {
885 bool computeVal = checkBooleanMask(p_mask, i, j);
887 dIy[i][j] = vpImageFilter::filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
893 template<
typename ImageType,
typename FilterType>
894 static inline FilterType
filterY(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
896 const unsigned int stop = (size - 1) / 2;
897 FilterType result =
static_cast<FilterType
>(0.);
899 for (
unsigned int i = 1; i <= stop; ++i) {
900 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
902 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
904 #ifndef DOXYGEN_SHOULD_SKIP_THIS
909 static double filterYR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
910 static double filterYG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
911 static double filterYB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
913 static double filterYTopBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
914 static double filterYTopBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
915 static double filterYTopBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
916 static double filterYBottomBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
917 static double filterYBottomBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
918 static double filterYBottomBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
920 template<
typename ImageType,
typename FilterType>
921 static inline FilterType filterYTopBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
922 const FilterType *filter,
unsigned int size)
924 const unsigned int stop = (size - 1) / 2;
925 FilterType result =
static_cast<FilterType
>(0.);
927 for (
unsigned int i = 1; i <= stop; ++i) {
929 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
932 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[i - r][c]);
935 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
938 template<
typename ImageType,
typename FilterType>
939 static inline FilterType filterYBottomBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
940 const FilterType *filter,
unsigned int size)
942 const unsigned int height = I.
getHeight();
943 const unsigned int stop = (size - 1) / 2;
944 FilterType result =
static_cast<FilterType
>(0.);
945 const unsigned int twiceHeight = 2 * height;
946 for (
unsigned int i = 1; i <= stop; ++i) {
947 if ((r + i) < height) {
948 result += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
951 result += filter[i] *
static_cast<FilterType
>(I[(twiceHeight - r) - i - 1][c] + I[r - i][c]);
954 return result + (filter[0] *
static_cast<FilterType
>(I[r][c]));
972 template <
typename ImageType,
typename FilterType>
976 FilterType *fg =
new FilterType[(size + 1) / 2];
977 vpImageFilter::getGaussianKernel<FilterType>(fg, size, sigma, normalize);
979 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, fg, size, p_mask);
980 vpImageFilter::filterY<FilterType, FilterType>(GIx, GI, fg, size, p_mask);
998 return ((15.0 * fr[r][c]) +
999 (12.0 * (fr[r - 1][c] + fr[r][c - 1] + fr[r + 1][c] + fr[r][c + 1])) +
1000 (9.0 * (fr[r - 1][c - 1] + fr[r + 1][c - 1] + fr[r - 1][c + 1] + fr[r + 1][c + 1])) +
1001 (5.0 * (fr[r - val2][c] + fr[r][c - val2] + fr[r + val2][c] + fr[r][c + val2])) +
1002 (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] +
1003 fr[r + val2][c + 1] + fr[r - 1][c + val2] + fr[r + 1][c + val2])) +
1004 (2.0 * (fr[r - val2][c - val2] + fr[r + val2][c - val2] + fr[r - val2][c + val2] + fr[r + val2][c + val2]))) / 159.0;
1027 template<
typename FilterType>
1028 static void getGaussianKernel(FilterType *filter,
unsigned int size, FilterType sigma = 0.,
bool normalize =
true)
1030 const unsigned int mod2 = 2;
1031 if ((size % mod2) != 1) {
1036 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1039 int middle = (
static_cast<int>(size) - 1) / 2;
1040 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(sigma));
1041 FilterType coef1 =
static_cast<FilterType
>(1. / (sigma * sqrt(2. * M_PI)));
1042 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. * sigma2);
1043 for (
int i = 0; i <= middle; ++i) {
1044 filter[i] = coef1 *
static_cast<FilterType
>(exp(-(i * i) / v_2_sigma2));
1049 const unsigned int val2 = 2U;
1050 for (
int i = 1; i <= middle; ++i) {
1051 sum += val2 * filter[i];
1055 for (
int i = 0; i <= middle; ++i) {
1056 filter[i] = filter[i] / sum;
1075 template <
typename FilterType>
1078 const unsigned int mod2 = 2;
1079 if ((size % mod2) != 1) {
1084 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1088 int middle = (
static_cast<int>(size) - 1) / half;
1089 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(sigma));
1090 FilterType coef_1 =
static_cast<FilterType
>(1. / (sigma * sqrt(2. * M_PI)));
1091 FilterType coef_1_over_2 = coef_1 /
static_cast<FilterType
>(2.);
1092 FilterType v_2_coef_1 =
static_cast<FilterType
>(2.) * coef_1;
1093 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. * sigma2);
1095 for (
int i = 1; i <= middle; ++i) {
1096 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)));
1101 for (
int i = 1; i <= middle; ++i) {
1102 sum += v_2_coef_1 *
static_cast<FilterType
>(exp(-(i * i) / v_2_sigma2));
1106 for (
int i = 1; i <= middle; ++i) {
1107 filter[i] = filter[i] / sum;
1113 template<
typename FilterType>
1117 const unsigned int stopJ = width - 3;
1118 const unsigned int val_3 = 3;
1119 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1121 for (
unsigned int i = 0; i < height; ++i) {
1122 for (
unsigned int j = 0; j < val_3; ++j) {
1124 bool computeVal = (p_mask ==
nullptr);
1126 dIx[i][j] =
static_cast<FilterType
>(0);
1129 for (
unsigned int j = 3; j < stopJ; ++j) {
1132 bool computeVal = checkBooleanMask(p_mask, i, j);
1137 for (
unsigned int j = stopJ; j < width; ++j) {
1139 bool computeVal = (p_mask ==
nullptr);
1141 dIx[i][j] =
static_cast<FilterType
>(0);
1147 template <
typename ImageType,
typename FilterType>
1151 const unsigned int stop1J = (size - 1) / 2;
1152 const unsigned int stop2J = width - ((size - 1) / 2);
1153 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1155 for (
unsigned int i = 0; i < height; ++i) {
1156 for (
unsigned int j = 0; j < stop1J; ++j) {
1158 bool computeVal = (p_mask ==
nullptr);
1160 dIx[i][j] =
static_cast<FilterType
>(0);
1163 for (
unsigned int j = stop1J; j < stop2J; ++j) {
1166 bool computeVal = checkBooleanMask(p_mask, i, j);
1168 dIx[i][j] = vpImageFilter::derivativeFilterX<ImageType, FilterType>(I, i, j, filter, size);
1171 for (
unsigned int j = stop2J; j < width; ++j) {
1173 bool computeVal = (p_mask ==
nullptr);
1175 dIx[i][j] =
static_cast<FilterType
>(0);
1192 template <
typename ImageType,
typename FilterType>
1194 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
1197 vpImageFilter::filterY<ImageType, FilterType>(I, GIy, gaussianKernel, size, p_mask);
1198 vpImageFilter::getGradX<FilterType, FilterType>(GIy, dIx, gaussianDerivativeKernel, size, p_mask);
1202 template <
typename FilterType>
1206 const unsigned int stopI = height - 3;
1207 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1208 const unsigned int val_3 = 3;
1209 for (
unsigned int i = 0; i < val_3; ++i) {
1210 for (
unsigned int j = 0; j < width; ++j) {
1213 bool computeVal = checkBooleanMask(p_mask, i, j);
1215 dIy[i][j] =
static_cast<FilterType
>(0);
1219 for (
unsigned int i = 3; i < stopI; ++i) {
1220 for (
unsigned int j = 0; j < width; ++j) {
1223 bool computeVal = checkBooleanMask(p_mask, i, j);
1229 for (
unsigned int i = stopI; i < height; ++i) {
1230 for (
unsigned int j = 0; j < width; ++j) {
1233 bool computeVal = checkBooleanMask(p_mask, i, j);
1235 dIy[i][j] =
static_cast<FilterType
>(0);
1241 template <
typename ImageType,
typename FilterType>
1245 const unsigned int stop1I = (size - 1) / 2;
1246 const unsigned int stop2I = height - ((size - 1) / 2);
1247 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1249 for (
unsigned int i = 0; i < stop1I; ++i) {
1250 for (
unsigned int j = 0; j < width; ++j) {
1253 bool computeVal = checkBooleanMask(p_mask, i, j);
1255 dIy[i][j] =
static_cast<FilterType
>(0);
1259 for (
unsigned int i = stop1I; i < stop2I; ++i) {
1260 for (
unsigned int j = 0; j < width; ++j) {
1263 bool computeVal = checkBooleanMask(p_mask, i, j);
1265 dIy[i][j] = vpImageFilter::derivativeFilterY<ImageType, FilterType>(I, i, j, filter, size);
1269 for (
unsigned int i = stop2I; i < height; ++i) {
1270 for (
unsigned int j = 0; j < width; ++j) {
1273 bool computeVal = checkBooleanMask(p_mask, i, j);
1275 dIy[i][j] =
static_cast<FilterType
>(0);
1292 template <
typename ImageType,
typename FilterType>
1294 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
1297 vpImageFilter::filterX<ImageType, FilterType>(I, GIx, gaussianKernel, size, p_mask);
1298 vpImageFilter::getGradY<FilterType, FilterType>(GIx, dIy, gaussianDerivativeKernel, size, p_mask);
1308 template <
typename FilterType>
1311 const unsigned int actualKernelSize = (size * 2) + 1;
1314 std::stringstream errMsg;
1315 errMsg <<
"Cannot get Scharr kernel of size " << actualKernelSize <<
" != 3";
1320 FilterType norm = getScharrKernelY<FilterType>(ScharrY.
data, size);
1321 memcpy(filter, ScharrY.
t().data, ScharrY.
getRows() * ScharrY.
getCols() *
sizeof(FilterType));
1332 template <
typename FilterType>
1336 static const FilterType ScharrY3x3[9] = { -3.0, -10.0, -3.0, 0.0, 0.0, 0.0, 3.0, 10.0, 3.0 };
1340 std::stringstream errMsg;
1341 errMsg <<
"Cannot get Scharr kernel of size " << ((size * 2) + 1) <<
" != 3";
1345 const unsigned int kernel_size = (size * 2) + 1;
1346 const unsigned int kernel3 = 3;
1347 if (kernel_size == kernel3) {
1348 memcpy(filter, ScharrY3x3, kernel_size * kernel_size *
sizeof(FilterType));
1349 return static_cast<FilterType
>(1.0 / 32.0);
1352 return static_cast<FilterType
>(0.);
1362 template <
typename FilterType>
1365 const unsigned int maxSize = 20;
1369 if (size > maxSize) {
1373 const unsigned int kernel_size = (size * 2) + 1;
1375 FilterType norm = getSobelKernelY<FilterType>(SobelY.
data, size);
1376 memcpy(filter, SobelY.
t().data, SobelY.
getRows() * SobelY.
getCols() *
sizeof(FilterType));
1387 template <
typename FilterType>
1391 static const FilterType SobelY3x3[9] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 };
1392 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,
1393 0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0 };
1394 static const FilterType SobelY7x7[49] = { -1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
1395 -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
1396 5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1 };
1398 const unsigned int index_0 = 0;
1399 const unsigned int index_1 = 1;
1400 const unsigned int index_2 = 2;
1401 smoothingKernel[index_0][index_0] = 1.0;
1402 smoothingKernel[index_0][index_1] = 2.0;
1403 smoothingKernel[index_0][index_2] = 1.0;
1404 smoothingKernel[index_1][index_0] = 2.0;
1405 smoothingKernel[index_1][index_1] = 4.0;
1406 smoothingKernel[index_1][index_2] = 2.0;
1407 smoothingKernel[index_2][index_0] = 1.0;
1408 smoothingKernel[index_2][index_1] = 2.0;
1409 smoothingKernel[index_2][index_2] = 1.0;
1411 const unsigned int maxSize = 20;
1415 if (size > maxSize) {
1419 const unsigned int kernel_size = (size * 2) + 1;
1420 FilterType scale =
static_cast<FilterType
>(1. / 8.);
1421 const unsigned int kernel3 = 3, kernel5 = 5, kernel7 = 7;
1422 if (kernel_size == kernel3) {
1423 memcpy(filter, SobelY3x3, kernel_size * kernel_size *
sizeof(FilterType));
1426 scale *=
static_cast<FilterType
>(1. / 16.);
1427 if (kernel_size == kernel5) {
1428 memcpy(filter, SobelY5x5, kernel_size * kernel_size *
sizeof(FilterType));
1431 scale *=
static_cast<FilterType
>(1. / 16.);
1432 if (kernel_size == kernel7) {
1433 memcpy(filter, SobelY7x7, kernel_size * kernel_size *
sizeof(FilterType));
1438 memcpy(sobelY.
data, SobelY7x7, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
1439 for (
unsigned int i = 4; i <= size; ++i) {
1442 scale *=
static_cast<FilterType
>(1. / 16.);
1445 memcpy(filter, sobelY.
data, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
1450 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
1451 static float median(
const cv::Mat &cv_I);
1467 template<
typename ImageType>
1470 if (p_mask ==
nullptr) {
1476 I.
resize(height, width,
static_cast<ImageType
>(0));
1489 static bool checkBooleanMask(
const vpImage<bool> *p_mask,
const unsigned int &r,
const unsigned int &c)
1491 bool computeVal =
true;
1492 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
1493 if (p_mask !=
nullptr)
1498 computeVal = (*p_mask)[r][c];
1505 #if ((__cplusplus <= 199711L) || (defined(_MSVC_LANG) && (_MSVC_LANG == 199711L)))
1507 template <
typename FilterType>
1510 const unsigned int nbRows = filter.
getRows();
1511 const unsigned int nbCols = filter.
getCols();
1512 for (
unsigned int r = 0; r < nbRows; ++r) {
1513 for (
unsigned int c = 0; c < nbCols; ++c) {
1514 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)