#include <visp3/core/vpConfig.h>
#include <visp3/core/vpCannyEdgeDetection.h>
#include <visp3/core/vpImageFilter.h>
#include <visp3/io/vpImageIo.h>
#ifdef HAVE_OPENCV_IMGPROC
#include <opencv2/imgproc/imgproc.hpp>
#endif
#include "drawingHelpers.h"
#ifdef ENABLE_VISP_NAMESPACE
#endif
{
std::string m_img;
bool m_gradientOutsideClass;
bool m_useVpImageFilterCanny;
bool m_saveEdgeList;
int m_gaussianKernelSize;
int m_apertureSize;
float m_gaussianStdev;
float m_lowerThresh;
float m_upperThresh;
float m_lowerThreshRatio;
float m_upperThreshRatio;
: m_img("")
, m_gradientOutsideClass(false)
, m_useVpImageFilterCanny(false)
, m_saveEdgeList(false)
, m_gaussianKernelSize(3)
, m_apertureSize(3)
, m_gaussianStdev(1.)
, m_lowerThresh(-1.)
, m_upperThresh(-1.)
, m_lowerThreshRatio(0.6f)
, m_upperThreshRatio(0.8f)
#ifdef VISP_HAVE_OPENCV
#else
#endif
{ }
template <class T>
void computeMeanMaxStdev(
const vpImage<T> &I,
float &mean,
float &max,
float &stdev)
{
max = std::numeric_limits<float>::epsilon();
mean = 0.;
stdev = 0.;
float scale = 1.f / (static_cast<float>(nbRows) * static_cast<float>(nbCols));
for (unsigned int r = 0; r < nbRows; r++) {
for (unsigned int c = 0; c < nbCols; c++) {
mean += I[r][c];
max = std::max<float>(max, static_cast<float>(I[r][c]));
}
}
mean *= scale;
for (unsigned int r = 0; r < nbRows; r++) {
for (unsigned int c = 0; c < nbCols; c++) {
stdev += (I[r][c] - mean) * (I[r][c] - mean);
}
}
stdev *= scale;
stdev = std::sqrt(stdev);
}
void setGradientOutsideClass(
const vpImage<unsigned char> &I,
const int &gaussianKernelSize,
const float &gaussianStdev,
)
{
apertureSize, filteringType);
float mean, max, stdev;
computeMeanMaxStdev(dIx, mean, max, stdev);
#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
std::string title = "Gradient along the horizontal axis. Mean = " + std::to_string(mean)
+ "+/-" + std::to_string(stdev) + " Max = " + std::to_string(max);
#else
std::string title;
{
std::stringstream ss;
ss << "Gradient along the horizontal axis. Mean = " << mean<< "+/-" << stdev<< " Max = " << max;
title = ss.str();
}
#endif
drawingHelpers::display(dIx_uchar, title);
computeMeanMaxStdev(dIy, mean, max, stdev);
#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
title = "Gradient along the horizontal axis. Mean = " + std::to_string(mean)
+ "+/-" + std::to_string(stdev) + " Max = " + std::to_string(max);
#else
{
std::stringstream ss;
ss << "Gradient along the horizontal axis. Mean = " << mean<< "+/-" << stdev<< " Max = " << max;
title = ss.str();
}
#endif
drawingHelpers::display(dIy_uchar, title);
}
{
return true;
}
return true;
}
return false;
}
{
std::vector<vpImagePoint> cpyListEdgePoints = listEdgePoints;
std::sort(cpyListEdgePoints.begin(), cpyListEdgePoints.end(), sortImagePoints);
std::vector<vpImagePoint>::iterator last = std::unique(cpyListEdgePoints.begin(), cpyListEdgePoints.end());
static_cast<void>(cpyListEdgePoints.erase(last, cpyListEdgePoints.end()));
if (listEdgePoints.size() != cpyListEdgePoints.size()) {
}
std::vector<vpImagePoint>::iterator start = listEdgePoints.begin();
std::vector<vpImagePoint>::iterator stop = listEdgePoints.end();
for (std::vector<vpImagePoint>::iterator it = start; it != stop; ++it) {
if (I_canny_visp[static_cast<unsigned int>(it->get_i())][static_cast<unsigned int>(it->get_j())] != 255) {
}
}
unsigned int nbRows = I_canny_visp.
getRows();
unsigned int nbCols = I_canny_visp.
getCols();
for (unsigned int i = 0; i < nbRows; ++i) {
for (unsigned int j = 0; j < nbCols; ++j) {
if (I_canny_visp[i][j] == 255) {
std::vector<vpImagePoint>::iterator idx = std::find(listEdgePoints.begin(), listEdgePoints.end(), searchedPoint);
if (idx == listEdgePoints.end()) {
}
}
}
}
std::cout << "All the edge-point list tests went well !" << std::endl;
}
{
std::cout << "NAME" << std::endl;
std::cout << softName << ": software to test the vpCannyEdgeComputation class and vpImageFilter::canny method" << std::endl;
std::cout << "SYNOPSIS" << std::endl;
std::cout << "\t" << softName
<< " [-i, --image <pathToImg>]"
<< " [-g, --gradient <kernelSize stdev>]"
<< " [-t, --thresh <lowerThresh upperThresh>]"
<< " [-a, --aperture <apertureSize>]"
<< " [-f, --filter <filterName>]"
<< " [-r, --ratio <lowerThreshRatio upperThreshRatio>]"
<< " [-b, --backend <backendName>]"
<< " [-e, --edge-list]" << std::endl
<< " [-h, --help]" << std::endl
<< std::endl;
std::cout << "DESCRIPTION" << std::endl;
std::cout << "\t-i, --image <pathToImg>" << std::endl
<< "\t\tPermits to load an image on which will be tested the vpCanny class." << std::endl
<< "\t\tWhen empty uses a simulated image." << std::endl
<< std::endl;
std::cout << "\t-g, --gradient <kernelSize stdev>" << std::endl
<< "\t\tPermits to compute the gradients of the image outside the vpCanny class." << std::endl
<< "\t\tFirst parameter is the size of the Gaussian kernel used to compute the gradients." << std::endl
<< "\t\tSecond parameter is the standard deviation of the Gaussian kernel used to compute the gradients." << std::endl
<< std::endl;
std::cout << "\t-t, --thresh <lowerThresh upperThresh>" << std::endl
<< "\t\tPermits to set the lower and upper thresholds of the vpCanny class." << std::endl
<< "\t\tFirst parameter is the lower threshold." << std::endl
<< "\t\tSecond parameter is the upper threshold." << std::endl
<< "\t\tWhen set to -1 thresholds are computed automatically." << std::endl
<< std::endl;
std::cout << "\t-a, --aperture <apertureSize>" << std::endl
<< "\t\tPermits to set the size of the gradient filter kernel." << std::endl
<< "\t\tParameter must be odd and positive." << std::endl
<< std::endl;
std::cout << "\t-f, --filter <filterName>" << std::endl
<< "\t\tPermits to choose the type of filter to apply to compute the gradient." << std::endl
<< std::endl;
std::cout << "\t-r, --ratio <lowerThreshRatio upperThreshRatio>" << std::endl
<< "\t\tPermits to set the lower and upper thresholds ratio of the vpCanny class." << std::endl
<< "\t\tFirst parameter is the lower threshold ratio." << std::endl
<< "\t\tSecond parameter is the upper threshold ratio." << std::endl
<< std::endl;
std::cout << "\t-b, --backend <backendName>" << std::endl
<< "\t\tPermits to use the vpImageFilter::canny method for comparison." << std::endl
<< std::endl;
std::cout << "\t-e, --edge-list" << std::endl
<< "\t\tPermits to save the edge list." << std::endl
<< "\t\tDefault: OFF" << std::endl
<< std::endl;
std::cout << "\t-h, --help" << std::endl
<< "\t\tPermits to display the different arguments this software handles." << std::endl
<< std::endl;
}
int main(int argc, const char *argv[])
{
for (int i = 1; i < argc; i++) {
std::string argv_str = std::string(argv[i]);
if ((argv_str == "-i" || argv_str == "--image") && i + 1 < argc) {
options.
m_img = std::string(argv[i + 1]);
i++;
}
else if ((argv_str == "-g" || argv_str == "--gradient") && i + 2 < argc) {
i += 2;
}
else if ((argv_str == "-t" || argv_str == "--thresh") && i + 2 < argc) {
i += 2;
}
else if ((argv_str == "-a" || argv_str == "--aperture") && i + 1 < argc) {
i++;
}
else if ((argv_str == "-f" || argv_str == "--filter") && i + 1 < argc) {
i++;
}
else if ((argv_str == "-r" || argv_str == "--ratio") && i + 2 < argc) {
i += 2;
}
else if ((argv_str == "-b" || argv_str == "--backend") && i + 1 < argc) {
i++;
}
else if ((argv_str == "-e") || (argv_str == "--edge-list")) {
}
else if (argv_str == "-h" || argv_str == "--help") {
usage(std::string(argv[0]), options);
return EXIT_SUCCESS;
}
else {
std::cerr << "Argument \"" << argv_str << "\" is unknown." << std::endl;
return EXIT_FAILURE;
}
}
std::string configAsTxt("Canny Configuration:\n");
#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
configAsTxt +=
"\tGaussian filter kernel size = " + std::to_string(options.
m_gaussianKernelSize) +
"\n";
configAsTxt +=
"\tGaussian filter standard deviation = " + std::to_string(options.
m_gaussianStdev) +
"\n";
configAsTxt +=
"\tGradient filter kernel size = " + std::to_string(options.
m_apertureSize) +
"\n";
configAsTxt +=
"\tCanny edge filter thresholds = [" + std::to_string(options.
m_lowerThresh) +
" ; " + std::to_string(options.
m_upperThresh) +
"]\n";
configAsTxt +=
"\tCanny edge filter thresholds ratio (for auto-thresholding) = [" + std::to_string(options.
m_lowerThreshRatio) +
" ; " + std::to_string(options.
m_upperThreshRatio) +
"]\n";
#else
{
std::stringstream ss;
ss <<
"\tGaussian filter standard deviation = " << options.
m_gaussianStdev <<
"\n";
ss <<
"\tGradient filter kernel size = " << options.
m_apertureSize <<
"\n";
configAsTxt += ss.str();
}
#endif
std::cout << configAsTxt << std::endl;
if (!options.
m_img.empty()) {
}
else {
I_canny_input.
resize(500, 500, 0);
for (unsigned int r = 150; r < 350; r++) {
for (unsigned int c = 150; c < 350; c++) {
I_canny_input[r][c] = 125;
}
}
}
I_canny_visp = I_canny_imgFilter = dIx_uchar = dIy_uchar = I_canny_input;
p_dIx = &dIx_uchar;
p_dIy = &dIy_uchar;
}
p_IcannyImgFilter = &I_canny_imgFilter;
}
drawingHelpers::init(I_canny_input, I_canny_visp, p_dIx, p_dIy, p_IcannyImgFilter);
}
I_canny_visp = cannyDetector.
detect(I_canny_input);
float mean, max, stdev;
computeMeanMaxStdev(I_canny_input, mean, max, stdev);
checkEdgeList(cannyDetector, I_canny_visp);
}
#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
std::string title("Input of the Canny edge detector. Mean = " + std::to_string(mean) + "+/-" + std::to_string(stdev) + " Max = " + std::to_string(max));
#else
std::string title;
{
std::stringstream ss;
ss << "Input of the Canny edge detector. Mean = " << mean << "+/-" << stdev << " Max = " << max;
title = ss.str();
}
#endif
drawingHelpers::display(I_canny_input, title);
drawingHelpers::display(I_canny_visp,
"Canny results on image " + options.
m_img);
}
drawingHelpers::waitForClick(I_canny_input, true);
return EXIT_SUCCESS;
}
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)
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.
@ CANNY_GBLUR_SOBEL_FILTERING
Apply Gaussian blur + Sobel operator on the input image.
vpCannyBackendType
Canny filter backends for the edge detection operations.
@ CANNY_VISP_BACKEND
Use ViSP.
@ CANNY_OPENCV_BACKEND
Use OpenCV.
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