31 std::vector<CalibPoint3D> pts;
32 pts.reserve(
static_cast<size_t>(std::max(0, spec.
num_rows)) *
33 static_cast<size_t>(std::max(0, spec.
num_columns)));
37 const double two_pi = 2.0 * M_PI;
43 const double theta0 = spec.
theta0_deg * M_PI / 180.0;
46 for (
int r = 0; r < spec.
num_rows; ++r) {
47 const double z = r * spec.
dz;
49 const double theta = theta0 + c * dtheta;
51 p.
x = spec.
radius * std::cos(theta);
52 p.
y = spec.
radius * std::sin(theta);
61 const std::string& path, std::string& error_message) {
62 std::ofstream ofs(path);
64 error_message =
"Cannot open for writing: " + path;
67 ofs <<
"# xdic cylindrical calibration object v1 (x y z, mm)\n";
68 for (
const auto& p : pts) {
69 ofs << p.x <<
" " << p.y <<
" " << p.z <<
"\n";
75 std::string& error_message) {
76 std::vector<CalibPoint3D> pts;
77 std::ifstream ifs(path);
79 error_message =
"Cannot open object file: " + path;
83 while (std::getline(ifs, line)) {
84 if (line.empty() || line[0] ==
'#')
continue;
85 std::istringstream iss(line);
87 if (iss >> p.
x >> p.
y >> p.
z) pts.push_back(p);
93 std::string& error_message) {
94 std::vector<CalibPoint2D> pts;
95 std::ifstream ifs(path);
97 error_message =
"Cannot open image-points file: " + path;
101 while (std::getline(ifs, line)) {
102 if (line.empty() || line[0] ==
'#')
continue;
103 std::istringstream iss(line);
105 if (iss >> p.
u >> p.
v) pts.push_back(p);
111 const std::vector<CalibPoint2D>& image_points,
112 const std::vector<CalibPoint3D>& object_points,
113 std::string& error_message) {
117 if (image_points.size() != object_points.size()) {
118 error_message =
"calcDLTParameters: image/object point count mismatch (" +
119 std::to_string(image_points.size()) +
" vs " +
120 std::to_string(object_points.size()) +
")";
123 const size_t N = image_points.size();
125 error_message =
"calcDLTParameters: need >=6 correspondences, got " + std::to_string(N);
130 std::vector<double> P2(N * 2);
131 std::vector<double> P3(N * 3);
132 for (
size_t i = 0; i < N; ++i) {
133 P2[i * 2 + 0] = image_points[i].u;
134 P2[i * 2 + 1] = image_points[i].v;
135 P3[i * 3 + 0] = object_points[i].x;
136 P3[i * 3 + 1] = object_points[i].y;
137 P3[i * 3 + 2] = object_points[i].z;
140 std::vector<double> L;
143 "calcDLTParameters: DLT11Calibration failed for camera " + std::to_string(camera_id);
146 for (
int i = 0; i < 11; ++i) cam.
L[i] = L[i];
152 for (
size_t i = 0; i < N; ++i) {
153 const double X = object_points[i].x;
154 const double Y = object_points[i].y;
155 const double Z = object_points[i].z;
156 const double den = cam.
L[8] * X + cam.
L[9] * Y + cam.
L[10] * Z + 1.0;
157 if (std::abs(den) < 1e-12)
continue;
158 const double u = (cam.
L[0] * X + cam.
L[1] * Y + cam.
L[2] * Z + cam.
L[3]) / den;
159 const double v = (cam.
L[4] * X + cam.
L[5] * Y + cam.
L[6] * Z + cam.
L[7]) / den;
160 const double du = u - image_points[i].u;
161 const double dv = v - image_points[i].v;
162 sse += du * du + dv * dv;
175 Eigen::Matrix<double, 4, 3> A;
176 Eigen::Matrix<double, 4, 1> b;
179 Eigen::Matrix<double, 4, 1>& b,
int row) {
180 A(row, 0) = p.u * c.
L[8] - c.
L[0];
181 A(row, 1) = p.u * c.
L[9] - c.
L[1];
182 A(row, 2) = p.u * c.
L[10] - c.
L[2];
183 b(row) = c.
L[3] - p.u;
184 A(row + 1, 0) = p.v * c.
L[8] - c.
L[4];
185 A(row + 1, 1) = p.v * c.
L[9] - c.
L[5];
186 A(row + 1, 2) = p.v * c.
L[10] - c.
L[6];
187 b(row + 1) = c.
L[7] - p.v;
190 fill(c1, p1, A, b, 0);
191 fill(c2, p2, A, b, 2);
193 Eigen::Vector3d X = A.colPivHouseholderQr().solve(b);
203 const std::vector<CalibPoint2D>& img2,
const std::vector<CalibPoint3D>& object_points,
204 std::vector<CalibPoint3D>& reconstructed_out) {
206 reconstructed_out.clear();
208 const size_t N = std::min({img1.size(), img2.size(), object_points.size()});
209 if (N == 0)
return err;
211 reconstructed_out.reserve(N);
216 for (
size_t i = 0; i < N; ++i) {
218 reconstructed_out.push_back(rec);
219 const double dx = rec.
x - object_points[i].x;
220 const double dy = rec.
y - object_points[i].y;
221 const double dz = rec.
z - object_points[i].z;
222 const double d = std::sqrt(dx * dx + dy * dy + dz * dz);
226 if (d > err.
max) err.
max = d;
228 const double n =
static_cast<double>(N);
230 err.
rms = std::sqrt(sum_sq / n);
233 err.
std = std::sqrt(var / n);
238 int cam_first_id,
const std::vector<CalibPoint2D>& img_first,
int cam_second_id,
239 const std::vector<CalibPoint2D>& img_second,
const std::vector<CalibPoint3D>& object_points,
240 std::string& error_message) {
static bool DLT11Calibration(const double *P2, const double *P3, size_t N, std::vector< double > &L)
Compute DLT (Direct Linear Transformation) 11 parameters from 2D-3D point correspondences Matches MAT...
static ReconstructionError reconstructionError(const CameraDLT &cam1, const std::vector< CalibPoint2D > &img1, const CameraDLT &cam2, const std::vector< CalibPoint2D > &img2, const std::vector< CalibPoint3D > &object_points, std::vector< CalibPoint3D > &reconstructed_out)
DLT reconstruction-error metric: triangulate every calibration point from the two cameras and compare...
static bool writeObjectFile(const std::vector< CalibPoint3D > &pts, const std::string &path, std::string &error_message)
Write generated 3D coordinates to a text file (one "x y z" per line).
static std::vector< CalibPoint3D > readObjectFile(const std::string &path, std::string &error_message)
Read a "x y z" per line 3D coordinate file.
static CalibPoint3D reconstructPoint(const CameraDLT &cam1, const CalibPoint2D &p1, const CameraDLT &cam2, const CalibPoint2D &p2)
Triangulate a 3D point from two cameras' DLT parameters and the matched image observations (linear le...
static CameraDLT calcDLTParameters(int camera_id, const std::vector< CalibPoint2D > &image_points, const std::vector< CalibPoint3D > &object_points, std::string &error_message)
Port of STEP1_CalcDLTparameters_rewrited.m for a single camera.
static std::vector< CalibPoint3D > generateCylindricalObject(const CylinderCalibSpec &spec)
Port of generate_cylindrical_calibration_object_coordinate_file.m.
static std::vector< CalibPoint2D > readImagePointsFile(const std::string &path, std::string &error_message)
Read a "u v" per line 2D image-point file (one per calibration dot).
static StereoCalibrationResult calibrateStereoPair(int cam_first_id, const std::vector< CalibPoint2D > &img_first, int cam_second_id, const std::vector< CalibPoint2D > &img_second, const std::vector< CalibPoint3D > &object_points, std::string &error_message)
Full StepC driver for one stereo pair: fit both cameras and compute the reconstruction error against ...
DataSerializer - Abstract base class for format-agnostic DIC data I/O.
A 2D image observation (pixels).
A single calibration point: 3D world coordinate (mm).
DLT parameters for one camera plus its fit residual.
std::array< double, 11 > L
Geometry of the cylindrical calibration object.
Reconstruction-error metrics for a stereo pair.
std::vector< double > per_point
Full StepC result for a stereo pair.
ReconstructionError recon_error
std::vector< CalibPoint3D > reconstructed