99 static std::string vpCannyBackendTypeList(
const std::string &pref =
"<",
const std::string &sep =
" , ",
100 const std::string &suf =
">");
102 static std::string vpCannyBackendTypeToString(
const vpCannyBackendType &type);
104 static vpCannyBackendType vpCannyBackendTypeFromString(
const std::string &name);
112 } vpCannyFilteringAndGradientType;
114 static std::string vpGetCannyFiltAndGradTypes(
const std::string &pref =
"<",
const std::string &sep =
" , ",
115 const std::string &suf =
">");
117 static std::string vpCannyFiltAndGradTypeToStr(
const vpCannyFilteringAndGradientType &type);
119 static vpCannyFilteringAndGradientType vpCannyFiltAndGradTypeFromStr(
const std::string &name);
122 const float &thresholdCanny,
const unsigned int &apertureSobel);
125 const float &lowerThresholdCanny,
const float &higherThresholdCanny,
126 const unsigned int &apertureSobel);
129 const float &lowerThresholdCanny,
const float &higherThresholdCanny,
130 const unsigned int &apertureSobel,
const float &gaussianStdev,
const float &lowerThresholdRatio,
131 const float &upperThresholdRatio,
const bool &normalizeGradients,
132 const vpCannyBackendType &cannyBackend,
const vpCannyFilteringAndGradientType &cannyFilteringSteps,
135#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
136 static float computeCannyThreshold(
const cv::Mat &cv_I,
const cv::Mat *p_cv_dIx,
const cv::Mat *p_cv_dIy,
137 float &lowerThresh,
const unsigned int &gaussianKernelSize = 5,
138 const float &gaussianStdev = 2.f,
const unsigned int &apertureGradient = 3,
139 const float &lowerThresholdRatio = 0.6f,
const float &upperThresholdRatio = 0.8f,
140 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
142 static void computePartialDerivatives(
const cv::Mat &cv_I,
143 cv::Mat &cv_dIx, cv::Mat &cv_dIy,
144 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
145 const unsigned int &gaussianKernelSize = 5,
const float &gaussianStdev = 2.f,
146 const unsigned int &apertureGradient = 3,
147 const vpCannyFilteringAndGradientType &filteringType = CANNY_GBLUR_SOBEL_FILTERING);
170 template <
typename ImageType,
typename FilterType>
173 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
174 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
175 const unsigned int &apertureGradient = 3,
181#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
182 cv::Mat cv_I, cv_dIx, cv_dIy;
185 static_cast<float>(gaussianStdev), apertureGradient, filteringType);
198 dIx.
resize(I.getHeight(), I.getWidth());
199 dIy.
resize(I.getHeight(), I.getWidth());
208#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
211 const unsigned int nbRows =
filter.getRows();
212 const unsigned int nbCols =
filter.getCols();
213 for (
unsigned int r = 0; r < nbRows; ++r) {
214 for (
unsigned int c = 0; c < nbCols; ++c) {
223 FilterType scaleX = 1.0;
224 FilterType scaleY = 1.0;
225 const unsigned int val2 = 2U;
264 std::string errMsg =
"[vpImageFilter::computePartialDerivatives] Filtering + gradient method \"";
266 errMsg +=
"\" is not implemented yet\n";
272#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
273 template <
typename FilterType>
276 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
277 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
278 const unsigned int &apertureGradient = 3,
282 template <
typename ImageType>
285 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
286 const unsigned int &gaussianKernelSize = 5,
const unsigned char &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 vpRGBa gaussianStdev =
vpRGBa(),
296 const unsigned int apertureGradient = 3,
300 template <
typename FilterType>
303 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
304 const unsigned int &gaussianKernelSize = 5,
const FilterType &gaussianStdev = 2.f,
305 const unsigned int &apertureGradient = 3,
309 template <
typename ImageType>
312 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
313 const unsigned int &gaussianKernelSize = 5,
const unsigned char &gaussianStdev = 2.f,
314 const unsigned int &apertureGradient = 3,
318 template <
typename ImageType>
321 const bool &computeDx =
true,
const bool &computeDy =
true,
const bool &normalize =
true,
322 const unsigned int gaussianKernelSize = 5,
const vpRGBa gaussianStdev =
vpRGBa(),
323 const unsigned int apertureGradient = 3,
348 template<
typename OutType>
351 const unsigned int &gaussianKernelSize = 5,
352 const OutType &gaussianStdev = 2.f,
const unsigned int &apertureGradient = 3,
353 const float &lowerThresholdRatio = 0.6f,
const float &upperThresholdRatio = 0.8f,
357 const unsigned int w = I.getWidth();
358 const unsigned int h = I.getHeight();
359 const int size =
static_cast<int>(I.getSize());
361 if ((lowerThresholdRatio <= 0.f) || (lowerThresholdRatio >= 1.f)) {
362 std::stringstream errMsg;
363 errMsg <<
"Lower ratio (" << lowerThresholdRatio <<
") " << (lowerThresholdRatio < 0.f ?
"should be greater than 0 !" :
"should be lower than 1 !");
367 if ((upperThresholdRatio <= 0.f) || (upperThresholdRatio >= 1.f)) {
368 std::stringstream errMsg;
369 errMsg <<
"Upper ratio (" << upperThresholdRatio <<
") " << (upperThresholdRatio < 0.f ?
"should be greater than 0 !" :
"should be lower than 1 !");
373 if (lowerThresholdRatio >= upperThresholdRatio) {
374 std::stringstream errMsg;
375 errMsg <<
"Lower ratio (" << lowerThresholdRatio <<
") should be lower than the upper ratio (" << upperThresholdRatio <<
")";
381 if ((p_dIx !=
nullptr) && (p_dIy !=
nullptr)) {
391#ifdef VISP_HAVE_OPENMP
392#pragma omp parallel for
394 for (
int iter = 0; iter < size; ++iter) {
397 bool computeVal = checkBooleanMask(p_mask, iter);
400 float dx =
static_cast<float>(dIx.
bitmap[iter]);
401 float dy =
static_cast<float>(dIy.
bitmap[iter]);
402 float gradient = std::abs(dx) + std::abs(dy);
403 float gradientClamped = std::min<float>(gradient,
static_cast<float>(std::numeric_limits<unsigned char>::max()));
404 dI.bitmap[iter] =
static_cast<unsigned char>(gradientClamped);
411 const unsigned int nbBins = 256;
413 float totalNbPixels =
static_cast<float>(hist.
getTotal());
415 float t = upperThresholdRatio * totalNbPixels;
416 float tLow = lowerThresholdRatio * totalNbPixels;
419 bool notFound =
true, notFoundLower =
true;
420 while ((i < nbBins) && notFound) {
421 float tf =
static_cast<float>(hist[
static_cast<unsigned char>(i)]);
423 if ((accu > tLow) && notFoundLower) {
424 lowerThresh =
static_cast<float>(i);
425 notFoundLower =
false;
428 bon =
static_cast<float>(i);
434 std::stringstream errMsg;
435 errMsg <<
"Could not find a bin for which " << upperThresholdRatio * 100.f <<
" percents of the pixels had a gradient lower than the upper threshold.";
439 float upperThresh = std::max<float>(bon, 1.f);
440 lowerThresh = std::max<float>(lowerThresh, std::numeric_limits<float>::epsilon());
444#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
465 template<
typename ArithmeticType,
bool useFullScale,
typename OutType>
468 const unsigned int &gaussianKernelSize = 5,
469 const OutType &gaussianStdev = 2.f,
470 const float &lowerThresholdRatio = 0.6f,
const float &upperThresholdRatio = 0.8f,
474 const unsigned int w = I.getWidth();
475 const unsigned int h = I.getHeight();
476 const int size = I.getSize();
478 if ((lowerThresholdRatio <= 0.f) || (lowerThresholdRatio >= 1.f)) {
479 std::stringstream errMsg;
480 errMsg <<
"Lower ratio (" << lowerThresholdRatio <<
") " << (lowerThresholdRatio < 0.f ?
"should be greater than 0 !" :
"should be lower than 1 !");
484 if ((upperThresholdRatio <= 0.f) || (upperThresholdRatio >= 1.f)) {
485 std::stringstream errMsg;
486 errMsg <<
"Upper ratio (" << upperThresholdRatio <<
") " << (upperThresholdRatio < 0.f ?
"should be greater than 0 !" :
"should be lower than 1 !");
490 if (lowerThresholdRatio >= upperThresholdRatio) {
491 std::stringstream errMsg;
492 errMsg <<
"Lower ratio (" << lowerThresholdRatio <<
") should be lower than the upper ratio (" << upperThresholdRatio <<
")";
497#ifdef VISP_HAVE_OPENMP
498 nbThread = omp_get_max_threads();
503 if ((p_dIx !=
nullptr) && (p_dIy !=
nullptr)) {
509 gaussianBlur(I, Iblur, gaussianKernelSize, gaussianStdev,
true, p_mask);
515 float dIMin = std::numeric_limits<OutType>::max();
516 int iter, istart = 0, istop = size;
517#ifdef VISP_HAVE_OPENMP
518 int iam, nt, ipoints, npoints(size);
519#pragma omp parallel default(shared) private(iter, iam, nt, ipoints, istart, istop)
521 iam = omp_get_thread_num();
522 nt = omp_get_num_threads();
523 ipoints = npoints / nt;
525 istart = iam * ipoints;
528 ipoints = npoints - istart;
530 istop = istart + ipoints;
532 float localdImin = std::numeric_limits<OutType>::max(), localdImax = -1.;
533 for (iter = istart; iter < istop; ++iter) {
536 bool computeVal = checkBooleanMask(p_mask, iter);
539 float dx =
static_cast<float>(dIx.
bitmap[iter]);
540 float dy =
static_cast<float>(dIy.
bitmap[iter]);
541 float gradient = std::abs(dx) + std::abs(dy);
542 localdImax = std::max(localdImax, gradient);
543 localdImin = std::min(localdImin, gradient);
544 dI.bitmap[iter] = gradient;
547#ifdef VISP_HAVE_OPENMP
550 dIMin = std::min(dIMin, localdImin);
551 dIMax = std::max(dIMax, localdImax);
557#ifdef VISP_HAVE_OPENMP
562#ifdef VISP_HAVE_THREADS
563 nbThread = std::max(
static_cast<int>(std::thread::hardware_concurrency()), 1);
565 const unsigned int nbBins = 1024;
569 hist.
calculate<OutType>(dI, dIMin, dIMax, step, nbBins, nbThread);
570 float totalNbPixels =
static_cast<float>(hist.
getTotal());
572 float t = upperThresholdRatio * totalNbPixels;
573 float tLow = lowerThresholdRatio * totalNbPixels;
576 bool notFound =
true, notFoundLower =
true;
577 while ((i < nbBins) && notFound) {
578 float tf =
static_cast<float>(hist[i]);
580 if ((accu > tLow) && notFoundLower) {
581 lowerThresh =
static_cast<float>(i) *
static_cast<float>(step) + dIMin;
582 notFoundLower =
false;
585 bon =
static_cast<float>(i);
591 std::stringstream errMsg;
592 errMsg <<
"Could not find a bin for which " << upperThresholdRatio * 100.f <<
" percents of the pixels had a gradient lower than the upper threshold.";
595 float upperThresh = bon *
static_cast<float>(step) + dIMin;
596 lowerThresh = std::max<float>(lowerThresh, std::numeric_limits<float>::epsilon());
610 const int val1 = 1, val2 = 2, val3 = 3;
611 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])) +
612 (112.0 *
static_cast<double>(I[r][c + val3] - I[r][c - val3]))) / 8418.0;
624 const int val1 = 1, val2 = 2, val3 = 3;
625 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])) +
626 (112.0 *
static_cast<double>(I[r + val3][c] - I[r - val3][c]))) / 8418.0;
642 template <
class ImageType,
typename FilterType>
645 const unsigned int stop = (size - 1) / 2;
651 for (i = 1; i <= stop; ++i) {
652 result +=
filter[i] *
static_cast<FilterType
>(I[r][c + i] - I[r][c - i]);
670 template <
class ImageType,
typename FilterType>
673 const unsigned int stop = (size - 1) / 2;
679 for (i = 1; i <= stop; ++i) {
680 result +=
filter[i] *
static_cast<FilterType
>(I[r + i][c] - I[r - i][c]);
714 template <
typename ImageType,
typename FilterType>
719 const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
721 const unsigned int inputHeight = I.getHeight(), inputWidth = I.getWidth();
722 If.
resize(inputHeight, inputWidth, 0.0);
725 const unsigned int stopHeight = inputHeight - half_size_y;
726 const unsigned int stopWidth = inputWidth - half_size_x;
727 for (
unsigned int i = half_size_y; i < stopHeight; ++i) {
728 for (
unsigned int j = half_size_x; j < stopWidth; ++j) {
731 bool computeVal = checkBooleanMask(p_mask, i, j);
735 for (
unsigned int a = 0; a < size_y; ++a) {
736 for (
unsigned int b = 0; b < size_x; ++b) {
737 FilterType val =
static_cast<FilterType
>(I[(i + half_size_y) - a][(j + half_size_x) - b]);
738 conv += M[a][b] * val;
747 const unsigned int stopHeight = inputHeight - half_size_y;
748 const unsigned int stopWidth = inputWidth - half_size_x;
749 for (
unsigned int i = half_size_y; i < stopHeight; ++i) {
750 for (
unsigned int j = half_size_x; j < stopWidth; ++j) {
753 bool computeVal = checkBooleanMask(p_mask, i, j);
757 for (
unsigned int a = 0; a < size_y; ++a) {
758 for (
unsigned int b = 0; b < size_x; ++b) {
759 FilterType val =
static_cast<FilterType
>(I[(i - half_size_y) + a][(j - half_size_x) + b]);
760 corr += M[a][b] * val;
779 template <
typename FilterType>
783 const unsigned int half_size_y = size_y / 2, half_size_x = size_x / 2;
786 for (
unsigned int a = 0; a < size_y; ++a) {
787 for (
unsigned int b = 0; b < size_x; ++b) {
788 FilterType val =
static_cast<FilterType
>(I[row - half_size_y + a][col - half_size_x + b]);
789 corr += M[a][b] * val;
795#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
796 template <
typename FilterType>
799 template <
typename FilterType>
816 template <
typename ImageType,
typename FilterType>
818 bool convolve =
false,
const vpImage<bool> *p_mask =
nullptr)
820 const unsigned int size = M.
getRows();
821 const unsigned int half_size = size / 2;
822 const unsigned int height = I.getHeight(), width = I.getWidth();
823 const unsigned int stopV = height - half_size;
824 const unsigned int stopU = width - half_size;
826 Iu.
resize(height, width, 0.0);
827 Iv.
resize(height, width, 0.0);
830 for (
unsigned int v = half_size; v < stopV; ++v) {
831 for (
unsigned int u = half_size; u < stopU; ++u) {
834 bool computeVal = checkBooleanMask(p_mask, v, u);
836 FilterType conv_u = 0;
837 FilterType conv_v = 0;
839 for (
unsigned int a = 0; a < size; ++a) {
840 for (
unsigned int b = 0; b < size; ++b) {
841 FilterType val =
static_cast<FilterType
>(I[(v + half_size) - a][(u + half_size) - b]);
842 conv_u += M[a][b] * val;
843 conv_v += M[b][a] * val;
853 for (
unsigned int v = half_size; v < stopV; ++v) {
854 for (
unsigned int u = half_size; u < stopU; ++u) {
857 bool computeVal = checkBooleanMask(p_mask, v, u);
860 FilterType conv_u = 0;
861 FilterType conv_v = 0;
863 for (
unsigned int a = 0; a < size; ++a) {
864 for (
unsigned int b = 0; b < size; ++b) {
865 FilterType val =
static_cast<FilterType
>(I[(v - half_size) + a][(u - half_size) + b]);
866 conv_u += M[a][b] * val;
867 conv_v += M[b][a] * val;
878#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
879 template<
typename FilterType>
882 template<
typename ImageType>
885 template<
typename FilterType>
888 template<
typename ImageType>
903 template <
typename ImageType,
typename FilterType>
915 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.);
920 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.);
923#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
924 template <
typename ImageType,
typename FilterType>
928 const unsigned int height = I.getHeight();
929 const unsigned int width = I.getWidth();
930 const unsigned int stop1J = (size - 1) / 2;
931 const unsigned int stop2J = width - ((size - 1) / 2);
932 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
934 for (
unsigned int i = 0; i < height; ++i) {
935 for (
unsigned int j = 0; j < stop1J; ++j) {
938 bool computeVal = checkBooleanMask(p_mask, i, j);
940 dIx[i][j] = vpImageFilter::filterXLeftBorder<ImageType, FilterType>(I, i, j, filter, size);
943 for (
unsigned int j = stop1J;
j < stop2J; ++
j) {
946 bool computeVal = checkBooleanMask(p_mask, i, j);
951 for (
unsigned int j = stop2J;
j <
width; ++
j) {
954 bool computeVal = checkBooleanMask(p_mask, i, j);
956 dIx[
i][
j] = vpImageFilter::filterXRightBorder<ImageType, FilterType>(I, i, j, filter, size);
962 static void filterX(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx,
const double *filter,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr);
964 template<
typename ImageType,
typename FilterType>
965 static inline FilterType filterX(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
967 const unsigned int stop = (size - 1) / 2;
968 FilterType result =
static_cast<FilterType
>(0.);
970 for (
unsigned int i = 1;
i <= stop; ++
i) {
971 result += filter[
i] *
static_cast<FilterType
>(I[
r][c +
i] + I[
r][c -
i]);
973 return result + (filter[0] *
static_cast<FilterType
>(I[
r][c]));
976#ifndef DOXYGEN_SHOULD_SKIP_THIS
977 static void filterXR(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx,
const double *filter,
unsigned int size);
978 static void filterXG(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx,
const double *filter,
unsigned int size);
979 static void filterXB(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx,
const double *filter,
unsigned int size);
981 static double filterXR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
982 static double filterXG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
983 static double filterXB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
985 static double filterXLeftBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
986 static double filterXLeftBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
987 static double filterXLeftBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
988 static double filterXRightBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
989 static double filterXRightBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
990 static double filterXRightBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
992 template <
typename ImageType,
typename FilterType>
993 static inline FilterType filterXLeftBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
994 const FilterType *filter,
unsigned int size)
996 const unsigned int stop = (size - 1) / 2;
997 FilterType result =
static_cast<FilterType
>(0.);
999 for (
unsigned int i = 1;
i <= stop; ++
i) {
1001 result += filter[
i] *
static_cast<FilterType
>(I[
r][c +
i] + I[
r][c -
i]);
1004 result += filter[
i] *
static_cast<FilterType
>(I[
r][c +
i] + I[
r][
i - c]);
1007 return result + (filter[0] *
static_cast<FilterType
>(I[
r][c]));
1010 template <
typename ImageType,
typename FilterType>
1011 static inline FilterType filterXRightBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
1012 const FilterType *filter,
unsigned int size)
1014 const unsigned int stop = (size - 1) / 2;
1016 FilterType result =
static_cast<FilterType
>(0.);
1017 const unsigned int twice = 2;
1019 for (
unsigned int i = 1;
i <= stop; ++
i) {
1020 if ((c + i) < width) {
1021 result += filter[
i] *
static_cast<FilterType
>(I[
r][c +
i] + I[
r][c -
i]);
1024 result += filter[
i] *
static_cast<FilterType
>(I[
r][((twice *
width) - c) -
i - 1] + I[
r][c -
i]);
1027 return result + (filter[0] *
static_cast<FilterType
>(I[
r][c]));
1031#ifndef DOXYGEN_SHOULD_SKIP_THIS
1041 template<
class Color,
typename FilterType>
1042 static inline typename std::enable_if<!std::is_same<Color, vpRGBa>::value,
void>::type
1043 filterChannel(
const Color &in, vpColVector &out,
const FilterType &coeff)
1058 template<
class Color,
typename FilterType>
1059 static inline typename std::enable_if<std::is_same<Color, vpRGBa>::value,
void>::type
1060 filterChannel(
const Color &in, vpColVector &out,
const FilterType &coeff)
1078 template<
class Color,
typename FilterType>
1080 filterChannel(
const Color &in1,
const Color &in2, vpColVector &out,
const FilterType &coeff)
1101 template<
typename ImageType,
typename OutputType,
typename FilterType>
1105 const int height =
static_cast<int>(I.getHeight());
1106 const int width =
static_cast<int>(I.getWidth());
1107 const int stop1J =
static_cast<int>((size - 1) / 2);
1108 const int stop2J =
static_cast<int>(width - ((size - 1) / 2));
1109 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1113#ifdef VISP_HAVE_OPENMP
1114 int iam, nt, ipoints, npoints(height);
1115#pragma omp parallel default(shared) private(iam, nt, ipoints, istart, istop)
1117 iam = omp_get_thread_num();
1118 nt = omp_get_num_threads();
1119 ipoints = npoints / nt;
1121 istart = iam * ipoints;
1124 ipoints = npoints - istart;
1126 istop = istart + ipoints;
1128 for (
int i = istart; i < istop; ++i) {
1129 for (
int j = 0; j < stop1J; ++j) {
1132 bool computeVal = checkBooleanMask(p_mask, i, j);
1134 vpImageFilter::filterXLeftBorder(I, dIx[i][j], i, j,
filter, size);
1138 for (
int j = stop1J; j < stop2J; ++j) {
1141 bool computeVal = checkBooleanMask(p_mask, i, j);
1146 for (
int j = stop2J; j < width; ++j) {
1149 bool computeVal = checkBooleanMask(p_mask, i, j);
1151 vpImageFilter::filterXRightBorder(I, dIx[i][j], i, j,
filter, size);
1155#ifdef VISP_HAVE_OPENMP
1174 template<
typename ImageType,
typename OutputType,
typename FilterType>
1175 static inline typename std::enable_if<std::is_arithmetic<ImageType>::value,
void>::type
1178 const unsigned int stop = (size - 1) / 2;
1179 FilterType res =
filter[0] *
static_cast<FilterType
>(I[r][c]);
1181 for (
unsigned int i = 1; i <= stop; ++i) {
1182 res +=
filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
1184 result =
static_cast<FilterType
>(res);
1201 template<
typename ImageType,
typename OutputType,
typename FilterType>
1202 static inline typename std::enable_if<!std::is_arithmetic<ImageType>::value,
void>::type
1205 const unsigned int stop = (size - 1) / 2;
1206#ifdef VISP_HAVE_OPENMP
1211 filterChannel(I[r][c], res,
filter[0]);
1213 for (
unsigned int i = 1; i <= stop; ++i) {
1214 filterChannel(I[r][c + i], I[r][c - i], res,
filter[i]);
1216 result = OutputType(res);
1219#ifndef DOXYGEN_SHOULD_SKIP_THIS
1235 template<
typename ImageType,
typename OutputType,
typename FilterType>
1236 static inline typename std::enable_if<std::is_arithmetic<ImageType>::value,
void>::type
1237 filterXLeftBorder(
const vpImage<ImageType> &I, OutputType &result,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
1239 const unsigned int stop = (size - 1) / 2;
1240 FilterType res = filter[0] *
static_cast<FilterType
>(I[r][c]);
1242 for (
unsigned int i = 1; i <= stop; ++i) {
1244 res += filter[i] *
static_cast<FilterType
>(I[r][c + i] + I[r][c - i]);
1247 res += filter[
i] *
static_cast<FilterType
>(I[
r][c +
i] + I[
r][
i - c]);
1250 result =
static_cast<OutputType
>(res);
1268 template<
typename ImageType,
typename OutputType,
typename FilterType>
1269 static inline typename std::enable_if<!std::is_arithmetic<ImageType>::value,
void>::type
1270 filterXLeftBorder(
const vpImage<ImageType> &I, OutputType &result,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
1272 const unsigned int stop = (size - 1) / 2;
1273#ifdef VISP_HAVE_OPENMP
1274 vpColVector res(ImageType::nbChannels);
1276 static vpColVector res(ImageType::nbChannels);
1278 filterChannel(I[r][c], res, filter[0]);
1280 for (
unsigned int i = 1;
i <= stop; ++
i) {
1282 filterChannel(I[r][c + i], I[r][c - i], res, filter[i]);
1285 filterChannel(I[r][c + i], I[r][i - c], res, filter[i]);
1288 result = OutputType(res);
1306 template<
typename ImageType,
typename OutputType,
typename FilterType>
1307 static inline typename std::enable_if<std::is_arithmetic<ImageType>::value,
void>::type
1308 filterXRightBorder(
const vpImage<ImageType> &I, OutputType &result,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
1310 const unsigned int stop = (size - 1) / 2;
1312 const unsigned int twice = 2;
1313 FilterType res = filter[0] *
static_cast<FilterType
>(I[
r][c]);
1315 for (
unsigned int i = 1;
i <= stop; ++
i) {
1316 if ((c + i) < width) {
1317 res += filter[
i] *
static_cast<FilterType
>(I[
r][c +
i] + I[
r][c -
i]);
1320 res += filter[
i] *
static_cast<FilterType
>(I[
r][((twice *
width) - c) -
i - 1] + I[
r][c -
i]);
1323 result =
static_cast<FilterType
>(res);
1341 template<
typename ImageType,
typename OutputType,
typename FilterType>
1342 static inline typename std::enable_if<!std::is_arithmetic<ImageType>::value,
void>::type
1343 filterXRightBorder(
const vpImage<ImageType> &I, OutputType &result,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
1345 const unsigned int stop = (size - 1) / 2;
1347 const unsigned int twice = 2;
1348#ifdef VISP_HAVE_OPENMP
1349 vpColVector res(ImageType::nbChannels);
1351 static vpColVector res(ImageType::nbChannels);
1353 filterChannel(I[r][c], res, filter[0]);
1355 for (
unsigned int i = 1;
i <= stop; ++
i) {
1356 if ((c + i) < width) {
1357 filterChannel(I[r][c + i], I[r][c - i], res, filter[i]);
1360 filterChannel(I[r][((twice * width) - c) - i - 1], I[r][c - i], res, filter[i]);
1363 result = OutputType(res);
1369#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
1370 static void filterY(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx,
const double *filter,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr);
1372 template<
typename ImageType,
typename FilterType>
1373 static void filterY(
const vpImage<ImageType> &I, vpImage<FilterType> &dIy,
const FilterType *filter,
unsigned int size,
1374 const vpImage<bool> *p_mask =
nullptr)
1377 const unsigned int stop1I = (size - 1) / 2;
1378 const unsigned int stop2I =
height - ((size - 1) / 2);
1379 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1381 for (
unsigned int i = 0;
i < stop1I; ++
i) {
1382 for (
unsigned int j = 0;
j <
width; ++
j) {
1385 bool computeVal = checkBooleanMask(p_mask, i, j);
1387 dIy[
i][
j] = vpImageFilter::filterYTopBorder<ImageType, FilterType>(I, i, j, filter, size);
1391 for (
unsigned int i = stop1I;
i < stop2I; ++
i) {
1392 for (
unsigned int j = 0;
j <
width; ++
j) {
1395 bool computeVal = checkBooleanMask(p_mask, i, j);
1401 for (
unsigned int i = stop2I;
i <
height; ++
i) {
1402 for (
unsigned int j = 0;
j <
width; ++
j) {
1405 bool computeVal = checkBooleanMask(p_mask, i, j);
1407 dIy[
i][
j] = vpImageFilter::filterYBottomBorder<ImageType, FilterType>(I, i, j, filter, size);
1413 template<
typename ImageType,
typename FilterType>
1414 static inline FilterType filterY(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
1416 const unsigned int stop = (size - 1) / 2;
1417 FilterType result =
static_cast<FilterType
>(0.);
1419 for (
unsigned int i = 1;
i <= stop; ++
i) {
1420 result += filter[
i] *
static_cast<FilterType
>(I[
r +
i][c] + I[
r -
i][c]);
1422 return result + (filter[0] *
static_cast<FilterType
>(I[
r][c]));
1424#ifndef DOXYGEN_SHOULD_SKIP_THIS
1425 static void filterYR(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx,
const double *filter,
unsigned int size);
1426 static void filterYG(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx,
const double *filter,
unsigned int size);
1427 static void filterYB(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &dIx,
const double *filter,
unsigned int size);
1429 static double filterYR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1430 static double filterYG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1431 static double filterYB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1433 static double filterYTopBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1434 static double filterYTopBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1435 static double filterYTopBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1436 static double filterYBottomBorderR(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1437 static double filterYBottomBorderG(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1438 static double filterYBottomBorderB(
const vpImage<vpRGBa> &I,
unsigned int r,
unsigned int c,
const double *filter,
unsigned int size);
1440 template<
typename ImageType,
typename FilterType>
1441 static inline FilterType filterYTopBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
1442 const FilterType *filter,
unsigned int size)
1444 const unsigned int stop = (size - 1) / 2;
1445 FilterType result =
static_cast<FilterType
>(0.);
1447 for (
unsigned int i = 1;
i <= stop; ++
i) {
1449 result += filter[
i] *
static_cast<FilterType
>(I[
r +
i][c] + I[
r -
i][c]);
1452 result += filter[
i] *
static_cast<FilterType
>(I[
r +
i][c] + I[
i -
r][c]);
1455 return result + (filter[0] *
static_cast<FilterType
>(I[
r][c]));
1458 template<
typename ImageType,
typename FilterType>
1459 static inline FilterType filterYBottomBorder(
const vpImage<ImageType> &I,
unsigned int r,
unsigned int c,
1460 const FilterType *filter,
unsigned int size)
1463 const unsigned int stop = (size - 1) / 2;
1464 FilterType result =
static_cast<FilterType
>(0.);
1465 const unsigned int twiceHeight = 2 *
height;
1466 for (
unsigned int i = 1;
i <= stop; ++
i) {
1467 if ((r + i) < height) {
1468 result += filter[
i] *
static_cast<FilterType
>(I[
r +
i][c] + I[
r -
i][c]);
1471 result += filter[
i] *
static_cast<FilterType
>(I[(twiceHeight -
r) -
i - 1][c] + I[
r -
i][c]);
1474 return result + (filter[0] *
static_cast<FilterType
>(I[
r][c]));
1492 template<
typename ImageType,
typename OutputType,
typename FilterType>
1496 const unsigned int height = I.getHeight(), width = I.getWidth();
1497 const unsigned int stop1I = (size - 1) / 2;
1498 const unsigned int stop2I = height - ((size - 1) / 2);
1499 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
1501 unsigned int jstart = 0;
1502 unsigned int jstop = width;
1503#ifdef VISP_HAVE_OPENMP
1504 unsigned int iam, nt, jpoints, npoints(width);
1505#pragma omp parallel default(shared) private(iam, nt, jpoints, jstart, jstop)
1507 iam = omp_get_thread_num();
1508 nt = omp_get_num_threads();
1509 jpoints = npoints / nt;
1511 jstart = iam * jpoints;
1514 jpoints = npoints - jstart;
1516 jstop = jstart + jpoints;
1518 for (
unsigned int i = 0; i < stop1I; ++i) {
1519 for (
unsigned int j = jstart; j < jstop; ++j) {
1522 bool computeVal = checkBooleanMask(p_mask, i, j);
1524 vpImageFilter::filterYTopBorder(I, dIy[i][j], i, j,
filter, size);
1528 for (
unsigned int i = stop1I; i < stop2I; ++i) {
1529 for (
unsigned int j = jstart; j < jstop; ++j) {
1532 bool computeVal = checkBooleanMask(p_mask, i, j);
1538 for (
unsigned int i = stop2I; i < height; ++i) {
1539 for (
unsigned int j = jstart; j < jstop; ++j) {
1542 bool computeVal = checkBooleanMask(p_mask, i, j);
1544 vpImageFilter::filterYBottomBorder(I, dIy[i][j], i, j,
filter, size);
1547#ifdef VISP_HAVE_OPENMP
1567 template<
typename ImageType,
typename OutputType,
typename FilterType>
1568 static inline typename std::enable_if<std::is_arithmetic<ImageType>::value,
void>::type
1571 const unsigned int stop = (size - 1) / 2;
1572 FilterType res = (
filter[0] *
static_cast<FilterType
>(I[r][c]));
1574 for (
unsigned int i = 1; i <= stop; ++i) {
1575 res +=
filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
1577 result =
static_cast<OutputType
>(res);
1594 template<
typename ImageType,
typename OutputType,
typename FilterType>
1595 static inline typename std::enable_if<!std::is_arithmetic<ImageType>::value,
void>::type
1598 const unsigned int stop = (size - 1) / 2;
1599#ifdef VISP_HAVE_OPENMP
1604 filterChannel(I[r][c], res,
filter[0]);
1606 for (
unsigned int i = 1; i <= stop; ++i) {
1607 filterChannel(I[r + i][c], I[r - i][c], res,
filter[i]);
1609 result = OutputType(res);
1612#ifndef DOXYGEN_SHOULD_SKIP_THIS
1628 template<
typename ImageType,
typename OutputType,
typename FilterType>
1629 static inline typename std::enable_if<std::is_arithmetic<ImageType>::value,
void>::type
1630 filterYTopBorder(
const vpImage<ImageType> &I, OutputType &result,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
1632 const unsigned int stop = (size - 1) / 2;
1633 FilterType res = (filter[0] *
static_cast<FilterType
>(I[r][c]));
1635 for (
unsigned int i = 1; i <= stop; ++i) {
1637 res += filter[i] *
static_cast<FilterType
>(I[r + i][c] + I[r - i][c]);
1640 res += filter[
i] *
static_cast<FilterType
>(I[
r +
i][c] + I[
i -
r][c]);
1643 result =
static_cast<OutputType
>(res);
1661 template<
typename ImageType,
typename OutputType,
typename FilterType>
1662 static inline typename std::enable_if<!std::is_arithmetic<ImageType>::value,
void>::type filterYTopBorder(
const vpImage<ImageType> &I, OutputType &result,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
1664 const unsigned int stop = (size - 1) / 2;
1665#ifdef VISP_HAVE_OPENMP
1666 vpColVector res(ImageType::nbChannels);
1668 static vpColVector res(ImageType::nbChannels);
1670 filterChannel(I[r][c], res, filter[0]);
1672 for (
unsigned int i = 1;
i <= stop; ++
i) {
1674 filterChannel(I[r + i][c], I[r - i][c], res, filter[i]);
1677 filterChannel(I[r + i][c], I[i - r][c], res, filter[i]);
1680 result = OutputType(res);
1698 template<
typename ImageType,
typename OutputType,
typename FilterType>
1699 static inline typename std::enable_if<std::is_arithmetic<ImageType>::value,
void>::type filterYBottomBorder(
const vpImage<ImageType> &I, OutputType &result,
unsigned int r,
unsigned int c,
1700 const FilterType *filter,
unsigned int size)
1703 const unsigned int stop = (size - 1) / 2;
1704 const unsigned int twiceHeight = 2 *
height;
1705 FilterType res = (filter[0] *
static_cast<FilterType
>(I[
r][c]));
1706 for (
unsigned int i = 1;
i <= stop; ++
i) {
1707 if ((r + i) < height) {
1708 res += filter[
i] *
static_cast<FilterType
>(I[
r +
i][c] + I[
r -
i][c]);
1711 res += filter[
i] *
static_cast<FilterType
>(I[(twiceHeight -
r) -
i - 1][c] + I[
r -
i][c]);
1714 result =
static_cast<OutputType
>(res);
1732 template<
typename ImageType,
typename OutputType,
typename FilterType>
1733 static inline typename std::enable_if<!std::is_arithmetic<ImageType>::value,
void>::type filterYBottomBorder(
const vpImage<ImageType> &I, OutputType &result,
unsigned int r,
unsigned int c,
const FilterType *filter,
unsigned int size)
1735 const unsigned int stop = (size - 1) / 2;
1737 const unsigned int twiceHeight = 2 *
height;
1738#ifdef VISP_HAVE_OPENMP
1739 vpColVector res(ImageType::nbChannels);
1741 static vpColVector res(ImageType::nbChannels);
1743 filterChannel(I[r][c], res, filter[0]);
1745 for (
unsigned int i = 1;
i <= stop; ++
i) {
1746 if ((r + i) < height) {
1747 filterChannel(I[r + i][c], I[r - i][c], res, filter[i]);
1750 filterChannel(I[(twiceHeight - r) - i - 1][c], I[r - i][c], res, filter[i]);
1753 result = OutputType(res);
1773#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
1774 template <
typename ImageType,
typename OutputType,
typename FilterType =
float>
1779 if (size == 0 || size-1 > I.getWidth() || size-1 > I.getHeight()) {
1780 std::ostringstream oss;
1781 oss <<
"Image size (" << I.getWidth() <<
"x" << I.getHeight() <<
") is too small for the Gaussian kernel ("
1782 <<
"size=" << size <<
"), min size is " << (size-1);
1786 FilterType *fg =
new FilterType[(size + 1) / 2];
1795 template <
typename ImageType,
typename OutputType>
1800 gaussianBlur<ImageType, OutputType, float>(I, GI, size, sigma, normalize, p_mask);
1803 template <
typename ImageType,
typename OutputType,
typename FilterType >
1805 gaussianBlur(
const vpImage<ImageType> &I, vpImage<OutputType> &GI,
unsigned int size = 7, FilterType sigma = 0.,
bool normalize =
true,
1806 const vpImage<bool> *p_mask =
nullptr)
1809 std::ostringstream oss;
1810 oss <<
"Image size (" << I.
getWidth() <<
"x" << I.
getHeight() <<
") is too small for the Gaussian kernel ("
1811 <<
"size=" << size <<
"), min size is " << (size-1);
1815 FilterType *fg =
new FilterType[(size + 1) / 2];
1817 vpImage<OutputType> GIx;
1825#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
1826 static void gaussianBlur(
const vpImage<vpRGBa> &I, vpImage<vpRGBa> &GI,
unsigned int size = 7,
double sigma = 0.,
bool normalize =
true,
1827 const vpImage<bool> *p_mask =
nullptr);
1840 return ((15.0 * fr[r][c]) +
1841 (12.0 * (fr[r - 1][c] + fr[r][c - 1] + fr[r + 1][c] + fr[r][c + 1])) +
1842 (9.0 * (fr[r - 1][c - 1] + fr[r + 1][c - 1] + fr[r - 1][c + 1] + fr[r + 1][c + 1])) +
1843 (5.0 * (fr[r - val2][c] + fr[r][c - val2] + fr[r + val2][c] + fr[r][c + val2])) +
1844 (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] +
1845 fr[r + val2][c + 1] + fr[r - 1][c + val2] + fr[r + 1][c + val2])) +
1846 (2.0 * (fr[r - val2][c - val2] + fr[r + val2][c - val2] + fr[r - val2][c + val2] + fr[r + val2][c + val2]))) / 159.0;
1869 template<
typename FilterType>
1872 const unsigned int mod2 = 2;
1873 if ((size % mod2) != 1) {
1878 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1881 int middle = (
static_cast<int>(size) - 1) / 2;
1882 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(
static_cast<double>(sigma)));
1883 FilterType coef1 =
static_cast<FilterType
>(1. / (
static_cast<double>(sigma) * sqrt(2. * M_PI)));
1884 FilterType v_2_sigma2 =
static_cast<FilterType
>(2. *
static_cast<double>(sigma2));
1885 for (
int i = 0; i <= middle; ++i) {
1886 filter[i] = coef1 *
static_cast<FilterType
>(exp(
static_cast<double>(-
static_cast<FilterType
>(i * i) / v_2_sigma2)));
1891 const unsigned int val2 = 2U;
1892 for (
int i = 1; i <= middle; ++i) {
1897 for (
int i = 0; i <= middle; ++i) {
1917 template <
typename FilterType>
1920 const unsigned int mod2 = 2;
1921 if ((size % mod2) != 1) {
1926 sigma =
static_cast<FilterType
>((size - 1) / 6.0);
1930 int middle = (
static_cast<int>(size) - 1) / half;
1931 FilterType sigma2 =
static_cast<FilterType
>(
vpMath::sqr(
static_cast<double>(sigma)));
1932 FilterType coef_1 =
static_cast<FilterType
>(1. / (
static_cast<double>(sigma) * sqrt(2. * M_PI)));
1933 FilterType coef_1_over_2 = coef_1 /
static_cast<FilterType
>(2.);
1934 FilterType v_2_coef_1 =
static_cast<FilterType
>(2.) * coef_1;
1935 FilterType v_2_sigma2 =
static_cast<FilterType
>(2.) * sigma2;
1937 for (
int i = 1; i <= middle; ++i) {
1938 FilterType i_plus_1 =
static_cast<FilterType
>(i + 1);
1939 FilterType i_minus_1 =
static_cast<FilterType
>(i - 1);
1940 filter[i] = -coef_1_over_2 * (
static_cast<FilterType
>(exp(-
static_cast<double>(i_plus_1 * i_plus_1 / v_2_sigma2))) -
static_cast<FilterType
>(exp(-
static_cast<double>(i_minus_1 * i_minus_1 / v_2_sigma2))));
1944 FilterType sum =
static_cast<FilterType
>(0);
1945 for (
int i = 1; i <= middle; ++i) {
1946 FilterType i_ =
static_cast<FilterType
>(i);
1947 sum += v_2_coef_1 *
static_cast<FilterType
>(exp(-
static_cast<double>(i_ * i_ / v_2_sigma2)));
1951 for (
int i = 1; i <= middle; ++i) {
1958 template<
typename FilterType>
1961 const unsigned int height = I.getHeight(), width = I.getWidth();
1962 const unsigned int stopJ = width - 3;
1963 const unsigned int val_3 = 3;
1964 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
1966 for (
unsigned int i = 0; i < height; ++i) {
1967 for (
unsigned int j = 0; j < val_3; ++j) {
1969 bool computeVal = (p_mask ==
nullptr);
1971 dIx[i][j] =
static_cast<FilterType
>(0);
1974 for (
unsigned int j = 3; j < stopJ; ++j) {
1977 bool computeVal = checkBooleanMask(p_mask, i, j);
1982 for (
unsigned int j = stopJ; j < width; ++j) {
1984 bool computeVal = (p_mask ==
nullptr);
1986 dIx[i][j] =
static_cast<FilterType
>(0);
1992 template <
typename ImageType,
typename FilterType>
1995 const unsigned int height = I.getHeight(), width = I.getWidth();
1996 const unsigned int stop1J = (size - 1) / 2;
1997 const unsigned int stop2J = width - ((size - 1) / 2);
1998 resizeAndInitializeIfNeeded(p_mask, height, width, dIx);
2000 for (
unsigned int i = 0; i < height; ++i) {
2001 for (
unsigned int j = 0; j < stop1J; ++j) {
2003 bool computeVal = (p_mask ==
nullptr);
2005 dIx[i][j] =
static_cast<FilterType
>(0);
2008 for (
unsigned int j = stop1J; j < stop2J; ++j) {
2011 bool computeVal = checkBooleanMask(p_mask, i, j);
2016 for (
unsigned int j = stop2J; j < width; ++j) {
2018 bool computeVal = (p_mask ==
nullptr);
2020 dIx[i][j] =
static_cast<FilterType
>(0);
2037 template <
typename ImageType,
typename FilterType>
2039 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
2046#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
2059 template <
typename ArithmeticType,
typename FilterType,
bool useFullScale>
2062 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
2063 GIx.
resize(nbRows, nbCols, 0.);
2064 std::vector<FilterType>
filter(3);
2072 filter = { 3., 10., 3. };
2079 for (
unsigned char i = 0; i < 3; ++i) {
2083#ifdef VISP_HAVE_OPENMP
2084 if (nbThread == 1) {
2085 gradientFilterXMonothread(I, GIx,
filter, p_mask);
2088 gradientFilterXMultithread(I, GIx,
filter, nbThread, p_mask);
2092 gradientFilterXMonothread(I, GIx,
filter, p_mask);
2098 template <
typename FilterType>
2101 const unsigned int height = I.getHeight(), width = I.getWidth();
2102 const unsigned int stopI = height - 3;
2103 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
2104 const unsigned int val_3 = 3;
2105 for (
unsigned int i = 0; i < val_3; ++i) {
2106 for (
unsigned int j = 0; j < width; ++j) {
2109 bool computeVal = checkBooleanMask(p_mask, i, j);
2111 dIy[i][j] =
static_cast<FilterType
>(0);
2115 for (
unsigned int i = 3; i < stopI; ++i) {
2116 for (
unsigned int j = 0; j < width; ++j) {
2119 bool computeVal = checkBooleanMask(p_mask, i, j);
2125 for (
unsigned int i = stopI; i < height; ++i) {
2126 for (
unsigned int j = 0; j < width; ++j) {
2129 bool computeVal = checkBooleanMask(p_mask, i, j);
2131 dIy[i][j] =
static_cast<FilterType
>(0);
2137 template <
typename ImageType,
typename FilterType>
2140 const unsigned int height = I.getHeight(), width = I.getWidth();
2141 const unsigned int stop1I = (size - 1) / 2;
2142 const unsigned int stop2I = height - ((size - 1) / 2);
2143 resizeAndInitializeIfNeeded(p_mask, height, width, dIy);
2145 for (
unsigned int i = 0; i < stop1I; ++i) {
2146 for (
unsigned int j = 0; j < width; ++j) {
2149 bool computeVal = checkBooleanMask(p_mask, i, j);
2151 dIy[i][j] =
static_cast<FilterType
>(0);
2155 for (
unsigned int i = stop1I; i < stop2I; ++i) {
2156 for (
unsigned int j = 0; j < width; ++j) {
2159 bool computeVal = checkBooleanMask(p_mask, i, j);
2165 for (
unsigned int i = stop2I; i < height; ++i) {
2166 for (
unsigned int j = 0; j < width; ++j) {
2169 bool computeVal = checkBooleanMask(p_mask, i, j);
2171 dIy[i][j] =
static_cast<FilterType
>(0);
2188 template <
typename ImageType,
typename FilterType>
2190 const FilterType *gaussianDerivativeKernel,
unsigned int size,
const vpImage<bool> *p_mask =
nullptr)
2197#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
2210 template <
typename ArithmeticType,
typename FilterType,
bool useFullScale>
2213 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
2214 GIy.
resize(nbRows, nbCols);
2215 std::vector<FilterType>
filter(3);
2228 filter = { 3., 10., 3. };
2234 for (
unsigned char i = 0; i < 3; ++i) {
2238#ifdef VISP_HAVE_OPENMP
2239 if (nbThread == 1) {
2240 gradientFilterYMonothread(I, GIy,
filter, p_mask);
2243 gradientFilterYMultithread(I, GIy,
filter, nbThread, p_mask);
2247 gradientFilterYMonothread(I, GIy,
filter, p_mask);
2259 template <
typename FilterType>
2262 const unsigned int actualKernelSize = (size * 2) + 1;
2265 std::stringstream errMsg;
2266 errMsg <<
"Cannot get Scharr kernel of size " << actualKernelSize <<
" != 3";
2283 template <
typename FilterType>
2287 static const FilterType ScharrY3x3[9] = { -3.0, -10.0, -3.0, 0.0, 0.0, 0.0, 3.0, 10.0, 3.0 };
2291 std::stringstream errMsg;
2292 errMsg <<
"Cannot get Scharr kernel of size " << ((size * 2) + 1) <<
" != 3";
2296 const unsigned int kernel_size = (size * 2) + 1;
2297 const unsigned int kernel3 = 3;
2298 if (kernel_size == kernel3) {
2299 memcpy(
filter, ScharrY3x3, kernel_size * kernel_size *
sizeof(FilterType));
2300 return static_cast<FilterType
>(1.0 / 32.0);
2303 return static_cast<FilterType
>(0.);
2313 template <
typename FilterType>
2316 const unsigned int maxSize = 20;
2320 if (size > maxSize) {
2324 const unsigned int kernel_size = (size * 2) + 1;
2338 template <
typename FilterType>
2342 static const FilterType SobelY3x3[9] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 };
2343 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,
2344 0.0, 0.0, 2.0, 8.0, 12.0, 8.0, 2.0, 1.0, 4.0, 6.0, 4.0, 1.0 };
2345 static const FilterType SobelY7x7[49] = { -1, -6, -15, -20, -15, -6, -1, -4, -24, -60, -80, -60, -24, -4, -5, -30, -75,
2346 -100, -75, -30, -5, 0, 0, 0, 0, 0, 0, 0, 5, 30, 75, 100, 75, 30,
2347 5, 4, 24, 60, 80, 60, 24, 4, 1, 6, 15, 20, 15, 6, 1 };
2349 const unsigned int index_0 = 0;
2350 const unsigned int index_1 = 1;
2351 const unsigned int index_2 = 2;
2352 smoothingKernel[index_0][index_0] = 1.0;
2353 smoothingKernel[index_0][index_1] = 2.0;
2354 smoothingKernel[index_0][index_2] = 1.0;
2355 smoothingKernel[index_1][index_0] = 2.0;
2356 smoothingKernel[index_1][index_1] = 4.0;
2357 smoothingKernel[index_1][index_2] = 2.0;
2358 smoothingKernel[index_2][index_0] = 1.0;
2359 smoothingKernel[index_2][index_1] = 2.0;
2360 smoothingKernel[index_2][index_2] = 1.0;
2362 const unsigned int maxSize = 20;
2366 if (size > maxSize) {
2370 const unsigned int kernel_size = (size * 2) + 1;
2371 FilterType scale =
static_cast<FilterType
>(1. / 8.);
2372 const unsigned int kernel3 = 3, kernel5 = 5, kernel7 = 7;
2373 if (kernel_size == kernel3) {
2374 memcpy(
filter, SobelY3x3, kernel_size * kernel_size *
sizeof(FilterType));
2377 scale *=
static_cast<FilterType
>(1. / 16.);
2378 if (kernel_size == kernel5) {
2379 memcpy(
filter, SobelY5x5, kernel_size * kernel_size *
sizeof(FilterType));
2382 scale *=
static_cast<FilterType
>(1. / 16.);
2383 if (kernel_size == kernel7) {
2384 memcpy(
filter, SobelY7x7, kernel_size * kernel_size *
sizeof(FilterType));
2389 memcpy(sobelY.
data, SobelY7x7, sobelY.
getRows() * sobelY.
getCols() *
sizeof(FilterType));
2390 for (
unsigned int i = 4; i <= size; ++i) {
2393 scale *=
static_cast<FilterType
>(1. / 16.);
2401#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
2402 static float median(
const cv::Mat &cv_I);
2407#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
2421 template <
typename ArithmeticType,
typename FilterType,
bool useFullScale>
2424 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
2425 GIx.
resize(nbRows, nbCols, 0.);
2426 GIy.
resize(nbRows, nbCols, 0.);
2443 template<
typename ImageType>
2446 if (p_mask ==
nullptr) {
2448 I.resize(height, width);
2452 I.
resize(height, width,
static_cast<ImageType
>(0));
2465 static bool checkBooleanMask(
const vpImage<bool> *p_mask,
const unsigned int &r,
const unsigned int &c)
2467 bool computeVal =
true;
2468#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
2469 if (p_mask !=
nullptr)
2474 computeVal = (*p_mask)[
r][c];
2487 static bool checkBooleanMask(
const vpImage<bool> *p_mask,
const int &
id)
2489 bool computeVal =
true;
2490#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
2491 if (p_mask !=
nullptr)
2496 computeVal = p_mask->
bitmap[id];
2503#if ((__cplusplus <= 199711L) || (defined(_MSVC_LANG) && (_MSVC_LANG == 199711L)))
2505 template <
typename FilterType>
2506 static void scaleFilter(vpArray2D<FilterType> &filter,
const float &scale)
2508 const unsigned int nbRows = filter.
getRows();
2509 const unsigned int nbCols = filter.
getCols();
2510 for (
unsigned int r = 0;
r < nbRows; ++
r) {
2511 for (
unsigned int c = 0; c < nbCols; ++c) {
2512 filter[
r][c] = filter[
r][c] * scale;
2518#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
2533 static bool checkBooleanPatch(
const vpImage<bool> *p_mask,
const int &iter,
const int &c,
2534 const int &h,
const int &w,
2535 const bool &isGradientX)
2540 const int maxIter = (
h - 1) * w;
2541 const int minIter =
w;
2545 if (iter < maxIter) {
2550 if (iter < maxIter) {
2555 if (iter > minIter) {
2565 if (iter < maxIter) {
2570 return hasToCompute;
2574 template <
typename HSVType,
bool useFullScale,
typename OutputType>
2575 static typename std::enable_if<std::is_arithmetic<OutputType>::value,
void>::type initGradientFilterDifferenceImageX(
2576 const vpImage<vpHSV<HSVType, useFullScale>> &I, std::vector<OutputType> &Idiff
2579 const unsigned int nbCols = I.
getCols();
2581 Idiff[0] =
static_cast<OutputType
>(I.
bitmap[1].V - I.
bitmap[0].V);
2584 Idiff[nbCols] =
static_cast<OutputType
>(I.
bitmap[nbCols + 1].V - I.
bitmap[nbCols].V);
2586 for (
unsigned int iter = 1;
iter < nbCols - 1; ++
iter) {
2589 Idiff[
iter] = distanceRow0;
2592 OutputType distanceRow1 =
static_cast<OutputType
>(I.
bitmap[nbCols +
iter + 1].V - I.
bitmap[nbCols +
iter].V);
2593 Idiff[nbCols +
iter] = distanceRow1;
2597 template <
typename HSVType,
bool useFullScale,
typename OutputType>
2598 static typename std::enable_if<std::is_arithmetic<OutputType>::value,
void>::type gradientFilterXMonothread(
2599 const vpImage<vpHSV<HSVType, useFullScale>> &I, vpImage<OutputType> &GI,
const std::vector<OutputType> &filter,
2600 const vpImage<bool> *p_mask =
nullptr
2605 const int offsetIdiff = nbCols;
2607 std::vector<OutputType> Idiff(size);
2608 initGradientFilterDifferenceImageX(I, Idiff);
2609 const int resetCounter = nbCols - 1;
2610 const int stopIter = size - (nbCols + 1);
2611 int counter = resetCounter, idCol = 0;
2612 for (
int iter = nbCols;
iter < stopIter; ++
iter) {
2615 OutputType futureDiff = 0.;
2616 if (checkBooleanPatch(p_mask, iter + offsetIdiff, idCol, nbRows, nbCols,
true)) {
2617 futureDiff =
static_cast<OutputType
>(I.
bitmap[
iter + nbCols +1].V - I.
bitmap[
iter + offsetIdiff].V);
2618 Idiff[
iter + offsetIdiff] = futureDiff;
2622 if ((counter != resetCounter)) {
2623 if (checkBooleanMask(p_mask, iter)) {
2624 OutputType gradient = 0.;
2625 int offset =
iter - nbCols;
2626 for (
int i = -1;
i <= 1; ++
i) {
2628 gradient += filter[
i + 1] * (Idiff[offset] + Idiff[offset - 1]);
2637 counter = resetCounter;
2640 if (idCol < resetCounter) {
2649 template <
typename HSVType,
bool useFullScale,
typename OutputType>
2650 static typename std::enable_if<std::is_arithmetic<OutputType>::value,
void>::type initGradientFilterDifferenceImageY(
2651 const vpImage<vpHSV<HSVType, useFullScale>> &I, std::vector<OutputType> &Idiff
2654 const unsigned int nbCols = I.
getCols();
2656 for (
unsigned int iter = 0;
iter < nbCols; ++
iter) {
2658 Idiff[
iter] = distance;
2661 OutputType distance =
static_cast<OutputType
>(I.
bitmap[nbCols + nbCols].V - I.
bitmap[nbCols].V);
2662 Idiff[nbCols] = distance;
2665 template <
typename HSVType,
bool useFullScale,
typename OutputType>
2666 static typename std::enable_if<std::is_arithmetic<OutputType>::value,
void>::type gradientFilterYMonothread(
2667 const vpImage<vpHSV<HSVType, useFullScale>> &I, vpImage<OutputType> &GI,
const std::vector<OutputType> &filter,
2668 const vpImage<bool> *p_mask =
nullptr
2673 const int offsetIdiff = 1;
2675 std::vector<OutputType> Idiff(size);
2676 initGradientFilterDifferenceImageY(I, Idiff);
2677 const int resetCounter = nbCols - 1;
2678 const int stopIter = size - (nbCols + 1);
2679 int counter = resetCounter, iterSign = offsetIdiff;
2680 for (
int iter = nbCols;
iter < stopIter; ++
iter) {
2682 OutputType futureDiff = 0.;
2684 if (checkBooleanPatch(p_mask, iter + offsetIdiff, iterSign, nbRows, nbCols,
false)) {
2685 futureDiff =
static_cast<OutputType
>(I.
bitmap[
iter + nbCols +1].V - I.
bitmap[
iter + offsetIdiff].V);
2686 Idiff[
iter + offsetIdiff] = futureDiff;
2690 if ((counter != resetCounter)) {
2691 if (checkBooleanMask(p_mask, iter)) {
2692 OutputType gradient = 0.;
2693 for (
int i = -1;
i <= 1; ++
i) {
2695 gradient += filter[
i + 1] * (Idiff[
iter +
i] + Idiff[
iter - nbCols +
i]);
2703 counter = resetCounter;
2705 if (iterSign < resetCounter) {
2714#ifdef VISP_HAVE_OPENMP
2715 template <
typename HSVType,
bool useFullScale,
typename OutputType>
2716 static typename std::enable_if<std::is_arithmetic<OutputType>::value,
void>::type initGradientFilterDifferenceImageX(
2717 const vpImage<vpHSV<HSVType, useFullScale>> &I, std::vector<OutputType> &Idiff,
2718 const int &istart,
const int &iam
2721 const int nbCols = I.
getCols();
2724 Idiff[0] =
static_cast<OutputType
>(I.
bitmap[istart - nbCols + 1].V - I.
bitmap[istart - nbCols].V);
2728 Idiff[nbCols] =
static_cast<OutputType
>(I.
bitmap[istart + 1].V - I.
bitmap[istart].V);
2730 for (
int iter = 1;
iter < nbCols - 1; ++
iter) {
2733 OutputType distanceRow0 =
static_cast<OutputType
>(I.
bitmap[istart - nbCols +
iter + 1].V - I.
bitmap[istart - nbCols +
iter].V);
2734 Idiff[
iter] = distanceRow0;
2738 OutputType distanceRow1 =
static_cast<OutputType
>(I.
bitmap[istart +
iter + 1].V - I.
bitmap[istart +
iter].V);
2739 Idiff[nbCols +
iter] = distanceRow1;
2743 template <
typename HSVType,
bool useFullScale,
typename OutputType>
2744 static typename std::enable_if<std::is_arithmetic<OutputType>::value,
void>::type gradientFilterXMultithread(
2745 const vpImage<vpHSV<HSVType, useFullScale>> &I, vpImage<OutputType> &GI,
const std::vector<OutputType> &filter,
2746 const int &maxNbThread,
const vpImage<bool> *p_mask =
nullptr)
2749 const int offsetIdiff = nbCols;
2750 const int resetCounter = nbCols - 1;
2751 const int nrows(nbRows - 1);
2753 int nbThread = maxNbThread;
2755 nbThread = omp_get_max_threads();
2758 if (
static_cast<int>(nbRows) < (4 * nbThread)) {
2759 gradientFilterXMonothread(I, GI, filter, p_mask);
2762 int iam, nt, irows, rstart, istart, istop;
2764#pragma omp parallel default(shared) private(iam, nt, irows, rstart, istart, istop) num_threads(nbThread)
2766 iam = omp_get_thread_num();
2767 nt = omp_get_num_threads();
2770 rstart = irows * iam;
2771 istart = rstart * nbCols;
2774 irows = nrows - rstart;
2776 istop = istart + irows * nbCols;
2778 std::vector<OutputType> Idiff((irows + 2) * nbCols);
2779 std::vector<OutputType> GItemp(irows * nbCols);
2780 initGradientFilterDifferenceImageX(I, Idiff, istart, iam);
2782 int counter = resetCounter, idCol = 0;
2783 int iterStart = (iam != 0 ? istart : istart + nbCols);
2784 for (
int iter = iterStart;
iter < istop; ++
iter) {
2787 OutputType futureDiff = 0.;
2788 if (checkBooleanPatch(p_mask, iter + offsetIdiff, idCol, nbRows, nbCols,
true)) {
2789 futureDiff =
static_cast<OutputType
>(I.
bitmap[
iter + nbCols +1].V - I.
bitmap[
iter + offsetIdiff].V);
2790 Idiff[
iter + 2 * offsetIdiff - istart] = futureDiff;
2794 if ((counter != resetCounter)) {
2795 if (checkBooleanMask(p_mask, iter)) {
2796 OutputType gradient = 0.;
2797 int offset =
iter - istart;
2798 for (
int i = -1;
i <= 1; ++
i) {
2800 gradient += filter[
i + 1] * (Idiff[offset] + Idiff[offset - 1]);
2803 GItemp[
iter - istart] = gradient;
2809 counter = resetCounter;
2812 if (idCol < resetCounter) {
2821 std::memcpy(GI.
bitmap + istart, GItemp.data(), GItemp.size() *
sizeof(OutputType));
2826 template <
typename HSVType,
bool useFullScale,
typename OutputType>
2827 static typename std::enable_if<std::is_arithmetic<OutputType>::value,
void>::type initGradientFilterDifferenceImageY(
2828 const vpImage<vpHSV<HSVType, useFullScale>> &I, std::vector<OutputType> &Idiff,
2832 const int nbCols = I.
getCols();
2835 for (
int iter = istart - nbCols;
iter < istart; ++
iter) {
2837 Idiff[idDiff] = distance;
2841 OutputType distance =
static_cast<OutputType
>(I.
bitmap[nbCols + nbCols].V - I.
bitmap[nbCols].V);
2842 Idiff[nbCols] = distance;
2845 template <
typename HSVType,
bool useFullScale,
typename OutputType>
2846 static typename std::enable_if<std::is_arithmetic<OutputType>::value,
void>::type gradientFilterYMultithread(
2847 const vpImage<vpHSV<HSVType, useFullScale>> &I, vpImage<OutputType> &GI,
const std::vector<OutputType> &filter,
2848 const int &maxNbThread,
const vpImage<bool> *p_mask =
nullptr)
2851 const int offsetIdiff = 1;
2852 const int resetCounter = nbCols - 1;
2853 const int nrows(nbRows - 1);
2855 int nbThread = maxNbThread;
2857 nbThread = omp_get_max_threads();
2860 if (
static_cast<int>(nbRows) < (4 * nbThread)) {
2861 gradientFilterXMonothread(I, GI, filter, p_mask);
2864 int iam, nt, irows, rstart, istart, istop;
2866#pragma omp parallel default(shared) private(iam, nt, irows, rstart, istart, istop) num_threads(nbThread)
2868 iam = omp_get_thread_num();
2869 nt = omp_get_num_threads();
2872 rstart = irows * iam;
2873 istart = rstart * nbCols;
2876 irows = nrows - rstart;
2878 istop = istart + irows * nbCols;
2880 std::vector<OutputType> Idiff((irows + 2) * nbCols);
2881 std::vector<OutputType> GItemp(irows * nbCols);
2884 initGradientFilterDifferenceImageY(I, Idiff);
2887 initGradientFilterDifferenceImageY(I, Idiff, istart);
2890 int counter = resetCounter, iterSign = offsetIdiff;
2891 int iterStart = (iam != 0 ? istart : istart + nbCols);
2892 for (
int iter = iterStart;
iter < istop; ++
iter) {
2894 OutputType futureDiff = 0.;
2896 if (checkBooleanPatch(p_mask, iter + offsetIdiff, iterSign, nbRows, nbCols,
false)) {
2897 futureDiff =
static_cast<OutputType
>(I.
bitmap[
iter + nbCols +1].V - I.
bitmap[
iter + offsetIdiff].V);
2898 Idiff[
iter - istart + nbCols + offsetIdiff] = futureDiff;
2902 if ((counter != resetCounter)) {
2903 if (checkBooleanMask(p_mask, iter)) {
2904 OutputType gradient = 0.;
2905 for (
int i = -1;
i <= 1; ++
i) {
2907 gradient += filter[
i + 1] * (Idiff[
iter - istart + nbCols +
i] + Idiff[
iter - istart +
i]);
2909 GItemp[
iter - istart] = gradient;
2915 counter = resetCounter;
2917 if (iterSign < resetCounter) {
2926 std::memcpy(GI.
bitmap + istart, GItemp.data(), GItemp.size() *
sizeof(OutputType));