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>
49 #define GETOPTARGS "cdi:o:t:h"
60 void usage(
const char *name,
const char *badparam,
const std::string &ipath,
const std::string &opath,
61 const std::string &user)
64 Test performance between methods to iterate over pixel image.\n\
67 %s [-i <input image path>] [-o <output image path>] [-t <nb threads>]\n\
74 -i <input image path> %s\n\
75 Set image input path.\n\
76 From this path read \"Klimt/Klimt.pgm\"\n\
78 Setting the VISP_INPUT_IMAGE_PATH environment\n\
79 variable produces the same behaviour than using\n\
82 -o <output image path> %s\n\
83 Set image output path.\n\
84 From this directory, creates the \"%s\"\n\
85 subdirectory depending on the username, where \n\
86 Klimt_grey.pgm output image is written.\n\
89 Set the number of threads to use for the computation.\n\
93 ipath.c_str(), opath.c_str(), user.c_str());
96 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
110 bool getOptions(
int argc,
const char **argv, std::string &ipath, std::string &opath,
const std::string &user,
111 unsigned int &nbThreads)
125 nbThreads = (
unsigned int)atoi(optarg_);
128 usage(argv[0],
nullptr, ipath, opath, user);
137 usage(argv[0], optarg_, ipath, opath, user);
143 if ((c == 1) || (c == -1)) {
145 usage(argv[0],
nullptr, ipath, opath, user);
146 std::cerr <<
"ERROR: " << std::endl;
147 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
154 unsigned char getRandomValues(
unsigned char min,
unsigned char max)
156 return static_cast<unsigned char>((max - min) *
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX) + min);
161 for (
unsigned int i = 0; i < I.
getHeight(); ++i) {
162 for (
unsigned int j = 0; j < I.
getWidth(); ++j) {
163 I[i][j] = getRandomValues(min, max);
168 void generateRandomImage(
vpImage<vpRGBa> &I,
unsigned int min = 0,
unsigned int max = 255)
170 for (
unsigned int i = 0; i < I.
getHeight(); ++i) {
171 for (
unsigned int j = 0; j < I.
getWidth(); ++j) {
172 I[i][j].R = getRandomValues(min, max);
173 I[i][j].G = getRandomValues(min, max);
174 I[i][j].B = getRandomValues(min, max);
175 I[i][j].A = getRandomValues(min, max);
191 unsigned char *ptrStart = (
unsigned char *)I.
bitmap;
192 unsigned char *ptrEnd = ptrStart + size * 4;
193 unsigned char *ptrCurrent = ptrStart;
195 while (ptrCurrent != ptrEnd) {
196 *ptrCurrent = vpMath::saturate<unsigned char>((*ptrCurrent) * alpha + beta);
212 unsigned char *ptrStart = (
unsigned char *)I.
bitmap;
213 unsigned char *ptrEnd = ptrStart + size;
214 unsigned char *ptrCurrent = ptrStart;
216 while (ptrCurrent != ptrEnd) {
217 *ptrCurrent = vpMath::saturate<unsigned char>((*ptrCurrent) * alpha + beta);
232 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
233 for (
unsigned int j = 0; j < I.
getWidth(); j++) {
234 I[i][j].R = vpMath::saturate<unsigned char>(I[i][j].R * alpha + beta);
235 I[i][j].G = vpMath::saturate<unsigned char>(I[i][j].G * alpha + beta);
236 I[i][j].B = vpMath::saturate<unsigned char>(I[i][j].B * alpha + beta);
237 I[i][j].A = vpMath::saturate<unsigned char>(I[i][j].A * alpha + beta);
242 int main(
int argc,
const char **argv)
245 std::string env_ipath;
246 std::string opt_ipath;
247 std::string opt_opath;
250 std::string filename;
251 std::string username;
252 unsigned int nbThreads = 4;
259 if (!env_ipath.empty())
264 opt_opath =
"C:/temp";
273 if (getOptions(argc, argv, opt_ipath, opt_opath, username, nbThreads) ==
false) {
278 if (!opt_ipath.empty())
280 if (!opt_opath.empty())
293 usage(argv[0],
nullptr, ipath, opt_opath, username);
294 std::cerr << std::endl <<
"ERROR:" << std::endl;
295 std::cerr <<
" Cannot create " << opath << std::endl;
296 std::cerr <<
" Check your -o " << opt_opath <<
" option " << std::endl;
303 if (!opt_ipath.empty() && !env_ipath.empty()) {
304 if (ipath != env_ipath) {
305 std::cout << std::endl <<
"WARNING: " << std::endl;
306 std::cout <<
" Since -i <visp image path=" << ipath <<
"> "
307 <<
" is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
308 <<
" we skip the environment variable." << std::endl;
313 if (opt_ipath.empty() && env_ipath.empty()) {
314 usage(argv[0],
nullptr, ipath, opt_opath, username);
315 std::cerr << std::endl <<
"ERROR:" << std::endl;
316 std::cerr <<
" Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
317 <<
" environment variable to specify the location of the " << std::endl
318 <<
" image path where test images are located." << std::endl
323 double alpha = 1.5, beta = -30.0;
324 unsigned int nbIterations = 10;
330 std::cout <<
"\n** Test LUT on color image" << std::endl;
336 std::cout <<
"Read image: " << filename << std::endl;
341 std::cout <<
"Image size: " << I_iterate1.
getWidth() <<
"x" << I_iterate1.
getHeight() << std::endl;
344 std::cout <<
"Run test n°1 " << nbIterations <<
" times" << std::endl;
346 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
347 iterate_method1(I_iterate1, alpha, beta);
350 std::cout <<
" Total time: " << t_iterate1 <<
" ms ; Mean time: "
351 << (t_iterate1 / nbIterations) <<
" ms" << std::endl;
354 std::cout <<
" Save " << filename << std::endl;
358 std::cout <<
"Run test n°2 " << nbIterations <<
" times" << std::endl;
360 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
361 iterate_method2(I_iterate2, alpha, beta);
364 std::cout <<
" Total time: " << t_iterate2 <<
" ms ; Mean time: " << (t_iterate2 / nbIterations) <<
" ms" << std::endl;
367 std::cout <<
" Save " << filename << std::endl;
372 for (
unsigned int i = 0; i < 256; i++) {
373 lut[i].
R = vpMath::saturate<unsigned char>(alpha * i + beta);
374 lut[i].
G = vpMath::saturate<unsigned char>(alpha * i + beta);
375 lut[i].
B = vpMath::saturate<unsigned char>(alpha * i + beta);
376 lut[i].
A = vpMath::saturate<unsigned char>(alpha * i + beta);
380 std::cout <<
"Run test n°3 " << nbIterations <<
" times" << std::endl;
382 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
386 std::cout <<
" Total time: " << t_lut <<
" ms ; Mean time: " << (t_lut / nbIterations) <<
" ms" << std::endl;
389 std::cout <<
" Save " << filename << std::endl;
392 if ((I_iterate1 == I_iterate2) && (I_iterate1 == I_lut)) {
393 std::cerr <<
"Color images are the same" << std::endl;
396 std::cerr <<
"Color images are different!" << std::endl;
397 std::cout <<
"Test failed" << std::endl;
403 std::cout <<
"\n** Test LUT on grayscale image" << std::endl;
408 std::cout <<
"Read image: " << filename << std::endl;
412 std::cout <<
"Image size: " << I_lut_grayscale.
getWidth() <<
"x" << I_lut_grayscale.
getHeight() << std::endl;
415 std::cout <<
"Run test n°1 " << nbIterations <<
" times" << std::endl;
417 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
418 iterate_method1(I_iterate_grayscale1, alpha, beta);
421 std::cout <<
" Total time: " << t_iterate_grayscale1 <<
" ms ; Mean time: "
422 << (t_iterate_grayscale1 / nbIterations) <<
" ms" << std::endl;
425 std::cout <<
" Save result in " << filename << std::endl;
429 unsigned char lut[256];
430 for (
unsigned int i = 0; i < 256; i++) {
431 lut[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
435 std::cout <<
"Run test n°2 " << nbIterations <<
" times with " << nbThreads <<
" threads" << std::endl;
437 for (
unsigned int cpt = 0; cpt < nbIterations; cpt++) {
441 std::cout <<
" Total time: " << t_lut_grayscale <<
" ms ; Mean time: "
442 << (t_lut_grayscale / nbIterations) <<
" ms" << std::endl;
445 std::cout <<
" Save result in " << filename << std::endl;
449 if (I_lut_grayscale == I_iterate_grayscale1) {
450 std::cout <<
"Grayscale images are same" << std::endl;
453 std::cerr <<
"Grayscale images are different!" << std::endl;
454 std::cout <<
"Test failed" << std::endl;
459 std::cout <<
"\n** Test multi-threaded LUT on color image" << std::endl;
464 std::cout <<
"Read image: " << filename << std::endl;
469 for (
unsigned int i = 0; i < 256; i++) {
470 lut[i].
R = vpMath::saturate<unsigned char>(alpha * i + beta);
471 lut[i].
G = vpMath::saturate<unsigned char>(alpha * i + beta);
472 lut[i].
B = vpMath::saturate<unsigned char>(alpha * i + beta);
473 lut[i].
A = vpMath::saturate<unsigned char>(alpha * i + beta);
477 std::cout <<
"Run test n°1 " << nbIterations* 10 <<
" times with " << nbThreads <<
" threads" << std::endl;
479 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
485 std::cout <<
" Save result in " << filename << std::endl;
490 std::cout <<
"Run test n°2 " << nbIterations* 10 <<
" times in a single thread" << std::endl;
492 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
498 std::cout <<
" Save result in " << filename << std::endl;
502 if (I_lut_multi == I_lut_single) {
503 std::cout <<
"Color images are the same" << std::endl;
504 std::cout <<
"Single-thread / multi-thread (color) gain: " << t_lut_singlethread / t_lut_multithread << std::endl;
507 std::cerr <<
"Color images are different!" << std::endl;
508 std::cout <<
"Test failed" << std::endl;
513 std::cout <<
"\n** Test multi-threaded LUT on gray image" << std::endl;
519 std::cout <<
"Read image: " << filename << std::endl;
523 unsigned char lut[256];
524 for (
unsigned int i = 0; i < 256; i++) {
525 lut[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
529 std::cout <<
"Run test n°1 " << nbIterations* 10 <<
" times with " << nbThreads <<
" threads" << std::endl;
531 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
532 I_lut_grayscale_multi.
performLut(lut, nbThreads);
537 std::cout <<
" Save result in " << filename << std::endl;
542 std::cout <<
"Run test n°2 " << nbIterations* 10 <<
" times in a single thread" << std::endl;
544 for (
unsigned int cpt = 0; cpt < nbIterations * 10; cpt++) {
550 std::cout <<
" Save result in " << filename << std::endl;
554 if (I_lut_grayscale_multi == I_lut_grayscale_single) {
555 std::cout <<
"Gray images are the same" << std::endl;
556 std::cout <<
"Single-thread / multi-thread (color) gain: " << t_lut_singlethread / t_lut_multithread << std::endl;
559 std::cerr <<
"Color images are different!" << std::endl;
560 std::cout <<
"Test failed" << std::endl;
565 std::cout <<
"\n** Test multi-threaded LUT on gray image which size is not divisible by 8" << std::endl;
569 generateRandomImage(I_test_grayscale_multi);
570 I_test_grayscale_single = I_test_grayscale_multi;
572 unsigned char lut_grayscale[256];
573 for (
unsigned int i = 0; i < 256; i++) {
574 lut_grayscale[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
576 std::cout <<
"Run test n°1 with " << nbThreads <<
" threads" << std::endl;
577 I_test_grayscale_multi.performLut(lut_grayscale, nbThreads);
578 std::cout <<
"Run test n°2 single threads" << std::endl;
579 I_test_grayscale_single.
performLut(lut_grayscale, 1);
582 if (I_test_grayscale_multi == I_test_grayscale_single) {
583 std::cout <<
"Gray images are the same" << std::endl;
586 std::cerr <<
"Gray images are different!" << std::endl;
587 std::cout <<
"Test failed" << std::endl;
592 std::cout <<
"\n** Test multi-threaded LUT on color image which size is not divisible by 8" << std::endl;
595 generateRandomImage(I_test_color_multi);
596 I_test_color_single = I_test_color_multi;
599 for (
unsigned int i = 0; i < 256; i++) {
600 lut_color[i].
R = vpMath::saturate<unsigned char>(alpha * i + beta);
601 lut_color[i].
G = vpMath::saturate<unsigned char>(alpha * i + beta);
602 lut_color[i].
B = vpMath::saturate<unsigned char>(alpha * i + beta);
603 lut_color[i].
A = vpMath::saturate<unsigned char>(alpha * i + beta);
605 std::cout <<
"Run test n°1 with " << nbThreads <<
" threads" << std::endl;
606 I_test_color_multi.performLut(lut_color, nbThreads);
607 std::cout <<
"Run test n°2 single threads" << std::endl;
611 if (I_test_color_multi == I_test_color_single) {
612 std::cout <<
"Color images are the same" << std::endl;
615 std::cerr <<
"Color images are different!" << std::endl;
616 std::cout <<
"Test failed" << std::endl;
620 std::cout <<
"Test succeed" << std::endl;
624 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()