1749 lines
58 KiB
Text
1749 lines
58 KiB
Text
/*
|
|
* thermo implementation
|
|
*
|
|
* Copyright (C) Dorit Borrmann
|
|
*
|
|
* Released under the GPL version 3.
|
|
*
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include "thermo/thermo.h"
|
|
#include "newmat/newmatap.h"
|
|
using namespace NEWMAT;
|
|
|
|
#include "cvblob.h"
|
|
using namespace cvb;
|
|
|
|
#include <slam6d/globals.icc>
|
|
|
|
#ifndef _MSC_VER
|
|
#include <getopt.h>
|
|
#include <sys/stat.h>
|
|
#else
|
|
#include "XGetopt.h"
|
|
#define strcasecmp _stricmp
|
|
#define strncasecmp _strnicmp
|
|
#include <windows.h>
|
|
#include <direct.h>
|
|
#endif
|
|
|
|
#ifdef _EiC
|
|
#define WIN32
|
|
#endif
|
|
|
|
Float2D data1;
|
|
Float2D data2;
|
|
|
|
unsigned int BLOB_SIZE = 55;
|
|
double AVG_THRES = 0.8;
|
|
|
|
/**
|
|
* Calculates the PCA of a two-dimensional point cloud
|
|
* @param x x coordinate of the axis
|
|
* @param y y coordinate of the axis
|
|
* @param pc true if the principal axis is wanted, false for the least dominant
|
|
* @param cx center x of the point cloud
|
|
* @param cy center y of the point cloud
|
|
*/
|
|
|
|
void calcBoard(double point_array[][2], int board_n, double &x, double &y, double &cx, double &cy, bool pc) {
|
|
cx = cy = 0;
|
|
for (int a = 0; a < board_n; a++) {
|
|
cx += point_array[a][0];
|
|
cy += point_array[a][1];
|
|
}
|
|
|
|
cx /= board_n;
|
|
cy /= board_n;
|
|
|
|
SymmetricMatrix A(2);
|
|
A = 0;
|
|
|
|
for(int a = 0; a < board_n; a++) {
|
|
A(1,1) += (point_array[a][0] - cx)*(point_array[a][0] - cx);
|
|
A(2,2) += (point_array[a][1] - cy)*(point_array[a][1] - cy);
|
|
A(1,2) += (point_array[a][0] - cx)*(point_array[a][1] - cy);
|
|
}
|
|
DiagonalMatrix D;
|
|
Matrix V;
|
|
try {
|
|
Jacobi(A,D,V);
|
|
} catch (ConvergenceException) {
|
|
cout << "couldn't find board..." << endl;
|
|
}
|
|
|
|
int min, max;
|
|
|
|
D.MaximumAbsoluteValue1(max);
|
|
D.MinimumAbsoluteValue1(min);
|
|
|
|
// return eigenvector with highest eigenvalue
|
|
if(pc) {
|
|
x = V(1,max);
|
|
y = V(2,max);
|
|
// return eigenvector with lowest eigenvalue
|
|
} else {
|
|
x = V(1,min);
|
|
y = V(2,min);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Sorts the detected light bulbs on the board.
|
|
* @param point_array list of detected points
|
|
* @param board_n number of lightbulbs
|
|
* @param board_h number of rows
|
|
* @param board_w number of columns
|
|
* @param quiet if true, debug information is printed
|
|
*/
|
|
void sortBlobs(double point_array[][2], int board_n, int board_h, int board_w, bool quiet) {
|
|
double x, y, cx, cy;
|
|
// align board using PCA
|
|
calcBoard(point_array, board_n, x, y, cx, cy, board_h <= board_w);
|
|
double point_array2[board_n][2];
|
|
double angle = -atan2(y,x);
|
|
for(int i = 0; i < board_n; i++) {
|
|
double tmpx = point_array[i][0] - cx;
|
|
double tmpy = point_array[i][1] - cy;
|
|
point_array2[i][0] = tmpx * cos(angle) - tmpy * sin(angle);
|
|
point_array2[i][1] = tmpx * sin(angle) + tmpy * cos(angle);
|
|
}
|
|
// sorting the points on the basis of y coordinate//////
|
|
int swapped1 = 0;
|
|
do {
|
|
swapped1 = 0;
|
|
|
|
for (int a = 1; a <= board_n - 1; a++) {
|
|
if (point_array2[a][1] < point_array2[a - 1][1]) {
|
|
//rotated points
|
|
double tempx = point_array2[a][0];
|
|
double tempy = point_array2[a][1];
|
|
point_array2[a][0] = point_array2[a - 1][0];
|
|
point_array2[a][1] = point_array2[a - 1][1];
|
|
point_array2[a - 1][0] = tempx;
|
|
point_array2[a - 1][1] = tempy;
|
|
|
|
//original points
|
|
double tmpx = point_array[a][0];
|
|
double tmpy = point_array[a][1];
|
|
point_array[a][0] = point_array[a - 1][0];
|
|
point_array[a][1] = point_array[a - 1][1];
|
|
point_array[a - 1][0] = tmpx;
|
|
point_array[a - 1][1] = tmpy;
|
|
swapped1 = 1;
|
|
}
|
|
}
|
|
} while (swapped1 == 1);
|
|
|
|
if(!quiet) {
|
|
cout << "sorted array:" << endl;
|
|
for (int f = 0; f < board_n; f++) {
|
|
cout << point_array2[f][0] << " " << point_array2[f][1] << endl;
|
|
}
|
|
}
|
|
// sorting the array rows now
|
|
for (int x = 0; x < board_h; x++) {
|
|
double row_points[board_w][2];
|
|
double row_points2[board_w][2];
|
|
for (int y = 0; y < board_w; y++) {
|
|
row_points[y][0] = point_array[x * board_w + y][0];
|
|
row_points[y][1] = point_array[x * board_w + y][1];
|
|
row_points2[y][0] = point_array2[x * board_w + y][0];
|
|
row_points2[y][1] = point_array2[x * board_w + y][1];
|
|
if(!quiet) cout << row_points[y][0] << " " << row_points[y][1] << " ";
|
|
}
|
|
if(!quiet) cout << endl;
|
|
int swapped = 0;
|
|
do {
|
|
swapped = 0;
|
|
for (int a = 1; a <= board_w - 1; a++) {
|
|
if (row_points2[a][0] < row_points2[a - 1][0]) {
|
|
// original points
|
|
double tempx = row_points[a][0];
|
|
double tempy = row_points[a][1];
|
|
row_points[a][0] = row_points[a - 1][0];
|
|
row_points[a][1] = row_points[a - 1][1];
|
|
row_points[a - 1][0] = tempx;
|
|
row_points[a - 1][1] = tempy;
|
|
// rotated points
|
|
double tmpx = row_points2[a][0];
|
|
double tmpy = row_points2[a][1];
|
|
row_points2[a][0] = row_points2[a - 1][0];
|
|
row_points2[a][1] = row_points2[a - 1][1];
|
|
row_points2[a - 1][0] = tmpx;
|
|
row_points2[a - 1][1] = tmpy;
|
|
swapped = 1;
|
|
}
|
|
}
|
|
} while (swapped == 1);
|
|
if(!quiet) cout << "sorted:" << endl;
|
|
for (int z = 0; z < board_w; z++) {
|
|
point_array2[x * board_w + z][0] = row_points2[z][0];
|
|
point_array2[x * board_w + z][1] = row_points2[z][1];
|
|
if(!quiet) cout << point_array[x * board_w + z][0] << " " << point_array[x * board_w + z][1] << " ";
|
|
point_array[x * board_w + z][0] = row_points[z][0];
|
|
point_array[x * board_w + z][1] = row_points[z][1];
|
|
}
|
|
if(!quiet) cout << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Detects the blobs.
|
|
*/
|
|
IplImage* detectBlobs(IplImage *org_image, int &corner_exp, int board_h, int board_w, bool quiet, double point_array2[][2]) {
|
|
|
|
IplImage *gray_image = cvCloneImage(org_image);
|
|
cvThreshold(gray_image, gray_image, 140, 255, CV_THRESH_BINARY);
|
|
IplImage *labelImg = cvCreateImage(cvGetSize(gray_image), IPL_DEPTH_LABEL, 1);
|
|
|
|
// detect blobs
|
|
CvBlobs blobs;
|
|
cvLabel(gray_image, labelImg, blobs);
|
|
double average_size = 0;
|
|
int count = 0;
|
|
for (CvBlobs::const_iterator it = blobs.begin(); it != blobs.end(); ++it) {
|
|
if (it->second->area < BLOB_SIZE) {
|
|
count++;
|
|
average_size += it->second->area;
|
|
}
|
|
}
|
|
if(!quiet) cout << "centroid:" << average_size << endl;
|
|
|
|
// refine blobs
|
|
average_size = average_size / count;
|
|
double average_size_min = average_size * (1.0 - AVG_THRES);
|
|
double average_size_max = average_size * (1.0 + AVG_THRES);
|
|
int blob_count = 0;
|
|
|
|
for (CvBlobs::const_iterator it2 = blobs.begin(); it2 != blobs.end(); ++it2) {
|
|
if (it2->second->area >= average_size_min &&
|
|
it2->second->area <= average_size_max &&
|
|
blob_count < corner_exp) {
|
|
|
|
point_array2[blob_count][0] = it2->second->centroid.x;
|
|
point_array2[blob_count][1] = it2->second->centroid.y;
|
|
double sumx = 0.0;
|
|
double sumy = 0.0;
|
|
double sum = 0.0;
|
|
|
|
/*
|
|
int step = 5;
|
|
int minx = ((int)it2->second->minx - step) > -1 ? (it2->second->minx - step) : 0;
|
|
int maxx = ((it2->second->maxx + step) < gray_image->width) ? (it2->second->maxx + step) : (gray_image->width - 1);
|
|
int miny = ((int)it2->second->miny - step) > -1 ? (it2->second->miny - step) : 0;
|
|
int maxy = ((it2->second->maxy + step) < gray_image->height) ? (it2->second->maxy + step) : (gray_image->height - 1);
|
|
*/
|
|
|
|
int minx = it2->second->minx;
|
|
int miny = it2->second->miny;
|
|
int maxx = it2->second->maxx;
|
|
int maxy = it2->second->maxy;
|
|
|
|
for(int x = minx; x <= maxx; x++) {
|
|
for(int y = miny; y <= maxy; y++) {
|
|
if(cvGet2D(gray_image, y, x).val[0] > 0) {
|
|
CvScalar c;
|
|
c = cvGet2D(org_image, y, x);
|
|
sum += c.val[0];
|
|
sumx += c.val[0]*x;
|
|
sumy += c.val[0]*y;
|
|
}
|
|
}
|
|
}
|
|
|
|
sumx /= sum;
|
|
sumy /= sum;
|
|
point_array2[blob_count][0] = sumx;
|
|
point_array2[blob_count][1] = sumy;
|
|
|
|
blob_count++;
|
|
}
|
|
}
|
|
|
|
if(!quiet) cout << "Refined number of blobs=" << blob_count << endl;
|
|
// sorting the points
|
|
sortBlobs(point_array2, corner_exp, board_h, board_w, true);
|
|
cvReleaseImage(&labelImg);
|
|
corner_exp = blob_count;
|
|
return gray_image;
|
|
}
|
|
|
|
/**
|
|
* Connects the detected calibration features in the image with lines.
|
|
*/
|
|
void drawLines(double point_array2[][2], int corner_exp, IplImage *image, bool color) {
|
|
for (int i = 0; i <= corner_exp - 2; i++) {
|
|
CvPoint pt1;
|
|
CvPoint pt2;
|
|
CvScalar s;
|
|
if(color) {
|
|
s = CV_RGB(255,0,0);
|
|
} else {
|
|
s.val[0] = 100;
|
|
}
|
|
double temp1 = point_array2[i][0] - floor(point_array2[i][0]);
|
|
if (temp1 < .5) {
|
|
pt1.x = floor(point_array2[i][0]);
|
|
} else {
|
|
pt1.x = floor(point_array2[i][0]) + 1;
|
|
}
|
|
double temp2 = point_array2[i][1] - floor(point_array2[i][1]);
|
|
if (temp2 < .5) {
|
|
pt1.y = floor(point_array2[i][1]);
|
|
} else {
|
|
pt1.y = floor(point_array2[i][1]) + 1;
|
|
}
|
|
double temp3 = point_array2[i + 1][0] - floor(
|
|
point_array2[i + 1][0]);
|
|
if (temp3 < .5) {
|
|
pt2.x = floor(point_array2[i + 1][0]);
|
|
} else {
|
|
pt2.x = floor(point_array2[i + 1][0]) + 1;
|
|
}
|
|
double temp4 = point_array2[i + 1][1] - floor(
|
|
point_array2[i + 1][1]);
|
|
if (temp4 < .5) {
|
|
pt2.y = floor(point_array2[i + 1][1]);
|
|
} else {
|
|
pt2.y = floor(point_array2[i + 1][1]) + 1;
|
|
}
|
|
cvLine(image, pt1, pt2, s, 1, 8);
|
|
}
|
|
cvShowImage("Final Result", image);
|
|
|
|
}
|
|
|
|
/**
|
|
* Resizes the image
|
|
*/
|
|
IplImage* resizeImage(IplImage *source, int scale) {
|
|
int width, height;
|
|
IplImage *image;
|
|
switch(scale) {
|
|
case 2:
|
|
width = 1200;
|
|
height = 900;
|
|
break;
|
|
case 3:
|
|
width = 800;
|
|
height = 600;
|
|
break;
|
|
case 4:
|
|
width = 400;
|
|
height = 300;
|
|
break;
|
|
case 5:
|
|
width = 160;
|
|
height = 120;
|
|
break;
|
|
case 1:
|
|
default:
|
|
return cvCloneImage(source);
|
|
}
|
|
|
|
image = cvCreateImage(cvSize(width,height),source->depth,source->nChannels);
|
|
cvResize(source,image);
|
|
return image;
|
|
}
|
|
|
|
/**
|
|
* Detects the corners of the chessboard pattern.
|
|
*/
|
|
IplImage* detectCorners(IplImage *orgimage, int corner_exp, int board_h, int board_w, bool quiet, double point_array2[][2], int scale) {
|
|
|
|
IplImage *image = resizeImage(orgimage, scale);
|
|
CvSize size = cvGetSize(image);
|
|
CvPoint2D32f* corners = new CvPoint2D32f[corner_exp];
|
|
CvSize board_sz = cvSize(board_w, board_h);
|
|
IplImage *gray_image = cvCreateImage(size,8,1);
|
|
|
|
if (image->nChannels == 3) {
|
|
cvCvtColor(image, gray_image, CV_BGR2GRAY);
|
|
} else {
|
|
gray_image = image;
|
|
}
|
|
|
|
int found = cvFindChessboardCorners(image, board_sz, corners, &corner_exp,
|
|
CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
|
|
|
|
cout << "found corners:" << corner_exp << endl;
|
|
if (found != 0) {//if all corners found successfully
|
|
//Get Subpixel accuracy on those corners
|
|
if(size.width > 400) {
|
|
cvFindCornerSubPix(gray_image, corners, corner_exp, cvSize(11, 11), cvSize(-1, -1),
|
|
cvTermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
|
|
}
|
|
else {
|
|
cvFindCornerSubPix(gray_image, corners, corner_exp, cvSize(2, 2), cvSize(-1, -1),
|
|
cvTermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < corner_exp; i++) {
|
|
point_array2[i][0] = corners[i].x;
|
|
point_array2[i][1] = corners[i].y;
|
|
}
|
|
return gray_image;
|
|
|
|
}
|
|
|
|
/**
|
|
* Writes the intrinsic calibration parameters to files.
|
|
*/
|
|
void writeCalibParam(int images, int corner_exp, int board_w, CvMat*
|
|
image_points, CvSize size, string dir, string substring) {
|
|
CvMat* intrinsic_matrix = cvCreateMat(3, 3, CV_32FC1);
|
|
CvMat* distortion_coeffs = cvCreateMat(5, 1, CV_32FC1);
|
|
//ALLOCATE MATRICES ACCORDING TO HOW MANY CHESSBOARDS FOUND
|
|
CvMat* object_points2 = cvCreateMat(images * corner_exp, 3, CV_32FC1);
|
|
CvMat* image_points2 = cvCreateMat(images * corner_exp, 2, CV_32FC1);
|
|
CvMat* point_counts2 = cvCreateMat(images, 1, CV_32SC1);
|
|
CvMat* Rotation = cvCreateMat(images, 3, CV_32FC1);
|
|
CvMat* Translation = cvCreateMat(images, 3, CV_32FC1);
|
|
//TRANSFER THE POINTS INTO THE CORRECT SIZE MATRICES
|
|
int j;
|
|
for (int i = 0; i < images * corner_exp; ++i) {
|
|
j = i % corner_exp;
|
|
CV_MAT_ELEM( *image_points2, float, i, 0) = CV_MAT_ELEM( *image_points, float, i, 0);
|
|
CV_MAT_ELEM( *image_points2, float,i,1) = CV_MAT_ELEM( *image_points, float, i, 1);
|
|
CV_MAT_ELEM(*object_points2, float, i, 0) = (j / board_w) * 8;
|
|
CV_MAT_ELEM( *object_points2, float, i, 1) = (j % board_w) * 8;
|
|
CV_MAT_ELEM( *object_points2, float, i, 2) = 0.0f;
|
|
}
|
|
for (int i = 0; i < images; ++i) { //These are all the same number
|
|
CV_MAT_ELEM( *point_counts2, int, i, 0) = corner_exp;
|
|
}
|
|
|
|
// Initialize the intrinsic matrix with focal length = 1.0
|
|
CV_MAT_ELEM( *intrinsic_matrix, float, 0, 0 ) = 1.0f;
|
|
CV_MAT_ELEM( *intrinsic_matrix, float, 1, 1 ) = 1.0f;
|
|
//CALIBRATE THE CAMERA!
|
|
cvCalibrateCamera2(object_points2, image_points2, point_counts2, size,
|
|
intrinsic_matrix, distortion_coeffs, Rotation, Translation, 0 //CV_CALIB_FIX_ASPECT_RATIO
|
|
);
|
|
// SAVE AND PRINT THE INTRINSICS AND DISTORTIONS
|
|
|
|
string file = dir + "Intrinsics" + substring + ".xml";
|
|
cvSave(file.c_str(), intrinsic_matrix);
|
|
file = dir + "Distortion" + substring + ".xml";
|
|
cvSave(file.c_str(), distortion_coeffs);
|
|
cout << "Camera Intrinsic Matrix is:" << endl;
|
|
for (int row = 0; row < 3; row++) {
|
|
for (int col = 0; col < 3; col++) {
|
|
cout << CV_MAT_ELEM( *intrinsic_matrix, float, row, col ) << "\t";
|
|
}
|
|
cout << endl;
|
|
}
|
|
cout << "Distortion Coefficients are:" << endl;
|
|
for (int row = 0; row < 5; row++) {
|
|
for (int col = 0; col < 1; col++) {
|
|
cout << CV_MAT_ELEM( *distortion_coeffs, float, row, col ) << "\t";
|
|
}
|
|
}
|
|
cout << endl;
|
|
CvMat *intrinsic = intrinsic_matrix;
|
|
CvMat *distortion = distortion_coeffs;
|
|
|
|
// CLEANUP
|
|
cvReleaseMat(&object_points2);
|
|
cvReleaseMat(&image_points2);
|
|
cvReleaseMat(&point_counts2);
|
|
cvReleaseMat(&Rotation);
|
|
cvReleaseMat(&Translation);
|
|
cvReleaseMat(&intrinsic);
|
|
cvReleaseMat(&distortion);
|
|
}
|
|
|
|
/**
|
|
* Main function for intrinsic calibration
|
|
*/
|
|
void CalibFunc(int board_w, int board_h, int start, int end, bool optical, bool
|
|
chess, bool quiet, string dir, int scale) {
|
|
cvNamedWindow("Original Image", 0);
|
|
cvResizeWindow( "Final Result", 320, 240 );
|
|
cvNamedWindow("Final Result", 0);
|
|
cvResizeWindow( "Final Result", 320, 240 );
|
|
|
|
int nr_img = end - start + 1;
|
|
if (nr_img == 0) {
|
|
cout << "ImageCount is zero!" << endl;
|
|
return;
|
|
}
|
|
|
|
int corner_exp = board_w * board_h;
|
|
CvSize board_sz = cvSize(board_w, board_h);
|
|
CvSize size;
|
|
//ALLOCATE STORAGE(depending upon the number of images in(in case if command line arguments are given )
|
|
//not on the basis of number of images in which all corner extracted/while in the other case the number is the same )
|
|
CvMat* image_points = cvCreateMat(nr_img * corner_exp, 2, CV_32FC1);
|
|
//TODO CvPoint2D32f* corners = new CvPoint2D32f[ board_n ];
|
|
|
|
int successes = 0;
|
|
int step = 0;
|
|
|
|
for (int count = start; count <= end; count++) {
|
|
string t;
|
|
string t1;
|
|
|
|
if(optical) {
|
|
t = dir + "/photo" + to_string(count, 3) + ".ppm";
|
|
t1 = dir + "/cimage" + to_string(count, 3) + ".ppm";
|
|
//t = dir + to_string(count, 3) + "/photo" + to_string(count, 3) + ".ppm";
|
|
//t1 = dir + to_string(count, 3) + "/cimage" + to_string(count, 3) + ".ppm";
|
|
} else {
|
|
//t = dir + to_string(count, 3) + "/image" + to_string(count, 3) + ".ppm";
|
|
//t1 = dir + to_string(count, 3) + "/timage" + to_string(count, 3) + ".ppm";
|
|
t = dir + "/image" + to_string(count, 3) + ".ppm";
|
|
t1 = dir + "/timage" + to_string(count, 3) + ".ppm";
|
|
}
|
|
cout << t << endl;
|
|
//loading images and finding corners
|
|
IplImage* image1 = cvLoadImage(t.c_str(), -1);
|
|
if (!image1) {
|
|
cout << "image cannot be loaded" << endl;
|
|
return;
|
|
}
|
|
cvShowImage("Original Image", image1);
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
double point_array2[corner_exp][2];
|
|
IplImage *image;
|
|
|
|
if(chess) {
|
|
cout << "detect corners" << endl;
|
|
image = detectCorners(image1, corner_exp, board_h, board_w, quiet, point_array2, scale);
|
|
} else {
|
|
cout << "detect blob" << endl;
|
|
int tmp_corners = corner_exp;
|
|
image = detectBlobs(image1, tmp_corners, board_h, board_w, quiet, point_array2);
|
|
}
|
|
|
|
for(int i = 0; i < corner_exp; i++) {
|
|
cout << (float) point_array2[i][0] << " " << (float) point_array2[i][1] <<
|
|
endl;
|
|
}
|
|
//drawing the lines on the image now
|
|
drawLines(point_array2, corner_exp, image);
|
|
|
|
cout << "\nDo you want to use the data from this image ('y' or 'n'). 'x' aborts the calibration? : ";
|
|
int c = cvWaitKey(100);
|
|
if (c == 27) {
|
|
break;
|
|
}
|
|
char in;
|
|
cin >> in;
|
|
if (in == 'y') {
|
|
cvSaveImage(t1.c_str(), image);
|
|
size = cvGetSize(image);
|
|
step = successes * corner_exp;
|
|
//appending corner data to a generic data structure for all images
|
|
for (int i = step, j = 0; j < corner_exp; ++i, ++j) {
|
|
CV_MAT_ELEM(*image_points, float,i,0) = (float) point_array2[j][0];
|
|
CV_MAT_ELEM(*image_points, float,i,1) = (float) point_array2[j][1];
|
|
}
|
|
successes++;
|
|
} else if(in == 'x') {
|
|
break;
|
|
}
|
|
cvReleaseImage(&image);
|
|
cvReleaseImage(&image1);
|
|
|
|
}
|
|
cout << "Images for which all corners were found successfully="
|
|
<< successes << endl;
|
|
if (successes == 0) {
|
|
cout << "No successful corners found from any image" << endl;
|
|
return;
|
|
}
|
|
|
|
string substring = optical? "Optical" : "";
|
|
writeCalibParam(successes, corner_exp, board_w, image_points, size, dir, substring);
|
|
|
|
cvReleaseMat(&image_points);
|
|
|
|
}
|
|
|
|
/**
|
|
* Reads the 3D information of the features from a file.
|
|
*/
|
|
bool readPoints(string filename, CvPoint3D32f *corners, int size) {
|
|
ifstream infile(filename.c_str(), ios::in);
|
|
if (!infile) {
|
|
cout << "3Ddata file cannot be loaded" << endl;
|
|
return false;
|
|
}
|
|
|
|
string verify;
|
|
infile >> verify;
|
|
if(strcmp(verify.c_str(), "failed") == 0) return false;
|
|
for(int l = 0; l < size; l++) {
|
|
infile >> corners[l].y;
|
|
infile >> corners[l].z;
|
|
infile >> corners[l].x;
|
|
corners[l].y = -corners[l].y;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Calculates the median of a set of translation vectors, i.e., the translation
|
|
* that has the smallest distance to all other translation.
|
|
*/
|
|
int realMedian(CvMat * vectors, int nr_vectors) {
|
|
double distances[nr_vectors];
|
|
|
|
for(int i = 0; i < nr_vectors; i++) {
|
|
double sum = 0;
|
|
double x1 = (CV_MAT_ELEM(*vectors,float,i,0));
|
|
double y1 = (CV_MAT_ELEM(*vectors,float,i,1));
|
|
double z1 = (CV_MAT_ELEM(*vectors,float,i,2));
|
|
for(int j = 0; j < nr_vectors; j++) {
|
|
double x2 = (CV_MAT_ELEM(*vectors,float,j,0));
|
|
double y2 = (CV_MAT_ELEM(*vectors,float,j,1));
|
|
double z2 = (CV_MAT_ELEM(*vectors,float,j,2));
|
|
double tmp = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1);
|
|
sum += sqrt(tmp);
|
|
}
|
|
distances[i] = sum;
|
|
}
|
|
int min_pos = -1;
|
|
double min_dist = DBL_MAX;
|
|
for(int i = 0; i < nr_vectors; i++) {
|
|
if(distances[i] < min_dist) {
|
|
min_pos = i;
|
|
min_dist = distances[i];
|
|
}
|
|
}
|
|
|
|
return min_pos;
|
|
}
|
|
|
|
/*
|
|
* Calculates the median of a set of vectors by iteratively calculating the
|
|
* median and cropping outliers.
|
|
*/
|
|
void filterMedian(CvMat * vectors, int nr_vectors, int threshold, CvMat * mean) {
|
|
|
|
// calculate Median
|
|
int min_pos = realMedian(vectors, nr_vectors);
|
|
|
|
// crop outliers
|
|
double x1 = (CV_MAT_ELEM(*vectors,float,min_pos,0));
|
|
double y1 = (CV_MAT_ELEM(*vectors,float,min_pos,1));
|
|
double z1 = (CV_MAT_ELEM(*vectors,float,min_pos,2));
|
|
|
|
int count = 0;
|
|
for(int i = 0; i < nr_vectors; i++) {
|
|
double x2 = (CV_MAT_ELEM(*vectors,float,i,0));
|
|
double y2 = (CV_MAT_ELEM(*vectors,float,i,1));
|
|
double z2 = (CV_MAT_ELEM(*vectors,float,i,2));
|
|
double tmp = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1);
|
|
if(sqrt(tmp) < 1.0/threshold) count++;
|
|
}
|
|
|
|
CvMat* some_vectors = cvCreateMat(count, 6, CV_32FC1);
|
|
count = 0;
|
|
for(int i = 0; i < nr_vectors; i++) {
|
|
double x2 = (CV_MAT_ELEM(*vectors,float,i,0));
|
|
double y2 = (CV_MAT_ELEM(*vectors,float,i,1));
|
|
double z2 = (CV_MAT_ELEM(*vectors,float,i,2));
|
|
double tmp = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1);
|
|
if(sqrt(tmp) < 1.0/threshold) {
|
|
for(int j = 0; j < 6; j++) {
|
|
(CV_MAT_ELEM(*some_vectors,float,count,j)) = (CV_MAT_ELEM(*vectors,float,i,j));
|
|
cout << (CV_MAT_ELEM(*some_vectors,float,count,j)) << " ";
|
|
}
|
|
cout << endl;
|
|
count++;
|
|
}
|
|
}
|
|
// recurse
|
|
if(threshold < 3) {
|
|
filterMedian(some_vectors, count, ++threshold, mean);
|
|
cvReleaseMat(&some_vectors);
|
|
// determine result
|
|
} else {
|
|
x1 = (CV_MAT_ELEM(*some_vectors,float,min_pos,0));
|
|
y1 = (CV_MAT_ELEM(*some_vectors,float,min_pos,1));
|
|
z1 = (CV_MAT_ELEM(*some_vectors,float,min_pos,2));
|
|
double x2 = 0;
|
|
double y2 = 0;
|
|
double z2 = 0;
|
|
double r1 = 0;
|
|
double r2 = 0;
|
|
double r3 = 0;
|
|
for(int i = 0; i < count; i++) {
|
|
x2 += (CV_MAT_ELEM(*some_vectors,float,i,0));
|
|
y2 += (CV_MAT_ELEM(*some_vectors,float,i,1));
|
|
z2 += (CV_MAT_ELEM(*some_vectors,float,i,2));
|
|
r1 += (CV_MAT_ELEM(*some_vectors,float,i,3));
|
|
r2 += (CV_MAT_ELEM(*some_vectors,float,i,4));
|
|
r3 += (CV_MAT_ELEM(*some_vectors,float,i,5));
|
|
}
|
|
(CV_MAT_ELEM(*mean,float,0,0)) = x2/count;
|
|
(CV_MAT_ELEM(*mean,float,0,1)) = y2/count;
|
|
(CV_MAT_ELEM(*mean,float,0,2)) = z2/count;
|
|
(CV_MAT_ELEM(*mean,float,0,3)) = r1/count;
|
|
(CV_MAT_ELEM(*mean,float,0,4)) = r2/count;
|
|
(CV_MAT_ELEM(*mean,float,0,5)) = r3/count;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sorts vectors element by element, enables one to calculate the median of
|
|
* each element separately.
|
|
*/
|
|
void sortElementByElement(CvMat * vectors, int nr_elems, int nr_vectors) {
|
|
bool swapped;
|
|
for (int i = 0; i < nr_elems; i++) {
|
|
do {
|
|
swapped = false;
|
|
for (int j = 1; j <= nr_vectors - 1; j++) {
|
|
if (CV_MAT_ELEM(*vectors,float,j,i) < CV_MAT_ELEM(*vectors,float,j-1,i)) {
|
|
float temp = CV_MAT_ELEM(*vectors,float,j,i);
|
|
CV_MAT_ELEM(*vectors,float,j,i) = CV_MAT_ELEM(*vectors,float,j-1,i);
|
|
CV_MAT_ELEM(*vectors,float,j-1,i) = temp;
|
|
swapped = true;
|
|
}
|
|
}
|
|
} while (swapped);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculates the extrinsic parameters of a set of matches. Find the best match
|
|
* by calculating the reprojection error of each set of calibration parameters.
|
|
*/
|
|
void calculateExtrinsicsWithReprojectionCheck(CvMat * points2D, CvMat *
|
|
points3D, CvMat * rotation_vectors_temp, CvMat * translation_vectors_temp, CvMat
|
|
* distortion, CvMat * intrinsics, int corners, int successes, string dir, bool quiet, string substring) {
|
|
double reprojectionError[successes];
|
|
for(int i = 0; i < successes; i++) {
|
|
reprojectionError[i] = 0.0;
|
|
}
|
|
|
|
for(int i = 0; i < successes; i++) {
|
|
reprojectionError[i] = 0.0;
|
|
CvMat * rotation = cvCreateMat(1, 3, CV_32FC1);
|
|
CvMat * translation = cvCreateMat(1, 3, CV_32FC1);
|
|
|
|
for(int k = 0; k < 3; k++) {
|
|
CV_MAT_ELEM(*rotation, float, 0, k) = CV_MAT_ELEM(*rotation_vectors_temp, float, i, k);
|
|
CV_MAT_ELEM(*translation, float, 0, k) = CV_MAT_ELEM(*translation_vectors_temp, float, i, k);
|
|
}
|
|
for(int j = 0; j < successes; j++) {
|
|
double tmp = 0;
|
|
//calculate reprojection error
|
|
CvMat * point_3Dcloud = cvCreateMat(corners, 3, CV_32FC1);
|
|
CvMat * point_2Dcloud = cvCreateMat(corners, 2, CV_32FC1);
|
|
for(int l = 0; l < corners; l++) {
|
|
CV_MAT_ELEM(*point_2Dcloud,float,l,0) = 0.0;
|
|
CV_MAT_ELEM(*point_2Dcloud,float,l,1) = 1.0;
|
|
CV_MAT_ELEM(*point_3Dcloud,float,l,0) = CV_MAT_ELEM(*points3D,CvPoint3D32f,j,l).x;
|
|
CV_MAT_ELEM(*point_3Dcloud,float,l,1) = CV_MAT_ELEM(*points3D,CvPoint3D32f,j,l).y;
|
|
CV_MAT_ELEM(*point_3Dcloud,float,l,2) = CV_MAT_ELEM(*points3D,CvPoint3D32f,j,l).z;
|
|
}
|
|
cvProjectPoints2(point_3Dcloud, rotation, translation, intrinsics,
|
|
distortion, point_2Dcloud, NULL, NULL, NULL, NULL, NULL, 0);
|
|
for(int l = 0; l < corners; l++) {
|
|
double x = CV_MAT_ELEM(*point_2Dcloud,float,l,0) - CV_MAT_ELEM(*points2D,CvPoint2D32f,j,l).x;
|
|
double y = CV_MAT_ELEM(*point_2Dcloud,float,l,1) - CV_MAT_ELEM(*points2D,CvPoint2D32f,j,l).y;
|
|
tmp += sqrt(x*x + y*y);
|
|
}
|
|
cvReleaseMat(&point_2Dcloud);
|
|
reprojectionError[i] += tmp;
|
|
cvReleaseMat(&point_3Dcloud);
|
|
}
|
|
cvReleaseMat(&rotation);
|
|
cvReleaseMat(&translation);
|
|
}
|
|
|
|
int maxindex = -1;
|
|
double max = DBL_MAX;
|
|
for(int i = 0; i < successes; i++) {
|
|
if(reprojectionError[i] < max) {
|
|
maxindex = i;
|
|
max = reprojectionError[i];
|
|
}
|
|
}
|
|
|
|
CvMat * rotation = cvCreateMat(1, 3, CV_32FC1);
|
|
CvMat * translation = cvCreateMat(1, 3, CV_32FC1);
|
|
|
|
for(int i = 0; i < 3; i++) {
|
|
CV_MAT_ELEM(*rotation, float, 0, i) = CV_MAT_ELEM(*rotation_vectors_temp, float, maxindex, i);
|
|
CV_MAT_ELEM(*translation, float, 0, i) = CV_MAT_ELEM(*translation_vectors_temp, float, maxindex, i);
|
|
}
|
|
string file = dir + "Rotation" + substring + ".xml";
|
|
cvSave(file.c_str(), rotation);
|
|
file = dir + "Translation" + substring + ".xml";
|
|
cvSave(file.c_str(), translation);
|
|
|
|
}
|
|
|
|
/**
|
|
* Calculates the extrinsic parameters given a set of feature matches using the
|
|
* mean and median method.
|
|
*/
|
|
void calculateExtrinsics(CvMat * rotation_vectors_temp, CvMat * translation_vectors_temp, int successes, string dir, bool quiet, string substring) {
|
|
|
|
CvMat* rotation_vectors = cvCreateMat(successes, 3, CV_32FC1);
|
|
CvMat* translation_vectors = cvCreateMat(successes, 3, CV_32FC1);
|
|
CvMat* vectors = cvCreateMat(successes, 6, CV_32FC1);
|
|
CvMat* rotation_vector_mean = cvCreateMat(1, 3, CV_32FC1);
|
|
CvMat* translation_vector_mean = cvCreateMat(1, 3, CV_32FC1);
|
|
CvMat* rotation_vector_median = cvCreateMat(1, 3, CV_32FC1);
|
|
CvMat* translation_vector_median = cvCreateMat(1, 3, CV_32FC1);
|
|
CvMat* median = cvCreateMat(1, 6, CV_32FC1);
|
|
for (int t = 0; t < 3; t++) {
|
|
CV_MAT_ELEM(*rotation_vector_mean,float,0,t) = 0;
|
|
CV_MAT_ELEM(*translation_vector_mean,float,0,t) = 0;
|
|
CV_MAT_ELEM(*rotation_vector_median,float,0,t) = 0;
|
|
CV_MAT_ELEM(*translation_vector_median,float,0,t) = 0;
|
|
CV_MAT_ELEM(*median,float,0,t) = 0;
|
|
CV_MAT_ELEM(*median,float,0,t + 3) = 0;
|
|
}
|
|
|
|
for (int h = 0; h < successes; h++) {
|
|
for(int t = 0; t < 3; t++) {
|
|
CV_MAT_ELEM(*rotation_vectors,float,h,t) =CV_MAT_ELEM(*rotation_vectors_temp,float,h,t);
|
|
CV_MAT_ELEM(*rotation_vector_mean,float,0,t) +=CV_MAT_ELEM(*rotation_vectors,float,h,t);
|
|
|
|
CV_MAT_ELEM(*translation_vectors,float,h,t) =CV_MAT_ELEM(*translation_vectors_temp,float,h,t);
|
|
CV_MAT_ELEM(*translation_vector_mean,float,0,t) +=CV_MAT_ELEM(*translation_vectors,float,h,t);
|
|
|
|
CV_MAT_ELEM(*vectors,float,h,t) =CV_MAT_ELEM(*translation_vectors_temp,float,h,t);
|
|
CV_MAT_ELEM(*vectors,float,h,t + 3) =CV_MAT_ELEM(*rotation_vectors_temp,float,h,t);
|
|
}
|
|
}
|
|
|
|
for(int t = 0; t < 3; t++) {
|
|
CV_MAT_ELEM(*rotation_vector_mean,float,0,t) /= successes;
|
|
CV_MAT_ELEM(*translation_vector_mean,float,0,t) /= successes;
|
|
}
|
|
|
|
// finding the median of rotation and translation
|
|
// sorting the rotation vectors element by element
|
|
/*
|
|
sortElementByElement(rotation_vectors, 3, successes);
|
|
sortElementByElement(translation_vectors, 3, successes);
|
|
|
|
if(!quiet) {
|
|
cout << "number of successes : " << successes << endl;
|
|
cout << "rotation vectors are" << endl;
|
|
for (int i = 0; i < successes; i++) {
|
|
cout << CV_MAT_ELEM(*rotation_vectors,float,i,0) << " "
|
|
<<CV_MAT_ELEM(*rotation_vectors,float,i,1) << " "
|
|
<<CV_MAT_ELEM(*rotation_vectors,float,i,2) << endl;
|
|
}
|
|
cout << "translation vectors are" << endl;
|
|
for (int i = 0; i < successes; i++) {
|
|
cout << CV_MAT_ELEM(*translation_vectors,float,i,0) << " "
|
|
<<CV_MAT_ELEM(*translation_vectors,float,i,1) << " "
|
|
<<CV_MAT_ELEM(*translation_vectors,float,i,2) << endl;
|
|
}
|
|
}
|
|
int index = successes / 2;
|
|
for(int t = 0; t < 3; t++) {
|
|
CV_MAT_ELEM(*translation_vector_median,float,0,t) = CV_MAT_ELEM(*translation_vectors,float,index,t);
|
|
CV_MAT_ELEM(*rotation_vector_median,float,0,t) = CV_MAT_ELEM(*rotation_vectors,float,index,t);
|
|
}
|
|
*/
|
|
// getting the median vectors
|
|
filterMedian(vectors, successes, 1, median);
|
|
|
|
for(int t = 0; t < 3; t++) {
|
|
CV_MAT_ELEM(*translation_vector_median,float,0,t) = CV_MAT_ELEM(*median,float,0,t);
|
|
CV_MAT_ELEM(*rotation_vector_median,float,0,t) = CV_MAT_ELEM(*median,float,0,t+3);
|
|
}
|
|
|
|
cout << "mean rotation vector is :" << endl;
|
|
for (int f = 0; f < 3; f++) {
|
|
cout << CV_MAT_ELEM(*rotation_vector_mean,float,0,f) << " ";
|
|
}
|
|
cout << endl;
|
|
cout << "mean translation vector is :" << endl;
|
|
for (int g = 0; g < 3; g++) {
|
|
cout << CV_MAT_ELEM(*translation_vector_mean,float,0,g) << " ";
|
|
}
|
|
cout << endl;
|
|
|
|
cout << "median rotation vector is :" << endl;
|
|
for (int ff = 0; ff < 3; ff++) {
|
|
cout << CV_MAT_ELEM(*rotation_vector_median,float,0,ff) << " ";
|
|
}
|
|
cout << endl;
|
|
cout << "median translation vector is :" << endl;
|
|
for (int gg = 0; gg < 3; gg++) {
|
|
cout << CV_MAT_ELEM(*translation_vector_median,float,0,gg) << " ";
|
|
}
|
|
cout << endl;
|
|
|
|
// write extrinsic parameters
|
|
string file = dir + "RotationMean" + substring + ".xml";
|
|
cvSave(file.c_str(), rotation_vector_mean);
|
|
file = dir + "TranslationMean" + substring + ".xml";
|
|
cvSave(file.c_str(), translation_vector_mean);
|
|
file = dir + "RotationMedian" + substring + ".xml";
|
|
cvSave(file.c_str(), rotation_vector_median);
|
|
file = dir + "TranslationMedian" + substring + ".xml";
|
|
cvSave(file.c_str(), translation_vector_median);
|
|
|
|
// cleanup
|
|
cvReleaseMat(&rotation_vector_mean);
|
|
cvReleaseMat(&translation_vector_mean);
|
|
cvReleaseMat(&rotation_vector_median);
|
|
cvReleaseMat(&translation_vector_median);
|
|
cout << "End calculateExtrinsics" << endl;
|
|
|
|
}
|
|
|
|
/**
|
|
* Main function for extrinsic calibration of laser scanner and camera.
|
|
*/
|
|
void ExtrCalibFunc(int board_w, int board_h, int start, int end, bool optical, bool chess, bool quiet, string dir, int scale) {
|
|
int nr_img = end - start + 1;
|
|
if (nr_img == 0) {
|
|
cout << "ImageCount is zero!" << endl;
|
|
return;
|
|
}
|
|
cvNamedWindow("Original Image", 0);
|
|
cvResizeWindow( "Final Result", 320, 240 );
|
|
cvNamedWindow("Final Result", 0);
|
|
cvResizeWindow( "Final Result", 320, 240 );
|
|
|
|
int corner_exp = board_w * board_h;
|
|
CvSize board_sz = cvSize(board_w, board_h);
|
|
CvSize size;
|
|
CvPoint3D32f* corners = new CvPoint3D32f[corner_exp];
|
|
//ALLOCATE STORAGE(depending upon the number of images in(in case if command line arguments are given )
|
|
//not on the basis of number of images in which all corner extracted/while in the other case the number is the same )
|
|
|
|
string substring = optical? "Optical" : "";
|
|
string file = dir + "Intrinsics" + substring + ".xml";
|
|
cout << file << endl;
|
|
CvMat *intrinsic = (CvMat*) cvLoad(file.c_str());
|
|
file = dir + "Distortion" + substring + ".xml";
|
|
CvMat *distortion = (CvMat*) cvLoad(file.c_str());
|
|
//for storing the rotations and translation vectors
|
|
CvMat* rotation_vectors_temp = cvCreateMat(nr_img, 3, CV_32FC1);
|
|
CvMat* translation_vectors_temp = cvCreateMat(nr_img, 3, CV_32FC1);
|
|
CvMat* points3D = cvCreateMat(nr_img, corner_exp, CV_32FC3);
|
|
CvMat* points2D = cvCreateMat(nr_img, corner_exp, CV_32FC2);
|
|
int successes = 0;
|
|
|
|
for (int count = start; count <= end; count++) {
|
|
string i;
|
|
string p;
|
|
|
|
cout << "Reading data " << to_string(count, 3) << endl;
|
|
if(optical) {
|
|
i = dir + "/photo" + to_string(count, 3) + ".ppm";
|
|
} else {
|
|
i = dir + "/image" + to_string(count, 3) + ".ppm";
|
|
}
|
|
p = dir + "cali/scan" + to_string(count,3) + ".3d";
|
|
cout << p << endl;
|
|
// Load points from scan
|
|
bool scan_cali = readPoints(p, corners, corner_exp);
|
|
if(!scan_cali) continue;
|
|
// Load image and detect corners
|
|
IplImage* image1 = cvLoadImage(i.c_str(), -1);
|
|
if (!image1) {
|
|
cout << "image cannot be loaded" << endl;
|
|
return;
|
|
}
|
|
cvShowImage("Original Image", image1);
|
|
|
|
double point_array2[corner_exp][2];
|
|
IplImage *image;
|
|
|
|
int tmp_corners = corner_exp;
|
|
if(chess) {
|
|
image = detectCorners(image1, corner_exp, board_h, board_w, quiet, point_array2, scale);
|
|
} else {
|
|
image = detectBlobs(image1, tmp_corners, board_h, board_w, quiet, point_array2);
|
|
}
|
|
if (!image) {
|
|
cout << "image cannot be loaded" << endl;
|
|
return;
|
|
}
|
|
//drawing the lines on the image now
|
|
drawLines(point_array2, corner_exp, image);
|
|
CvMat* image_points = cvCreateMat(corner_exp, 2, CV_32FC1);
|
|
CvMat* object_points = cvCreateMat(corner_exp, 3, CV_32FC1);
|
|
CvMat* Rotation = cvCreateMat(1, 3, CV_32FC1);
|
|
CvMat* Translation = cvCreateMat(1, 3, CV_32FC1);
|
|
|
|
cout << "\nDo you want to use the data from this image ('y' or 'n'). 'x' aborts the calibration? : ";
|
|
int c = cvWaitKey(100);
|
|
if (c == 27) {
|
|
break;
|
|
}
|
|
char in;
|
|
cin >> in;
|
|
if(tmp_corners == corner_exp) {
|
|
if (in == 'y') {
|
|
size = cvGetSize(image);
|
|
//appending corner data to a generic data structure for all images
|
|
for (int j = 0; j < corner_exp; ++j) {
|
|
CV_MAT_ELEM(*image_points, float,j,0) = (float) point_array2[j][0];
|
|
CV_MAT_ELEM(*image_points, float,j,1) = (float) point_array2[j][1];
|
|
CV_MAT_ELEM(*object_points,float,j,0) = corners[j].x;
|
|
CV_MAT_ELEM(*object_points,float,j,1) = corners[j].y;
|
|
CV_MAT_ELEM(*object_points,float,j,2) = corners[j].z;
|
|
|
|
CV_MAT_ELEM(*points2D, CvPoint2D32f, successes, j).x = (float)point_array2[j][0];
|
|
CV_MAT_ELEM(*points2D, CvPoint2D32f, successes, j).y = (float)point_array2[j][1];
|
|
CV_MAT_ELEM(*points3D, CvPoint3D32f, successes, j).x = corners[j].x;
|
|
CV_MAT_ELEM(*points3D, CvPoint3D32f, successes, j).y = corners[j].y;
|
|
CV_MAT_ELEM(*points3D, CvPoint3D32f, successes, j).z = corners[j].z;
|
|
}
|
|
cvFindExtrinsicCameraParams2(object_points, image_points, intrinsic, distortion, Rotation, Translation);
|
|
// append data to vectors
|
|
if(!quiet) cout << "Rotation is:" << endl;
|
|
for (int row = 0; row < 1; row++) {
|
|
for (int col = 0; col < 3; col++) {
|
|
if(!quiet) cout << CV_MAT_ELEM( *Rotation, float, row, col ) << " ";
|
|
CV_MAT_ELEM( *rotation_vectors_temp, float, successes, col ) = CV_MAT_ELEM( *Rotation, float, row, col );
|
|
}
|
|
if(!quiet) cout << endl;
|
|
}
|
|
if(!quiet) cout << "Translation is:" << endl;
|
|
for (int row = 0; row < 1; row++) {
|
|
for (int col = 0; col < 3; col++) {
|
|
if(!quiet) cout << CV_MAT_ELEM( *Translation, float, row, col ) << " ";
|
|
CV_MAT_ELEM( *translation_vectors_temp, float, successes, col ) = CV_MAT_ELEM( *Translation, float, row, col );
|
|
}
|
|
if(!quiet) cout << endl;
|
|
}
|
|
successes++;
|
|
|
|
} else if(in == 'x') {
|
|
break;
|
|
}
|
|
}
|
|
cvReleaseImage(&image);
|
|
cvReleaseImage(&image1);
|
|
cvReleaseMat(&image_points);
|
|
cvReleaseMat(&object_points);
|
|
cvReleaseMat(&Rotation);
|
|
cvReleaseMat(&Translation);
|
|
}//for loop for imagecount
|
|
cvDestroyWindow("Original Image");
|
|
cvDestroyWindow("Final Result");
|
|
|
|
cout << "Number of successes: " << successes << endl;
|
|
// Now calculating mean and median rotation and trans
|
|
//calculateExtrinsics(rotation_vectors_temp, translation_vectors_temp, successes, dir, quiet, substring);
|
|
calculateExtrinsicsWithReprojectionCheck(points2D, points3D, rotation_vectors_temp, translation_vectors_temp, distortion, intrinsic, corner_exp, successes, dir, quiet, substring);
|
|
cvReleaseMat(&intrinsic);
|
|
cvReleaseMat(&distortion);
|
|
cvReleaseMat(&translation_vectors_temp);
|
|
cvReleaseMat(&rotation_vectors_temp);
|
|
cvReleaseMat(&points2D);
|
|
cvReleaseMat(&points3D);
|
|
}
|
|
|
|
/**
|
|
* Main function for projecting the 3D points onto the corresponding image and
|
|
* associating temperature values to the data points.
|
|
*/
|
|
void ProjectAndMap(int start, int end, bool optical, bool quiet, string dir,
|
|
IOType type, int scale, double rot_angle, double minDist, double maxDist,
|
|
bool correction, int neighborhood, int method) {
|
|
|
|
int nr_img = end - start + 1;
|
|
if (nr_img < 1) {
|
|
cout << "ImageCount is zero!" << endl;
|
|
return;
|
|
}
|
|
string substring = optical? "Optical" : "";
|
|
string file = dir + "Intrinsics" + substring + ".xml";
|
|
CvMat *intrinsic = (CvMat*) cvLoad(file.c_str());
|
|
file = dir + "Distortion" + substring + ".xml";
|
|
CvMat *distortion = (CvMat*) cvLoad(file.c_str());
|
|
switch(method) {
|
|
case 0:
|
|
file = dir + "Rotation" + substring + ".xml";
|
|
break;
|
|
case 1:
|
|
file = dir + "RotationMedian" + substring + ".xml";
|
|
break;
|
|
case 2:
|
|
file = dir + "RotationMean" + substring + ".xml";
|
|
break;
|
|
}
|
|
CvMat *Rotation = (CvMat*) cvLoad(file.c_str());
|
|
switch(method) {
|
|
case 0:
|
|
file = dir + "Translation" + substring + ".xml";
|
|
break;
|
|
case 1:
|
|
file = dir + "TranslationMedian" + substring + ".xml";
|
|
break;
|
|
case 2:
|
|
file = dir + "TranslationMean" + substring + ".xml";
|
|
break;
|
|
}
|
|
CvMat *Translation = (CvMat*) cvLoad(file.c_str());
|
|
CvMat* undistort = cvCreateMat(5,1,CV_32FC1);
|
|
for (int hh = 0; hh < 5; hh++) {
|
|
CV_MAT_ELEM(*undistort, float,hh,0) = 0;
|
|
}
|
|
|
|
double starttime = GetCurrentTimeInMilliSec();
|
|
|
|
// filling the rotation matrix
|
|
double rPosTheta[3] = {0.0, rad(rot_angle), 0.0};
|
|
double rPos[3] = {0.0, 0.0, 0.0};
|
|
double alignxf[16];
|
|
EulerToMatrix4(rPos, rPosTheta, alignxf);
|
|
|
|
string outdir = dir + "/labscan-map";
|
|
#ifdef _MSC_VER
|
|
int success = mkdir(outdir.c_str());
|
|
#else
|
|
int success = mkdir(outdir.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
|
|
#endif
|
|
if(success == 0) {
|
|
cout << "Writing scans to " << outdir << endl;
|
|
} else if(errno == EEXIST) {
|
|
cout << "Directory " << outdir << " exists already. CONTINUE" << endl;
|
|
} else {
|
|
cerr << "Creating directory " << outdir << " failed" << endl;
|
|
exit(1);
|
|
}
|
|
for (int count = start; count <= end; count++) {
|
|
CvMat* point_3Dcloud;
|
|
CvMat* point_2Dcloud;
|
|
CvMat* undistort_2Dcloud;
|
|
|
|
CvMat* point_3Dcloud_2;
|
|
CvMat* point_2Dcloud_2;
|
|
CvMat* undistort_2Dcloud_2;
|
|
|
|
// loading images
|
|
int count0;
|
|
if(rot_angle < 180 && rot_angle > 0) {
|
|
count0 = count % 9 == 8 ? count - 8 : count + 1;
|
|
} else {
|
|
count0 = count % 9 == 0 ? count + 8 : count - 1;
|
|
}
|
|
string t, t0;
|
|
if(optical) {
|
|
t = dir + "/photo" + to_string(count, 3) + ".ppm";
|
|
t0 = dir + "/photo" + to_string(count0, 3) + ".ppm";
|
|
} else {
|
|
t = dir + "/image" + to_string(count, 3) + ".ppm";
|
|
t0 = dir + "/image" + to_string(count0, 3) + ".ppm";
|
|
}
|
|
|
|
IplImage* image = cvLoadImage(t.c_str(), -1);
|
|
if (!image) {
|
|
cout << "first image " << t << " cannot be loaded" << endl;
|
|
return;
|
|
}
|
|
CvSize size = cvGetSize(image);
|
|
|
|
IplImage* image0;
|
|
if(fabs(rot_angle) > 1) {
|
|
image0 = cvLoadImage(t0.c_str(), -1);
|
|
|
|
if (!image0) {
|
|
cout << "second image " << t0 << " cannot be loaded" << endl;
|
|
return;
|
|
}
|
|
image0 = resizeImage(image0, scale);
|
|
}
|
|
image = resizeImage(image, scale);
|
|
if(image)
|
|
|
|
// reading the 3D points and projecting them back to 2d
|
|
Scan::readScans(type, count, count, dir, maxDist, minDist, 0);
|
|
Scan::allScans[0]->calcReducedPoints(-1, 0);
|
|
point_3Dcloud = cvCreateMat(Scan::allScans[0]->get_points_red_size(), 3, CV_32FC1);
|
|
point_2Dcloud = cvCreateMat(Scan::allScans[0]->get_points_red_size(), 2, CV_32FC1);
|
|
undistort_2Dcloud = cvCreateMat(Scan::allScans[0]->get_points_red_size(), 2, CV_32FC1);
|
|
for (int j = 0; j < Scan::allScans[0]->get_points_red_size(); j++) {
|
|
CV_MAT_ELEM(*point_3Dcloud, float,j,0) = Scan::allScans[0]->get_points_red()[j][2];
|
|
CV_MAT_ELEM(*point_3Dcloud, float,j,1) = -Scan::allScans[0]->get_points_red()[j][0];
|
|
CV_MAT_ELEM(*point_3Dcloud, float,j,2) = Scan::allScans[0]->get_points_red()[j][1];
|
|
}
|
|
|
|
cout << "Number of points read: " << Scan::allScans[0]->get_points_red_size() << endl;
|
|
cvProjectPoints2(point_3Dcloud, Rotation, Translation, intrinsic,
|
|
distortion, point_2Dcloud, NULL, NULL, NULL, NULL, NULL, 0);
|
|
|
|
cvProjectPoints2(point_3Dcloud, Rotation, Translation, intrinsic,
|
|
undistort, undistort_2Dcloud, NULL, NULL, NULL, NULL, NULL, 0);
|
|
|
|
// second image in case of overlap
|
|
if(fabs(rot_angle) > 1) {
|
|
point_3Dcloud_2 = cvCreateMat(Scan::allScans[0]->get_points_red_size(), 3, CV_32FC1);
|
|
point_2Dcloud_2 = cvCreateMat(Scan::allScans[0]->get_points_red_size(), 2, CV_32FC1);
|
|
undistort_2Dcloud_2 = cvCreateMat(Scan::allScans[0]->get_points_red_size(), 2, CV_32FC1);
|
|
for (int j = 0; j < Scan::allScans[0]->get_points_red_size(); j++) {
|
|
Point p(Scan::allScans[0]->get_points_red()[j]);
|
|
p.transform(alignxf);
|
|
|
|
CV_MAT_ELEM(*point_3Dcloud_2, float,j,0) = p.z;
|
|
CV_MAT_ELEM(*point_3Dcloud_2, float,j,1) = -p.x;
|
|
CV_MAT_ELEM(*point_3Dcloud_2, float,j,2) = p.y;
|
|
}
|
|
|
|
cvProjectPoints2(point_3Dcloud_2, Rotation, Translation, intrinsic,
|
|
distortion, point_2Dcloud_2, NULL, NULL, NULL, NULL, NULL, 0);
|
|
|
|
cvProjectPoints2(point_3Dcloud_2, Rotation, Translation, intrinsic,
|
|
undistort, undistort_2Dcloud_2, NULL, NULL, NULL, NULL, NULL, 0);
|
|
}
|
|
// write colored data
|
|
string outname = outdir + "/scan" + to_string(count, 3) + ".3d";
|
|
fstream outfile;
|
|
outfile.open(outname.c_str(), ios::out);
|
|
|
|
//for counting how many points get mapped to first and second image file
|
|
int point_map1 = 0; // #points mapped to first image
|
|
int point_map2 = 0; // " " " second image
|
|
|
|
// checking whether projection lies within the image boundaries
|
|
for (int k = 0; k < Scan::allScans[0]->get_points_red_size(); k++) {
|
|
float px = CV_MAT_ELEM(*undistort_2Dcloud,float,k,0);
|
|
float py = CV_MAT_ELEM(*undistort_2Dcloud,float,k,1);
|
|
if (px < image->width - .5 && px >= 0 && py >= 0 && py < image->height - .5) {
|
|
px = CV_MAT_ELEM(*point_2Dcloud,float,k,0);
|
|
py = CV_MAT_ELEM(*point_2Dcloud,float,k,1);
|
|
if (px < image->width - .5 && px >= 0 && py >= 0 && py < image->height - .5) {
|
|
point_map1++;
|
|
int ppx = 0;
|
|
int ppy = 0;
|
|
if (px - int(px) < .5) {
|
|
ppx = int(px);
|
|
} else {
|
|
ppx = int(px) + 1;
|
|
}
|
|
if (py - int(py) < .5) {
|
|
ppy = int(py);
|
|
} else {
|
|
ppy = int(py) + 1;
|
|
}
|
|
|
|
CvScalar c;
|
|
c = cvGet2D(image, ppy, ppx);
|
|
// check for overlap
|
|
if(correction) {
|
|
vector<float> temp_vec;
|
|
float p_id = 1; // 1 for pixel, 0 for neighboring pixel
|
|
temp_vec.push_back(-(CV_MAT_ELEM(*point_3Dcloud,float,k,1)));
|
|
temp_vec.push_back((CV_MAT_ELEM(*point_3Dcloud,float,k,2)));
|
|
temp_vec.push_back((CV_MAT_ELEM(*point_3Dcloud,float,k,0)));
|
|
temp_vec.push_back(c.val[2]);
|
|
temp_vec.push_back(c.val[1]);
|
|
temp_vec.push_back(c.val[0]);
|
|
temp_vec.push_back(p_id);
|
|
if(neighborhood > 1) {
|
|
int limit = neighborhood / 2;
|
|
|
|
int lower_y = ppy - limit > 0 ? ppy - limit : 0;
|
|
int upper_y = ppy + limit < size.height ? ppy + limit : size.height - 1;
|
|
int lower_x = ppx - limit > 0 ? ppx - limit : 0;
|
|
int upper_x = ppx + limit < size.width ? ppx + limit : size.width - 1;
|
|
|
|
for (int y = lower_y; y < upper_y; y++) {
|
|
for (int x = lower_x; x < upper_x; x++) {
|
|
if(x == ppx && y == ppy) {
|
|
temp_vec[6] = 1;
|
|
} else {
|
|
temp_vec[6] = 0;
|
|
}
|
|
data1[y][x].push_back(temp_vec);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
data1[ppy][ppx].push_back(temp_vec);
|
|
}
|
|
temp_vec.clear();
|
|
} else {
|
|
// write all the data
|
|
outfile << -(CV_MAT_ELEM(*point_3Dcloud,float,k,1))<<" ";
|
|
outfile << CV_MAT_ELEM(*point_3Dcloud,float,k,2)<<" ";
|
|
outfile << CV_MAT_ELEM(*point_3Dcloud,float,k,0)<<" ";
|
|
outfile << (c.val[0] - 1000.0)/10.0 << endl;
|
|
//outfile << c.val[2] <<" "<< c.val[1]<<" "<<c.val[0]<<endl;
|
|
}
|
|
}
|
|
// second image
|
|
} else if(fabs(rot_angle) > 1) {
|
|
// check for overlap
|
|
px = CV_MAT_ELEM(*undistort_2Dcloud_2,float,k,0);
|
|
py = CV_MAT_ELEM(*undistort_2Dcloud_2,float,k,1);
|
|
if (px < image0->width - .5 && px >= 0 && py >= 0 && py < image0->height - .5) {
|
|
px = CV_MAT_ELEM(*point_2Dcloud_2,float,k,0);
|
|
py = CV_MAT_ELEM(*point_2Dcloud_2,float,k,1);
|
|
if (px < image0->width - .5 && px >= 0 && py >= 0 && py < image0->height - .5) {
|
|
point_map2++;
|
|
int ppx = 0;
|
|
int ppy = 0;
|
|
|
|
if (px - int(px) < .5) {
|
|
ppx = int(px);
|
|
} else {
|
|
ppx = int(px) + 1;
|
|
}
|
|
if (py - int(py) < .5) {
|
|
ppy = int(py);
|
|
} else {
|
|
ppy = int(py) + 1;
|
|
}
|
|
CvScalar c;
|
|
|
|
c = cvGet2D(image0, ppy, ppx);
|
|
if(correction) {
|
|
vector<float> temp_vec;
|
|
float p2_id = 1;
|
|
temp_vec.push_back(-(CV_MAT_ELEM(*point_3Dcloud,float,k,1)));
|
|
temp_vec.push_back((CV_MAT_ELEM(*point_3Dcloud,float,k,2)));
|
|
temp_vec.push_back((CV_MAT_ELEM(*point_3Dcloud,float,k,0)));
|
|
temp_vec.push_back(c.val[2]);
|
|
temp_vec.push_back(c.val[1]);
|
|
temp_vec.push_back(c.val[0]);
|
|
temp_vec.push_back(p2_id);
|
|
if(neighborhood > 1) {
|
|
int neighbors = 3;
|
|
int limit = neighbors / 2;
|
|
|
|
int lower_y = ppy - limit > 0 ? ppy - limit : 0;
|
|
int upper_y = ppy + limit < size.height ? ppy + limit : size.height - 1;
|
|
int lower_x = ppx - limit > 0 ? ppx - limit : 0;
|
|
int upper_x = ppx + limit < size.width ? ppx + limit : size.width - 1;
|
|
|
|
for (int y = lower_y; y < upper_y; y++) {
|
|
for (int x = lower_x; x < upper_x; x++) {
|
|
if(x == ppx && y == ppy) {
|
|
temp_vec[6] = 1;
|
|
} else {
|
|
temp_vec[6] = 0;
|
|
}
|
|
data2[y][x].push_back(temp_vec);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
data2[ppy][ppx].push_back(temp_vec);
|
|
}
|
|
temp_vec.clear();
|
|
} else {
|
|
// write all the data
|
|
outfile << -(CV_MAT_ELEM(*point_3Dcloud,float,k,1))<<" ";
|
|
outfile << CV_MAT_ELEM(*point_3Dcloud,float,k,2)<<" ";
|
|
outfile << CV_MAT_ELEM(*point_3Dcloud,float,k,0)<<" ";
|
|
outfile << (c.val[0] - 1000.0)/10.0 << endl;
|
|
//outfile << c.val[2] <<" "<< c.val[1]<<" "<<c.val[0]<<endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
// write data with overlap correction
|
|
if(correction) {
|
|
CorrectErrorAndWrite(data1, outfile, size);
|
|
if(fabs(rot_angle) > 1) {
|
|
if(size.width > 0 && size.height > 0) {
|
|
CorrectErrorAndWrite(data2, outfile, size);
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up
|
|
outfile.flush();
|
|
outfile.close();
|
|
|
|
delete Scan::allScans[0];
|
|
Scan::allScans.clear();
|
|
|
|
double endtime = GetCurrentTimeInMilliSec();
|
|
double time = endtime - starttime;
|
|
time = time/1000.0;
|
|
cout<<"runtime for scan " << count << " in seconds is: " << time << endl;
|
|
|
|
cvReleaseImage(&image);
|
|
cvReleaseMat(&point_2Dcloud);
|
|
cvReleaseMat(&point_3Dcloud);
|
|
cvReleaseMat(&undistort_2Dcloud);
|
|
if(fabs(rot_angle) > 1) {
|
|
cvReleaseImage(&image0);
|
|
cvReleaseMat(&point_2Dcloud_2);
|
|
cvReleaseMat(&point_3Dcloud_2);
|
|
cvReleaseMat(&undistort_2Dcloud_2);
|
|
}
|
|
for (int i = 0; i < size.height; i++) {
|
|
for (int j = 0; j < size.width; j++) {
|
|
data1[i][j].clear();
|
|
data2[i][j].clear();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
cvReleaseMat(&intrinsic);
|
|
cvReleaseMat(&distortion);
|
|
cvReleaseMat(&Rotation);
|
|
cvReleaseMat(&Translation);
|
|
cvReleaseMat(&undistort);
|
|
|
|
}
|
|
|
|
/**
|
|
* Sorts a number of float array according to their distance to the origin.
|
|
*/
|
|
void sortDistances(float ** points, int size) {
|
|
int swapped1 = 0;
|
|
do {
|
|
swapped1 = 0;
|
|
for(int a = 1; a <= size - 1; a++) {
|
|
if(Len(points[a]) < Len(points[a - 1])) {
|
|
float * tmp = points[a-1];
|
|
points[a-1] = points[a];
|
|
points[a] = tmp;
|
|
swapped1 = 1;
|
|
}
|
|
}
|
|
} while (swapped1 == 1);
|
|
}
|
|
|
|
/**
|
|
* Performs clustering on all points that are projected onto one pixel.
|
|
* Writes only the points from the largest closest cluster.
|
|
*/
|
|
void clusterSearch(float ** points, int size, double thresh1, double thres2, fstream &outfile) {
|
|
int position = 0;
|
|
int cluster_count = 0;
|
|
|
|
double max_cluster = 0;
|
|
int max_position = 0;
|
|
vector<double*> clusters;
|
|
while (position < size) {
|
|
double sum = 0.0;
|
|
int j = position + 1;
|
|
while(j < size && (Len(points[j]) < (Len(points[j-1]) + thresh1))) {
|
|
j++;
|
|
cluster_count++;
|
|
sum+=Len(points[j-1]);
|
|
}
|
|
double * tmp = new double[4];
|
|
tmp[0] = position;
|
|
tmp[1] = j - 1;
|
|
tmp[2] = sum / (j - position);
|
|
// weird heuristic ;-) (clustersize/(rank of the cluster))
|
|
tmp[3] = (double)(j - position) / (clusters.size() + 1.0);
|
|
if(tmp[3] > max_cluster) {
|
|
max_position = clusters.size();
|
|
max_cluster = tmp[3];
|
|
}
|
|
clusters.push_back(tmp);
|
|
position = j;
|
|
}
|
|
|
|
for(int p = clusters[max_position][0]; p <= clusters[max_position][1]; p++) {
|
|
if(points[p][6] == 1) {
|
|
outfile << points[p][0] << " " << points[p][1] << " " << points[p][2] << " ";
|
|
//outfile << points[p][3] << " " << points[p][4] << " " << points[p][5] << endl;
|
|
outfile << (points[p][5] - 1000.0)/10.0 << endl;
|
|
}
|
|
}
|
|
|
|
for(unsigned int i = 0; i < clusters.size(); i++) {
|
|
delete[] clusters[i];
|
|
}
|
|
}
|
|
|
|
void CorrectErrorAndWrite(Float2D &data, fstream &outfile, CvSize size) {
|
|
double thresh1 = 4;
|
|
double thresh2 = 5;
|
|
|
|
// getting points mapping to one pixel
|
|
for (int i = 0; i < size.height; i++) {
|
|
for (int j = 0; j < size.width; j++) {
|
|
int tmp_size = data[i][j].size();
|
|
if (tmp_size > 0) {
|
|
float ** points = new float*[tmp_size];
|
|
for (int k = 0; k < tmp_size; k++) {
|
|
points[k] = new float[7];
|
|
for(int l = 0; l < 7; l++) {
|
|
points[k][l] = data[i][j][k][l];
|
|
}
|
|
}
|
|
|
|
//sorting the points now in ascending order wrt distance
|
|
sortDistances(points, tmp_size);
|
|
//look for clusters
|
|
clusterSearch(points, tmp_size, thresh1, thresh2, outfile);
|
|
|
|
for (int k = 0; k < tmp_size; k++) {
|
|
delete[] points[k];
|
|
}
|
|
delete[] points;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Prints out usage message
|
|
*/
|
|
void usage(char* prog) {
|
|
#ifndef _MSC_VER
|
|
const string bold("\033[1m");
|
|
const string normal("\033[m");
|
|
#else
|
|
const string bold("");
|
|
const string normal("");
|
|
#endif
|
|
cout << endl
|
|
<< bold << "USAGE " << normal << endl
|
|
<< " " << prog << " [options] directory" << endl << endl;
|
|
cout << bold << "OPTIONS" << normal << endl
|
|
|
|
<< bold << " -f" << normal << " F, " << bold << "--format=" << normal << "F" << endl
|
|
<< " using shared library F for input" << endl
|
|
<< " (chose F from {uos, uos_map, uos_rgb, uos_frames, uos_map_frames, old, rts, rts_map, ifp, riegl_txt, riegl_rgb, riegl_bin, zahn, ply})" << endl
|
|
<< endl
|
|
<< bold << " -s" << normal << " NR, " << bold << "--start=" << normal << "NR" << endl
|
|
<< " start at scan NR (i.e., neglects the first NR scans)" << endl
|
|
<< " [ATTENTION: counting naturally starts with 0]" << endl
|
|
<< endl
|
|
<< bold << " -e" << normal << " NR, " << bold << "--end=" << normal << "NR" << endl
|
|
<< " end at scan NR" << endl
|
|
<< endl
|
|
<< bold << " -x" << normal << " NR, " << bold << "--width=" << normal << "NR" << endl
|
|
<< " NR of lamps/corners in x direction" << endl
|
|
<< endl
|
|
<< bold << " -y" << normal << " NR, " << bold << "--height=" << normal << "NR" << endl
|
|
<< " NR of lamps/corners in y direction" << endl
|
|
<< endl
|
|
<< bold << " -o --=optical" << normal << endl
|
|
<< " use optical camera instead of thermal camera" << endl
|
|
<< endl
|
|
<< bold << " -c --=chess" << normal << endl
|
|
<< " use chessboard pattern for calibration instead of lightbulb pattern" << endl
|
|
<< endl
|
|
<< bold << " -I --=intrinsic" << normal << endl
|
|
<< " perform intrinsic calibration" << endl
|
|
<< endl
|
|
<< bold << " -E --=extrinsic" << normal << endl
|
|
<< " perform extrinsic calibration" << endl
|
|
<< endl
|
|
<< bold << " -P --=mapping" << normal << endl
|
|
<< " perform mapping of image data to point cloud" << endl
|
|
<< endl
|
|
<< bold << " -q --=quiet" << normal << endl
|
|
<< " " << endl
|
|
<< endl << endl;
|
|
|
|
cout << bold << "EXAMPLES " << normal << endl
|
|
<< " " << prog << " -s 2 -e 10 dat" << endl << endl;
|
|
exit(1);
|
|
|
|
}
|
|
|
|
/**
|
|
* Parses command line arguments needed for plane detection. For details about
|
|
* the argument see usage().
|
|
*/
|
|
|
|
int parseArgs(int argc, char **argv, string &dir, int &start, int &end, double
|
|
&maxDist, double &minDist, IOType &type, bool &optical, bool &chess, int
|
|
&width, int &height, bool &intrinsic, bool &extrinsic, bool &mapping, bool
|
|
&correction, int &scale, int &neighborhood, double &angle, bool &quiet ) {
|
|
// from unistd.h:
|
|
int c;
|
|
extern char *optarg;
|
|
extern int optind;
|
|
|
|
/* options descriptor */
|
|
// 0: no arguments, 1: required argument, 2: optional argument
|
|
static struct option longopts[] = {
|
|
{ "correction", no_argument, 0, 'C' },
|
|
{ "scale", required_argument, 0, 'S' },
|
|
{ "neighborhood", required_argument, 0, 'n' },
|
|
{ "angle", required_argument, 0, 'a' },
|
|
{ "format", required_argument, 0, 'f' },
|
|
{ "max", required_argument, 0, 'm' },
|
|
{ "min", required_argument, 0, 'M' },
|
|
{ "start", required_argument, 0, 's' },
|
|
{ "end", required_argument, 0, 'e' },
|
|
{ "width", required_argument, 0, 'x' },
|
|
{ "height", required_argument, 0, 'y' },
|
|
{ "quiet", no_argument, 0, 'q' },
|
|
{ "optical", no_argument, 0, 'o' },
|
|
{ "intrinsic", no_argument, 0, 'I' },
|
|
{ "extrinsic", no_argument, 0, 'E' },
|
|
{ "mapping", no_argument, 0, 'P' },
|
|
{ "chess", no_argument, 0, 'c' },
|
|
{ 0, 0, 0, 0} // needed, cf. getopt.h
|
|
};
|
|
|
|
cout << endl;
|
|
while ((c = getopt_long(argc, argv, "f:s:e:x:y:m:M:qoIEPcCS:n:a:", longopts, NULL)) != -1) {
|
|
switch (c)
|
|
{
|
|
case 's':
|
|
start = atoi(optarg);
|
|
if (start < 0) { cerr << "Error: Cannot start at a negative scan number.\n"; exit(1); }
|
|
break;
|
|
case 'e':
|
|
end = atoi(optarg);
|
|
if (end < 0) { cerr << "Error: Cannot end at a negative scan number.\n"; exit(1); }
|
|
if (end < start) { cerr << "Error: <end> cannot be smaller than <start>.\n"; exit(1); }
|
|
break;
|
|
case 'f':
|
|
try {
|
|
type = formatname_to_io_type(optarg);
|
|
} catch (...) { // runtime_error
|
|
cerr << "Format " << optarg << " unknown." << endl;
|
|
abort();
|
|
}
|
|
break;
|
|
case 'q':
|
|
quiet = true;
|
|
break;
|
|
case 'm':
|
|
maxDist = atoi(optarg);
|
|
break;
|
|
case 'M':
|
|
minDist = atoi(optarg);
|
|
break;
|
|
case 'o':
|
|
optical = true;
|
|
break;
|
|
case 'I':
|
|
intrinsic = true;
|
|
break;
|
|
case 'E':
|
|
extrinsic = true;
|
|
break;
|
|
case 'P':
|
|
mapping = true;
|
|
break;
|
|
case 'c':
|
|
chess = true;
|
|
break;
|
|
case 'x':
|
|
width = atoi(optarg);
|
|
break;
|
|
case 'y':
|
|
height = atoi(optarg);
|
|
break;
|
|
case 'S':
|
|
scale = atoi(optarg);
|
|
break;
|
|
case 'a':
|
|
angle = atof(optarg);
|
|
break;
|
|
case 'n':
|
|
neighborhood = atoi(optarg);
|
|
break;
|
|
case 'C':
|
|
correction = true;
|
|
break;
|
|
case '?':
|
|
usage(argv[0]);
|
|
return 1;
|
|
default:
|
|
cout << "Abort" << endl;
|
|
abort ();
|
|
}
|
|
}
|
|
if (optind != argc-1) {
|
|
cerr << "\n*** Directory missing ***" << endl;
|
|
usage(argv[0]);
|
|
}
|
|
dir = argv[optind];
|
|
#ifndef _MSC_VER
|
|
if (dir[dir.length()-1] != '/') dir = dir + "/";
|
|
#else
|
|
if (dir[dir.length()-1] != '\\') dir = dir + "\\";
|
|
#endif
|
|
|
|
if(!(intrinsic || extrinsic || mapping)) {
|
|
cerr << "\n*** Please choose at least one method (intrinsic calibration, "
|
|
<< "extrinsic calibration, mapping of image data to point data! ***\n" <<
|
|
endl;
|
|
usage(argv[0]);
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
/**
|
|
* Main function. Calls either function for color mapping or function for
|
|
* intrinsic and/or extrinsic calibration.
|
|
*/
|
|
int main(int argc, char** argv) {
|
|
string dir;
|
|
int start = 0;
|
|
int end = -1;
|
|
int width = 5;
|
|
int height = 6;
|
|
double maxDist = -1;
|
|
double minDist = -1;
|
|
IOType type = UOS;
|
|
bool optical = false;
|
|
bool chess = false;
|
|
bool intrinsic = false;
|
|
bool extrinsic = false;
|
|
bool mapping = false;
|
|
bool quiet = false;
|
|
int scale = 1;
|
|
//double rot_angle = -40;
|
|
double rot_angle = 0;
|
|
bool correction = false;
|
|
int neighborhood = 1;
|
|
|
|
parseArgs(argc, argv, dir, start, end, maxDist, minDist, type, optical, chess,
|
|
width, height, intrinsic, extrinsic, mapping, correction, scale, neighborhood,
|
|
rot_angle, quiet);
|
|
|
|
// either mapping
|
|
if(mapping) {
|
|
if(!quiet) cout << "Starting projecting and mapping image data to point cloud..." << endl;
|
|
ProjectAndMap(start, end, optical, quiet, dir, type, scale, rot_angle, minDist, maxDist, correction, neighborhood);
|
|
if(!quiet) cout << "\nDONE" << endl;
|
|
return 0;
|
|
}
|
|
|
|
// or calibration
|
|
if(intrinsic) {
|
|
if(!quiet) {
|
|
cout << "Starting intrinsic calibration using ";
|
|
if(chess) cout << "chessboard pattern..." << endl;
|
|
else cout << "lightbulb pattern..." << endl;
|
|
}
|
|
CalibFunc(width, height, start, end, optical, chess, quiet, dir, scale);
|
|
if(!quiet) cout << "\nDONE" << endl;
|
|
}
|
|
|
|
if(extrinsic) {
|
|
if(!quiet) {
|
|
cout << "Starting extrinsic calibration using ";
|
|
if(chess) cout << "chessboard pattern..." << endl;
|
|
else cout << "lightbulb pattern..." << endl;
|
|
}
|
|
ExtrCalibFunc(width, height, start, end, optical, chess, quiet, dir, scale);
|
|
if(!quiet) cout << "\nDONE" << endl;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|