Skip to content
Draft
165 changes: 129 additions & 36 deletions apps/calibration/intrinsic/calibration-helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,45 @@
#include <visp3/core/vpPixelMeterConversion.h>
#include <visp3/core/vpPoint.h>
#include <visp3/core/vpPolygon.h>
#include <visp3/core/vpColormap.h>

#ifndef DOXYGEN_SHOULD_SKIP_THIS

#if defined(ENABLE_VISP_NAMESPACE)
using namespace VISP_NAMESPACE_NAME;
#endif

namespace calib_helper
{

// Adapted from:
// https://stackoverflow.com/questions/58881746/c-how-to-cout-and-write-at-the-same-time/58881939#58881939
class Tee
{
private:
std::ostream &os;
std::ofstream &file;

public:
Tee(std::ostream &os_, std::ofstream &file_) : os(os_), file(file_) { }

template <typename T>
Tee &operator<<(const T &thing)
{
os << thing;
if (file.is_open()) {
file << thing;
}
return *this;
}
};

class Settings
{
public:
Settings()
: boardSize(), calibrationPattern(UNDEFINED), squareSize(0.), input(), tempo(0.), goodInput(false), patternToUse()
Settings(Tee &tee_)
: boardSize(), calibrationPattern(UNDEFINED), squareSize(0.), input(), tempo(0.), goodInput(false), patternToUse(),
tee(tee_)
{
boardSize = cv::Size(0, 0);
calibrationPattern = UNDEFINED;
Expand All @@ -65,21 +94,21 @@ class Settings
bool read(const std::string &filename) // Read the parameters
{
// reading configuration file
if (!VISP_NAMESPACE_ADDRESSING vpIoTools::loadConfigFile(filename))
if (!vpIoTools::loadConfigFile(filename))
return false;
VISP_NAMESPACE_ADDRESSING vpIoTools::readConfigVar("BoardSize_Width:", boardSize.width);
VISP_NAMESPACE_ADDRESSING vpIoTools::readConfigVar("BoardSize_Height:", boardSize.height);
VISP_NAMESPACE_ADDRESSING vpIoTools::readConfigVar("Square_Size:", squareSize);
VISP_NAMESPACE_ADDRESSING vpIoTools::readConfigVar("Calibrate_Pattern:", patternToUse);
VISP_NAMESPACE_ADDRESSING vpIoTools::readConfigVar("Input:", input);
VISP_NAMESPACE_ADDRESSING vpIoTools::readConfigVar("Tempo:", tempo);

std::cout << "grid width : " << boardSize.width << std::endl;
std::cout << "grid height: " << boardSize.height << std::endl;
std::cout << "square size: " << squareSize << std::endl;
std::cout << "pattern : " << patternToUse << std::endl;
std::cout << "input seq : " << input << std::endl;
std::cout << "tempo : " << tempo << std::endl;
vpIoTools::readConfigVar("BoardSize_Width:", boardSize.width);
vpIoTools::readConfigVar("BoardSize_Height:", boardSize.height);
vpIoTools::readConfigVar("Square_Size:", squareSize);
vpIoTools::readConfigVar("Calibrate_Pattern:", patternToUse);
vpIoTools::readConfigVar("Input:", input);
vpIoTools::readConfigVar("Tempo:", tempo);

tee << "grid width : " << boardSize.width << "\n";
tee << "grid height: " << boardSize.height << "\n";
tee << "square size: " << squareSize << "\n";
tee << "pattern : " << patternToUse << "\n";
tee << "input seq : " << input << "\n";
tee << "tempo : " << tempo << "\n";
interprate();
return true;
}
Expand All @@ -88,11 +117,11 @@ class Settings
{
goodInput = true;
if (boardSize.width <= 0 || boardSize.height <= 0) {
std::cerr << "Invalid Board size: " << boardSize.width << " " << boardSize.height << std::endl;
tee << "Invalid Board size: " << boardSize.width << " " << boardSize.height << "\n";
goodInput = false;
}
if (squareSize <= 10e-6) {
std::cerr << "Invalid square size " << squareSize << std::endl;
tee << "Invalid square size " << squareSize << "\n";
goodInput = false;
}

Expand All @@ -105,7 +134,7 @@ class Settings
else if (patternToUse.compare("CIRCLES_GRID") == 0)
calibrationPattern = CIRCLES_GRID;
if (calibrationPattern == UNDEFINED) {
std::cerr << " Inexistent camera calibration mode: " << patternToUse << std::endl;
tee << " Inexistent camera calibration mode: " << patternToUse << "\n";
goodInput = false;
}
}
Expand All @@ -124,57 +153,57 @@ class Settings

private:
std::string patternToUse;
Tee &tee;
};

struct CalibInfo
{
CalibInfo(const VISP_NAMESPACE_ADDRESSING vpImage<unsigned char> &img, const std::vector<VISP_NAMESPACE_ADDRESSING vpPoint> &points,
const std::vector<VISP_NAMESPACE_ADDRESSING vpImagePoint> &imPts, const std::string &frame_name)
CalibInfo(const vpImage<unsigned char> &img, const std::vector<vpPoint> &points,
const std::vector<vpImagePoint> &imPts, const std::string &frame_name)
: m_img(img), m_points(points), m_imPts(imPts), m_frame_name(frame_name)
{ }

VISP_NAMESPACE_ADDRESSING vpImage<unsigned char> m_img;
std::vector<VISP_NAMESPACE_ADDRESSING vpPoint> m_points;
std::vector<VISP_NAMESPACE_ADDRESSING vpImagePoint> m_imPts;
vpImage<unsigned char> m_img;
std::vector<vpPoint> m_points;
std::vector<vpImagePoint> m_imPts;
std::string m_frame_name;
};

void drawCalibrationOccupancy(VISP_NAMESPACE_ADDRESSING vpImage<unsigned char> &I, const std::vector<CalibInfo> &calib_info,
unsigned int patternW)
void drawCalibrationOccupancy(vpImage<unsigned char> &I, const std::vector<CalibInfo> &calib_info, unsigned int patternW)
{
I = 0u;
unsigned char pixel_value = static_cast<unsigned char>(255.0 / calib_info.size());
for (size_t idx = 0; idx < calib_info.size(); idx++) {
const CalibInfo &calib = calib_info[idx];

std::vector<VISP_NAMESPACE_ADDRESSING vpImagePoint> corners;
std::vector<vpImagePoint> corners;
corners.push_back(calib.m_imPts.front());
corners.push_back(*(calib.m_imPts.begin() + patternW - 1));
corners.push_back(calib.m_imPts.back());
corners.push_back(*(calib.m_imPts.end() - patternW));
VISP_NAMESPACE_ADDRESSING vpPolygon poly(corners);
vpPolygon poly(corners);

for (unsigned int i = 0; i < I.getHeight(); i++) {
for (unsigned int j = 0; j < I.getWidth(); j++) {
if (poly.isInside(VISP_NAMESPACE_ADDRESSING vpImagePoint(i, j))) {
if (poly.isInside(vpImagePoint(i, j))) {
I[i][j] += pixel_value;
}
}
}
}
}

std::vector<VISP_NAMESPACE_ADDRESSING vpImagePoint> undistort(const VISP_NAMESPACE_ADDRESSING vpCameraParameters &cam_dist, const std::vector<VISP_NAMESPACE_ADDRESSING vpImagePoint> &imPts)
std::vector<vpImagePoint> undistort(const vpCameraParameters &cam_dist, const std::vector<vpImagePoint> &imPts)
{
std::vector<VISP_NAMESPACE_ADDRESSING vpImagePoint> imPts_undist;
std::vector<vpImagePoint> imPts_undist;

VISP_NAMESPACE_ADDRESSING vpCameraParameters cam(cam_dist.get_px(), cam_dist.get_py(), cam_dist.get_u0(), cam_dist.get_v0());
vpCameraParameters cam(cam_dist.get_px(), cam_dist.get_py(), cam_dist.get_u0(), cam_dist.get_v0());
for (size_t i = 0; i < imPts.size(); i++) {
double x = 0, y = 0;
VISP_NAMESPACE_ADDRESSING vpPixelMeterConversion::convertPoint(cam_dist, imPts[i], x, y);
vpPixelMeterConversion::convertPoint(cam_dist, imPts[i], x, y);

VISP_NAMESPACE_ADDRESSING vpImagePoint imPt;
VISP_NAMESPACE_ADDRESSING vpMeterPixelConversion::convertPoint(cam, x, y, imPt);
vpImagePoint imPt;
vpMeterPixelConversion::convertPoint(cam, x, y, imPt);
imPts_undist.push_back(imPt);
}

Expand Down Expand Up @@ -205,7 +234,7 @@ bool extractCalibrationPoints(const Settings &s, const cv::Mat &cvI, std::vector

if (found) // If done with success,
{
std::vector<VISP_NAMESPACE_ADDRESSING vpImagePoint> data;
std::vector<vpImagePoint> data;

if (s.calibrationPattern == Settings::CHESSBOARD) {
// improve the found corners' coordinate accuracy for chessboard
Expand All @@ -221,6 +250,70 @@ bool extractCalibrationPoints(const Settings &s, const cv::Mat &cvI, std::vector
return found;
}

void computeDistortionDisplacementMap(const vpCameraParameters &cam_dist, vpImage<vpRGBa> &I_color)
{
vpImage<double> displacement_map(I_color.getHeight(), I_color.getWidth());

double min_displ = 1e12, max_displ = 0;
for (unsigned int i = 0; i < I_color.getHeight(); i++) {
for (unsigned int j = 0; j < I_color.getWidth(); j++) {
double x = 0, y = 0, id = 0, jd = 0;
vpPixelMeterConversion::convertPointWithoutDistortion(cam_dist, j, i, x, y);
vpMeterPixelConversion::convertPoint(cam_dist, x, y, jd, id);

double erri = id - i;
double errj = jd - j;
double displ = std::sqrt(erri*erri + errj*errj);
displacement_map[i][j] = displ;
min_displ = displ < min_displ ? displ : min_displ;
max_displ = displ > max_displ ? displ : max_displ;
}
}

double a = 255 / (max_displ - min_displ);
double b = (-255 * min_displ) / (max_displ - min_displ);

vpImage<unsigned char> I_gray(I_color.getHeight(), I_color.getWidth());
for (unsigned int i = 0; i < displacement_map.getHeight(); i++) {
for (unsigned int j = 0; j < displacement_map.getWidth(); j++) {
I_gray[i][j] = static_cast<unsigned char>(vpMath::clamp(a * displacement_map[i][j] + b, 0.0, 255.0));
}
}

vpColormap colormap(vpColormap::COLORMAP_TURBO);
colormap.convert(I_gray, I_color);
}

void createMosaic(const std::vector<vpImage<vpRGBa>> &list_imgs, std::vector<vpImage<vpRGBa>> &list_mosaics)
{
const unsigned int nb_rows = 4, nb_cols = 6;
const unsigned int nb_totals = nb_rows*nb_cols;
if (list_imgs.empty()) {
return;
}

const unsigned int img_h = list_imgs[0].getHeight();
const unsigned int img_w = list_imgs[0].getWidth();
vpImage<vpRGBa> mosaic(img_h*nb_rows, img_w*nb_cols);
for (size_t i = 0; i < list_imgs.size(); i += nb_totals) {
mosaic = vpRGBa(0, 0, 0);

for (size_t j = 0; j < nb_totals; j++) {
const size_t idx = i + j;
const unsigned int pos_mod = idx % nb_totals;
if (idx >= list_imgs.size()) {
break;
}

const unsigned int pos_row = pos_mod / nb_cols;
vpImagePoint top_left(pos_row*img_h, (pos_mod - pos_row*nb_cols)*img_w);
mosaic.insert(list_imgs[idx], top_left);
}

list_mosaics.push_back(mosaic);
}
}

} // namespace calib_helper

#endif // DOXYGEN_SHOULD_SKIP_THIS
Expand Down
Loading
Loading