32 #include <visp3/core/vpConfig.h>
34 #include <visp3/core/vpCannyEdgeDetection.h>
35 #include <visp3/core/vpImageFilter.h>
36 #include <visp3/io/vpImageIo.h>
38 #ifdef HAVE_OPENCV_IMGPROC
39 #include <opencv2/imgproc/imgproc.hpp>
42 #include "drawingHelpers.h"
45 void computeMeanMaxStdev(
const vpImage<T> &I,
float &mean,
float &max,
float &stdev)
47 max = std::numeric_limits<float>::epsilon();
50 unsigned int nbRows = I.
getRows();
51 unsigned int nbCols = I.
getCols();
52 float scale = 1.f / (
static_cast<float>(nbRows) *
static_cast<float>(nbCols));
53 for (
unsigned int r = 0; r < nbRows; r++) {
54 for (
unsigned int c = 0; c < nbCols; c++) {
56 max = std::max<float>(max,
static_cast<float>(I[r][c]));
60 for (
unsigned int r = 0; r < nbRows; r++) {
61 for (
unsigned int c = 0; c < nbCols; c++) {
62 stdev += (I[r][c] - mean) * (I[r][c] - mean);
66 stdev = std::sqrt(stdev);
69 void setGradientOutsideClass(
const vpImage<unsigned char> &I,
const int &gaussianKernelSize,
const float &gaussianStdev,
78 apertureSize, filteringType);
84 float mean, max, stdev;
85 computeMeanMaxStdev(dIx, mean, max, stdev);
87 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
88 std::string title =
"Gradient along the horizontal axis. Mean = " + std::to_string(mean)
89 +
"+/-" + std::to_string(stdev) +
" Max = " + std::to_string(max);
94 ss <<
"Gradient along the horizontal axis. Mean = " << mean<<
"+/-" << stdev<<
" Max = " << max;
100 computeMeanMaxStdev(dIy, mean, max, stdev);
101 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
102 title =
"Gradient along the horizontal axis. Mean = " + std::to_string(mean)
103 +
"+/-" + std::to_string(stdev) +
" Max = " + std::to_string(max);
106 std::stringstream ss;
107 ss <<
"Gradient along the horizontal axis. Mean = " << mean<<
"+/-" << stdev<<
" Max = " << max;
115 void usage(
const std::string &softName,
int gaussianKernelSize,
float gaussianStdev,
float lowerThresh,
float upperThresh,
119 std::cout <<
"NAME" << std::endl;
120 std::cout << softName <<
": software to test the vpCannyEdgeComputation class and vpImageFilter::canny method" << std::endl;
121 std::cout <<
"SYNOPSIS" << std::endl;
122 std::cout <<
"\t" << softName
123 <<
" [-i, --image <pathToImg>]"
124 <<
" [-g, --gradient <kernelSize stdev>]"
125 <<
" [-t, --thresh <lowerThresh upperThresh>]"
126 <<
" [-a, --aperture <apertureSize>]"
127 <<
" [-f, --filter <filterName>]"
128 <<
" [-r, --ratio <lowerThreshRatio upperThreshRatio>]"
129 <<
" [-b, --backend <backendName>]"
130 <<
" [-h, --help]" << std::endl
132 std::cout <<
"DESCRIPTION" << std::endl;
133 std::cout <<
"\t-i, --image <pathToImg>" << std::endl
134 <<
"\t\tPermits to load an image on which will be tested the vpCanny class." << std::endl
135 <<
"\t\tWhen empty uses a simulated image." << std::endl
137 std::cout <<
"\t-g, --gradient <kernelSize stdev>" << std::endl
138 <<
"\t\tPermits to compute the gradients of the image outside the vpCanny class." << std::endl
139 <<
"\t\tFirst parameter is the size of the Gaussian kernel used to compute the gradients." << std::endl
140 <<
"\t\tSecond parameter is the standard deviation of the Gaussian kernel used to compute the gradients." << std::endl
141 <<
"\t\tDefault: " << gaussianKernelSize <<
" " << gaussianStdev << std::endl
143 std::cout <<
"\t-t, --thresh <lowerThresh upperThresh>" << std::endl
144 <<
"\t\tPermits to set the lower and upper thresholds of the vpCanny class." << std::endl
145 <<
"\t\tFirst parameter is the lower threshold." << std::endl
146 <<
"\t\tSecond parameter is the upper threshold." << std::endl
147 <<
"\t\tWhen set to -1 thresholds are computed automatically." << std::endl
148 <<
"\t\tDefault: " << lowerThresh <<
" " << upperThresh << std::endl
150 std::cout <<
"\t-a, --aperture <apertureSize>" << std::endl
151 <<
"\t\tPermits to set the size of the gradient filter kernel." << std::endl
152 <<
"\t\tParameter must be odd and positive." << std::endl
153 <<
"\t\tDefault: " << apertureSize << std::endl
155 std::cout <<
"\t-f, --filter <filterName>" << std::endl
156 <<
"\t\tPermits to choose the type of filter to apply to compute the gradient." << std::endl
160 std::cout <<
"\t-r, --ratio <lowerThreshRatio upperThreshRatio>" << std::endl
161 <<
"\t\tPermits to set the lower and upper thresholds ratio of the vpCanny class." << std::endl
162 <<
"\t\tFirst parameter is the lower threshold ratio." << std::endl
163 <<
"\t\tSecond parameter is the upper threshold ratio." << std::endl
164 <<
"\t\tDefault: " << lowerThreshRatio <<
" " << upperThreshRatio << std::endl
166 std::cout <<
"\t-b, --backend <backendName>" << std::endl
167 <<
"\t\tPermits to use the vpImageFilter::canny method for comparison." << std::endl
171 std::cout <<
"\t-h, --help" << std::endl
172 <<
"\t\tPermits to display the different arguments this software handles." << std::endl
176 int main(
int argc,
const char *argv[])
179 bool opt_gradientOutsideClass =
false;
180 bool opt_useVpImageFilterCanny =
false;
181 int opt_gaussianKernelSize = 3;
182 int opt_apertureSize = 3;
184 float opt_gaussianStdev = 1.;
185 float opt_lowerThresh = -1.;
186 float opt_upperThresh = -1.;
187 float opt_lowerThreshRatio = 0.6f;
188 float opt_upperThreshRatio = 0.8f;
190 for (
int i = 1; i < argc; i++) {
191 std::string argv_str = std::string(argv[i]);
192 if ((argv_str ==
"-i" || argv_str ==
"--image") && i + 1 < argc) {
193 opt_img = std::string(argv[i + 1]);
196 else if ((argv_str ==
"-g" || argv_str ==
"--gradient") && i + 2 < argc) {
197 opt_gradientOutsideClass =
true;
198 opt_gaussianKernelSize = atoi(argv[i + 1]);
199 opt_gaussianStdev =
static_cast<float>(atof(argv[i + 2]));
202 else if ((argv_str ==
"-t" || argv_str ==
"--thresh") && i + 2 < argc) {
203 opt_lowerThresh =
static_cast<float>(atof(argv[i + 1]));
204 opt_upperThresh =
static_cast<float>(atof(argv[i + 2]));
207 else if ((argv_str ==
"-a" || argv_str ==
"--aperture") && i + 1 < argc) {
208 opt_apertureSize = std::atoi(argv[i + 1]);
211 else if ((argv_str ==
"-f" || argv_str ==
"--filter") && i + 1 < argc) {
215 else if ((argv_str ==
"-r" || argv_str ==
"--ratio") && i + 2 < argc) {
216 opt_lowerThreshRatio =
static_cast<float>(std::atof(argv[i + 1]));
217 opt_upperThreshRatio =
static_cast<float>(std::atof(argv[i + 2]));
220 else if ((argv_str ==
"-b" || argv_str ==
"--backend") && i + 1 < argc) {
221 opt_useVpImageFilterCanny =
true;
225 else if (argv_str ==
"-h" || argv_str ==
"--help") {
226 usage(std::string(argv[0]), opt_gaussianKernelSize, opt_gaussianStdev, opt_lowerThresh, opt_upperThresh,
227 opt_apertureSize, opt_filteringType, opt_lowerThreshRatio, opt_upperThreshRatio, opt_backend);
231 std::cerr <<
"Argument \"" << argv_str <<
"\" is unknown." << std::endl;
236 std::string configAsTxt(
"Canny Configuration:\n");
238 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
239 configAsTxt +=
"\tGaussian filter kernel size = " + std::to_string(opt_gaussianKernelSize) +
"\n";
240 configAsTxt +=
"\tGaussian filter standard deviation = " + std::to_string(opt_gaussianStdev) +
"\n";
241 configAsTxt +=
"\tGradient filter kernel size = " + std::to_string(opt_apertureSize) +
"\n";
242 configAsTxt +=
"\tCanny edge filter thresholds = [" + std::to_string(opt_lowerThresh) +
" ; " + std::to_string(opt_upperThresh) +
"]\n";
243 configAsTxt +=
"\tCanny edge filter thresholds ratio (for auto-thresholding) = [" + std::to_string(opt_lowerThreshRatio) +
" ; " + std::to_string(opt_upperThreshRatio) +
"]\n";
246 std::stringstream ss;
247 ss <<
"\tGaussian filter kernel size = " << opt_gaussianKernelSize <<
"\n";
248 ss <<
"\tGaussian filter standard deviation = " << opt_gaussianStdev <<
"\n";
249 ss <<
"\tGradient filter kernel size = " << opt_apertureSize <<
"\n";
250 ss <<
"\tCanny edge filter thresholds = [" << opt_lowerThresh <<
" ; " << opt_upperThresh <<
"]\n";
251 ss <<
"\tCanny edge filter thresholds ratio (for auto-thresholding) = [" << opt_lowerThreshRatio <<
" ; " << opt_upperThreshRatio <<
"]\n";
252 configAsTxt += ss.str();
255 std::cout << configAsTxt << std::endl;
258 opt_lowerThresh, opt_upperThresh, opt_lowerThreshRatio, opt_upperThreshRatio,
261 if (!opt_img.empty()) {
267 I_canny_input.
resize(500, 500, 0);
268 for (
unsigned int r = 150; r < 350; r++) {
269 for (
unsigned int c = 150; c < 350; c++) {
270 I_canny_input[r][c] = 125;
276 I_canny_visp = I_canny_imgFilter = dIx_uchar = dIy_uchar = I_canny_input;
279 if (opt_gradientOutsideClass) {
284 if (opt_useVpImageFilterCanny) {
285 p_IcannyImgFilter = &I_canny_imgFilter;
290 if (opt_gradientOutsideClass) {
291 setGradientOutsideClass(I_canny_input, opt_gaussianKernelSize, opt_gaussianStdev, cannyDetector, opt_apertureSize,
292 opt_filteringType, dIx_uchar, dIy_uchar);
294 I_canny_visp = cannyDetector.
detect(I_canny_input);
295 float mean, max, stdev;
296 computeMeanMaxStdev(I_canny_input, mean, max, stdev);
297 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
298 std::string title(
"Input of the Canny edge detector. Mean = " + std::to_string(mean) +
"+/-" + std::to_string(stdev) +
" Max = " + std::to_string(max));
302 std::stringstream ss;
303 ss <<
"Input of the Canny edge detector. Mean = " << mean <<
"+/-" << stdev <<
" Max = " << max;
310 if (opt_useVpImageFilterCanny) {
311 float cannyThresh = opt_upperThresh;
312 float lowerThresh(opt_lowerThresh);
313 vpImageFilter::canny(I_canny_input, I_canny_imgFilter, opt_gaussianKernelSize, lowerThresh, cannyThresh,
314 opt_apertureSize, opt_gaussianStdev, opt_lowerThreshRatio, opt_upperThreshRatio,
true,
315 opt_backend, opt_filteringType);
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.
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)
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.
static vpCannyFilteringAndGradientType vpCannyFilteringAndGradientTypeFromString(const std::string &name)
Cast a string into a vpImageFilter::vpCannyFilteringAndGradientType.
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.
static std::string vpCannyBackendTypeList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpCannyBackendType.
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 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.
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
unsigned int getCols() const
unsigned int getRows() const
bool waitForClick(const vpImage< unsigned char > &I, const bool &blockingMode)
Catch the user clicks to know if the user wants to stop the program.
void display(vpImage< unsigned char > &I, const std::string &title)
Display a gray-scale image.
void init(vpImage< unsigned char > &Iinput, vpImage< unsigned char > &IcannyVisp, vpImage< unsigned char > *p_dIx, vpImage< unsigned char > *p_dIy, vpImage< unsigned char > *p_IcannyimgFilter)
Initialize the different displays.