36#include <visp3/core/vpImage.h>
37#include <visp3/core/vpIoTools.h>
38#include <visp3/core/vpMath.h>
39#include <visp3/io/vpImageIo.h>
40#include <visp3/io/vpParseArgv.h>
42#ifdef ENABLE_VISP_NAMESPACE
53#define GETOPTARGS "cdi:o:t:h"
55void usage(
const char *name,
const char *badparam,
const std::string &ipath,
const std::string &opath,
56 const std::string &user);
57bool getOptions(
int argc,
const char **argv, std::string &ipath, std::string &opath,
const std::string &user,
58 unsigned int &nbThreads);
59unsigned char getRandomValues(
unsigned char min,
unsigned char max);
61void generateRandomImage(
vpImage<vpRGBa> &I,
unsigned int min = 0,
unsigned int max = 255);
75void usage(
const char *name,
const char *badparam,
const std::string &ipath,
const std::string &opath,
76 const std::string &user)
79Test performance between methods to iterate over pixel image.\n\
82 %s [-i <input image path>] [-o <output image path>] [-t <nb threads>]\n\
89 -i <input image path> %s\n\
90 Set image input path.\n\
91 From this path read \"Klimt/Klimt.pgm\"\n\
93 Setting the VISP_INPUT_IMAGE_PATH environment\n\
94 variable produces the same behaviour than using\n\
97 -o <output image path> %s\n\
98 Set image output path.\n\
99 From this directory, creates the \"%s\"\n\
100 subdirectory depending on the username, where \n\
101 Klimt_grey.pgm output image is written.\n\
104 Set the number of threads to use for the computation.\n\
107 Print the help.\n\n",
108 ipath.c_str(), opath.c_str(), user.c_str());
111 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
125bool getOptions(
int argc,
const char **argv, std::string &ipath, std::string &opath,
const std::string &user,
126 unsigned int &nbThreads)
140 nbThreads =
static_cast<unsigned int>(atoi(optarg_));
143 usage(argv[0],
nullptr, ipath, opath, user);
151 usage(argv[0], optarg_, ipath, opath, user);
156 if ((c == 1) || (c == -1)) {
158 usage(argv[0],
nullptr, ipath, opath, user);
159 std::cerr <<
"ERROR: " << std::endl;
160 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
167unsigned char getRandomValues(
unsigned char min,
unsigned char max)
169 return static_cast<unsigned char>((max - min) *
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX) + min);
174 for (
unsigned int i = 0;
i < I.getHeight(); ++
i) {
175 for (
unsigned int j = 0;
j < I.getWidth(); ++
j) {
176 I[
i][
j] = getRandomValues(min, max);
181void generateRandomImage(
vpImage<vpRGBa> &I,
unsigned int min,
unsigned int max)
183 for (
unsigned int i = 0;
i < I.getHeight(); ++
i) {
184 for (
unsigned int j = 0;
j < I.getWidth(); ++
j) {
185 I[
i][
j].R = getRandomValues(min, max);
186 I[
i][
j].G = getRandomValues(min, max);
187 I[
i][
j].B = getRandomValues(min, max);
188 I[
i][
j].A = getRandomValues(min, max);
203 unsigned int size = I.getWidth() * I.getHeight();
204 unsigned char *ptrStart = (
unsigned char *)I.bitmap;
205 unsigned char *ptrEnd = ptrStart + size * 4;
206 unsigned char *ptrCurrent = ptrStart;
208 while (ptrCurrent != ptrEnd) {
224 unsigned int size = I.getWidth() * I.getHeight();
225 unsigned char *ptrStart = (
unsigned char *)I.bitmap;
226 unsigned char *ptrEnd = ptrStart + size;
227 unsigned char *ptrCurrent = ptrStart;
229 while (ptrCurrent != ptrEnd) {
245 for (
unsigned int i = 0;
i < I.getHeight();
i++) {
246 for (
unsigned int j = 0;
j < I.getWidth();
j++) {
255int main(
int argc,
const char **argv)
258 std::string env_ipath;
259 std::string opt_ipath;
260 std::string opt_opath;
264 std::string username;
265 unsigned int nbThreads = 4;
272 if (!env_ipath.empty())
277 opt_opath =
"C:/temp";
286 if (getOptions(argc, argv, opt_ipath, opt_opath, username, nbThreads) ==
false) {
291 if (!opt_ipath.empty())
293 if (!opt_opath.empty())
306 usage(argv[0],
nullptr, ipath, opt_opath, username);
307 std::cerr << std::endl <<
"ERROR:" << std::endl;
308 std::cerr <<
" Cannot create " << opath << std::endl;
309 std::cerr <<
" Check your -o " << opt_opath <<
" option " << std::endl;
316 if (!opt_ipath.empty() && !env_ipath.empty()) {
317 if (ipath != env_ipath) {
318 std::cout << std::endl <<
"WARNING: " << std::endl;
319 std::cout <<
" Since -i <visp image path=" << ipath <<
"> "
320 <<
" is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
321 <<
" we skip the environment variable." << std::endl;
326 if (opt_ipath.empty() && env_ipath.empty()) {
327 usage(argv[0],
nullptr, ipath, opt_opath, username);
328 std::cerr << std::endl <<
"ERROR:" << std::endl;
329 std::cerr <<
" Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
330 <<
" environment variable to specify the location of the " << std::endl
331 <<
" image path where test images are located." << std::endl
336 double alpha = 1.5, beta = -30.0;
337 unsigned int nbIterations = 10;
343 std::cout <<
"\n** Test LUT on color image" << std::endl;
349 std::cout <<
"Read image: " <<
filename << std::endl;
354 std::cout <<
"Image size: " << I_iterate1.
getWidth() <<
"x" << I_iterate1.
getHeight() << std::endl;
357 std::cout <<
"Run test n°1 " << nbIterations <<
" times" << std::endl;
359 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
360 iterate_method1(I_iterate1, alpha, beta);
363 std::cout <<
" Total time: " << t_iterate1 <<
" ms ; Mean time: "
364 << (t_iterate1 / nbIterations) <<
" ms" << std::endl;
367 std::cout <<
" Save " <<
filename << std::endl;
371 std::cout <<
"Run test n°2 " << nbIterations <<
" times" << std::endl;
373 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
374 iterate_method2(I_iterate2, alpha, beta);
377 std::cout <<
" Total time: " << t_iterate2 <<
" ms ; Mean time: " << (t_iterate2 / nbIterations) <<
" ms" << std::endl;
380 std::cout <<
" Save " <<
filename << std::endl;
385 for (
unsigned int i = 0;
i < 256;
i++) {
393 std::cout <<
"Run test n°3 " << nbIterations <<
" times" << std::endl;
395 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
399 std::cout <<
" Total time: " << t_lut <<
" ms ; Mean time: " << (t_lut / nbIterations) <<
" ms" << std::endl;
402 std::cout <<
" Save " <<
filename << std::endl;
405 if ((I_iterate1 == I_iterate2) && (I_iterate1 == I_lut)) {
406 std::cerr <<
"Color images are the same" << std::endl;
409 std::cerr <<
"Color images are different!" << std::endl;
410 std::cout <<
"Test failed" << std::endl;
416 std::cout <<
"\n** Test LUT on grayscale image" << std::endl;
421 std::cout <<
"Read image: " <<
filename << std::endl;
425 std::cout <<
"Image size: " << I_lut_grayscale.
getWidth() <<
"x" << I_lut_grayscale.
getHeight() << std::endl;
428 std::cout <<
"Run test n°1 " << nbIterations <<
" times" << std::endl;
430 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
431 iterate_method1(I_iterate_grayscale1, alpha, beta);
434 std::cout <<
" Total time: " << t_iterate_grayscale1 <<
" ms ; Mean time: "
435 << (t_iterate_grayscale1 / nbIterations) <<
" ms" << std::endl;
438 std::cout <<
" Save result in " <<
filename << std::endl;
442 unsigned char lut[256];
443 for (
unsigned int i = 0;
i < 256;
i++) {
448 std::cout <<
"Run test n°2 " << nbIterations <<
" times with " << nbThreads <<
" threads" << std::endl;
450 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
454 std::cout <<
" Total time: " << t_lut_grayscale <<
" ms ; Mean time: "
455 << (t_lut_grayscale / nbIterations) <<
" ms" << std::endl;
458 std::cout <<
" Save result in " <<
filename << std::endl;
462 if (I_lut_grayscale == I_iterate_grayscale1) {
463 std::cout <<
"Grayscale images are same" << std::endl;
466 std::cerr <<
"Grayscale images are different!" << std::endl;
467 std::cout <<
"Test failed" << std::endl;
472 std::cout <<
"\n** Test multi-threaded LUT on color image" << std::endl;
477 std::cout <<
"Read image: " <<
filename << std::endl;
482 for (
unsigned int i = 0;
i < 256;
i++) {
490 std::cout <<
"Run test n°1 " << nbIterations* 10 <<
" times with " << nbThreads <<
" threads" << std::endl;
492 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
498 std::cout <<
" Save result in " <<
filename << std::endl;
503 std::cout <<
"Run test n°2 " << nbIterations* 10 <<
" times in a single thread" << std::endl;
505 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
511 std::cout <<
" Save result in " <<
filename << std::endl;
515 if (I_lut_multi == I_lut_single) {
516 std::cout <<
"Color images are the same" << std::endl;
517 std::cout <<
"Single-thread / multi-thread (color) gain: " << t_lut_singlethread / t_lut_multithread << std::endl;
520 std::cerr <<
"Color images are different!" << std::endl;
521 std::cout <<
"Test failed" << std::endl;
526 std::cout <<
"\n** Test multi-threaded LUT on gray image" << std::endl;
532 std::cout <<
"Read image: " <<
filename << std::endl;
536 unsigned char lut[256];
537 for (
unsigned int i = 0;
i < 256;
i++) {
542 std::cout <<
"Run test n°1 " << nbIterations* 10 <<
" times with " << nbThreads <<
" threads" << std::endl;
544 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
545 I_lut_grayscale_multi.
performLut(lut, nbThreads);
550 std::cout <<
" Save result in " <<
filename << std::endl;
555 std::cout <<
"Run test n°2 " << nbIterations* 10 <<
" times in a single thread" << std::endl;
557 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
563 std::cout <<
" Save result in " <<
filename << std::endl;
567 if (I_lut_grayscale_multi == I_lut_grayscale_single) {
568 std::cout <<
"Gray images are the same" << std::endl;
569 std::cout <<
"Single-thread / multi-thread (color) gain: " << t_lut_singlethread / t_lut_multithread << std::endl;
572 std::cerr <<
"Color images are different!" << std::endl;
573 std::cout <<
"Test failed" << std::endl;
578 std::cout <<
"\n** Test multi-threaded LUT on gray image which size is not divisible by 8" << std::endl;
582 generateRandomImage(I_test_grayscale_multi);
583 I_test_grayscale_single = I_test_grayscale_multi;
585 unsigned char lut_grayscale[256];
586 for (
unsigned int i = 0;
i < 256;
i++) {
589 std::cout <<
"Run test n°1 with " << nbThreads <<
" threads" << std::endl;
590 I_test_grayscale_multi.
performLut(lut_grayscale, nbThreads);
591 std::cout <<
"Run test n°2 single threads" << std::endl;
592 I_test_grayscale_single.
performLut(lut_grayscale, 1);
595 if (I_test_grayscale_multi == I_test_grayscale_single) {
596 std::cout <<
"Gray images are the same" << std::endl;
599 std::cerr <<
"Gray images are different!" << std::endl;
600 std::cout <<
"Test failed" << std::endl;
605 std::cout <<
"\n** Test multi-threaded LUT on color image which size is not divisible by 8" << std::endl;
608 generateRandomImage(I_test_color_multi);
609 I_test_color_single = I_test_color_multi;
612 for (
unsigned int i = 0;
i < 256;
i++) {
618 std::cout <<
"Run test n°1 with " << nbThreads <<
" threads" << std::endl;
619 I_test_color_multi.performLut(lut_color, nbThreads);
620 std::cout <<
"Run test n°2 single threads" << std::endl;
624 if (I_test_color_multi == I_test_color_single) {
625 std::cout <<
"Color images are the same" << std::endl;
628 std::cerr <<
"Color images are different!" << std::endl;
629 std::cout <<
"Test failed" << std::endl;
633 std::cout <<
"Test succeed" << std::endl;
637 std::cerr <<
"Catch an exception: " <<
e.what() << std::endl;
error that can be emitted by ViSP classes.
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
unsigned int getWidth() const
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
unsigned int getHeight() const
static Tp saturate(unsigned char v)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
unsigned char B
Blue component.
unsigned char R
Red component.
unsigned char G
Green component.
unsigned char A
Additional component.
VISP_EXPORT double measureTimeMs()