Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
tutorial-canny.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 */
30
32
33#include <visp3/core/vpConfig.h>
34
35#include <visp3/core/vpCannyEdgeDetection.h>
36#include <visp3/core/vpImageFilter.h>
37#include <visp3/core/vpTime.h>
38#include <visp3/io/vpImageIo.h>
39
40#ifdef HAVE_OPENCV_IMGPROC
41#include <opencv2/imgproc/imgproc.hpp>
42#endif
43
44#include "drawingHelpers.h"
45
46#ifdef ENABLE_VISP_NAMESPACE
47using namespace VISP_NAMESPACE_NAME;
48#endif
49
50typedef struct SoftwareArguments
51{
52 std::string m_img;
59 float m_gaussianStdev;
60 float m_lowerThresh;
61 float m_upperThresh;
65 int m_nbThread;
66
68 : m_img("")
71 , m_saveEdgeList(false)
74 , m_filteringType(vpImageFilter::CANNY_GBLUR_SOBEL_FILTERING)
75 , m_gaussianStdev(1.)
76 , m_lowerThresh(-1.)
77 , m_upperThresh(-1.)
78 , m_lowerThreshRatio(0.6f)
79 , m_upperThreshRatio(0.8f)
80#ifdef VISP_HAVE_OPENCV
81 , m_backend(vpImageFilter::CANNY_OPENCV_BACKEND)
82#else
83 , m_backend(vpImageFilter::CANNY_VISP_BACKEND)
84#endif
85 , m_nbThread(-1)
86 { }
88
89void setGradientOutsideClass(const vpImage<unsigned char> &I, const int &gaussianKernelSize, const float &gaussianStdev,
90 vpCannyEdgeDetection &cannyDetector, const unsigned int apertureSize,
92 vpImage<unsigned char> &dIx_uchar, vpImage<unsigned char> &dIy_uchar);
93bool sortImagePoints(const vpImagePoint &a, const vpImagePoint &b);
94void checkEdgeList(const vpCannyEdgeDetection &cannyDetector, const vpImage<unsigned char> &I_canny_visp);
95void usage(const std::string &softName, const SoftwareArguments &options);
96
97template <class T>
98void computeMeanMaxStdev(const vpImage<T> &I, float &mean, float &max, float &stdev)
99{
100 max = std::numeric_limits<float>::epsilon();
101 mean = 0.;
102 stdev = 0.;
103 unsigned int nbRows = I.getRows();
104 unsigned int nbCols = I.getCols();
105 float scale = 1.f / (static_cast<float>(nbRows) * static_cast<float>(nbCols));
106 for (unsigned int r = 0; r < nbRows; r++) {
107 for (unsigned int c = 0; c < nbCols; c++) {
108 mean += I[r][c];
109 max = std::max<float>(max, static_cast<float>(I[r][c]));
110 }
111 }
112 mean *= scale;
113 for (unsigned int r = 0; r < nbRows; r++) {
114 for (unsigned int c = 0; c < nbCols; c++) {
115 stdev += (I[r][c] - mean) * (I[r][c] - mean);
116 }
117 }
118 stdev *= scale;
119 stdev = std::sqrt(stdev);
120}
121
122void setGradientOutsideClass(const vpImage<unsigned char> &I, const int &gaussianKernelSize, const float &gaussianStdev,
123 vpCannyEdgeDetection &cannyDetector, const unsigned int apertureSize,
125 vpImage<unsigned char> &dIx_uchar, vpImage<unsigned char> &dIy_uchar)
126{
127 // Computing the gradients
128 vpImage<float> dIx, dIy;
129 vpImageFilter::computePartialDerivatives(I, dIx, dIy, true, true, true, gaussianKernelSize, gaussianStdev,
130 apertureSize, filteringType);
131
132 // Set the gradients of the vpCannyEdgeDetection
133 cannyDetector.setGradients(dIx, dIy);
134
135 // Display the gradients
136 float mean, max, stdev;
137 computeMeanMaxStdev(dIx, mean, max, stdev);
138
139#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
140 std::string title = "Gradient along the horizontal axis. Mean = " + std::to_string(mean)
141 + "+/-" + std::to_string(stdev) + " Max = " + std::to_string(max);
142#else
143 std::string title;
144 {
145 std::stringstream ss;
146 ss << "Gradient along the horizontal axis. Mean = " << mean<< "+/-" << stdev<< " Max = " << max;
147 title = ss.str();
148 }
149#endif
150 vpImageConvert::convert(dIx, dIx_uchar);
151 drawingHelpers::display(dIx_uchar, title);
152 computeMeanMaxStdev(dIy, mean, max, stdev);
153#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
154 title = "Gradient along the horizontal axis. Mean = " + std::to_string(mean)
155 + "+/-" + std::to_string(stdev) + " Max = " + std::to_string(max);
156#else
157 {
158 std::stringstream ss;
159 ss << "Gradient along the horizontal axis. Mean = " << mean<< "+/-" << stdev<< " Max = " << max;
160 title = ss.str();
161 }
162#endif
163 vpImageConvert::convert(dIy, dIy_uchar);
164 drawingHelpers::display(dIy_uchar, title);
165}
166
167bool sortImagePoints(const vpImagePoint &a, const vpImagePoint &b)
168{
169 if (a.get_i() < b.get_i()) {
170 return true;
171 }
172 else if (vpMath::equal(a.get_i(), b.get_i()) && (a.get_j() < b.get_j())) {
173 return true;
174 }
175 return false;
176}
177
178void checkEdgeList(const vpCannyEdgeDetection &cannyDetector, const vpImage<unsigned char> &I_canny_visp)
179{
180 std::vector<vpImagePoint> listEdgePoints = cannyDetector.getEdgePointsList();
181 // Check if the edge points are uniquely present in the edge lists
182 std::vector<vpImagePoint> cpyListEdgePoints = listEdgePoints;
183 std::sort(cpyListEdgePoints.begin(), cpyListEdgePoints.end(), sortImagePoints);
184 std::vector<vpImagePoint>::iterator last = std::unique(cpyListEdgePoints.begin(), cpyListEdgePoints.end());
185 static_cast<void>(cpyListEdgePoints.erase(last, cpyListEdgePoints.end()));
186 if (listEdgePoints.size() != cpyListEdgePoints.size()) {
187 throw(vpException(vpException::fatalError, "There are duplicated points in the edge points list !"));
188 }
189 // Check if all the edge points in the list have been set in the image
190 std::vector<vpImagePoint>::iterator start = listEdgePoints.begin();
191 std::vector<vpImagePoint>::iterator stop = listEdgePoints.end();
192 for (std::vector<vpImagePoint>::iterator it = start; it != stop; ++it) {
193 if (I_canny_visp[static_cast<unsigned int>(it->get_i())][static_cast<unsigned int>(it->get_j())] != 255) {
194 throw(vpException(vpException::fatalError, "A point of the edge-point list has not been set in the image !"));
195 }
196 }
197 // Check if all the edge points in the image have been set in the list
198 unsigned int nbRows = I_canny_visp.getRows();
199 unsigned int nbCols = I_canny_visp.getCols();
200 for (unsigned int i = 0; i < nbRows; ++i) {
201 for (unsigned int j = 0; j < nbCols; ++j) {
202 if (I_canny_visp[i][j] == 255) {
203 vpImagePoint searchedPoint(i, j);
204 std::vector<vpImagePoint>::iterator idx = std::find(listEdgePoints.begin(), listEdgePoints.end(), searchedPoint);
205 if (idx == listEdgePoints.end()) {
206 throw(vpException(vpException::fatalError, "A point of the image has not been set in the edge-point list !"));
207 }
208 }
209 }
210 }
211
212 std::cout << "All the edge-point list tests went well !" << std::endl;
213}
214
215void usage(const std::string &softName, const SoftwareArguments &options)
216{
217 std::cout << "NAME" << std::endl;
218 std::cout << softName << ": software to test the vpCannyEdgeComputation class and vpImageFilter::canny method" << std::endl;
219 std::cout << "SYNOPSIS" << std::endl;
220 std::cout << "\t" << softName
221 << " [-i, --image <pathToImg>]"
222 << " [-g, --gradient <kernelSize stdev>]"
223 << " [-t, --thresh <lowerThresh upperThresh>]"
224 << " [-a, --aperture <apertureSize>]"
225 << " [-f, --filter <filterName>]"
226 << " [-r, --ratio <lowerThreshRatio upperThreshRatio>]"
227 << " [-b, --backend <backendName>]"
228 << " [-n, --nb-threads <number of threads>]"
229 << " [-e, --edge-list]" << std::endl
230 << " [-h, --help]" << std::endl
231 << std::endl;
232 std::cout << "DESCRIPTION" << std::endl;
233 std::cout << "\t-i, --image <pathToImg>" << std::endl
234 << "\t\tPermits to load an image on which will be tested the vpCanny class." << std::endl
235 << "\t\tWhen empty uses a simulated image." << std::endl
236 << std::endl;
237 std::cout << "\t-g, --gradient <kernelSize stdev>" << std::endl
238 << "\t\tPermits to compute the gradients of the image outside the vpCanny class." << std::endl
239 << "\t\tFirst parameter is the size of the Gaussian kernel used to compute the gradients." << std::endl
240 << "\t\tSecond parameter is the standard deviation of the Gaussian kernel used to compute the gradients." << std::endl
241 << "\t\tDefault: " << options.m_gaussianKernelSize << " " << options.m_gaussianStdev << std::endl
242 << std::endl;
243 std::cout << "\t-t, --thresh <lowerThresh upperThresh>" << std::endl
244 << "\t\tPermits to set the lower and upper thresholds of the vpCanny class." << std::endl
245 << "\t\tFirst parameter is the lower threshold." << std::endl
246 << "\t\tSecond parameter is the upper threshold." << std::endl
247 << "\t\tWhen set to -1 thresholds are computed automatically." << std::endl
248 << "\t\tDefault: " << options.m_lowerThresh << " " << options.m_upperThresh << std::endl
249 << std::endl;
250 std::cout << "\t-a, --aperture <apertureSize>" << std::endl
251 << "\t\tPermits to set the size of the gradient filter kernel." << std::endl
252 << "\t\tParameter must be odd and positive." << std::endl
253 << "\t\tDefault: " << options.m_apertureSize << std::endl
254 << std::endl;
255 std::cout << "\t-f, --filter <filterName>" << std::endl
256 << "\t\tPermits to choose the type of filter to apply to compute the gradient." << std::endl
257 << "\t\tAvailable values: " << vpImageFilter::vpGetCannyFiltAndGradTypes("<", " | ", ">") << std::endl
258 << "\t\tDefault: " << vpImageFilter::vpCannyFiltAndGradTypeToStr(options.m_filteringType) << std::endl
259 << std::endl;
260 std::cout << "\t-r, --ratio <lowerThreshRatio upperThreshRatio>" << std::endl
261 << "\t\tPermits to set the lower and upper thresholds ratio of the vpCanny class." << std::endl
262 << "\t\tFirst parameter is the lower threshold ratio." << std::endl
263 << "\t\tSecond parameter is the upper threshold ratio." << std::endl
264 << "\t\tDefault: " << options.m_lowerThreshRatio << " " << options.m_upperThreshRatio << std::endl
265 << std::endl;
266 std::cout << "\t-b, --backend <backendName>" << std::endl
267 << "\t\tPermits to use the vpImageFilter::canny method for comparison." << std::endl
268 << "\t\tAvailable values: " << vpImageFilter::vpCannyBackendTypeList("<", " | ", ">") << std::endl
269 << "\t\tDefault: " << vpImageFilter::vpCannyBackendTypeToString(options.m_backend) << std::endl
270 << std::endl;
271 std::cout << "\t-n, --nb-threads <number of threads>" << std::endl
272 << "\t\tPermits to choose the number of threads to use for the Canny." << std::endl
273 << "\t\tUse -1 to automatically choose the highest possible number of threads." << std::endl
274 << "\t\tDefault: " << options.m_nbThread << std::endl
275 << std::endl;
276 std::cout << "\t-e, --edge-list" << std::endl
277 << "\t\tPermits to save the edge list." << std::endl
278 << "\t\tDefault: OFF" << std::endl
279 << std::endl;
280 std::cout << "\t-h, --help" << std::endl
281 << "\t\tPermits to display the different arguments this software handles." << std::endl
282 << std::endl;
283}
284
285int main(int argc, const char *argv[])
286{
287 SoftwareArguments options;
288 for (int i = 1; i < argc; i++) {
289 std::string argv_str = std::string(argv[i]);
290 if ((argv_str == "-i" || argv_str == "--image") && i + 1 < argc) {
291 options.m_img = std::string(argv[i + 1]);
292 i++;
293 }
294 else if ((argv_str == "-g" || argv_str == "--gradient") && i + 2 < argc) {
295 options.m_gradientOutsideClass = true;
296 options.m_gaussianKernelSize = atoi(argv[i + 1]);
297 options.m_gaussianStdev = static_cast<float>(atof(argv[i + 2]));
298 i += 2;
299 }
300 else if ((argv_str == "-t" || argv_str == "--thresh") && i + 2 < argc) {
301 options.m_lowerThresh = static_cast<float>(atof(argv[i + 1]));
302 options.m_upperThresh = static_cast<float>(atof(argv[i + 2]));
303 i += 2;
304 }
305 else if ((argv_str == "-a" || argv_str == "--aperture") && i + 1 < argc) {
306 options.m_apertureSize = std::atoi(argv[i + 1]);
307 i++;
308 }
309 else if ((argv_str == "-f" || argv_str == "--filter") && i + 1 < argc) {
310 options.m_filteringType = vpImageFilter::vpCannyFiltAndGradTypeFromStr(std::string(argv[i + 1]));
311 i++;
312 }
313 else if ((argv_str == "-r" || argv_str == "--ratio") && i + 2 < argc) {
314 options.m_lowerThreshRatio = static_cast<float>(std::atof(argv[i + 1]));
315 options.m_upperThreshRatio = static_cast<float>(std::atof(argv[i + 2]));
316 i += 2;
317 }
318 else if ((argv_str == "-b" || argv_str == "--backend") && i + 1 < argc) {
319 options.m_useVpImageFilterCanny = true;
320 options.m_backend = vpImageFilter::vpCannyBackendTypeFromString(std::string(argv[i+1]));
321 i++;
322 }
323 else if ((argv_str == "-n" || argv_str == "--nb-threads") && i + 1 < argc) {
324 options.m_nbThread = std::atoi(argv[i + 1]);
325 i++;
326 }
327 else if ((argv_str == "-e") || (argv_str == "--edge-list")) {
328 options.m_saveEdgeList = true;
329 }
330 else if (argv_str == "-h" || argv_str == "--help") {
331 usage(std::string(argv[0]), options);
332 return EXIT_SUCCESS;
333 }
334 else {
335 std::cerr << "Argument \"" << argv_str << "\" is unknown." << std::endl;
336 return EXIT_FAILURE;
337 }
338 }
339
340 std::string configAsTxt("Canny Configuration:\n");
341 configAsTxt += "\tFiltering + gradient operators = " + vpImageFilter::vpCannyFiltAndGradTypeToStr(options.m_filteringType) + "\n";
342#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
343 configAsTxt += "\tGaussian filter kernel size = " + std::to_string(options.m_gaussianKernelSize) + "\n";
344 configAsTxt += "\tGaussian filter standard deviation = " + std::to_string(options.m_gaussianStdev) + "\n";
345 configAsTxt += "\tGradient filter kernel size = " + std::to_string(options.m_apertureSize) + "\n";
346 configAsTxt += "\tCanny edge filter thresholds = [" + std::to_string(options.m_lowerThresh) + " ; " + std::to_string(options.m_upperThresh) + "]\n";
347 configAsTxt += "\tCanny edge filter thresholds ratio (for auto-thresholding) = [" + std::to_string(options.m_lowerThreshRatio) + " ; " + std::to_string(options.m_upperThreshRatio) + "]\n";
348 configAsTxt += "\tCanny edge filter nb threads = " + (options.m_nbThread > 0 ? std::to_string(options.m_nbThread) : std::string("auto")) + "\n";
349#else
350 {
351 std::stringstream ss;
352 ss << "\tGaussian filter kernel size = " << options.m_gaussianKernelSize << "\n";
353 ss << "\tGaussian filter standard deviation = " << options.m_gaussianStdev << "\n";
354 ss << "\tGradient filter kernel size = " << options.m_apertureSize << "\n";
355 ss << "\tCanny edge filter thresholds = [" << options.m_lowerThresh << " ; " << options.m_upperThresh << "]\n";
356 ss << "\tCanny edge filter thresholds ratio (for auto-thresholding) = [" << options.m_lowerThreshRatio << " ; " << options.m_upperThreshRatio << "]\n";
357 ss << "\tCanny edge filter nb threads = ";
358 if (options.m_nbThread > 0) {
359 ss << options.m_nbThread;
360 }
361 else {
362 ss << "auto";
363 }
364 ss << "\n";
365 configAsTxt += ss.str();
366 }
367#endif
368 std::cout << configAsTxt << std::endl;
369
370 vpCannyEdgeDetection cannyDetector(options.m_gaussianKernelSize, options.m_gaussianStdev, options.m_apertureSize,
371 options.m_lowerThresh, options.m_upperThresh, options.m_lowerThreshRatio, options.m_upperThreshRatio,
372 options.m_filteringType, options.m_saveEdgeList);
373 cannyDetector.setNbThread(options.m_nbThread);
374 vpImage<unsigned char> I_canny_input, I_canny_visp, dIx_uchar, dIy_uchar, I_canny_imgFilter;
375 if (!options.m_img.empty()) {
376 // Detection on the user image
377 vpImageIo::read(I_canny_input, options.m_img);
378 }
379 else {
380 // Detection on a fake image of a square
381 I_canny_input.resize(720, 1280, 0);
382 for (unsigned int r = 150; r < 350; r++) {
383 for (unsigned int c = 150; c < 350; c++) {
384 I_canny_input[r][c] = 125;
385 }
386 }
387 }
388
389 // Initialization of the displays
390 I_canny_visp = I_canny_imgFilter = dIx_uchar = dIy_uchar = I_canny_input;
391 vpImage<unsigned char> *p_dIx = nullptr, *p_dIy = nullptr, *p_IcannyImgFilter = nullptr;
392
393 if (options.m_gradientOutsideClass) {
394 p_dIx = &dIx_uchar;
395 p_dIy = &dIy_uchar;
396 }
397
398 if (options.m_useVpImageFilterCanny) {
399 p_IcannyImgFilter = &I_canny_imgFilter;
400 }
401 drawingHelpers::init(I_canny_input, I_canny_visp, p_dIx, p_dIy, p_IcannyImgFilter);
402
403 // Computing the gradient outside the vpCannyEdgeDetection class if asked
404 if (options.m_gradientOutsideClass) {
405 setGradientOutsideClass(I_canny_input, options.m_gaussianKernelSize, options.m_gaussianStdev, cannyDetector, options.m_apertureSize,
406 options.m_filteringType, dIx_uchar, dIy_uchar);
407 }
408 double tStart = vpTime::measureTimeMicros();
409 I_canny_visp = cannyDetector.detect(I_canny_input);
410 double tEnd = vpTime::measureTimeMicros();
411 std::cout << "Time to compute the edge-map: " << (tEnd - tStart) / 1000. << " ms" << std::endl;
412
413 float mean, max, stdev;
414 computeMeanMaxStdev(I_canny_input, mean, max, stdev);
415 if (options.m_saveEdgeList) {
416 checkEdgeList(cannyDetector, I_canny_visp);
417 }
418#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
419 std::string title("Input of the Canny edge detector. Mean = " + std::to_string(mean) + "+/-" + std::to_string(stdev) + " Max = " + std::to_string(max));
420#else
421 std::string title;
422 {
423 std::stringstream ss;
424 ss << "Input of the Canny edge detector. Mean = " << mean << "+/-" << stdev << " Max = " << max;
425 title = ss.str();
426 }
427#endif
428 drawingHelpers::display(I_canny_input, title);
429 drawingHelpers::display(I_canny_visp, "Canny results on image " + options.m_img);
430
431 if (options.m_useVpImageFilterCanny) {
432 float cannyThresh = options.m_upperThresh;
433 float lowerThresh(options.m_lowerThresh);
434 vpImageFilter::canny(I_canny_input, I_canny_imgFilter, options.m_gaussianKernelSize, lowerThresh, cannyThresh,
435 options.m_apertureSize, options.m_gaussianStdev, options.m_lowerThreshRatio, options.m_upperThreshRatio, true,
436 options.m_backend, options.m_filteringType);
437 drawingHelpers::display(I_canny_imgFilter, "Canny results with \"" + vpImageFilter::vpCannyBackendTypeToString(options.m_backend) + "\" backend");
438 }
439
440 drawingHelpers::waitForClick(I_canny_input, true);
441 return EXIT_SUCCESS;
442}
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.
const std::vector< vpImagePoint > & getEdgePointsList() const
Get the list of edge-points that have been detected.
void setNbThread(const int &maxNbThread)
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.
Definition vpException.h:60
@ fatalError
Fatal error.
Definition vpException.h:72
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 ...
double get_j() const
double get_i() const
Definition of the vpImage class member functions.
Definition vpImage.h:131
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:544
unsigned int getCols() const
Definition vpImage.h:171
unsigned int getRows() const
Definition vpImage.h:212
static bool equal(double x, double y, double threshold=0.001)
Definition vpMath.h:470
VISP_EXPORT double measureTimeMicros()
vpImageFilter::vpCannyFilteringAndGradientType m_filteringType
vpImageFilter::vpCannyBackendType m_backend