41#include <visp3/core/vpImageConvert.h>
42#include <visp3/core/vpImageFilter.h>
43#include <visp3/core/vpIoTools.h>
44#include <visp3/core/vpMath.h>
45#include <visp3/core/vpRGBa.h>
46#include <visp3/io/vpImageIo.h>
47#include <visp3/io/vpParseArgv.h>
50#define GETOPTARGS "cdi:p:h"
52#ifdef ENABLE_VISP_NAMESPACE
65void usage(
const char *name,
const char *badparam, std::string ipath)
68 Test vpImageFilter class.\n\
71 %s [-i <input image path>] [-p <personal image path>]\n\
78 -i <input image path> %s\n\
79 Set image input path.\n\
80 From this path read \"Klimt/Klimt.pgm,\n\
81 .ppm, .jpeg and .png images.\n\
82 Setting the VISP_INPUT_IMAGE_PATH environment\n\
83 variable produces the same behaviour than using\n\
86 -p <personal image path> \n\
87 Path to an image used to test image reading function.\n\
88 Example: -p /my_path_to/image.png\n\
95 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
107bool getOptions(
int argc,
const char **argv, std::string &ipath, std::string &ppath)
121 usage(argv[0],
nullptr, ipath);
129 usage(argv[0], optarg_, ipath);
134 if ((c == 1) || (c == -1)) {
136 usage(argv[0],
nullptr, ipath);
137 std::cerr <<
"ERROR: " << std::endl;
138 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
145#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
146bool check_results(
const cv::Mat &mat,
const vpImage<double> &I,
unsigned int half_size_y,
unsigned int half_size_x)
148 for (
unsigned int i = half_size_y;
i < I.getHeight() - half_size_y;
i++) {
149 for (
unsigned int j = half_size_x;
j < I.getWidth() - half_size_x;
j++) {
150 if (!
vpMath::equal(mat.at<
double>(
static_cast<int>(i),
static_cast<int>(j)), I[i][j],
151 std::numeric_limits<double>::epsilon())) {
160bool check_results(
const cv::Mat &mat,
const vpImage<double> &I,
unsigned int margin,
double threshold)
162 for (
unsigned int i = margin;
i < I.getHeight() - margin;
i++) {
163 for (
unsigned int j = margin;
j < I.getWidth() - margin;
j++) {
164 if (!
vpMath::equal(mat.at<
unsigned char>(
static_cast<int>(i),
static_cast<int>(j)), I[i][j], threshold)) {
173bool check_results(
const cv::Mat &mat,
const vpImage<vpRGBa> &I,
unsigned int margin,
double threshold)
175 for (
unsigned int i = margin;
i < I.getHeight() - margin;
i++) {
176 for (
unsigned int j = margin;
j < I.getWidth() - margin;
j++) {
177 if (!
vpMath::equal(
static_cast<double>(mat.at<cv::Vec3b>(
static_cast<int>(i),
static_cast<int>(j))[2]), I[i][j].R,
181 if (!
vpMath::equal(
static_cast<double>(mat.at<cv::Vec3b>(
static_cast<int>(i),
static_cast<int>(j))[1]), I[i][j].G,
185 if (!
vpMath::equal(
static_cast<double>(mat.at<cv::Vec3b>(
static_cast<int>(i),
static_cast<int>(j))[0]), I[i][j].B,
197int main(
int argc,
const char *argv[])
200 std::string env_ipath;
201 std::string opt_ipath;
202 std::string opt_ppath;
211 if (!env_ipath.empty())
215 if (getOptions(argc, argv, opt_ipath, opt_ppath) ==
false) {
220 if (!opt_ipath.empty())
225 if (!opt_ipath.empty() && !env_ipath.empty()) {
226 if (ipath != env_ipath) {
227 std::cout << std::endl <<
"WARNING: " << std::endl;
228 std::cout <<
" Since -i <visp image path=" << ipath <<
"> "
229 <<
" is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
230 <<
" we skip the environment variable." << std::endl;
238 for (
unsigned int i = 0, cpt = 1;
i < kernel_1.getRows();
i++) {
239 for (
unsigned int j = 0;
j < kernel_1.getCols();
j++, cpt++) {
240 kernel_1[
i][
j] = cpt;
243 std::cout <<
"kernel_1:\n" << kernel_1 << std::endl;
246 for (
unsigned int i = 0, cpt = 1;
i < kernel_2.getRows();
i++) {
247 for (
unsigned int j = 0;
j < kernel_2.getCols();
j++, cpt++) {
248 kernel_2[
i][
j] = cpt;
251 std::cout <<
"kernel_2:\n" << kernel_2 << std::endl;
254 for (
unsigned int i = 0, cpt = 1;
i < kernel_3.getRows();
i++) {
255 for (
unsigned int j = 0;
j < kernel_3.getCols();
j++, cpt++) {
256 kernel_3[
i][
j] = cpt;
259 std::cout <<
"kernel_3:\n" << kernel_3 << std::endl;
264 for (
unsigned int i = 0;
i < I.getSize();
i++) {
265 I.bitmap[
i] = (
unsigned char)i;
267 std::cout <<
"I:\n" << I << std::endl;
275 std::cout <<
"\nI_correlation_1:\n" << I_correlation_1 << std::endl;
276 std::cout <<
"I_correlation_2:\n" << I_correlation_2 << std::endl;
277 std::cout <<
"I_correlation_3:\n" << I_correlation_3 << std::endl;
279#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
283 cv::Mat mat_kernel_1(2, 2, CV_64F);
284 for (
int i = 0, cpt = 1;
i < mat_kernel_1.rows;
i++) {
285 for (
int j = 0;
j < mat_kernel_1.cols;
j++, cpt++) {
286 mat_kernel_1.at<
double>(
i,
j) = cpt;
290 cv::Mat mat_kernel_2(3, 3, CV_64F);
291 for (
int i = 0, cpt = 1;
i < mat_kernel_2.rows;
i++) {
292 for (
int j = 0;
j < mat_kernel_2.cols;
j++, cpt++) {
293 mat_kernel_2.at<
double>(
i,
j) = cpt;
297 cv::Mat mat_kernel_3(2, 3, CV_64F);
298 for (
int i = 0, cpt = 1;
i < mat_kernel_3.rows;
i++) {
299 for (
int j = 0;
j < mat_kernel_3.cols;
j++, cpt++) {
300 mat_kernel_3.at<
double>(
i,
j) = cpt;
304 cv::Mat matImg_correlation_1, matImg_correlation_2, matImg_correlation_3;
305 cv::filter2D(matImg, matImg_correlation_1, CV_64F, mat_kernel_1);
306 cv::filter2D(matImg, matImg_correlation_2, CV_64F, mat_kernel_2);
307 cv::filter2D(matImg, matImg_correlation_3, CV_64F, mat_kernel_3);
309 std::cout <<
"\nTest correlation on small image:" << std::endl;
310 std::cout <<
"(I_correlation_1 == matImg_correlation_1)? "
311 << check_results(matImg_correlation_1, I_correlation_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2)
313 std::cout <<
"(I_correlation_2 == matImg_correlation_2)? "
314 << check_results(matImg_correlation_2, I_correlation_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2)
316 std::cout <<
"(I_correlation_3 == matImg_correlation_3)? "
317 << check_results(matImg_correlation_3, I_correlation_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2)
327 std::cout <<
"\nI_convolution_1:\n" << I_convolution_1 << std::endl;
328 std::cout <<
"I_convolution_2:\n" << I_convolution_2 << std::endl;
329 std::cout <<
"I_convolution_3:\n" << I_convolution_3 << std::endl;
331#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
332 cv::Mat mat_kernel_1_flip, mat_kernel_2_flip, mat_kernel_3_flip;
333 cv::flip(mat_kernel_1, mat_kernel_1_flip, -1);
334 cv::flip(mat_kernel_2, mat_kernel_2_flip, -1);
335 cv::flip(mat_kernel_3, mat_kernel_3_flip, -1);
337 cv::Mat matImg_convolution_1, matImg_convolution_2, matImg_convolution_3;
339 cv::Point anchor1(mat_kernel_1_flip.cols - mat_kernel_1_flip.cols / 2 - 1,
340 mat_kernel_1_flip.rows - mat_kernel_1_flip.rows / 2 - 1);
341 cv::filter2D(matImg, matImg_convolution_1, CV_64F, mat_kernel_1_flip, anchor1);
343 cv::Point anchor2(mat_kernel_2_flip.cols - mat_kernel_2_flip.cols / 2 - 1,
344 mat_kernel_2_flip.rows - mat_kernel_2_flip.rows / 2 - 1);
345 cv::filter2D(matImg, matImg_convolution_2, CV_64F, mat_kernel_2_flip, anchor2);
347 cv::Point anchor3(mat_kernel_3_flip.cols - mat_kernel_3_flip.cols / 2 - 1,
348 mat_kernel_3_flip.rows - mat_kernel_3_flip.rows / 2 - 1);
349 cv::filter2D(matImg, matImg_convolution_3, CV_64F, mat_kernel_3_flip, anchor3);
351 std::cout <<
"\nTest convolution on small image:" << std::endl;
352 std::cout <<
"(I_convolution_1 == matImg_convolution_1)? "
353 << check_results(matImg_convolution_1, I_convolution_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2)
355 std::cout <<
"(I_convolution_2 == matImg_convolution_2)? "
356 << check_results(matImg_convolution_2, I_convolution_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2)
358 std::cout <<
"(I_convolution_3 == matImg_convolution_3)? "
359 << check_results(matImg_convolution_3, I_convolution_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2)
362 if (opt_ppath.empty()) {
369 printf(
"Image \"%s\" read successfully\n",
filename.c_str());
378 std::cout <<
"\nTime to do 3 correlation filtering: " <<
t <<
" ms ; Mean: " <<
t / 3.0 <<
" ms" << std::endl;
380#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
384 cv::filter2D(matImg, matImg_correlation_1, CV_64F, mat_kernel_1);
385 cv::filter2D(matImg, matImg_correlation_2, CV_64F, mat_kernel_2);
386 cv::filter2D(matImg, matImg_correlation_3, CV_64F, mat_kernel_3);
388 std::cout <<
"Time to do 3 cv::filter2D: " <<
t <<
" ms ; Mean: " <<
t / 3.0 <<
" ms" << std::endl;
390 std::cout <<
"\nTest correlation on Klimt image:" << std::endl;
391 bool test = check_results(matImg_correlation_1, I_correlation_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2);
392 std::cout <<
"(I_correlation_1 == matImg_correlation_1)? " << test << std::endl;
394 std::cerr <<
"Failed test1 correlation with vpImageFilter::filter()!" << std::endl;
398 test = check_results(matImg_correlation_2, I_correlation_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2);
399 std::cout <<
"(I_correlation_2 == matImg_correlation_2)? " << test << std::endl;
401 std::cerr <<
"Failed test2 correlation with vpImageFilter::filter()!" << std::endl;
405 test = check_results(matImg_correlation_3, I_correlation_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2);
406 std::cout <<
"(I_correlation_3 == matImg_correlation_3)? " << test << std::endl;
408 std::cerr <<
"Failed test3 correlation with vpImageFilter::filter()!" << std::endl;
419 std::cout <<
"\nTime to do 3 convolution filtering: " <<
t <<
" ms ; Mean: " <<
t / 3.0 <<
" ms" << std::endl;
421#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
424 cv::filter2D(matImg, matImg_convolution_1, CV_64F, mat_kernel_1_flip, anchor1);
425 cv::filter2D(matImg, matImg_convolution_2, CV_64F, mat_kernel_2_flip, anchor2);
426 cv::filter2D(matImg, matImg_convolution_3, CV_64F, mat_kernel_3_flip, anchor3);
428 std::cout <<
"Time to do 3 cv::filter2D: " <<
t <<
" ms ; Mean: " <<
t / 3.0 <<
" ms" << std::endl;
430 std::cout <<
"\nTest convolution on Klimt image:" << std::endl;
431 test = check_results(matImg_convolution_1, I_convolution_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2);
432 std::cout <<
"(I_convolution_1 == matImg_convolution_1)? " << test << std::endl;
434 std::cerr <<
"Failed test1 convolution with vpImageFilter::filter()!" << std::endl;
438 test = check_results(matImg_convolution_2, I_convolution_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2);
439 std::cout <<
"(I_convolution_2 == matImg_convolution_2)? " << test << std::endl;
441 std::cerr <<
"Failed test2 convolution with vpImageFilter::filter()!" << std::endl;
445 test = check_results(matImg_convolution_3, I_convolution_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2);
446 std::cout <<
"(I_convolution_3 == matImg_convolution_3)? " << test << std::endl;
448 std::cerr <<
"Failed test3 convolution with vpImageFilter::filter()!" << std::endl;
457 for (
unsigned int i = 0;
i < kernel_sobel_x.getRows();
i++) {
458 for (
unsigned int j = 0;
j < kernel_sobel_x.getCols();
j++) {
459 kernel_sobel_x[
i][
j] = kernel_sobel_x_flip[
i][kernel_sobel_x.getCols() - 1 -
j];
467 std::cout <<
"\nTime to do Sobel: " <<
t <<
" ms" << std::endl;
469#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
470 cv::Mat matImg_sobel_x;
472 cv::Sobel(matImg, matImg_sobel_x, CV_64F, 1, 0, 5);
474 std::cout <<
"Time to do cv::Sobel: " <<
t <<
" ms" << std::endl;
476 std::cout <<
"\nTest Sobel on Klimt image:" << std::endl;
477 std::cout <<
"(I_sobel_x == matImg_sobel_x)? "
478 << check_results(matImg_sobel_x, I_sobel_x, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
487 std::cout <<
"\nTime to do Sobel Iu and Iv: " <<
t <<
" ms" << std::endl;
489#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
490 cv::Mat matImg_sobel_y;
491 cv::Sobel(matImg, matImg_sobel_y, CV_64F, 0, 1, 5);
493 std::cout <<
"(Iu == matImg_sobel_x)? "
494 << check_results(matImg_sobel_x, Iu, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
496 std::cout <<
"(Iv == matImg_sobel_y)? "
497 << check_results(matImg_sobel_y, Iv, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
504 kernel_sep_x[0] = 1.0;
505 kernel_sep_x[1] = 2.0;
506 kernel_sep_x[2] = 0.0;
507 kernel_sep_x[3] = -2.0;
508 kernel_sep_x[4] = -1.0;
510 kernel_sep_y[0] = 1.0;
511 kernel_sep_y[1] = 4.0;
512 kernel_sep_y[2] = 6.0;
513 kernel_sep_y[3] = 4.0;
514 kernel_sep_y[4] = 1.0;
519 std::cout <<
"\nTime to do sepFilter: " <<
t <<
" ms" << std::endl;
521#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
522 test = check_results(matImg_sobel_x, Iu, I_sep_filtered.
getRows() / 2, kernel_sobel_x.getCols() / 2);
523 std::cout <<
"(I_sep_filtered == matImg_sobel_x)? " << test << std::endl;
526 std::cerr <<
"Failed separable filter!" << std::endl;
531 std::cout <<
"\nTest median on grayscale image:" << std::endl;
533 for (
unsigned int r = 0;
r < 3;
r++) {
534 for (
unsigned int c = 0; c < 3; c++) {
535 I_median[
r][c] =
r * 3 + c;
539 double expectedMedian = 4.;
541 std::cout <<
"(median (=" << median <<
") == expectedMedian(" << expectedMedian <<
"))? " << test << std::endl;
544 std::cerr <<
"Failed median filter on gray-scale image!" << std::endl;
548 std::cout <<
"\nTest median on vpRGBa image:" << std::endl;
550 for (
unsigned int r = 0;
r < 3;
r++) {
551 for (
unsigned int c = 0; c < 3; c++) {
552 I_median_rgba[
r][c].R =
r * 3 + c;
553 I_median_rgba[
r][c].G = 2 * (
r * 3 + c);
554 I_median_rgba[
r][c].B = 3 * (
r * 3 + c);
558 std::vector<float> expected_median_rgba = { 4.f, 8.f, 12.f };
559 for (
unsigned int i = 0;
i < 3;
i++) {
560 bool test_local =
vpMath::equal(median_rgba[i], expected_median_rgba[i]);
562 std::cout <<
"(median_rgba[" <<
i <<
"] (=" << median_rgba[
i] <<
") == expected_median_rgba[" <<
i <<
"] ( " << expected_median_rgba[
i] <<
"))? " << test_local << std::endl;
565 std::cerr <<
"Failed median filter on vpRGBa image!" << std::endl;
573 std::cout <<
"\nTest Gaussian Blur on Klimt grayscale image:" << std::endl;
578 if (opt_ppath.empty()) {
585 printf(
"Image \"%s\" read successfully\n",
filename.c_str());
588 unsigned int gaussian_filter_size = 7;
593 std::cout <<
"Time to do ViSP Gaussian Blur on grayscale images: " <<
t <<
" ms" << std::endl;
595#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
596 cv::Mat matImg, matImg_blur;
599 cv::GaussianBlur(matImg, matImg_blur, cv::Size(gaussian_filter_size, gaussian_filter_size), sigma, 0);
601 std::cout <<
"Time to do OpenCV Gaussian Blur on grayscale images: " <<
t <<
" ms" << std::endl;
603 double threshold = 3.;
604 unsigned int margin = 3;
605 bool test = check_results(matImg_blur, I_blur, margin, threshold);
606 std::cout <<
"(I_blur == matImg_blur)? " << test << std::endl;
609 std::cerr <<
"Failed Gaussian blur filter on grayscale image!" << std::endl;
617 std::cout <<
"\nTest Gaussian Blur on Klimt color image:" << std::endl;
622 if (opt_ppath.empty()) {
629 printf(
"Image \"%s\" read successfully\n",
filename.c_str());
632 unsigned int gaussian_filter_size = 7;
637 std::cout <<
"Time to do ViSP Gaussian Blur on color images: " <<
t <<
" ms" << std::endl;
639#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
640 cv::Mat matImg_rgb, matImg_rgb_blur;
643 cv::GaussianBlur(matImg_rgb, matImg_rgb_blur, cv::Size(gaussian_filter_size, gaussian_filter_size), sigma, 0);
645 std::cout <<
"Time to do OpenCV Gaussian Blur on color images: " <<
t <<
" ms" << std::endl;
647 double threshold = 3.;
648 unsigned int margin = 3;
649 bool test = check_results(matImg_rgb_blur, I_rgb_blur, margin, threshold);
650 std::cout <<
"(I_rgb_blur == matImg_rgb_blur)? " << test << std::endl;
653 std::cerr <<
"Failed Gaussian blur filter on color image!" << std::endl;
661 std::cerr <<
"Catch an exception: " <<
e.what() << std::endl;
665 std::cout <<
"\ntestImageFilter is ok." << std::endl;
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &If, const vpArray2D< FilterType > &M, bool convolve=false, const vpImage< bool > *p_mask=nullptr)
static void sepFilter(const vpImage< unsigned char > &I, vpImage< double > &If, const vpColVector &kernelH, const vpColVector &kernelV)
static void gaussianBlur(const vpImage< ImageType > &I, vpImage< OutputType > &GI, unsigned int size=7, FilterType sigma=0., bool normalize=true, const vpImage< bool > *p_mask=nullptr)
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 void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
unsigned int getRows() const
static bool equal(double x, double y, double threshold=0.001)
Implementation of a matrix and operations on matrices.
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
VISP_EXPORT double measureTimeMs()