34 #include <visp3/core/vpCannyEdgeDetection.h>
35 #include <visp3/core/vpImageFilter.h>
36 #include <visp3/core/vpIoTools.h>
37 #include <visp3/core/vpRGBa.h>
48 const std::string &suf)
50 std::string list(pref);
51 for (
unsigned int i = 0; i < vpCannyBackendType::CANNY_COUNT_BACKEND - 1; i++) {
72 case vpCannyBackendType::CANNY_OPENCV_BACKEND:
73 name =
"opencv-backend";
75 case vpCannyBackendType::CANNY_VISP_BACKEND:
76 name =
"visp-backend";
78 case vpCannyBackendType::CANNY_COUNT_BACKEND:
80 return "unknown-backend";
95 unsigned int count = (
unsigned int)vpCannyBackendType::CANNY_COUNT_BACKEND;
97 for (
unsigned int i = 0; i < count && !found; i++) {
116 const std::string &suf)
118 std::string list(pref);
119 for (
unsigned int i = 0; i < vpCannyFilteringAndGradientType::CANNY_COUNT_FILTERING - 1; i++) {
140 case vpCannyFilteringAndGradientType::CANNY_GBLUR_SOBEL_FILTERING:
141 name =
"gaussianblur+sobel-filtering";
143 case vpCannyFilteringAndGradientType::CANNY_GBLUR_SCHARR_FILTERING:
144 name =
"gaussianblur+scharr-filtering";
146 case vpCannyFilteringAndGradientType::CANNY_COUNT_FILTERING:
148 return "unknown-filtering";
163 unsigned int count = (
unsigned int)vpCannyFilteringAndGradientType::CANNY_COUNT_FILTERING;
165 for (
unsigned int i = 0; i < count && !found; i++) {
263 unsigned int size = kernelH.
size();
264 unsigned int half_size = size / 2;
269 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
270 for (
unsigned int j = half_size; j < I.
getWidth() - half_size; j++) {
272 for (
unsigned int a = 0; a < kernelH.
size(); a++) {
273 conv += kernelH[a] * I[i][j + half_size - a];
276 I_filter[i][j] = conv;
280 for (
unsigned int i = half_size; i < I.
getHeight() - half_size; i++) {
281 for (
unsigned int j = 0; j < I.
getWidth(); j++) {
283 for (
unsigned int a = 0; a < kernelV.
size(); a++) {
284 conv += kernelV[a] * I_filter[i + half_size - a][j];
315 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
316 for (
unsigned int j = 0; j < (size - 1) / 2; j++) {
321 for (
unsigned int j = (size - 1) / 2; j < I.
getWidth() - (size - 1) / 2; j++) {
326 for (
unsigned int j = I.
getWidth() - (size - 1) / 2; j < I.
getWidth(); j++) {
357 for (
unsigned int i = 0; i < (size - 1) / 2; i++) {
358 for (
unsigned int j = 0; j < I.
getWidth(); j++) {
364 for (
unsigned int i = (size - 1) / 2; i < I.
getHeight() - (size - 1) / 2; i++) {
365 for (
unsigned int j = 0; j < I.
getWidth(); j++) {
372 for (
unsigned int j = 0; j < I.
getWidth(); j++) {
390 void vpImageFilter::gaussianBlur<float, float>(
const vpImage<float> &I,
vpImage<float> &GI,
unsigned int size,
float sigma,
bool normalize);
411 double *fg =
new double[(size + 1) / 2];
424 void vpImageFilter::getGaussianKernel<float>(
float *filter,
unsigned int size,
float sigma,
bool normalize);
427 void vpImageFilter::getGaussianDerivativeKernel<float>(
float *filter,
unsigned int size,
float sigma,
bool normalize);
430 void vpImageFilter::getGaussianDerivativeKernel<double>(
double *filter,
unsigned int size,
double sigma,
bool normalize);
470 const float *gaussianDerivativeKernel,
unsigned int size);
474 const double *gaussianDerivativeKernel,
unsigned int size);
478 const float *gaussianDerivativeKernel,
unsigned int size);
482 const double *gaussianDerivativeKernel,
unsigned int size);
486 const float *gaussianDerivativeKernel,
unsigned int size);
490 const double *gaussianDerivativeKernel,
unsigned int size);
494 const float *gaussianDerivativeKernel,
unsigned int size);
498 const double *gaussianDerivativeKernel,
unsigned int size);
507 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
508 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
509 cv::Mat imgsrc, imgdest;
511 cv::pyrDown(imgsrc, imgdest, cv::Size((
int)I.
getWidth() / 2, (
int)I.
getHeight() / 2));
514 cv::Mat imgsrc, imgdest;
516 cv::pyrDown(imgsrc, imgdest, cvSize((
int)I.
getWidth() / 2, (
int)I.
getHeight() / 2));
530 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
532 for (
unsigned int j = 1; j < w - 1; j++) {
535 GI[i][w - 1] = I[i][2 * w - 1];
544 for (
unsigned int j = 0; j < I.
getWidth(); j++) {
546 for (
unsigned int i = 1; i < h - 1; i++) {
549 GI[h - 1][j] = I[2 * h - 1][j];
557 double vpImageFilter::getSobelKernelX<double>(
double *filter,
unsigned int size);
560 float vpImageFilter::getSobelKernelX<float>(
float *filter,
unsigned int size);
563 double vpImageFilter::getSobelKernelY<double>(
double *filter,
unsigned int size);
566 float vpImageFilter::getSobelKernelY<float>(
float *filter,
unsigned int size);
572 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
580 float m = (channel.rows * channel.cols) / 2.f;
585 float range[] = { 0, 256 };
586 const float *histRange = { range };
588 bool accumulate =
false;
590 cv::calcHist(&channel, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange, uniform, accumulate);
592 for (
int i = 0; i < histSize && med < 0.0; ++i) {
593 bin += cvRound(hist.at<
float>(i));
594 if (bin > m && med < 0.0)
595 med =
static_cast<float>(i);
627 std::vector<cv::Mat> channels;
628 cv::split(cv_I_bgr, channels);
629 std::vector<float> meds(3);
630 const int orderMeds[] = { 2, 1, 0 };
631 const int orderCvChannels[] = { 0, 1, 2 };
632 for (
unsigned int i = 0; i < 3; i++) {
633 meds[orderMeds[i]] =
median(channels[orderCvChannels[i]]);
657 float &lowerThresh,
const unsigned int &gaussianKernelSize,
658 const float &gaussianStdev,
const unsigned int &apertureGradient,
659 const float &lowerThresholdRatio,
const float &upperThresholdRatio,
662 double w = cv_I.cols;
663 double h = cv_I.rows;
665 cv::Mat dI, dIx, dIy, dIx_abs, dIy_abs;
667 if (p_cv_dIx ==
nullptr || p_cv_dIy ==
nullptr) {
677 cv::convertScaleAbs(dIx, dIx_abs);
678 cv::convertScaleAbs(dIy, dIy_abs);
679 cv::addWeighted(dIx_abs, 1, dIy_abs, 1, 0, dI);
680 dI.convertTo(dI, CV_8U);
684 const float range[] = { 0.f, 256.f };
685 const float *ranges[] = { range };
686 int channels[] = { 0 };
688 int histSize[] = { bins };
690 bool accumulate =
false;
691 cv::calcHist(&dI, 1, channels, cv::Mat(), hist, dims, histSize, ranges, uniform, accumulate);
693 float t = (float)(upperThresholdRatio * w * h);
695 for (
int i = 0; i < bins; i++) {
696 float tf = hist.at<
float>(i);
703 float upperThresh = std::max(bon, 1.f);
704 lowerThresh = lowerThresholdRatio * bon;
725 cv::Mat &cv_dIx, cv::Mat &cv_dIy,
726 const bool &computeDx,
const bool &computeDy,
const bool &normalize,
727 const unsigned int &gaussianKernelSize,
const float &gaussianStdev,
728 const unsigned int &apertureGradient,
735 cv::Size gsz(gaussianKernelSize, gaussianKernelSize);
736 cv::GaussianBlur(cv_I, img_blur, gsz, gaussianStdev);
743 if (apertureGradient > 3) {
744 scale *= std::pow(1./16., ((apertureGradient -1.)/2.) - 1.);
748 cv::Sobel(img_blur, cv_dIx, CV_16S, 1, 0, apertureGradient, 1, 0, scale);
751 cv::Sobel(img_blur, cv_dIy, CV_16S, 0, 1, apertureGradient, 1, 0, scale);
760 cv::Scharr(img_blur, cv_dIx, CV_16S, 1, 0, scale);
763 cv::Scharr(img_blur, cv_dIy, CV_16S, 0, 1, scale);
776 const bool &computeDx,
const bool &computeDy,
const bool &normalize,
777 const unsigned int &gaussianKernelSize,
const float &gaussianStdev,
778 const unsigned int &apertureGradient,
779 const vpCannyFilteringAndGradientType &filteringType,
780 const vpCannyBackendType &backend);
785 const bool &computeDx,
const bool &computeDy,
const bool &normalize,
786 const unsigned int &gaussianKernelSize,
const double &gaussianStdev,
787 const unsigned int &apertureGradient,
788 const vpCannyFilteringAndGradientType &filteringType,
789 const vpCannyBackendType &backend);
792 void vpImageFilter::computePartialDerivatives<float, float>(
const vpImage<float> &I,
794 const bool &computeDx,
const bool &computeDy,
const bool &normalize,
795 const unsigned int &gaussianKernelSize,
const float &gaussianStdev,
796 const unsigned int &apertureGradient,
797 const vpCannyFilteringAndGradientType &filteringType,
798 const vpCannyBackendType &backend);
801 void vpImageFilter::computePartialDerivatives<float, double>(
const vpImage<float> &I,
803 const bool &computeDx,
const bool &computeDy,
const bool &normalize,
804 const unsigned int &gaussianKernelSize,
const double &gaussianStdev,
805 const unsigned int &apertureGradient,
806 const vpCannyFilteringAndGradientType &filteringType,
807 const vpCannyBackendType &backend);
810 void vpImageFilter::computePartialDerivatives<double, float>(
const vpImage<double> &I,
812 const bool &computeDx,
const bool &computeDy,
const bool &normalize,
813 const unsigned int &gaussianKernelSize,
const float &gaussianStdev,
814 const unsigned int &apertureGradient,
815 const vpCannyFilteringAndGradientType &filteringType,
816 const vpCannyBackendType &backend);
819 void vpImageFilter::computePartialDerivatives<double, double>(
const vpImage<double> &I,
821 const bool &computeDx,
const bool &computeDy,
const bool &normalize,
822 const unsigned int &gaussianKernelSize,
const double &gaussianStdev,
823 const unsigned int &apertureGradient,
824 const vpCannyFilteringAndGradientType &filteringType,
825 const vpCannyBackendType &backend);
830 const unsigned int &gaussianKernelSize,
831 const double &gaussianStdev,
const unsigned int &apertureGradient,
832 const float &lowerThresholdRatio,
const float &upperThresholdRatio,
838 const unsigned int &gaussianKernelSize,
839 const float &gaussianStdev,
const unsigned int &apertureGradient,
840 const float &lowerThresholdRatio,
const float &upperThresholdRatio,
886 const unsigned int &gaussianFilterSize,
const float &thresholdCanny,
887 const unsigned int &apertureSobel)
889 vpImageFilter::canny(Isrc, Ires, gaussianFilterSize, thresholdCanny / 3.f, thresholdCanny, apertureSobel);
936 const unsigned int &gaussianFilterSize,
937 const float &lowerThreshold,
const float &upperThreshold,
938 const unsigned int &apertureSobel)
940 const float gaussianStdev = 2.f;
941 const float upperThresholdRatio = 0.8f;
942 const float lowerThresholdRatio = 0.6f;
943 #if defined(HAVE_OPENCV_IMGPROC)
949 canny(Isrc, Ires, gaussianFilterSize, lowerThreshold, upperThreshold, apertureSobel,
950 gaussianStdev, lowerThresholdRatio, upperThresholdRatio,
false, cannyBackend, cannyFilteringSteps);
1017 const unsigned int &gaussianFilterSize,
1018 const float &lowerThreshold,
const float &upperThreshold,
const unsigned int &apertureGradient,
1019 const float &gaussianStdev,
const float &lowerThresholdRatio,
const float &upperThresholdRatio,
1020 const bool &normalizeGradients,
1024 #if defined(HAVE_OPENCV_IMGPROC)
1025 cv::Mat img_cvmat, cv_dx, cv_dy, edges_cvmat;
1028 gaussianStdev, apertureGradient, cannyFilteringSteps);
1029 float upperCannyThresh = upperThreshold;
1030 float lowerCannyThresh = lowerThreshold;
1031 if (upperCannyThresh < 0) {
1032 upperCannyThresh =
computeCannyThreshold(img_cvmat, &cv_dx, &cv_dy, lowerCannyThresh, gaussianFilterSize,
1033 gaussianStdev, apertureGradient, lowerThresholdRatio, upperThresholdRatio,
1034 cannyFilteringSteps);
1036 else if (lowerCannyThresh < 0) {
1037 lowerCannyThresh = upperCannyThresh / 3.f;
1039 #if (VISP_HAVE_OPENCV_VERSION >= 0x030200)
1040 cv::Canny(cv_dx, cv_dy, edges_cvmat, lowerCannyThresh, upperCannyThresh,
false);
1042 cv::GaussianBlur(img_cvmat, img_cvmat, cv::Size((
int)gaussianFilterSize, (
int)gaussianFilterSize),
1043 gaussianStdev, gaussianStdev);
1044 cv::Canny(img_cvmat, edges_cvmat, lowerCannyThresh, upperCannyThresh);
1048 std::string errMsg(
"[vpImageFilter::canny]You asked for CANNY_OPENCV_BACKEND but ViSP has not been compiled with OpenCV");
1053 float upperCannyThresh = upperThreshold;
1054 float lowerCannyThresh = lowerThreshold;
1058 gaussianStdev, apertureGradient, cannyFilteringSteps, cannyBackend);
1060 if (upperCannyThresh < 0) {
1061 upperCannyThresh =
computeCannyThreshold(Isrc, lowerCannyThresh, &dIx, &dIy, gaussianFilterSize, gaussianStdev,
1062 apertureGradient, lowerThresholdRatio, upperThresholdRatio,
1063 cannyFilteringSteps);
1065 else if (lowerCannyThresh < 0) {
1066 lowerCannyThresh = upperCannyThresh / 3.;
1068 vpCannyEdgeDetection edgeDetector(gaussianFilterSize, gaussianStdev, apertureGradient, lowerCannyThresh, upperCannyThresh,
1069 lowerThresholdRatio, upperThresholdRatio, cannyFilteringSteps);
1071 Ires = edgeDetector.
detect(Isrc);
unsigned int size() const
Return the number of elements of the 2D array.
vpImage< unsigned char > detect(const vpImage< vpRGBa > &I_color)
Detect the edges in an image. Convert the color image into a gray-scale image.
void setGradients(const vpImage< float > &dIx, const vpImage< float > &dIy)
Set the Gradients of the image that will be processed.
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.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static std::string vpCannyBackendTypeToString(const vpCannyBackendType &type)
Cast a vpImageFilter::vpCannyBackendTypeToString into a string, to know its name.
static void canny(const vpImage< unsigned char > &I, vpImage< unsigned char > &Ic, const unsigned int &gaussianFilterSize, const float &thresholdCanny, const unsigned int &apertureSobel)
static unsigned char filterGaussXPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static double filterYTopBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterYB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterYBottomBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterXRightBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &If, const vpArray2D< FilterType > &M, bool convolve=false)
static double filterYBottomBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterYTopBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterXB(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterXLeftBorderB(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterYR(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void sepFilter(const vpImage< unsigned char > &I, vpImage< double > &If, const vpColVector &kernelH, const vpColVector &kernelV)
vpCannyFilteringAndGradientType
Canny filter and gradient operators to apply on the image before the edge detection stage.
@ CANNY_GBLUR_SOBEL_FILTERING
Apply Gaussian blur + Sobel operator on the input image.
@ CANNY_GBLUR_SCHARR_FILTERING
Apply Gaussian blur + Scharr operator on the input image.
static vpCannyFilteringAndGradientType vpCannyFilteringAndGradientTypeFromString(const std::string &name)
Cast a string into a vpImageFilter::vpCannyFilteringAndGradientType.
static void filterY(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static std::string vpCannyFilteringAndGradientTypeToString(const vpCannyFilteringAndGradientType &type)
Cast a vpImageFilter::vpCannyFilteringAndGradientType into a string, to know its name.
vpCannyBackendType
Canny filter backends for the edge detection operations.
@ CANNY_VISP_BACKEND
Use ViSP.
@ CANNY_OPENCV_BACKEND
Use OpenCV.
static double filterXLeftBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static std::string vpCannyBackendTypeList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpCannyBackendType.
static double filterXLeftBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static double filterXRightBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterXR(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static float computeCannyThreshold(const cv::Mat &cv_I, const cv::Mat *p_cv_dIx, const cv::Mat *p_cv_dIy, float &lowerThresh, const unsigned int &gaussianKernelSize=5, const float &gaussianStdev=2.f, const unsigned int &apertureGradient=3, const float &lowerThresholdRatio=0.6, const float &upperThresholdRatio=0.8, const vpCannyFilteringAndGradientType &filteringType=CANNY_GBLUR_SOBEL_FILTERING)
Compute the upper Canny edge filter threshold, using Gaussian blur + Sobel or + Scharr operators to c...
static void getGaussXPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
static void getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma=0., bool normalize=true)
static double filterYTopBorderR(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterYG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static void getGaussYPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
static float median(const cv::Mat &cv_I)
Calculates the median value of a single channel. The algorithm is based on based on https://github....
static double filterXRightBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static void filterX(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, const FilterType *filter, unsigned int size)
static std::string vpCannyFilteringAndGradientTypeList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpCannyFilteringAndGradientType.
static vpCannyBackendType vpCannyBackendTypeFromString(const std::string &name)
Cast a string into a vpImageFilter::vpCannyBackendTypeToString.
static void filterXG(const vpImage< vpRGBa > &I, vpImage< vpRGBa > &dIx, const double *filter, unsigned int size)
static double filterYBottomBorderG(const vpImage< vpRGBa > &I, unsigned int r, unsigned int c, const double *filter, unsigned int size)
static unsigned char filterGaussYPyramidal(const vpImage< unsigned char > &I, unsigned int i, unsigned int j)
static void gaussianBlur(const vpImage< ImageType > &I, vpImage< FilterType > &GI, unsigned int size=7, FilterType sigma=0., bool normalize=true)
static void getGaussPyramidal(const vpImage< unsigned char > &I, vpImage< unsigned char > &GI)
static void computePartialDerivatives(const cv::Mat &cv_I, cv::Mat &cv_dIx, cv::Mat &cv_dIy, const bool &computeDx=true, const bool &computeDy=true, const bool &normalize=true, const unsigned int &gaussianKernelSize=5, const float &gaussianStdev=2.f, const unsigned int &apertureGradient=3, const vpCannyFilteringAndGradientType &filteringType=CANNY_GBLUR_SOBEL_FILTERING)
Compute the partial derivatives (i.e. horizontal and vertical gradients) of the input image.
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