33 #include <visp3/core/vpConfig.h>
35 #include <visp3/core/vpCannyEdgeDetection.h>
36 #include <visp3/core/vpImageFilter.h>
37 #include <visp3/io/vpImageIo.h>
39 #ifdef HAVE_OPENCV_IMGPROC
40 #include <opencv2/imgproc/imgproc.hpp>
43 #include "drawingHelpers.h"
45 #ifdef ENABLE_VISP_NAMESPACE
67 , m_gradientOutsideClass(false)
68 , m_useVpImageFilterCanny(false)
69 , m_saveEdgeList(false)
70 , m_gaussianKernelSize(3)
76 , m_lowerThreshRatio(0.6f)
77 , m_upperThreshRatio(0.8f)
78 #ifdef VISP_HAVE_OPENCV
87 void computeMeanMaxStdev(
const vpImage<T> &I,
float &mean,
float &max,
float &stdev)
89 max = std::numeric_limits<float>::epsilon();
92 unsigned int nbRows = I.
getRows();
93 unsigned int nbCols = I.
getCols();
94 float scale = 1.f / (
static_cast<float>(nbRows) *
static_cast<float>(nbCols));
95 for (
unsigned int r = 0; r < nbRows; r++) {
96 for (
unsigned int c = 0; c < nbCols; c++) {
98 max = std::max<float>(max,
static_cast<float>(I[r][c]));
102 for (
unsigned int r = 0; r < nbRows; r++) {
103 for (
unsigned int c = 0; c < nbCols; c++) {
104 stdev += (I[r][c] - mean) * (I[r][c] - mean);
108 stdev = std::sqrt(stdev);
111 void setGradientOutsideClass(
const vpImage<unsigned char> &I,
const int &gaussianKernelSize,
const float &gaussianStdev,
120 apertureSize, filteringType);
126 float mean, max, stdev;
127 computeMeanMaxStdev(dIx, mean, max, stdev);
129 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
130 std::string title =
"Gradient along the horizontal axis. Mean = " + std::to_string(mean)
131 +
"+/-" + std::to_string(stdev) +
" Max = " + std::to_string(max);
135 std::stringstream ss;
136 ss <<
"Gradient along the horizontal axis. Mean = " << mean<<
"+/-" << stdev<<
" Max = " << max;
141 drawingHelpers::display(dIx_uchar, title);
142 computeMeanMaxStdev(dIy, mean, max, stdev);
143 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
144 title =
"Gradient along the horizontal axis. Mean = " + std::to_string(mean)
145 +
"+/-" + std::to_string(stdev) +
" Max = " + std::to_string(max);
148 std::stringstream ss;
149 ss <<
"Gradient along the horizontal axis. Mean = " << mean<<
"+/-" << stdev<<
" Max = " << max;
154 drawingHelpers::display(dIy_uchar, title);
172 std::vector<vpImagePoint> cpyListEdgePoints = listEdgePoints;
173 std::sort(cpyListEdgePoints.begin(), cpyListEdgePoints.end(), sortImagePoints);
174 std::unique(cpyListEdgePoints.begin(), cpyListEdgePoints.end());
175 if (listEdgePoints.size() != cpyListEdgePoints.size()) {
179 std::vector<vpImagePoint>::iterator start = listEdgePoints.begin();
180 std::vector<vpImagePoint>::iterator stop = listEdgePoints.end();
181 for (std::vector<vpImagePoint>::iterator it = start; it != stop; ++it) {
182 if (I_canny_visp[
static_cast<unsigned int>(it->get_i())][
static_cast<unsigned int>(it->get_j())] != 255) {
187 unsigned int nbRows = I_canny_visp.
getRows();
188 unsigned int nbCols = I_canny_visp.
getCols();
189 for (
unsigned int i = 0; i < nbRows; ++i) {
190 for (
unsigned int j = 0; j < nbCols; ++j) {
191 if (I_canny_visp[i][j] == 255) {
193 std::vector<vpImagePoint>::iterator idx = std::find(listEdgePoints.begin(), listEdgePoints.end(), searchedPoint);
194 if (idx == listEdgePoints.end()) {
201 std::cout <<
"All the edge-point list tests went well !" << std::endl;
206 std::cout <<
"NAME" << std::endl;
207 std::cout << softName <<
": software to test the vpCannyEdgeComputation class and vpImageFilter::canny method" << std::endl;
208 std::cout <<
"SYNOPSIS" << std::endl;
209 std::cout <<
"\t" << softName
210 <<
" [-i, --image <pathToImg>]"
211 <<
" [-g, --gradient <kernelSize stdev>]"
212 <<
" [-t, --thresh <lowerThresh upperThresh>]"
213 <<
" [-a, --aperture <apertureSize>]"
214 <<
" [-f, --filter <filterName>]"
215 <<
" [-r, --ratio <lowerThreshRatio upperThreshRatio>]"
216 <<
" [-b, --backend <backendName>]"
217 <<
" [-e, --edge-list]" << std::endl
218 <<
" [-h, --help]" << std::endl
220 std::cout <<
"DESCRIPTION" << std::endl;
221 std::cout <<
"\t-i, --image <pathToImg>" << std::endl
222 <<
"\t\tPermits to load an image on which will be tested the vpCanny class." << std::endl
223 <<
"\t\tWhen empty uses a simulated image." << std::endl
225 std::cout <<
"\t-g, --gradient <kernelSize stdev>" << std::endl
226 <<
"\t\tPermits to compute the gradients of the image outside the vpCanny class." << std::endl
227 <<
"\t\tFirst parameter is the size of the Gaussian kernel used to compute the gradients." << std::endl
228 <<
"\t\tSecond parameter is the standard deviation of the Gaussian kernel used to compute the gradients." << std::endl
231 std::cout <<
"\t-t, --thresh <lowerThresh upperThresh>" << std::endl
232 <<
"\t\tPermits to set the lower and upper thresholds of the vpCanny class." << std::endl
233 <<
"\t\tFirst parameter is the lower threshold." << std::endl
234 <<
"\t\tSecond parameter is the upper threshold." << std::endl
235 <<
"\t\tWhen set to -1 thresholds are computed automatically." << std::endl
238 std::cout <<
"\t-a, --aperture <apertureSize>" << std::endl
239 <<
"\t\tPermits to set the size of the gradient filter kernel." << std::endl
240 <<
"\t\tParameter must be odd and positive." << std::endl
243 std::cout <<
"\t-f, --filter <filterName>" << std::endl
244 <<
"\t\tPermits to choose the type of filter to apply to compute the gradient." << std::endl
248 std::cout <<
"\t-r, --ratio <lowerThreshRatio upperThreshRatio>" << std::endl
249 <<
"\t\tPermits to set the lower and upper thresholds ratio of the vpCanny class." << std::endl
250 <<
"\t\tFirst parameter is the lower threshold ratio." << std::endl
251 <<
"\t\tSecond parameter is the upper threshold ratio." << std::endl
254 std::cout <<
"\t-b, --backend <backendName>" << std::endl
255 <<
"\t\tPermits to use the vpImageFilter::canny method for comparison." << std::endl
259 std::cout <<
"\t-e, --edge-list" << std::endl
260 <<
"\t\tPermits to save the edge list." << std::endl
261 <<
"\t\tDefault: OFF" << std::endl
263 std::cout <<
"\t-h, --help" << std::endl
264 <<
"\t\tPermits to display the different arguments this software handles." << std::endl
268 int main(
int argc,
const char *argv[])
271 for (
int i = 1; i < argc; i++) {
272 std::string argv_str = std::string(argv[i]);
273 if ((argv_str ==
"-i" || argv_str ==
"--image") && i + 1 < argc) {
274 options.
m_img = std::string(argv[i + 1]);
277 else if ((argv_str ==
"-g" || argv_str ==
"--gradient") && i + 2 < argc) {
283 else if ((argv_str ==
"-t" || argv_str ==
"--thresh") && i + 2 < argc) {
284 options.
m_lowerThresh =
static_cast<float>(atof(argv[i + 1]));
285 options.
m_upperThresh =
static_cast<float>(atof(argv[i + 2]));
288 else if ((argv_str ==
"-a" || argv_str ==
"--aperture") && i + 1 < argc) {
292 else if ((argv_str ==
"-f" || argv_str ==
"--filter") && i + 1 < argc) {
296 else if ((argv_str ==
"-r" || argv_str ==
"--ratio") && i + 2 < argc) {
301 else if ((argv_str ==
"-b" || argv_str ==
"--backend") && i + 1 < argc) {
306 else if ((argv_str ==
"-e") || (argv_str ==
"--edge-list")) {
309 else if (argv_str ==
"-h" || argv_str ==
"--help") {
310 usage(std::string(argv[0]), options);
314 std::cerr <<
"Argument \"" << argv_str <<
"\" is unknown." << std::endl;
319 std::string configAsTxt(
"Canny Configuration:\n");
321 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
322 configAsTxt +=
"\tGaussian filter kernel size = " + std::to_string(options.
m_gaussianKernelSize) +
"\n";
323 configAsTxt +=
"\tGaussian filter standard deviation = " + std::to_string(options.
m_gaussianStdev) +
"\n";
324 configAsTxt +=
"\tGradient filter kernel size = " + std::to_string(options.
m_apertureSize) +
"\n";
325 configAsTxt +=
"\tCanny edge filter thresholds = [" + std::to_string(options.
m_lowerThresh) +
" ; " + std::to_string(options.
m_upperThresh) +
"]\n";
326 configAsTxt +=
"\tCanny edge filter thresholds ratio (for auto-thresholding) = [" + std::to_string(options.
m_lowerThreshRatio) +
" ; " + std::to_string(options.
m_upperThreshRatio) +
"]\n";
329 std::stringstream ss;
331 ss <<
"\tGaussian filter standard deviation = " << options.
m_gaussianStdev <<
"\n";
332 ss <<
"\tGradient filter kernel size = " << options.
m_apertureSize <<
"\n";
335 configAsTxt += ss.str();
338 std::cout << configAsTxt << std::endl;
344 if (!options.
m_img.empty()) {
350 I_canny_input.
resize(500, 500, 0);
351 for (
unsigned int r = 150; r < 350; r++) {
352 for (
unsigned int c = 150; c < 350; c++) {
353 I_canny_input[r][c] = 125;
359 I_canny_visp = I_canny_imgFilter = dIx_uchar = dIy_uchar = I_canny_input;
368 p_IcannyImgFilter = &I_canny_imgFilter;
370 drawingHelpers::init(I_canny_input, I_canny_visp, p_dIx, p_dIy, p_IcannyImgFilter);
377 I_canny_visp = cannyDetector.
detect(I_canny_input);
378 float mean, max, stdev;
379 computeMeanMaxStdev(I_canny_input, mean, max, stdev);
381 checkEdgeList(cannyDetector, I_canny_visp);
383 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
384 std::string title(
"Input of the Canny edge detector. Mean = " + std::to_string(mean) +
"+/-" + std::to_string(stdev) +
" Max = " + std::to_string(max));
388 std::stringstream ss;
389 ss <<
"Input of the Canny edge detector. Mean = " << mean <<
"+/-" << stdev <<
" Max = " << max;
393 drawingHelpers::display(I_canny_input, title);
394 drawingHelpers::display(I_canny_visp,
"Canny results on image " + options.
m_img);
405 drawingHelpers::waitForClick(I_canny_input,
true);
Class that implements the Canny's edge detector. It is possible to use a boolean mask to ignore some ...
vpImage< unsigned char > detect(const vpImage< vpRGBa > &I_color)
Detect the edges in an image. Convert the color image into a gray-scale image.
std::vector< vpImagePoint > getEdgePointsList() const
Get the list of edge-points that have been detected.
void setGradients(const vpImage< float > &dIx, const vpImage< float > &dIy)
Set the Gradients of the image that will be processed.
error that can be emitted by ViSP classes.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Various image filter, convolution, etc...
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 std::string vpCannyBackendTypeList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpCannyBackendType.
static std::string vpCannyFiltAndGradTypeToStr(const vpCannyFilteringAndGradientType &type)
Cast a vpImageFilter::vpCannyFilteringAndGradientType into a string, to know its name.
vpCannyFilteringAndGradientType
Canny filter and gradient operators to apply on the image before the edge detection stage.
vpCannyBackendType
Canny filter backends for the edge detection operations.
static vpCannyFilteringAndGradientType vpCannyFiltAndGradTypeFromStr(const std::string &name)
Cast a string into a vpImageFilter::vpCannyFilteringAndGradientType.
static vpCannyBackendType vpCannyBackendTypeFromString(const std::string &name)
Cast a string into a vpImageFilter::vpCannyBackendTypeToString.
static std::string vpGetCannyFiltAndGradTypes(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpCannyFilteringAndGradientType.
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)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
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
static bool equal(double x, double y, double threshold=0.001)
bool m_gradientOutsideClass
vpImageFilter::vpCannyFilteringAndGradientType m_filteringType
bool m_useVpImageFilterCanny
vpImageFilter::vpCannyBackendType m_backend