Undistort an image.Read an image from the disk, undistort it and save the undistorted image on the disk.
#include <stdlib.h>
#include <visp3/core/vpDebug.h>
#include <visp3/core/vpImage.h>
#include <visp3/core/vpImageTools.h>
#include <visp3/core/vpIoTools.h>
#include <visp3/core/vpRGBa.h>
#include <visp3/core/vpTime.h>
#include <visp3/io/vpImageIo.h>
#include <visp3/io/vpParseArgv.h>
#define GETOPTARGS "cdi:o:t:s:h"
#ifdef ENABLE_VISP_NAMESPACE
#endif
void usage(const char *name, const char *badparam, const std::string &ipath, const std::string &opath,
const std::string &user)
{
#if VISP_HAVE_DATASET_VERSION >= 0x030600
std::string ext("png");
#else
std::string ext("pgm");
#endif
fprintf(stdout, "\n\
Read an image from the disk, undistort it \n\
and save the undistorted image on the disk.\n\
(grid36-01_undistorted.pgm).\n\
\n\
SYNOPSIS\n\
%s [-i <input image path>] [-o <output image path>] [-t <nThreads>] [-s <scale>]\n\
[-h]\n\
",
name);
fprintf(stdout, "\n\
OPTIONS: Default\n\
-i <input image path> %s\n\
Set image input path.\n\
From this path read \"calibration/grid36-01.%s\"\n\
image.\n\
Setting the VISP_INPUT_IMAGE_PATH environment\n\
variable produces the same behaviour than using\n\
this option.\n\
\n\
-o <output image path> %s\n\
Set image output path.\n\
From this directory, creates the \"%s\"\n\
subdirectory depending on the username, where \n\
grid36-01_undistorted.pgm output image is written.\n\
\n\
-t <nThreads> \n\
Set the number of threads to use for vpImageTools::undistort().\n\
\n\
-s <scale> \n\
Resize the image by the specified scale factor.\n\
\n\
-h\n\
Print the help.\n\n",
ext.c_str(), ipath.c_str(), opath.c_str(), user.c_str());
if (badparam)
fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
}
bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, const std::string &user,
unsigned int &nThreads, unsigned int &scale)
{
const char *optarg_;
int c;
switch (c) {
case 'i':
ipath = optarg_;
break;
case 'o':
opath = optarg_;
break;
case 't':
nThreads = atoi(optarg_);
break;
case 's':
scale = atoi(optarg_);
break;
case 'h':
usage(argv[0], nullptr, ipath, opath, user);
return false;
case 'c':
case 'd':
break;
default:
usage(argv[0], optarg_, ipath, opath, user);
return false;
}
}
if ((c == 1) || (c == -1)) {
usage(argv[0], nullptr, ipath, opath, user);
std::cerr << "ERROR: " << std::endl;
std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
return false;
}
return true;
}
int main(int argc, const char **argv)
{
try {
std::string env_ipath;
std::string opt_ipath;
std::string opt_opath;
std::string ipath;
std::string opath;
std::string filename;
std::string username;
unsigned int nThreads = 2;
unsigned int scale = 1;
#if VISP_HAVE_DATASET_VERSION >= 0x030600
std::string ext("png");
#else
std::string ext("pgm");
#endif
if (!env_ipath.empty())
ipath = env_ipath;
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
opt_opath = "/tmp";
#elif defined(_WIN32)
opt_opath = "C:\\temp";
#endif
if (getOptions(argc, argv, opt_ipath, opt_opath, username, nThreads, scale) == false) {
return EXIT_FAILURE;
}
if (!opt_ipath.empty())
ipath = opt_ipath;
if (!opt_opath.empty())
opath = opt_opath;
try {
}
catch (...) {
usage(argv[0], nullptr, ipath, opt_opath, username);
std::cerr << std::endl << "ERROR:" << std::endl;
std::cerr << " Cannot create " << opath << std::endl;
std::cerr << " Check your -o " << opt_opath << " option " << std::endl;
return EXIT_FAILURE;
}
}
if (opt_ipath.empty()) {
if (ipath != env_ipath) {
std::cout << std::endl << "WARNING: " << std::endl;
std::cout << " Since -i <visp image path=" << ipath << "> "
<< " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
<< " we skip the environment variable." << std::endl;
}
}
if (opt_ipath.empty() && env_ipath.empty()) {
usage(argv[0], nullptr, ipath, opt_opath, username);
std::cerr << std::endl << "ERROR:" << std::endl;
std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
<< " environment variable to specify the location of the " << std::endl
<< " image path where test images are located." << std::endl
<< std::endl;
return EXIT_FAILURE;
}
std::cout << "Read image: " << filename << std::endl;
if (scale > 1) {
std::cout << "Scale the image by a factor of " << scale << std::endl;
}
else {
I = I_;
}
std::cout << "Nb threads to use for vpImageTools::undistort(): " << nThreads << std::endl;
double t_undistort = 0.0, t_remap = 0.0;
{
std::cout << "\nUndistortion in process (color image)... " << std::endl;
for (unsigned int i = 0; i < 10; i++)
t_undistort = endtime - begintime;
std::cout << "Time for 10 color image undistortion (ms): " << t_undistort << std::endl;
}
{
std::cout << "Undistortion in process with remap (color image)... " << std::endl;
for (unsigned int i = 0; i < 10; i++) {
if (i == 0) {
}
}
t_remap = endtime - begintime;
std::cout << "Time for 10 color image undistortion with remap (ms): " << t_remap << std::endl;
std::cout << "Speed-up: " << t_undistort / t_remap << "X" << std::endl;
}
{
std::cout << "\nUndistortion in process (gray image)... " << std::endl;
for (unsigned int i = 0; i < 100; i++)
t_undistort = endtime - begintime;
std::cout << "Time for 100 gray image undistortion (ms): " << t_undistort << std::endl;
}
{
std::cout << "Undistortion in process with remap (gray image)... " << std::endl;
for (unsigned int i = 0; i < 10; i++) {
if (i == 0) {
}
}
t_remap = endtime - begintime;
std::cout << "Time for 100 gray image undistortion with remap (ms): " << t_remap << std::endl;
std::cout << "Speed-up: " << t_undistort / t_remap << "X" << std::endl;
}
std::cout << "\nWrite undistorted image: " << filename << std::endl;
std::cout << "Write undistorted image: " << filename << std::endl;
std::cout << "\nWrite undistorted image with remap: " << filename << std::endl;
std::cout << "Write undistorted image with remap: " << filename << std::endl;
double mean_diff = 0.0;
for (
unsigned int i = 0; i < U_diff_abs.
getHeight(); i++) {
for (
unsigned int j = 0; j < U_diff_abs.
getWidth(); j++) {
mean_diff += U_diff_abs[i][j].R;
mean_diff += U_diff_abs[i][j].G;
mean_diff += U_diff_abs[i][j].B;
mean_diff += U_diff_abs[i][j].A;
}
}
double remap_mean_error = mean_diff / (4 * U_diff_abs.
getSize());
std::cout << "U_diff_abs mean value: " << remap_mean_error << std::endl;
const double remap_error_threshold = 0.5;
if (remap_mean_error > remap_error_threshold) {
std::cerr << "Issue with vpImageTools::remap() with vpRGBa image" << std::endl;
return EXIT_FAILURE;
}
double remap_mean_error_gray = U_diff_gray_abs.
getSum() / U_diff_gray_abs.
getSize();
std::cout << "U_diff_gray_abs mean value: " << remap_mean_error_gray << std::endl;
if (remap_mean_error_gray > remap_error_threshold) {
std::cerr << "Issue with vpImageTools::remap() with unsigned char image" << std::endl;
return EXIT_FAILURE;
}
std::cout << "\nWrite undistorted image: " << filename << std::endl;
std::cout << "Write undistorted image: " << filename << std::endl;
return EXIT_SUCCESS;
}
std::cout << "Catch an exception: " << e << std::endl;
return EXIT_FAILURE;
}
}
Implementation of a generic 2D array used as base class for matrices and vectors.
Generic class defining intrinsic camera parameters.
void initPersProjWithDistortion(double px, double py, double u0, double v0, double kud, double kdu)
error that can be emitted by ViSP classes.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
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)
double getSum(const vpImage< bool > *p_mask=nullptr, unsigned int *nbValidPoints=nullptr) const
Compute the sum of image intensities.
unsigned int getWidth() const
unsigned int getSize() const
unsigned int getHeight() const
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
VISP_EXPORT double measureTimeMs()