Subversion Repositories seema-scanner

Rev

Rev 195 | Rev 197 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 195 Rev 196
Line 3... Line 3...
3
 
3
 
4
#include "cvtools.h"
4
#include "cvtools.h"
5
 
5
 
6
#include <QSettings>
6
#include <QSettings>
7
 
7
 
-
 
8
#include <ceres/ceres.h>
-
 
9
 
-
 
10
 
-
 
11
struct CircleResidual {
-
 
12
  CircleResidual(std::vector<cv::Point3f> _pointsOnArc)
-
 
13
      : pointsOnArc(_pointsOnArc) {}
-
 
14
 
-
 
15
  template <typename T>
-
 
16
  bool operator()(const T* const point_x, const T* const point_y, const T* const point_z,
-
 
17
                  const T* const axis_x, const T* const axis_y, const T* const axis_z,
-
 
18
                  T* residual) const {
-
 
19
 
-
 
20
    cv::Vec3f axis(*axis_x, *axis_y, *axis_z);
-
 
21
    cv::Vec3f point(*point_x, *point_y, *point_z);
-
 
22
 
-
 
23
    unsigned int l = pointsOnArc.size();
-
 
24
    std::vector<float> dI(l);
-
 
25
    for(unsigned int i=0; i<l; i++){
-
 
26
      cv::Vec3f p = cv::Vec3f(pointsOnArc[i]);
-
 
27
      // point to line distance
-
 
28
      dI[i] = cv::norm((point-p)-(point-p).dot(axis)*axis);
-
 
29
    }
-
 
30
    float sum = std::accumulate(dI.begin(), dI.end(), 0.0);
-
 
31
    float mean = sum / dI.size();
-
 
32
    float meanDev = 0;
-
 
33
    for(unsigned int k=0; k<l; k++){
-
 
34
      meanDev += std::abs(dI[k] - mean);
-
 
35
    }
-
 
36
    meanDev /= l;
-
 
37
 
-
 
38
    residual[0] = T(meanDev);
-
 
39
 
-
 
40
    return true;
-
 
41
  }
-
 
42
 
-
 
43
 private:
-
 
44
 
-
 
45
  // Observations for one checkerboard corner.
-
 
46
  const std::vector<cv::Point3f> pointsOnArc;
-
 
47
};
-
 
48
 
-
 
49
 
-
 
50
// Closed form solution to solve for the rotation axis from sets of 3D point coordinates of flat pattern feature points
-
 
51
// Algorithm according to Chen et al., Rotation axis calibration of a turntable using constrained global optimization, Optik 2014
-
 
52
// DTU, 2014, Jakob Wilm
-
 
53
static void rotationAxisCalibration(const std::vector< std::vector<cv::Point3f> > Qcam, const std::vector<cv::Point3f> Qobj, cv::Vec3f &axis, cv::Vec3f &point, float &error){
-
 
54
 
-
 
55
    // number of frames (points on each arch)
-
 
56
    int l = Qcam.size();
-
 
57
 
-
 
58
    // number of points in each frame
-
 
59
    size_t mn = Qobj.size();
-
 
60
 
-
 
61
    assert(mn == Qcam[0].size());
-
 
62
 
-
 
63
    // construct matrix for axis determination
-
 
64
    cv::Mat M(6, 6, CV_32F, cv::Scalar(0));
-
 
65
 
-
 
66
    for(int k=0; k<l; k++){
-
 
67
        for(unsigned int idx=0; idx<mn; idx++){
-
 
68
 
-
 
69
//            float i = Qobj[idx].x+4;
-
 
70
//            float j = Qobj[idx].y+4;
-
 
71
            float i = Qobj[idx].x;
-
 
72
            float j = Qobj[idx].y;
-
 
73
 
-
 
74
            float x = Qcam[k][idx].x;
-
 
75
            float y = Qcam[k][idx].y;
-
 
76
            float z = Qcam[k][idx].z;
-
 
77
 
-
 
78
            M += (cv::Mat_<float>(6,6) << x*x, x*y, x*z, x, i*x, j*x,
-
 
79
                                            0, y*y, y*z, y, i*y, j*y,
-
 
80
                                            0,   0, z*z, z, i*z, j*z,
-
 
81
                                            0,   0,   0, 1,   i,   j,
-
 
82
                                            0,   0,   0, 0, i*i, i*j,
-
 
83
                                            0,   0,   0, 0,   0, j*j);
-
 
84
 
-
 
85
        }
-
 
86
    }
-
 
87
 
-
 
88
    cv::completeSymm(M, false);
-
 
89
 
-
 
90
    // solve for axis
-
 
91
    std::vector<float> lambda;
-
 
92
    cv::Mat u;
-
 
93
    cv::eigen(M, lambda, u);
-
 
94
 
-
 
95
    float minLambda = std::abs(lambda[0]);
-
 
96
    int idx = 0;
-
 
97
    for(unsigned int i=1; i<lambda.size(); i++){
-
 
98
        if(abs(lambda[i]) < minLambda){
-
 
99
            minLambda = lambda[i];
-
 
100
            idx = i;
-
 
101
        }
-
 
102
    }
-
 
103
 
-
 
104
    axis = u.row(idx).colRange(0, 3);
-
 
105
    axis = cv::normalize(axis);
-
 
106
 
-
 
107
    float nx = u.at<float>(idx, 0);
-
 
108
    float ny = u.at<float>(idx, 1);
-
 
109
    float nz = u.at<float>(idx, 2);
-
 
110
    //float d  = u.at<float>(idx, 3);
-
 
111
    float dh = u.at<float>(idx, 4);
-
 
112
    float dv = u.at<float>(idx, 5);
-
 
113
 
-
 
114
//    // Paper version: c is initially eliminated
-
 
115
//    cv::Mat A(l*mn, mn+2, CV_32F, cv::Scalar(0.0));
-
 
116
//    cv::Mat bb(l*mn, 1, CV_32F);
-
 
117
 
-
 
118
//    for(int k=0; k<l; k++){
-
 
119
//        for(unsigned int idx=0; idx<mn; idx++){
-
 
120
 
-
 
121
//            float i = Qobj[idx].x;
-
 
122
//            float j = Qobj[idx].y;
-
 
123
 
-
 
124
//            float x = Qcam[k][idx].x;
-
 
125
//            float y = Qcam[k][idx].y;
-
 
126
//            float z = Qcam[k][idx].z;
-
 
127
 
-
 
128
//            float f = x*x + y*y + z*z + (2*x*nx + 2*y*ny + 2*z*nz)*(i*dh + j*dv);
-
 
129
 
-
 
130
//            int row = k*mn+idx;
-
 
131
//            A.at<float>(row, 0) = 2*x - (2*z*nx)/nz;
-
 
132
//            A.at<float>(row, 1) = 2*y - (2*z*ny)/nz;
-
 
133
//            A.at<float>(row, idx+2) = 1.0;
-
 
134
 
-
 
135
//            bb.at<float>(row, 0) = f + (2*z*d)/nz;
-
 
136
//        }
-
 
137
//    }
-
 
138
 
-
 
139
//    // solve for point
-
 
140
//    cv::Mat abe;
-
 
141
//    cv::solve(A, bb, abe, cv::DECOMP_SVD);
-
 
142
 
-
 
143
//    float a = abe.at<float>(0, 0);
-
 
144
//    float b = abe.at<float>(1, 0);
-
 
145
//    float c = -(nx*a+ny*b+d)/nz;
-
 
146
 
-
 
147
    // Our version: solve simultanously for a,b,c
-
 
148
    cv::Mat A(l*mn, mn+3, CV_32F, cv::Scalar(0.0));
-
 
149
    cv::Mat bb(l*mn, 1, CV_32F);
-
 
150
 
-
 
151
    for(int k=0; k<l; k++){
-
 
152
        for(unsigned int idx=0; idx<mn; idx++){
-
 
153
 
-
 
154
            float i = Qobj[idx].x;
-
 
155
            float j = Qobj[idx].y;
-
 
156
 
-
 
157
            float x = Qcam[k][idx].x;
-
 
158
            float y = Qcam[k][idx].y;
-
 
159
            float z = Qcam[k][idx].z;
-
 
160
 
-
 
161
            float f = x*x + y*y + z*z + (2*x*nx + 2*y*ny + 2*z*nz)*(i*dh + j*dv);
-
 
162
 
-
 
163
            int row = k*mn+idx;
-
 
164
            A.at<float>(row, 0) = 2*x;
-
 
165
            A.at<float>(row, 1) = 2*y;
-
 
166
            A.at<float>(row, 2) = 2*z;
-
 
167
            A.at<float>(row, idx+3) = 1.0;
-
 
168
 
-
 
169
            bb.at<float>(row, 0) = f;
-
 
170
        }
-
 
171
    }
-
 
172
 
-
 
173
    // solve for point
-
 
174
    cv::Mat abe;
-
 
175
    cv::solve(A, bb, abe, cv::DECOMP_SVD);
-
 
176
 
-
 
177
    float a = abe.at<float>(0, 0);
-
 
178
    float b = abe.at<float>(1, 0);
-
 
179
    float c = abe.at<float>(2, 0);
-
 
180
 
-
 
181
    point[0] = a;
-
 
182
    point[1] = b;
-
 
183
    point[2] = c;
-
 
184
 
-
 
185
    // Non-linear optimization using Ceres
-
 
186
    double point_x = point[0];
-
 
187
    double point_y = point[1];
-
 
188
    double point_z = point[2];
-
 
189
    double axis_x = axis[0];
-
 
190
    double axis_y = axis[1];
-
 
191
    double axis_z = axis[2];
-
 
192
 
-
 
193
    ceres::Problem problem;
-
 
194
    // loop through saddle points
-
 
195
    for(unsigned int idx=0; idx<mn; idx++){
-
 
196
        std::vector<cv::Point3f> pointsOnArch(l);
-
 
197
        for(int k=0; k<l; k++){
-
 
198
            pointsOnArch[k] = Qcam[k][idx];
-
 
199
        }
-
 
200
        ceres::CostFunction* cost_function =
-
 
201
           new ceres::NumericDiffCostFunction<CircleResidual, ceres::CENTRAL, 1, 1, 1, 1, 1, 1, 1>(
-
 
202
               new CircleResidual(pointsOnArch));
-
 
203
        problem.AddResidualBlock(cost_function, NULL, &point_x, &point_y, &point_z, &axis_x, &axis_y, &axis_z);
-
 
204
    }
-
 
205
 
-
 
206
    // Run the solver!
-
 
207
    ceres::Solver::Options options;
-
 
208
    options.linear_solver_type = ceres::DENSE_QR;
-
 
209
    options.minimizer_progress_to_stdout = true;
-
 
210
    ceres::Solver::Summary summary;
-
 
211
    ceres::Solve(options, &problem, &summary);
-
 
212
 
-
 
213
    std::cout << summary.BriefReport() << "\n";
-
 
214
 
-
 
215
 
-
 
216
    point = cv::Point3f(point_x, point_y, point_z);
-
 
217
    axis = cv::Point3f(axis_x, axis_y, axis_z);
-
 
218
 
-
 
219
 
-
 
220
    // Error estimate (mean 3D point deviations from circles around rotation axis)
-
 
221
    error = 0;
-
 
222
    // loop through saddle points
-
 
223
    for(unsigned int idx=0; idx<mn; idx++){
-
 
224
 
-
 
225
        // vector of distances from rotation axis
-
 
226
        std::vector<float> dI(l);
-
 
227
        // loop through angular positions
-
 
228
        for(int k=0; k<l; k++){
-
 
229
            cv::Vec3f p = cv::Vec3f(Qcam[k][idx]);
-
 
230
            // point to line distance
-
 
231
            dI[k] = cv::norm((point-p)-(point-p).dot(axis)*axis);
-
 
232
        }
-
 
233
        float sum = std::accumulate(dI.begin(), dI.end(), 0.0);
-
 
234
        float mean = sum / dI.size();
-
 
235
        float meanDev = 0;
-
 
236
        for(int k=0; k<l; k++){
-
 
237
            meanDev += std::abs(dI[k] - mean);
-
 
238
        }
-
 
239
        meanDev /= l;
-
 
240
        //std::cout << meanDev << std::endl;
-
 
241
        error += meanDev;
-
 
242
    }
-
 
243
    error /= mn;
-
 
244
 
-
 
245
}
-
 
246
 
8
void SMCalibrationWorker::performCalibration(std::vector<SMCalibrationSet> calibrationData){
247
void SMCalibrationWorker::performCalibration(std::vector<SMCalibrationSet> calibrationData){
9
 
248
 
10
    QSettings settings;
249
    QSettings settings;
11
 
250
 
12
    // Number of saddle points on calibration pattern
251
    // Number of saddle points on calibration pattern
Line 297... Line 536...
297
//            QcamMat.at<cv::Point3f>(i,j) = Qcam[i][j];
536
//            QcamMat.at<cv::Point3f>(i,j) = Qcam[i][j];
298
//    cvtools::writeMat(QcamMat, "Qcam.mat", "Qcam");
537
//    cvtools::writeMat(QcamMat, "Qcam.mat", "Qcam");
299
 
538
 
300
    cv::Vec3f axis, point;
539
    cv::Vec3f axis, point;
301
    float rot_axis_error;
540
    float rot_axis_error;
302
    cvtools::rotationAxisCalibration(Qcam, Qi, axis, point, rot_axis_error);
541
    rotationAxisCalibration(Qcam, Qi, axis, point, rot_axis_error);
303
 
542
 
304
    // construct transformation matrix
543
    // construct transformation matrix
305
    cv::Vec3f ex = axis.cross(cv::Vec3f(0,0,1.0));
544
    cv::Vec3f ex = axis.cross(cv::Vec3f(0,0,1.0));
306
    ex = cv::normalize(ex);
545
    ex = cv::normalize(ex);
307
    cv::Vec3f ez = ex.cross(axis);
546
    cv::Vec3f ez = ex.cross(axis);