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"
64 void usage(
const char *name,
const char *badparam,
const std::string &ipath,
const std::string &opath,
65 const std::string &user)
68 Test performance between methods to iterate over pixel image.\n\
71 %s [-i <input image path>] [-o <output image path>] [-t <nb threads>]\n\
78 -i <input image path> %s\n\
79 Set image input path.\n\
80 From this path read \"Klimt/Klimt.pgm\"\n\
82 Setting the VISP_INPUT_IMAGE_PATH environment\n\
83 variable produces the same behaviour than using\n\
86 -o <output image path> %s\n\
87 Set image output path.\n\
88 From this directory, creates the \"%s\"\n\
89 subdirectory depending on the username, where \n\
90 Klimt_grey.pgm output image is written.\n\
93 Set the number of threads to use for the computation.\n\
97 ipath.c_str(), opath.c_str(), user.c_str());
100 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
114 bool getOptions(
int argc,
const char **argv, std::string &ipath, std::string &opath,
const std::string &user,
115 unsigned int &nbThreads)
129 nbThreads = (
unsigned int)atoi(optarg_);
132 usage(argv[0],
nullptr, ipath, opath, user);
141 usage(argv[0], optarg_, ipath, opath, user);
147 if ((c == 1) || (c == -1)) {
149 usage(argv[0],
nullptr, ipath, opath, user);
150 std::cerr <<
"ERROR: " << std::endl;
151 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
158 unsigned char getRandomValues(
unsigned char min,
unsigned char max)
160 return static_cast<unsigned char>((max - min) *
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX) + min);
165 for (
unsigned int i = 0; i < I.
getHeight(); ++i) {
166 for (
unsigned int j = 0; j < I.
getWidth(); ++j) {
167 I[i][j] = getRandomValues(min, max);
172 void generateRandomImage(
vpImage<vpRGBa> &I,
unsigned int min = 0,
unsigned int max = 255)
174 for (
unsigned int i = 0; i < I.
getHeight(); ++i) {
175 for (
unsigned int j = 0; j < I.
getWidth(); ++j) {
176 I[i][j].R = getRandomValues(min, max);
177 I[i][j].G = getRandomValues(min, max);
178 I[i][j].B = getRandomValues(min, max);
179 I[i][j].A = getRandomValues(min, max);
195 unsigned char *ptrStart = (
unsigned char *)I.
bitmap;
196 unsigned char *ptrEnd = ptrStart + size * 4;
197 unsigned char *ptrCurrent = ptrStart;
199 while (ptrCurrent != ptrEnd) {
200 *ptrCurrent = vpMath::saturate<unsigned char>((*ptrCurrent) * alpha + beta);
216 unsigned char *ptrStart = (
unsigned char *)I.
bitmap;
217 unsigned char *ptrEnd = ptrStart + size;
218 unsigned char *ptrCurrent = ptrStart;
220 while (ptrCurrent != ptrEnd) {
221 *ptrCurrent = vpMath::saturate<unsigned char>((*ptrCurrent) * alpha + beta);
236 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
237 for (
unsigned int j = 0; j < I.
getWidth(); j++) {
238 I[i][j].R = vpMath::saturate<unsigned char>(I[i][j].R * alpha + beta);
239 I[i][j].G = vpMath::saturate<unsigned char>(I[i][j].G * alpha + beta);
240 I[i][j].B = vpMath::saturate<unsigned char>(I[i][j].B * alpha + beta);
241 I[i][j].A = vpMath::saturate<unsigned char>(I[i][j].A * alpha + beta);
246 int main(
int argc,
const char **argv)
249 std::string env_ipath;
250 std::string opt_ipath;
251 std::string opt_opath;
254 std::string filename;
255 std::string username;
256 unsigned int nbThreads = 4;
263 if (!env_ipath.empty())
268 opt_opath =
"C:/temp";
277 if (getOptions(argc, argv, opt_ipath, opt_opath, username, nbThreads) ==
false) {
282 if (!opt_ipath.empty())
284 if (!opt_opath.empty())
297 usage(argv[0],
nullptr, ipath, opt_opath, username);
298 std::cerr << std::endl <<
"ERROR:" << std::endl;
299 std::cerr <<
" Cannot create " << opath << std::endl;
300 std::cerr <<
" Check your -o " << opt_opath <<
" option " << std::endl;
307 if (!opt_ipath.empty() && !env_ipath.empty()) {
308 if (ipath != env_ipath) {
309 std::cout << std::endl <<
"WARNING: " << std::endl;
310 std::cout <<
" Since -i <visp image path=" << ipath <<
"> "
311 <<
" is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
312 <<
" we skip the environment variable." << std::endl;
317 if (opt_ipath.empty() && env_ipath.empty()) {
318 usage(argv[0],
nullptr, ipath, opt_opath, username);
319 std::cerr << std::endl <<
"ERROR:" << std::endl;
320 std::cerr <<
" Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
321 <<
" environment variable to specify the location of the " << std::endl
322 <<
" image path where test images are located." << std::endl
327 double alpha = 1.5, beta = -30.0;
328 unsigned int nbIterations = 10;
334 std::cout <<
"\n** Test LUT on color image" << std::endl;
340 std::cout <<
"Read image: " << filename << std::endl;
345 std::cout <<
"Image size: " << I_iterate1.
getWidth() <<
"x" << I_iterate1.
getHeight() << std::endl;
348 std::cout <<
"Run test n°1 " << nbIterations <<
" times" << std::endl;
350 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
351 iterate_method1(I_iterate1, alpha, beta);
354 std::cout <<
" Total time: " << t_iterate1 <<
" ms ; Mean time: "
355 << (t_iterate1 / nbIterations) <<
" ms" << std::endl;
358 std::cout <<
" Save " << filename << std::endl;
362 std::cout <<
"Run test n°2 " << nbIterations <<
" times" << std::endl;
364 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
365 iterate_method2(I_iterate2, alpha, beta);
368 std::cout <<
" Total time: " << t_iterate2 <<
" ms ; Mean time: " << (t_iterate2 / nbIterations) <<
" ms" << std::endl;
371 std::cout <<
" Save " << filename << std::endl;
376 for (
unsigned int i = 0; i < 256; i++) {
377 lut[i].
R = vpMath::saturate<unsigned char>(alpha * i + beta);
378 lut[i].
G = vpMath::saturate<unsigned char>(alpha * i + beta);
379 lut[i].
B = vpMath::saturate<unsigned char>(alpha * i + beta);
380 lut[i].
A = vpMath::saturate<unsigned char>(alpha * i + beta);
384 std::cout <<
"Run test n°3 " << nbIterations <<
" times" << std::endl;
386 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
390 std::cout <<
" Total time: " << t_lut <<
" ms ; Mean time: " << (t_lut / nbIterations) <<
" ms" << std::endl;
393 std::cout <<
" Save " << filename << std::endl;
396 if ((I_iterate1 == I_iterate2) && (I_iterate1 == I_lut)) {
397 std::cerr <<
"Color images are the same" << std::endl;
400 std::cerr <<
"Color images are different!" << std::endl;
401 std::cout <<
"Test failed" << std::endl;
407 std::cout <<
"\n** Test LUT on grayscale image" << std::endl;
412 std::cout <<
"Read image: " << filename << std::endl;
416 std::cout <<
"Image size: " << I_lut_grayscale.
getWidth() <<
"x" << I_lut_grayscale.
getHeight() << std::endl;
419 std::cout <<
"Run test n°1 " << nbIterations <<
" times" << std::endl;
421 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
422 iterate_method1(I_iterate_grayscale1, alpha, beta);
425 std::cout <<
" Total time: " << t_iterate_grayscale1 <<
" ms ; Mean time: "
426 << (t_iterate_grayscale1 / nbIterations) <<
" ms" << std::endl;
429 std::cout <<
" Save result in " << filename << std::endl;
433 unsigned char lut[256];
434 for (
unsigned int i = 0; i < 256; i++) {
435 lut[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
439 std::cout <<
"Run test n°2 " << nbIterations <<
" times with " << nbThreads <<
" threads" << std::endl;
441 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
445 std::cout <<
" Total time: " << t_lut_grayscale <<
" ms ; Mean time: "
446 << (t_lut_grayscale / nbIterations) <<
" ms" << std::endl;
449 std::cout <<
" Save result in " << filename << std::endl;
453 if (I_lut_grayscale == I_iterate_grayscale1) {
454 std::cout <<
"Grayscale images are same" << std::endl;
457 std::cerr <<
"Grayscale images are different!" << std::endl;
458 std::cout <<
"Test failed" << std::endl;
463 std::cout <<
"\n** Test multi-threaded LUT on color image" << std::endl;
468 std::cout <<
"Read image: " << filename << std::endl;
473 for (
unsigned int i = 0; i < 256; i++) {
474 lut[i].
R = vpMath::saturate<unsigned char>(alpha * i + beta);
475 lut[i].
G = vpMath::saturate<unsigned char>(alpha * i + beta);
476 lut[i].
B = vpMath::saturate<unsigned char>(alpha * i + beta);
477 lut[i].
A = vpMath::saturate<unsigned char>(alpha * i + beta);
481 std::cout <<
"Run test n°1 " << nbIterations* 10 <<
" times with " << nbThreads <<
" threads" << std::endl;
483 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
489 std::cout <<
" Save result in " << filename << std::endl;
494 std::cout <<
"Run test n°2 " << nbIterations* 10 <<
" times in a single thread" << std::endl;
496 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
502 std::cout <<
" Save result in " << filename << std::endl;
506 if (I_lut_multi == I_lut_single) {
507 std::cout <<
"Color images are the same" << std::endl;
508 std::cout <<
"Single-thread / multi-thread (color) gain: " << t_lut_singlethread / t_lut_multithread << std::endl;
511 std::cerr <<
"Color images are different!" << std::endl;
512 std::cout <<
"Test failed" << std::endl;
517 std::cout <<
"\n** Test multi-threaded LUT on gray image" << std::endl;
523 std::cout <<
"Read image: " << filename << std::endl;
527 unsigned char lut[256];
528 for (
unsigned int i = 0; i < 256; i++) {
529 lut[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
533 std::cout <<
"Run test n°1 " << nbIterations* 10 <<
" times with " << nbThreads <<
" threads" << std::endl;
535 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
536 I_lut_grayscale_multi.
performLut(lut, nbThreads);
541 std::cout <<
" Save result in " << filename << std::endl;
546 std::cout <<
"Run test n°2 " << nbIterations* 10 <<
" times in a single thread" << std::endl;
548 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
554 std::cout <<
" Save result in " << filename << std::endl;
558 if (I_lut_grayscale_multi == I_lut_grayscale_single) {
559 std::cout <<
"Gray images are the same" << std::endl;
560 std::cout <<
"Single-thread / multi-thread (color) gain: " << t_lut_singlethread / t_lut_multithread << std::endl;
563 std::cerr <<
"Color images are different!" << std::endl;
564 std::cout <<
"Test failed" << std::endl;
569 std::cout <<
"\n** Test multi-threaded LUT on gray image which size is not divisible by 8" << std::endl;
573 generateRandomImage(I_test_grayscale_multi);
574 I_test_grayscale_single = I_test_grayscale_multi;
576 unsigned char lut_grayscale[256];
577 for (
unsigned int i = 0; i < 256; i++) {
578 lut_grayscale[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
580 std::cout <<
"Run test n°1 with " << nbThreads <<
" threads" << std::endl;
581 I_test_grayscale_multi.performLut(lut_grayscale, nbThreads);
582 std::cout <<
"Run test n°2 single threads" << std::endl;
583 I_test_grayscale_single.
performLut(lut_grayscale, 1);
586 if (I_test_grayscale_multi == I_test_grayscale_single) {
587 std::cout <<
"Gray images are the same" << std::endl;
590 std::cerr <<
"Gray images are different!" << std::endl;
591 std::cout <<
"Test failed" << std::endl;
596 std::cout <<
"\n** Test multi-threaded LUT on color image which size is not divisible by 8" << std::endl;
599 generateRandomImage(I_test_color_multi);
600 I_test_color_single = I_test_color_multi;
603 for (
unsigned int i = 0; i < 256; i++) {
604 lut_color[i].
R = vpMath::saturate<unsigned char>(alpha * i + beta);
605 lut_color[i].
G = vpMath::saturate<unsigned char>(alpha * i + beta);
606 lut_color[i].
B = vpMath::saturate<unsigned char>(alpha * i + beta);
607 lut_color[i].
A = vpMath::saturate<unsigned char>(alpha * i + beta);
609 std::cout <<
"Run test n°1 with " << nbThreads <<
" threads" << std::endl;
610 I_test_color_multi.performLut(lut_color, nbThreads);
611 std::cout <<
"Run test n°2 single threads" << std::endl;
615 if (I_test_color_multi == I_test_color_single) {
616 std::cout <<
"Color images are the same" << std::endl;
619 std::cerr <<
"Color images are different!" << std::endl;
620 std::cout <<
"Test failed" << std::endl;
624 std::cout <<
"Test succeed" << std::endl;
628 std::cerr <<
"Catch an exception: " << e.
what() << std::endl;
error that can be emitted by ViSP classes.
const char * what() const
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)
unsigned int getWidth() const
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
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
Additionnal component.
VISP_EXPORT double measureTimeMs()