Subversion Repositories seema-scanner

Rev

Rev 82 | Rev 86 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 82 Rev 83
1
#include "cvtools.h"
1
#include "cvtools.h"
2
 
2
 
3
#ifdef _WIN32
3
#ifdef _WIN32
4
#include <cstdint>
4
#include <cstdint>
5
#endif
5
#endif
6
 
6
 
7
#include <stdio.h>
7
#include <stdio.h>
8
 
8
 
9
namespace cvtools{
9
namespace cvtools{
10
 
10
 
11
// Lightly modified OpenCV function which accepts a line width argument
11
// Lightly modified OpenCV function which accepts a line width argument
12
void drawChessboardCorners(cv::InputOutputArray _image, cv::Size patternSize, cv::InputArray _corners, bool patternWasFound, int line_width){
12
void drawChessboardCorners(cv::InputOutputArray _image, cv::Size patternSize, cv::InputArray _corners, bool patternWasFound, int line_width){
13
    cv::Mat corners = _corners.getMat();
13
    cv::Mat corners = _corners.getMat();
14
    if( corners.empty() )
14
    if( corners.empty() )
15
        return;
15
        return;
16
    cv::Mat image = _image.getMat(); CvMat c_image = _image.getMat();
16
    cv::Mat image = _image.getMat(); CvMat c_image = _image.getMat();
17
    int nelems = corners.checkVector(2, CV_32F, true);
17
    int nelems = corners.checkVector(2, CV_32F, true);
18
    CV_Assert(nelems >= 0);
18
    CV_Assert(nelems >= 0);
19
    cvDrawChessboardCorners( &c_image, patternSize, (CvPoint2D32f*)corners.data,
19
    cvDrawChessboardCorners( &c_image, patternSize, (CvPoint2D32f*)corners.data,
20
                             nelems, patternWasFound, line_width);
20
                             nelems, patternWasFound, line_width);
21
}
21
}
22
 
22
 
23
void cvDrawChessboardCorners(CvArr* _image, CvSize pattern_size, CvPoint2D32f* corners, int count, int found, int line_width){
23
void cvDrawChessboardCorners(CvArr* _image, CvSize pattern_size, CvPoint2D32f* corners, int count, int found, int line_width){
24
    const int shift = 0;
24
    const int shift = 0;
25
    const int radius = 12;
25
    const int radius = 12;
26
    const int r = radius*(1 << shift);
26
    const int r = radius*(1 << shift);
27
    int i;
27
    int i;
28
    CvMat stub, *image;
28
    CvMat stub, *image;
29
    double scale = 1;
29
    double scale = 1;
30
    int type, cn, line_type;
30
    int type, cn, line_type;
31
 
31
 
32
    image = cvGetMat( _image, &stub );
32
    image = cvGetMat( _image, &stub );
33
 
33
 
34
    type = CV_MAT_TYPE(image->type);
34
    type = CV_MAT_TYPE(image->type);
35
    cn = CV_MAT_CN(type);
35
    cn = CV_MAT_CN(type);
36
    if( cn != 1 && cn != 3 && cn != 4 )
36
    if( cn != 1 && cn != 3 && cn != 4 )
37
        CV_Error( CV_StsUnsupportedFormat, "Number of channels must be 1, 3 or 4" );
37
        CV_Error( CV_StsUnsupportedFormat, "Number of channels must be 1, 3 or 4" );
38
 
38
 
39
    switch( CV_MAT_DEPTH(image->type) )
39
    switch( CV_MAT_DEPTH(image->type) )
40
    {
40
    {
41
    case CV_8U:
41
    case CV_8U:
42
        scale = 1;
42
        scale = 1;
43
        break;
43
        break;
44
    case CV_16U:
44
    case CV_16U:
45
        scale = 256;
45
        scale = 256;
46
        break;
46
        break;
47
    case CV_32F:
47
    case CV_32F:
48
        scale = 1./255;
48
        scale = 1./255;
49
        break;
49
        break;
50
    default:
50
    default:
51
        CV_Error( CV_StsUnsupportedFormat,
51
        CV_Error( CV_StsUnsupportedFormat,
52
            "Only 8-bit, 16-bit or floating-point 32-bit images are supported" );
52
            "Only 8-bit, 16-bit or floating-point 32-bit images are supported" );
53
    }
53
    }
54
 
54
 
55
    line_type = type == CV_8UC1 || type == CV_8UC3 ? CV_AA : 8;
55
    line_type = type == CV_8UC1 || type == CV_8UC3 ? CV_AA : 8;
56
 
56
 
57
    if( !found )
57
    if( !found )
58
    {
58
    {
59
        CvScalar color = {{0,0,255}};
59
        CvScalar color = {{0,0,255}};
60
        if( cn == 1 )
60
        if( cn == 1 )
61
            color = cvScalarAll(200);
61
            color = cvScalarAll(200);
62
        color.val[0] *= scale;
62
        color.val[0] *= scale;
63
        color.val[1] *= scale;
63
        color.val[1] *= scale;
64
        color.val[2] *= scale;
64
        color.val[2] *= scale;
65
        color.val[3] *= scale;
65
        color.val[3] *= scale;
66
 
66
 
67
        for( i = 0; i < count; i++ )
67
        for( i = 0; i < count; i++ )
68
        {
68
        {
69
            CvPoint pt;
69
            CvPoint pt;
70
            pt.x = cvRound(corners[i].x*(1 << shift));
70
            pt.x = cvRound(corners[i].x*(1 << shift));
71
            pt.y = cvRound(corners[i].y*(1 << shift));
71
            pt.y = cvRound(corners[i].y*(1 << shift));
72
            cvLine( image, cvPoint( pt.x - r, pt.y - r ),
72
            cvLine( image, cvPoint( pt.x - r, pt.y - r ),
73
                    cvPoint( pt.x + r, pt.y + r ), color, line_width, line_type, shift );
73
                    cvPoint( pt.x + r, pt.y + r ), color, line_width, line_type, shift );
74
            cvLine( image, cvPoint( pt.x - r, pt.y + r),
74
            cvLine( image, cvPoint( pt.x - r, pt.y + r),
75
                    cvPoint( pt.x + r, pt.y - r), color, line_width, line_type, shift );
75
                    cvPoint( pt.x + r, pt.y - r), color, line_width, line_type, shift );
76
            cvCircle( image, pt, r+(1<<shift), color, line_width, line_type, shift );
76
            cvCircle( image, pt, r+(1<<shift), color, line_width, line_type, shift );
77
        }
77
        }
78
    }
78
    }
79
    else
79
    else
80
    {
80
    {
81
        int x, y;
81
        int x, y;
82
        CvPoint prev_pt = {0, 0};
82
        CvPoint prev_pt = {0, 0};
83
        const int line_max = 7;
83
        const int line_max = 7;
84
        static const CvScalar line_colors[line_max] =
84
        static const CvScalar line_colors[line_max] =
85
        {
85
        {
86
            {{0,0,255}},
86
            {{0,0,255}},
87
            {{0,128,255}},
87
            {{0,128,255}},
88
            {{0,200,200}},
88
            {{0,200,200}},
89
            {{0,255,0}},
89
            {{0,255,0}},
90
            {{200,200,0}},
90
            {{200,200,0}},
91
            {{255,0,0}},
91
            {{255,0,0}},
92
            {{255,0,255}}
92
            {{255,0,255}}
93
        };
93
        };
94
 
94
 
95
        for( y = 0, i = 0; y < pattern_size.height; y++ )
95
        for( y = 0, i = 0; y < pattern_size.height; y++ )
96
        {
96
        {
97
            CvScalar color = line_colors[y % line_max];
97
            CvScalar color = line_colors[y % line_max];
98
            if( cn == 1 )
98
            if( cn == 1 )
99
                color = cvScalarAll(200);
99
                color = cvScalarAll(200);
100
            color.val[0] *= scale;
100
            color.val[0] *= scale;
101
            color.val[1] *= scale;
101
            color.val[1] *= scale;
102
            color.val[2] *= scale;
102
            color.val[2] *= scale;
103
            color.val[3] *= scale;
103
            color.val[3] *= scale;
104
 
104
 
105
            for( x = 0; x < pattern_size.width; x++, i++ )
105
            for( x = 0; x < pattern_size.width; x++, i++ )
106
            {
106
            {
107
                CvPoint pt;
107
                CvPoint pt;
108
                pt.x = cvRound(corners[i].x*(1 << shift));
108
                pt.x = cvRound(corners[i].x*(1 << shift));
109
                pt.y = cvRound(corners[i].y*(1 << shift));
109
                pt.y = cvRound(corners[i].y*(1 << shift));
110
 
110
 
111
                if( i != 0 )
111
                if( i != 0 )
112
                    cvLine( image, prev_pt, pt, color, 1, line_type, shift );
112
                    cvLine( image, prev_pt, pt, color, 1, line_type, shift );
113
 
113
 
114
                cvLine( image, cvPoint(pt.x - r, pt.y - r),
114
                cvLine( image, cvPoint(pt.x - r, pt.y - r),
115
                        cvPoint(pt.x + r, pt.y + r), color, line_width, line_type, shift );
115
                        cvPoint(pt.x + r, pt.y + r), color, line_width, line_type, shift );
116
                cvLine( image, cvPoint(pt.x - r, pt.y + r),
116
                cvLine( image, cvPoint(pt.x - r, pt.y + r),
117
                        cvPoint(pt.x + r, pt.y - r), color, line_width, line_type, shift );
117
                        cvPoint(pt.x + r, pt.y - r), color, line_width, line_type, shift );
118
                cvCircle( image, pt, r+(1<<shift), color, line_width, line_type, shift );
118
                cvCircle( image, pt, r+(1<<shift), color, line_width, line_type, shift );
119
                prev_pt = pt;
119
                prev_pt = pt;
120
            }
120
            }
121
        }
121
        }
122
    }
122
    }
123
}
123
}
124
 
124
 
125
// Returns the result of mod(mat(x,y), moduli) for each matrix element
125
// Returns the result of mod(mat(x,y), moduli) for each matrix element
126
cv::Mat modulo(const cv::Mat &mat, float n){
126
cv::Mat modulo(const cv::Mat &mat, float n){
127
 
127
 
128
    cv::Mat ret(mat.rows, mat.cols, mat.type());
128
    cv::Mat ret(mat.rows, mat.cols, mat.type());
129
 
129
 
130
    for(int row=0; row<ret.rows; row++){
130
    for(int row=0; row<ret.rows; row++){
131
        for(int col=0; col<ret.cols; col++){
131
        for(int col=0; col<ret.cols; col++){
132
            float val = mat.at<float>(row, col);
132
            float val = mat.at<float>(row, col);
133
            // note: std::fmod calculates the remainder, not arithmetic modulo
133
            // note: std::fmod calculates the remainder, not arithmetic modulo
134
            ret.at<float>(row, col) = val - n * std::floor(val / n);
134
            ret.at<float>(row, col) = val - n * std::floor(val / n);
135
        }
135
        }
136
    }
136
    }
137
 
137
 
138
    return ret;
138
    return ret;
139
}
139
}
140
 
140
 
141
// Convert a 3xN matrix to a vector of Point3fs.
141
// Convert a 3xN matrix to a vector of Point3fs.
142
void matToPoints3f(const cv::Mat &mat, std::vector<cv::Point3f> &points){
142
void matToPoints3f(const cv::Mat &mat, std::vector<cv::Point3f> &points){
143
 
143
 
144
    unsigned int nPoints = mat.cols;
144
    unsigned int nPoints = mat.cols;
145
    points.resize(nPoints);
145
    points.resize(nPoints);
146
 
146
 
147
    for(unsigned int i=0; i<nPoints; i++)
147
    for(unsigned int i=0; i<nPoints; i++)
148
        points[i] = cv::Point3f(mat.at<float>(0, i), mat.at<float>(1, i), mat.at<float>(2, i));
148
        points[i] = cv::Point3f(mat.at<float>(0, i), mat.at<float>(1, i), mat.at<float>(2, i));
149
}
149
}
150
 
150
 
151
// Convert a (Dim+1)xN matrix of homogenous points to a DimxN matrix of points in non-homogenous coordinates.
151
// Convert a (Dim+1)xN matrix of homogenous points to a DimxN matrix of points in non-homogenous coordinates.
152
void convertMatFromHomogeneous(cv::Mat &src, cv::Mat &dst){
152
void convertMatFromHomogeneous(cv::Mat &src, cv::Mat &dst){
153
    unsigned int N = src.cols;
153
    unsigned int N = src.cols;
154
    unsigned int Dim = src.rows-1;
154
    unsigned int Dim = src.rows-1;
155
    dst.create(Dim, N, src.type());
155
    dst.create(Dim, N, src.type());
156
    for(unsigned int i=0; i<N; i++){
156
    for(unsigned int i=0; i<N; i++){
157
        for(unsigned int j=0; j<Dim; j++)
157
        for(unsigned int j=0; j<Dim; j++)
158
            dst.at<float>(j,i) = src.at<float>(j,i)/src.at<float>(Dim,i);
158
            dst.at<float>(j,i) = src.at<float>(j,i)/src.at<float>(Dim,i);
159
    }
159
    }
160
 
160
 
161
}
161
}
162
 
162
 
163
// Function to solve the hand-eye (or eye-in-hand) calibration problem.
163
// Function to solve the hand-eye (or eye-in-hand) calibration problem.
164
// Finds [Omega | tau], to minimize ||[R_mark | t_mark][Omega | tau] - [Omega | tau][R | t]||^2
164
// Finds [Omega | tau], to minimize ||[R_mark | t_mark][Omega | tau] - [Omega | tau][R | t]||^2
165
// Algorithm according to Tsai, Lenz, A new technique for fully autonomous and efficient 3d robotics hand-eye calibration
165
// Algorithm according to Tsai, Lenz, A new technique for fully autonomous and efficient 3d robotics hand-eye calibration
166
// DTU, 2014, Jakob Wilm
166
// DTU, 2014, Jakob Wilm
167
void handEyeCalibrationTsai(const std::vector<cv::Matx33f> R, const std::vector<cv::Vec3f> t, const std::vector<cv::Matx33f> R_mark, const std::vector<cv::Vec3f> t_mark, cv::Matx33f &Omega, cv::Vec3f &tau){
167
void handEyeCalibrationTsai(const std::vector<cv::Matx33f> R, const std::vector<cv::Vec3f> t, const std::vector<cv::Matx33f> R_mark, const std::vector<cv::Vec3f> t_mark, cv::Matx33f &Omega, cv::Vec3f &tau){
168
 
168
 
169
    int N = R.size();
169
    int N = R.size();
170
    assert(N == R_mark.size());
170
    assert(N == R_mark.size());
171
    assert(N == t.size());
171
    assert(N == t.size());
172
    assert(N == t_mark.size());
172
    assert(N == t_mark.size());
173
 
173
 
174
    // construct equations for rotation
174
    // construct equations for rotation
175
    cv::Mat A(3*N, 3, CV_32F);
175
    cv::Mat A(3*N, 3, CV_32F);
176
    cv::Mat b(3*N, 1, CV_32F);
176
    cv::Mat b(3*N, 1, CV_32F);
177
    for(int i=0; i<N; i++){
177
    for(int i=0; i<N; i++){
178
        // angle axis representations
178
        // angle axis representations
179
        cv::Vec3f rot;
179
        cv::Vec3f rot;
180
        cv::Vec3f rot_mark;
180
        cv::Vec3f rot_mark;
181
        cv::Rodrigues(R[i], rot);
181
        cv::Rodrigues(R[i], rot);
182
        cv::Rodrigues(R_mark[i], rot_mark);
182
        cv::Rodrigues(R_mark[i], rot_mark);
183
 
183
 
184
        cv::Vec3f P = 2.0*sin(cv::norm(rot)/2.0)*cv::normalize(rot);
184
        cv::Vec3f P = 2.0*sin(cv::norm(rot)/2.0)*cv::normalize(rot);
185
//std::cout << "P: " << std::endl << P << std::endl;
185
//std::cout << "P: " << std::endl << P << std::endl;
186
        cv::Vec3f P_mark = 2.0*sin(cv::norm(rot_mark)/2.0)*cv::normalize(rot_mark);
186
        cv::Vec3f P_mark = 2.0*sin(cv::norm(rot_mark)/2.0)*cv::normalize(rot_mark);
187
//std::cout << "P_mark: " << std::endl << P_mark << std::endl;
187
//std::cout << "P_mark: " << std::endl << P_mark << std::endl;
188
        cv::Vec3f sum = P+P_mark;
188
        cv::Vec3f sum = P+P_mark;
189
        cv::Mat crossProduct = (cv::Mat_<float>(3,3) << 0.0, -sum(2), sum(1), sum(2), 0.0, -sum(0), -sum(1), sum(0), 0.0);
189
        cv::Mat crossProduct = (cv::Mat_<float>(3,3) << 0.0, -sum(2), sum(1), sum(2), 0.0, -sum(0), -sum(1), sum(0), 0.0);
190
//std::cout << "crossProduct: " << std::endl << crossProduct << std::endl;
190
//std::cout << "crossProduct: " << std::endl << crossProduct << std::endl;
191
        crossProduct.copyTo(A.rowRange(i*3, i*3+3));
191
        crossProduct.copyTo(A.rowRange(i*3, i*3+3));
192
 
192
 
193
        cv::Mat(P-P_mark).copyTo(b.rowRange(i*3, i*3+3));
193
        cv::Mat(P-P_mark).copyTo(b.rowRange(i*3, i*3+3));
194
    }
194
    }
195
 
195
 
196
    // solve for rotation
196
    // solve for rotation
197
    cv::Vec3f P_prime;
197
    cv::Vec3f P_prime;
198
    cv::solve(A, b, P_prime, cv::DECOMP_SVD);
198
    cv::solve(A, b, P_prime, cv::DECOMP_SVD);
199
    cv::Vec3f P = 2.0*P_prime/(cv::sqrt(1.0 + cv::norm(P_prime)*cv::norm(P_prime)));
199
    cv::Vec3f P = 2.0*P_prime/(cv::sqrt(1.0 + cv::norm(P_prime)*cv::norm(P_prime)));
200
    float nP = cv::norm(P);
200
    float nP = cv::norm(P);
201
    cv::Mat crossProduct = (cv::Mat_<float>(3,3) << 0.0, -P(2), P(1), P(2), 0.0, -P(0), -P(1), P(0), 0.0);
201
    cv::Mat crossProduct = (cv::Mat_<float>(3,3) << 0.0, -P(2), P(1), P(2), 0.0, -P(0), -P(1), P(0), 0.0);
202
    cv::Mat OmegaMat = (1.0-nP*nP/2.0)*cv::Mat::eye(3,3,CV_32F) + 0.5*(cv::Mat(P)*cv::Mat(P).t() + cv::sqrt(4.0 - nP*nP)*crossProduct);
202
    cv::Mat OmegaMat = (1.0-nP*nP/2.0)*cv::Mat::eye(3,3,CV_32F) + 0.5*(cv::Mat(P)*cv::Mat(P).t() + cv::sqrt(4.0 - nP*nP)*crossProduct);
203
    Omega = cv::Matx33f(OmegaMat);
203
    Omega = cv::Matx33f(OmegaMat);
204
 
204
 
205
    // construct equations for translation
205
    // construct equations for translation
206
    A.setTo(0.0);
206
    A.setTo(0.0);
207
    b.setTo(0.0);
207
    b.setTo(0.0);
208
    for(int i=0; i<N; i++){
208
    for(int i=0; i<N; i++){
209
 
209
 
210
        cv::Mat diff = cv::Mat(R_mark[i]) - cv::Mat::eye(3, 3, CV_32F);
210
        cv::Mat diff = cv::Mat(R_mark[i]) - cv::Mat::eye(3, 3, CV_32F);
211
        diff.copyTo(A.rowRange(i*3, i*3+3));
211
        diff.copyTo(A.rowRange(i*3, i*3+3));
212
 
212
 
213
        cv::Mat diff_mark = cv::Mat(Omega*t[i] - t_mark[i]);
213
        cv::Mat diff_mark = cv::Mat(Omega*t[i] - t_mark[i]);
214
        diff_mark.copyTo(b.rowRange(i*3, i*3+3));
214
        diff_mark.copyTo(b.rowRange(i*3, i*3+3));
215
    }
215
    }
216
 
216
 
217
    // solve for translation
217
    // solve for translation
218
    cv::solve(A, b, tau, cv::DECOMP_SVD);
218
    cv::solve(A, b, tau, cv::DECOMP_SVD);
219
 
219
 
220
    cv::Mat err_tau = b - (A*cv::Mat(tau));
220
    cv::Mat err_tau = b - (A*cv::Mat(tau));
221
    std::cout << err_tau << std::endl;
221
    std::cout << err_tau << std::endl;
222
}
222
}
223
 
223
 
224
// Function to solve for the rotation axis from sets of 3D point coordinates of flat pattern feature points
224
// Function to solve for the rotation axis from sets of 3D point coordinates of flat pattern feature points
225
// Algorithm according to Chen et al., Rotation axis calibration of a turntable using constrained global optimization, Optik 2014
225
// Algorithm according to Chen et al., Rotation axis calibration of a turntable using constrained global optimization, Optik 2014
226
// DTU, 2014, Jakob Wilm
226
// DTU, 2014, Jakob Wilm
227
void rotationAxisCalibration(const std::vector< std::vector<cv::Point3f> > Qcam, const std::vector<cv::Point3f> Qobj, cv::Vec3f &axis, cv::Vec3f &point){
227
void rotationAxisCalibration(const std::vector< std::vector<cv::Point3f> > Qcam, const std::vector<cv::Point3f> Qobj, cv::Vec3f &axis, cv::Vec3f &point){
228
 
228
 
229
    // number of frames (points on each arch)
229
    // number of frames (points on each arch)
230
    int l = Qcam.size();
230
    int l = Qcam.size();
231
 
231
 
232
    // number of points in each frame
232
    // number of points in each frame
233
    int mn = Qobj.size();
233
    int mn = Qobj.size();
234
 
234
 
235
    assert(mn == Qcam[0].size());
235
    assert(mn == Qcam[0].size());
236
 
236
 
237
    // construct matrix for axis determination
237
    // construct matrix for axis determination
238
    cv::Mat M(6, 6, CV_32F, cv::Scalar(0));
238
    cv::Mat M(6, 6, CV_32F, cv::Scalar(0));
239
 
239
 
240
    for(int k=0; k<l; k++){
240
    for(int k=0; k<l; k++){
241
        for(int idx=0; idx<mn; idx++){
241
        for(int idx=0; idx<mn; idx++){
242
 
242
 
243
            float i = Qobj[idx].x+4;
243
//            float i = Qobj[idx].x+4;
244
            float j = Qobj[idx].y+4;
244
//            float j = Qobj[idx].y+4;
-
 
245
            float i = Qobj[idx].x;
-
 
246
            float j = Qobj[idx].y;
245
 
247
 
246
            float x = Qcam[k][idx].x;
248
            float x = Qcam[k][idx].x;
247
            float y = Qcam[k][idx].y;
249
            float y = Qcam[k][idx].y;
248
            float z = Qcam[k][idx].z;
250
            float z = Qcam[k][idx].z;
249
 
251
 
250
            M += (cv::Mat_<float>(6,6) << x*x, x*y, x*z, x, i*x, j*x,
252
            M += (cv::Mat_<float>(6,6) << x*x, x*y, x*z, x, i*x, j*x,
251
                                            0, y*y, y*z, y, i*y, j*y,
253
                                            0, y*y, y*z, y, i*y, j*y,
252
                                            0,   0, z*z, z, i*z, j*z,
254
                                            0,   0, z*z, z, i*z, j*z,
253
                                            0,   0,   0, 1,   i,   j,
255
                                            0,   0,   0, 1,   i,   j,
254
                                            0,   0,   0, 0, i*i, i*j,
256
                                            0,   0,   0, 0, i*i, i*j,
255
                                            0,   0,   0, 0,   0, j*j);
257
                                            0,   0,   0, 0,   0, j*j);
256
 
258
 
257
        }
259
        }
258
    }
260
    }
259
//std::cout << M << std::endl;
261
//std::cout << M << std::endl;
260
    //M *= 1.0/(l*mn);
262
    //M *= 1.0/(l*mn);
261
    cv::completeSymm(M, false);
263
    cv::completeSymm(M, false);
262
//std::cout << M << std::endl;
264
//std::cout << M << std::endl;
263
    // solve for axis
265
    // solve for axis
264
    std::vector<float> lambda;
266
    std::vector<float> lambda;
265
    cv::Mat u;
267
    cv::Mat u;
266
    cv::eigen(M, lambda, u);
268
    cv::eigen(M, lambda, u);
267
 
269
 
268
    float minLambda = abs(lambda[0]);
270
    float minLambda = abs(lambda[0]);
269
    int idx = 0;
271
    int idx = 0;
270
    for(int i=1; i<lambda.size(); i++){
272
    for(int i=1; i<lambda.size(); i++){
271
        if(abs(lambda[i]) < minLambda){
273
        if(abs(lambda[i]) < minLambda){
272
            minLambda = lambda[i];
274
            minLambda = lambda[i];
273
            idx = i;
275
            idx = i;
274
        }
276
        }
275
    }
277
    }
276
 
278
 
277
std::cout << "u:" <<  u << std::endl;
279
//std::cout << "u:" <<  u << std::endl;
278
 
280
 
279
    axis = u.row(idx).colRange(0, 3);
281
    axis = u.row(idx).colRange(0, 3);
280
    axis /= cv::norm(axis);
282
    axis /= cv::norm(axis);
281
 
283
 
282
    float nx = u.at<float>(5, 0);
284
    float nx = u.at<float>(idx, 0);
283
    float ny = u.at<float>(5, 1);
285
    float ny = u.at<float>(idx, 1);
284
    float nz = u.at<float>(5, 2);
286
    float nz = u.at<float>(idx, 2);
285
    float d  = u.at<float>(5, 3);
287
    float d  = u.at<float>(idx, 3);
286
    float dh = u.at<float>(5, 4);
288
    float dh = u.at<float>(idx, 4);
287
    float dv = u.at<float>(5, 5);
289
    float dv = u.at<float>(idx, 5);
288
 
290
 
289
    cv::Mat A(l*mn, mn+2, CV_32F, cv::Scalar(0.0));
291
    cv::Mat A(l*mn, mn+2, CV_32F, cv::Scalar(0.0));
290
    cv::Mat b(l*mn, 1, CV_32F);
292
    cv::Mat bb(l*mn, 1, CV_32F);
291
 
293
 
292
    for(int k=0; k<l; k++){
294
    for(int k=0; k<l; k++){
293
        for(int idx=0; idx<mn; idx++){
295
        for(int idx=0; idx<mn; idx++){
294
 
296
 
295
            float i = Qobj[idx].x;
297
            float i = Qobj[idx].x;
296
            float j = Qobj[idx].y;
298
            float j = Qobj[idx].y;
297
 
299
 
298
            float x = Qcam[k][idx].x;
300
            float x = Qcam[k][idx].x;
299
            float y = Qcam[k][idx].y;
301
            float y = Qcam[k][idx].y;
300
            float z = Qcam[k][idx].z;
302
            float z = Qcam[k][idx].z;
301
 
303
 
302
            float f = x*x + y*y + z*z + (2*x*nx + 2*y*ny + 2*z*nz)*(i*dh + j*dv);
304
            float f = x*x + y*y + z*z + (2*x*nx + 2*y*ny + 2*z*nz)*(i*dh + j*dv);
303
 
305
 
304
            int row = k*mn+idx;
306
            int row = k*mn+idx;
305
            A.at<float>(row, 0) = 2*x - (2*z*nx)/nz;
307
            A.at<float>(row, 0) = 2*x - (2*z*nx)/nz;
306
            A.at<float>(row, 1) = 2*y - (2*z*ny)/nz;
308
            A.at<float>(row, 1) = 2*y - (2*z*ny)/nz;
307
            A.at<float>(row, idx+2) = 1.0;
309
            A.at<float>(row, idx+2) = 1.0;
308
 
310
 
309
            b.at<float>(row, 0) = f + (2*z*d)/nz;
311
            bb.at<float>(row, 0) = f + (2*z*d)/nz;
310
        }
312
        }
311
    }
313
    }
312
 
314
 
313
    // solve for point
315
    // solve for point
314
    cv::Mat abe;
316
    cv::Mat abe;
315
    cv::solve(A, b, abe, cv::DECOMP_SVD);
317
    cv::solve(A, bb, abe, cv::DECOMP_SVD);
316
 
318
 
317
    point[0] = abe.at<float>(0, 0);
319
    float a = abe.at<float>(0, 0);
318
    point[1] = abe.at<float>(1, 0);
320
    float b = abe.at<float>(1, 0);
-
 
321
    float c = -(nx*a+ny*b)/nz;
-
 
322
 
-
 
323
    point[0] = a;
-
 
324
    point[1] = b;
319
    point[2] = abe.at<float>(2, 0);
325
    point[2] = c;
320
 
326
 
321
}
327
}
322
 
328
 
323
// Function to fit two sets of corresponding pose data.
329
// Function to fit two sets of corresponding pose data.
324
// Finds [Omega | tau], to minimize ||[R_mark | t_mark] - [Omega | tau][R | t]||^2
330
// Finds [Omega | tau], to minimize ||[R_mark | t_mark] - [Omega | tau][R | t]||^2
325
// Algorithm and notation according to Mili Shah, Comparing two sets of corresponding six degree of freedom data, CVIU 2011.
331
// Algorithm and notation according to Mili Shah, Comparing two sets of corresponding six degree of freedom data, CVIU 2011.
326
// DTU, 2013, Oline V. Olesen, Jakob Wilm
332
// DTU, 2013, Oline V. Olesen, Jakob Wilm
327
void fitSixDofData(const std::vector<cv::Matx33f> R, const std::vector<cv::Vec3f> t, const std::vector<cv::Matx33f> R_mark, const std::vector<cv::Vec3f> t_mark, cv::Matx33f &Omega, cv::Vec3f &tau){
333
void fitSixDofData(const std::vector<cv::Matx33f> R, const std::vector<cv::Vec3f> t, const std::vector<cv::Matx33f> R_mark, const std::vector<cv::Vec3f> t_mark, cv::Matx33f &Omega, cv::Vec3f &tau){
328
 
334
 
329
    int N = R.size();
335
    int N = R.size();
330
    assert(N == R_mark.size());
336
    assert(N == R_mark.size());
331
    assert(N == t.size());
337
    assert(N == t.size());
332
    assert(N == t_mark.size());
338
    assert(N == t_mark.size());
333
 
339
 
334
    // Mean translations
340
    // Mean translations
335
    cv::Vec3f t_mean;
341
    cv::Vec3f t_mean;
336
    cv::Vec3f t_mark_mean;
342
    cv::Vec3f t_mark_mean;
337
    for(int i=0; i<N; i++){
343
    for(int i=0; i<N; i++){
338
        t_mean += 1.0/N * t[i];
344
        t_mean += 1.0/N * t[i];
339
        t_mark_mean += 1.0/N * t_mark[i];
345
        t_mark_mean += 1.0/N * t_mark[i];
340
    }
346
    }
341
 
347
 
342
    // Data with mean adjusted translations
348
    // Data with mean adjusted translations
343
    cv::Mat X_bar(3, 4*N, CV_32F);
349
    cv::Mat X_bar(3, 4*N, CV_32F);
344
    cv::Mat X_mark_bar(3, 4*N, CV_32F);
350
    cv::Mat X_mark_bar(3, 4*N, CV_32F);
345
    for(int i=0; i<N; i++){
351
    for(int i=0; i<N; i++){
346
        cv::Mat(R[i]).copyTo(X_bar.colRange(i*4,i*4+3));
352
        cv::Mat(R[i]).copyTo(X_bar.colRange(i*4,i*4+3));
347
        cv::Mat(t[i] - t_mean).copyTo(X_bar.col(i*4+3));
353
        cv::Mat(t[i] - t_mean).copyTo(X_bar.col(i*4+3));
348
        cv::Mat(R_mark[i]).copyTo(X_mark_bar.colRange(i*4,i*4+3));
354
        cv::Mat(R_mark[i]).copyTo(X_mark_bar.colRange(i*4,i*4+3));
349
        cv::Mat(t_mark[i] - t_mark_mean).copyTo(X_mark_bar.col(i*4+3));
355
        cv::Mat(t_mark[i] - t_mark_mean).copyTo(X_mark_bar.col(i*4+3));
350
    }
356
    }
351
    //std::cout << X_bar << std::endl;
357
    //std::cout << X_bar << std::endl;
352
    // SVD
358
    // SVD
353
    cv::Mat W, U, VT;
359
    cv::Mat W, U, VT;
354
    cv::SVDecomp(X_bar*X_mark_bar.t(), W, U, VT);
360
    cv::SVDecomp(X_bar*X_mark_bar.t(), W, U, VT);
355
 
361
 
356
    cv::Matx33f D = cv::Matx33f::eye();
362
    cv::Matx33f D = cv::Matx33f::eye();
357
    if(cv::determinant(VT*U) < 0)
363
    if(cv::determinant(VT*U) < 0)
358
        D(3,3) = -1;
364
        D(3,3) = -1;
359
 
365
 
360
    // Best rotation
366
    // Best rotation
361
    Omega = cv::Matx33f(cv::Mat(VT.t()))*D*cv::Matx33f(cv::Mat(U.t()));
367
    Omega = cv::Matx33f(cv::Mat(VT.t()))*D*cv::Matx33f(cv::Mat(U.t()));
362
 
368
 
363
    // Best translation
369
    // Best translation
364
    tau = t_mark_mean - Omega*t_mean;
370
    tau = t_mark_mean - Omega*t_mean;
365
 
371
 
366
}
372
}
367
 
373
 
368
// Forward distortion of points. The inverse of the undistortion in cv::initUndistortRectifyMap().
374
// Forward distortion of points. The inverse of the undistortion in cv::initUndistortRectifyMap().
369
// Inspired by Pascal Thomet, http://code.opencv.org/issues/1387#note-11
375
// Inspired by Pascal Thomet, http://code.opencv.org/issues/1387#note-11
370
// Convention for distortion parameters: http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/parameters.html
376
// Convention for distortion parameters: http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/parameters.html
371
void initDistortMap(const cv::Matx33f cameraMatrix, const cv::Vec<float, 5> distCoeffs, const cv::Size size, cv::Mat &map1, cv::Mat &map2){
377
void initDistortMap(const cv::Matx33f cameraMatrix, const cv::Vec<float, 5> distCoeffs, const cv::Size size, cv::Mat &map1, cv::Mat &map2){
372
 
378
 
373
    float fx = cameraMatrix(0,0);
379
    float fx = cameraMatrix(0,0);
374
    float fy = cameraMatrix(1,1);
380
    float fy = cameraMatrix(1,1);
375
    float ux = cameraMatrix(0,2);
381
    float ux = cameraMatrix(0,2);
376
    float uy = cameraMatrix(1,2);
382
    float uy = cameraMatrix(1,2);
377
 
383
 
378
    float k1 = distCoeffs[0];
384
    float k1 = distCoeffs[0];
379
    float k2 = distCoeffs[1];
385
    float k2 = distCoeffs[1];
380
    float p1 = distCoeffs[2];
386
    float p1 = distCoeffs[2];
381
    float p2 = distCoeffs[3];
387
    float p2 = distCoeffs[3];
382
    float k3 = distCoeffs[4];
388
    float k3 = distCoeffs[4];
383
 
389
 
384
    map1.create(size, CV_32F);
390
    map1.create(size, CV_32F);
385
    map2.create(size, CV_32F);
391
    map2.create(size, CV_32F);
386
 
392
 
387
    for(int col = 0; col < size.width; col++){
393
    for(int col = 0; col < size.width; col++){
388
        for(int row = 0; row < size.height; row++){
394
        for(int row = 0; row < size.height; row++){
389
 
395
 
390
            // move origo to principal point and convert using focal length
396
            // move origo to principal point and convert using focal length
391
            float x = (col-ux)/fx;
397
            float x = (col-ux)/fx;
392
            float y = (row-uy)/fy;
398
            float y = (row-uy)/fy;
393
 
399
 
394
            float xCorrected, yCorrected;
400
            float xCorrected, yCorrected;
395
 
401
 
396
            //Step 1 : correct distortion
402
            //Step 1 : correct distortion
397
            float r2 = x*x + y*y;
403
            float r2 = x*x + y*y;
398
            //radial
404
            //radial
399
            xCorrected = x * (1. + k1*r2 + k2*r2*r2 + k3*r2*r2*r2);
405
            xCorrected = x * (1. + k1*r2 + k2*r2*r2 + k3*r2*r2*r2);
400
            yCorrected = y * (1. + k1*r2 + k2*r2*r2 + k3*r2*r2*r2);
406
            yCorrected = y * (1. + k1*r2 + k2*r2*r2 + k3*r2*r2*r2);
401
            //tangential
407
            //tangential
402
            xCorrected = xCorrected + (2.*p1*x*y + p2*(r2+2.*x*x));
408
            xCorrected = xCorrected + (2.*p1*x*y + p2*(r2+2.*x*x));
403
            yCorrected = yCorrected + (p1*(r2+2.*y*y) + 2.*p2*x*y);
409
            yCorrected = yCorrected + (p1*(r2+2.*y*y) + 2.*p2*x*y);
404
 
410
 
405
            //convert back to pixel coordinates
411
            //convert back to pixel coordinates
406
            float col_displaced = xCorrected * fx + ux;
412
            float col_displaced = xCorrected * fx + ux;
407
            float row_displaced = yCorrected * fy + uy;
413
            float row_displaced = yCorrected * fy + uy;
408
 
414
 
409
            // correct the vector in the opposite direction
415
            // correct the vector in the opposite direction
410
            map1.at<float>(row,col) = col+(col-col_displaced);
416
            map1.at<float>(row,col) = col+(col-col_displaced);
411
            map2.at<float>(row,col) = row +(row-row_displaced);
417
            map2.at<float>(row,col) = row +(row-row_displaced);
412
        }
418
        }
413
    }
419
    }
414
}
420
}
415
 
421
 
416
// Downsample a texture which was created in virtual column/row space for a diamond pixel array projector
422
// Downsample a texture which was created in virtual column/row space for a diamond pixel array projector
417
cv::Mat diamondDownsample(cv::Mat &pattern){
423
cv::Mat diamondDownsample(cv::Mat &pattern){
418
 
424
 
419
    cv::Mat pattern_diamond(pattern.rows,pattern.cols/2,CV_8UC3);
425
    cv::Mat pattern_diamond(pattern.rows,pattern.cols/2,CV_8UC3);
420
 
426
 
421
    for(unsigned int col = 0; col < pattern_diamond.cols; col++){
427
    for(unsigned int col = 0; col < pattern_diamond.cols; col++){
422
        for(unsigned int row = 0; row < pattern_diamond.rows; row++){
428
        for(unsigned int row = 0; row < pattern_diamond.rows; row++){
423
 
429
 
424
            pattern_diamond.at<cv::Vec3b>(row,col)=pattern.at<cv::Vec3b>(row,col*2+row%2);
430
            pattern_diamond.at<cv::Vec3b>(row,col)=pattern.at<cv::Vec3b>(row,col*2+row%2);
425
        }
431
        }
426
    }
432
    }
427
 
433
 
428
    return pattern_diamond;
434
    return pattern_diamond;
429
 
435
 
430
}
436
}
431
 
437
 
432
 
438
 
433
void mouseCallback(int evt, int x, int y, int flags, void* param){
439
void mouseCallback(int evt, int x, int y, int flags, void* param){
434
    cv::Mat *im = (cv::Mat*) param;
440
    cv::Mat *im = (cv::Mat*) param;
435
    if (evt == CV_EVENT_LBUTTONDOWN) {
441
    if (evt == CV_EVENT_LBUTTONDOWN) {
436
        if(im->type() == CV_8UC3){
442
        if(im->type() == CV_8UC3){
437
            printf("%d %d: %d, %d, %d\n",
443
            printf("%d %d: %d, %d, %d\n",
438
                   x, y,
444
                   x, y,
439
                   (int)(*im).at<cv::Vec3b>(y, x)[0],
445
                   (int)(*im).at<cv::Vec3b>(y, x)[0],
440
                    (int)(*im).at<cv::Vec3b>(y, x)[1],
446
                    (int)(*im).at<cv::Vec3b>(y, x)[1],
441
                    (int)(*im).at<cv::Vec3b>(y, x)[2]);
447
                    (int)(*im).at<cv::Vec3b>(y, x)[2]);
442
        } else if (im->type() == CV_32F) {
448
        } else if (im->type() == CV_32F) {
443
            printf("%d %d: %f\n",
449
            printf("%d %d: %f\n",
444
                   x, y,
450
                   x, y,
445
                   im->at<float>(y, x));
451
                   im->at<float>(y, x));
446
        }
452
        }
447
    }
453
    }
448
}
454
}
449
 
455
 
450
void imshow(const char *windowName, cv::Mat im, unsigned int x, unsigned int y){
456
void imshow(const char *windowName, cv::Mat im, unsigned int x, unsigned int y){
451
 
457
 
452
    // Imshow
458
    // Imshow
453
    if(!cvGetWindowHandle(windowName)){
459
    if(!cvGetWindowHandle(windowName)){
454
        int windowFlags = CV_GUI_EXPANDED | CV_WINDOW_KEEPRATIO;
460
        int windowFlags = CV_GUI_EXPANDED | CV_WINDOW_KEEPRATIO;
455
        cv::namedWindow(windowName, windowFlags);
461
        cv::namedWindow(windowName, windowFlags);
456
        cv::moveWindow(windowName, x, y);
462
        cv::moveWindow(windowName, x, y);
457
    }
463
    }
458
    cv::imshow(windowName, im);
464
    cv::imshow(windowName, im);
459
}
465
}
460
 
466
 
461
void imagesc(const char *windowName, cv::Mat im){
467
void imagesc(const char *windowName, cv::Mat im){
462
 
468
 
463
    // Imshow with scaled image
469
    // Imshow with scaled image
464
 
470
 
465
 
471
 
466
}
472
}
467
 
473
 
468
cv::Mat histimage(cv::Mat histogram){
474
cv::Mat histimage(cv::Mat histogram){
469
 
475
 
470
    cv::Mat histImage(512, 640, CV_8UC3, cv::Scalar(0));
476
    cv::Mat histImage(512, 640, CV_8UC3, cv::Scalar(0));
471
 
477
 
472
    // Normalize the result to [ 2, histImage.rows-2 ]
478
    // Normalize the result to [ 2, histImage.rows-2 ]
473
    cv::normalize(histogram, histogram, 2, histImage.rows-2, cv::NORM_MINMAX, -1, cv::Mat());
479
    cv::normalize(histogram, histogram, 2, histImage.rows-2, cv::NORM_MINMAX, -1, cv::Mat());
474
 
480
 
475
    float bin_w = (float)histImage.cols/(float)histogram.rows;
481
    float bin_w = (float)histImage.cols/(float)histogram.rows;
476
 
482
 
477
    // Draw main histogram
483
    // Draw main histogram
478
    for(int i = 1; i < histogram.rows-10; i++){
484
    for(int i = 1; i < histogram.rows-10; i++){
479
        cv::line(histImage, cv::Point( bin_w*(i-1), histImage.rows - cvRound(histogram.at<float>(i-1)) ),
485
        cv::line(histImage, cv::Point( bin_w*(i-1), histImage.rows - cvRound(histogram.at<float>(i-1)) ),
480
                 cv::Point( bin_w*(i), histImage.rows - cvRound(histogram.at<float>(i)) ),
486
                 cv::Point( bin_w*(i), histImage.rows - cvRound(histogram.at<float>(i)) ),
481
                 cv::Scalar(255, 255, 255), 2, 4);
487
                 cv::Scalar(255, 255, 255), 2, 4);
482
    }
488
    }
483
 
489
 
484
    // Draw red max
490
    // Draw red max
485
    for(int i = histogram.rows-10; i < histogram.rows; i++){
491
    for(int i = histogram.rows-10; i < histogram.rows; i++){
486
        cv::line(histImage, cv::Point( bin_w*(i-1), histImage.rows - cvRound(histogram.at<float>(i-1)) ),
492
        cv::line(histImage, cv::Point( bin_w*(i-1), histImage.rows - cvRound(histogram.at<float>(i-1)) ),
487
                 cv::Point( bin_w*(i), histImage.rows - cvRound(histogram.at<float>(i)) ),
493
                 cv::Point( bin_w*(i), histImage.rows - cvRound(histogram.at<float>(i)) ),
488
                 cv::Scalar(0, 0, 255), 2, 4);
494
                 cv::Scalar(0, 0, 255), 2, 4);
489
    }
495
    }
490
 
496
 
491
    return histImage;
497
    return histImage;
492
}
498
}
493
 
499
 
494
void hist(const char *windowName, cv::Mat histogram, unsigned int x, unsigned int y){
500
void hist(const char *windowName, cv::Mat histogram, unsigned int x, unsigned int y){
495
 
501
 
496
    // Display
502
    // Display
497
    imshow(windowName, histimage(histogram), x, y);
503
    imshow(windowName, histimage(histogram), x, y);
498
    cv::Point(1,2);
504
    cv::Point(1,2);
499
}
505
}
500
 
506
 
501
 
507
 
502
void writeMat(cv::Mat const& mat, const char* filename, const char* varName, bool bgr2rgb){
508
void writeMat(cv::Mat const& mat, const char* filename, const char* varName, bool bgr2rgb){
503
    /*!
509
    /*!
504
         *  \author Philip G. Lee <rocketman768@gmail.com>
510
         *  \author Philip G. Lee <rocketman768@gmail.com>
505
         *  Write \b mat into \b filename
511
         *  Write \b mat into \b filename
506
         *  in uncompressed .mat format (Level 5 MATLAB) for Matlab.
512
         *  in uncompressed .mat format (Level 5 MATLAB) for Matlab.
507
         *  The variable name in matlab will be \b varName. If
513
         *  The variable name in matlab will be \b varName. If
508
         *  \b bgr2rgb is true and there are 3 channels, swaps 1st and 3rd
514
         *  \b bgr2rgb is true and there are 3 channels, swaps 1st and 3rd
509
         *  channels in the output. This is needed because OpenCV matrices
515
         *  channels in the output. This is needed because OpenCV matrices
510
         *  are bgr, while Matlab is rgb. This has been tested to work with
516
         *  are bgr, while Matlab is rgb. This has been tested to work with
511
         *  3-channel single-precision floating point matrices, and I hope
517
         *  3-channel single-precision floating point matrices, and I hope
512
         *  it works on other types/channels, but not exactly sure.
518
         *  it works on other types/channels, but not exactly sure.
513
         *  Documentation at <http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf>
519
         *  Documentation at <http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf>
514
         */
520
         */
515
    int textLen = 116;
521
    int textLen = 116;
516
    char* text;
522
    char* text;
517
    int subsysOffsetLen = 8;
523
    int subsysOffsetLen = 8;
518
    char* subsysOffset;
524
    char* subsysOffset;
519
    int verLen = 2;
525
    int verLen = 2;
520
    char* ver;
526
    char* ver;
521
    char flags;
527
    char flags;
522
    int bytes;
528
    int bytes;
523
    int padBytes;
529
    int padBytes;
524
    int bytesPerElement;
530
    int bytesPerElement;
525
    int i,j,k,k2;
531
    int i,j,k,k2;
526
    bool doBgrSwap;
532
    bool doBgrSwap;
527
    char mxClass;
533
    char mxClass;
528
    int32_t miClass;
534
    int32_t miClass;
529
    uchar const* rowPtr;
535
    uchar const* rowPtr;
530
    uint32_t tmp32;
536
    uint32_t tmp32;
531
    float tmp;
537
    float tmp;
532
    FILE* fp;
538
    FILE* fp;
533
 
539
 
534
    // Matlab constants.
540
    // Matlab constants.
535
    const uint16_t MI = 0x4d49; // Contains "MI" in ascii.
541
    const uint16_t MI = 0x4d49; // Contains "MI" in ascii.
536
    const int32_t miINT8 = 1;
542
    const int32_t miINT8 = 1;
537
    const int32_t miUINT8 = 2;
543
    const int32_t miUINT8 = 2;
538
    const int32_t miINT16 = 3;
544
    const int32_t miINT16 = 3;
539
    const int32_t miUINT16 = 4;
545
    const int32_t miUINT16 = 4;
540
    const int32_t miINT32 = 5;
546
    const int32_t miINT32 = 5;
541
    const int32_t miUINT32 = 6;
547
    const int32_t miUINT32 = 6;
542
    const int32_t miSINGLE = 7;
548
    const int32_t miSINGLE = 7;
543
    const int32_t miDOUBLE = 9;
549
    const int32_t miDOUBLE = 9;
544
    const int32_t miMATRIX = 14;
550
    const int32_t miMATRIX = 14;
545
    const char mxDOUBLE_CLASS = 6;
551
    const char mxDOUBLE_CLASS = 6;
546
    const char mxSINGLE_CLASS = 7;
552
    const char mxSINGLE_CLASS = 7;
547
    const char mxINT8_CLASS = 8;
553
    const char mxINT8_CLASS = 8;
548
    const char mxUINT8_CLASS = 9;
554
    const char mxUINT8_CLASS = 9;
549
    const char mxINT16_CLASS = 10;
555
    const char mxINT16_CLASS = 10;
550
    const char mxUINT16_CLASS = 11;
556
    const char mxUINT16_CLASS = 11;
551
    const char mxINT32_CLASS = 12;
557
    const char mxINT32_CLASS = 12;
552
    const char mxUINT32_CLASS = 13;
558
    const char mxUINT32_CLASS = 13;
553
    const uint64_t zero = 0; // Used for padding.
559
    const uint64_t zero = 0; // Used for padding.
554
 
560
 
555
    fp = fopen( filename, "wb" );
561
    fp = fopen( filename, "wb" );
556
 
562
 
557
    if( fp == 0 )
563
    if( fp == 0 )
558
        return;
564
        return;
559
 
565
 
560
    const int rows = mat.rows;
566
    const int rows = mat.rows;
561
    const int cols = mat.cols;
567
    const int cols = mat.cols;
562
    const int chans = mat.channels();
568
    const int chans = mat.channels();
563
 
569
 
564
    doBgrSwap = (chans==3) && bgr2rgb;
570
    doBgrSwap = (chans==3) && bgr2rgb;
565
 
571
 
566
    // I hope this mapping is right :-/
572
    // I hope this mapping is right :-/
567
    switch( mat.depth() ){
573
    switch( mat.depth() ){
568
    case CV_8U:
574
    case CV_8U:
569
        mxClass = mxUINT8_CLASS;
575
        mxClass = mxUINT8_CLASS;
570
        miClass = miUINT8;
576
        miClass = miUINT8;
571
        bytesPerElement = 1;
577
        bytesPerElement = 1;
572
        break;
578
        break;
573
    case CV_8S:
579
    case CV_8S:
574
        mxClass = mxINT8_CLASS;
580
        mxClass = mxINT8_CLASS;
575
        miClass = miINT8;
581
        miClass = miINT8;
576
        bytesPerElement = 1;
582
        bytesPerElement = 1;
577
        break;
583
        break;
578
    case CV_16U:
584
    case CV_16U:
579
        mxClass = mxUINT16_CLASS;
585
        mxClass = mxUINT16_CLASS;
580
        miClass = miUINT16;
586
        miClass = miUINT16;
581
        bytesPerElement = 2;
587
        bytesPerElement = 2;
582
        break;
588
        break;
583
    case CV_16S:
589
    case CV_16S:
584
        mxClass = mxINT16_CLASS;
590
        mxClass = mxINT16_CLASS;
585
        miClass = miINT16;
591
        miClass = miINT16;
586
        bytesPerElement = 2;
592
        bytesPerElement = 2;
587
        break;
593
        break;
588
    case CV_32S:
594
    case CV_32S:
589
        mxClass = mxINT32_CLASS;
595
        mxClass = mxINT32_CLASS;
590
        miClass = miINT32;
596
        miClass = miINT32;
591
        bytesPerElement = 4;
597
        bytesPerElement = 4;
592
        break;
598
        break;
593
    case CV_32F:
599
    case CV_32F:
594
        mxClass = mxSINGLE_CLASS;
600
        mxClass = mxSINGLE_CLASS;
595
        miClass = miSINGLE;
601
        miClass = miSINGLE;
596
        bytesPerElement = 4;
602
        bytesPerElement = 4;
597
        break;
603
        break;
598
    case CV_64F:
604
    case CV_64F:
599
        mxClass = mxDOUBLE_CLASS;
605
        mxClass = mxDOUBLE_CLASS;
600
        miClass = miDOUBLE;
606
        miClass = miDOUBLE;
601
        bytesPerElement = 8;
607
        bytesPerElement = 8;
602
        break;
608
        break;
603
    default:
609
    default:
604
        return;
610
        return;
605
    }
611
    }
606
 
612
 
607
    //==================Mat-file header (128 bytes, page 1-5)==================
613
    //==================Mat-file header (128 bytes, page 1-5)==================
608
    text = new char[textLen]; // Human-readable text.
614
    text = new char[textLen]; // Human-readable text.
609
    memset( text, ' ', textLen );
615
    memset( text, ' ', textLen );
610
    text[textLen-1] = '\0';
616
    text[textLen-1] = '\0';
611
    const char* t = "MATLAB 5.0 MAT-file, Platform: PCWIN";
617
    const char* t = "MATLAB 5.0 MAT-file, Platform: PCWIN";
612
    memcpy( text, t, strlen(t) );
618
    memcpy( text, t, strlen(t) );
613
 
619
 
614
    subsysOffset = new char[subsysOffsetLen]; // Zeros for us.
620
    subsysOffset = new char[subsysOffsetLen]; // Zeros for us.
615
    memset( subsysOffset, 0x00, subsysOffsetLen );
621
    memset( subsysOffset, 0x00, subsysOffsetLen );
616
    ver = new char[verLen];
622
    ver = new char[verLen];
617
    ver[0] = 0x00;
623
    ver[0] = 0x00;
618
    ver[1] = 0x01;
624
    ver[1] = 0x01;
619
 
625
 
620
    fwrite( text, 1, textLen, fp );
626
    fwrite( text, 1, textLen, fp );
621
    fwrite( subsysOffset, 1, subsysOffsetLen, fp );
627
    fwrite( subsysOffset, 1, subsysOffsetLen, fp );
622
    fwrite( ver, 1, verLen, fp );
628
    fwrite( ver, 1, verLen, fp );
623
    // Endian indicator. MI will show up as "MI" on big-endian
629
    // Endian indicator. MI will show up as "MI" on big-endian
624
    // systems and "IM" on little-endian systems.
630
    // systems and "IM" on little-endian systems.
625
    fwrite( &MI, 2, 1, fp );
631
    fwrite( &MI, 2, 1, fp );
626
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
632
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
627
 
633
 
628
    //===================Data element tag (8 bytes, page 1-8)==================
634
    //===================Data element tag (8 bytes, page 1-8)==================
629
    bytes = 16 + 24 + (8 + strlen(varName) + (8-(strlen(varName)%8))%8)
635
    bytes = 16 + 24 + (8 + strlen(varName) + (8-(strlen(varName)%8))%8)
630
            + (8 + rows*cols*chans*bytesPerElement);
636
            + (8 + rows*cols*chans*bytesPerElement);
631
    fwrite( &miMATRIX, 4, 1, fp ); // Data type.
637
    fwrite( &miMATRIX, 4, 1, fp ); // Data type.
632
    fwrite( &bytes, 4, 1, fp); // Data size in bytes.
638
    fwrite( &bytes, 4, 1, fp); // Data size in bytes.
633
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
639
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
634
 
640
 
635
    //====================Array flags (16 bytes, page 1-15)====================
641
    //====================Array flags (16 bytes, page 1-15)====================
636
    bytes = 8;
642
    bytes = 8;
637
    fwrite( &miUINT32, 4, 1, fp );
643
    fwrite( &miUINT32, 4, 1, fp );
638
    fwrite( &bytes, 4, 1, fp );
644
    fwrite( &bytes, 4, 1, fp );
639
    flags = 0x00; // Complex, logical, and global flags all off.
645
    flags = 0x00; // Complex, logical, and global flags all off.
640
 
646
 
641
    tmp32 = 0;
647
    tmp32 = 0;
642
    tmp32 = (flags << 8 ) | (mxClass);
648
    tmp32 = (flags << 8 ) | (mxClass);
643
    fwrite( &tmp32, 4, 1, fp );
649
    fwrite( &tmp32, 4, 1, fp );
644
 
650
 
645
    fwrite( &zero, 4, 1, fp ); // Padding to 64-bit boundary.
651
    fwrite( &zero, 4, 1, fp ); // Padding to 64-bit boundary.
646
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
652
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
647
 
653
 
648
    //===============Dimensions subelement (24 bytes, page 1-17)===============
654
    //===============Dimensions subelement (24 bytes, page 1-17)===============
649
    bytes = 12;
655
    bytes = 12;
650
    fwrite( &miINT32, 4, 1, fp );
656
    fwrite( &miINT32, 4, 1, fp );
651
    fwrite( &bytes, 4, 1, fp );
657
    fwrite( &bytes, 4, 1, fp );
652
 
658
 
653
    fwrite( &rows, 4, 1, fp );
659
    fwrite( &rows, 4, 1, fp );
654
    fwrite( &cols, 4, 1, fp );
660
    fwrite( &cols, 4, 1, fp );
655
    fwrite( &chans, 4, 1, fp );
661
    fwrite( &chans, 4, 1, fp );
656
    fwrite( &zero, 4, 1, fp ); // Padding to 64-bit boundary.
662
    fwrite( &zero, 4, 1, fp ); // Padding to 64-bit boundary.
657
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
663
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
658
 
664
 
659
    //==Array name (8 + strlen(varName) + (8-(strlen(varName)%8))%8 bytes, page 1-17)==
665
    //==Array name (8 + strlen(varName) + (8-(strlen(varName)%8))%8 bytes, page 1-17)==
660
    bytes = strlen(varName);
666
    bytes = strlen(varName);
661
 
667
 
662
    fwrite( &miINT8, 4, 1, fp );
668
    fwrite( &miINT8, 4, 1, fp );
663
    fwrite( &bytes, 4, 1, fp );
669
    fwrite( &bytes, 4, 1, fp );
664
    fwrite( varName, 1, bytes, fp );
670
    fwrite( varName, 1, bytes, fp );
665
 
671
 
666
    // Pad to nearest 64-bit boundary.
672
    // Pad to nearest 64-bit boundary.
667
    padBytes = (8-(bytes%8))%8;
673
    padBytes = (8-(bytes%8))%8;
668
    fwrite( &zero, 1, padBytes, fp );
674
    fwrite( &zero, 1, padBytes, fp );
669
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
675
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
670
 
676
 
671
    //====Matrix data (rows*cols*chans*bytesPerElement+8 bytes, page 1-20)=====
677
    //====Matrix data (rows*cols*chans*bytesPerElement+8 bytes, page 1-20)=====
672
    bytes = rows*cols*chans*bytesPerElement;
678
    bytes = rows*cols*chans*bytesPerElement;
673
    fwrite( &miClass, 4, 1, fp );
679
    fwrite( &miClass, 4, 1, fp );
674
    fwrite( &bytes, 4, 1, fp );
680
    fwrite( &bytes, 4, 1, fp );
675
 
681
 
676
    for( k = 0; k < chans; ++k )
682
    for( k = 0; k < chans; ++k )
677
    {
683
    {
678
        if( doBgrSwap )
684
        if( doBgrSwap )
679
        {
685
        {
680
            k2 = (k==0)? 2 : ((k==2)? 0 : 1);
686
            k2 = (k==0)? 2 : ((k==2)? 0 : 1);
681
        }
687
        }
682
        else
688
        else
683
            k2 = k;
689
            k2 = k;
684
 
690
 
685
        for( j = 0; j < cols; ++j )
691
        for( j = 0; j < cols; ++j )
686
        {
692
        {
687
            for( i = 0; i < rows; ++i )
693
            for( i = 0; i < rows; ++i )
688
            {
694
            {
689
                rowPtr = mat.data + mat.step*i;
695
                rowPtr = mat.data + mat.step*i;
690
                fwrite( rowPtr + (chans*j + k2)*bytesPerElement, bytesPerElement, 1, fp );
696
                fwrite( rowPtr + (chans*j + k2)*bytesPerElement, bytesPerElement, 1, fp );
691
            }
697
            }
692
        }
698
        }
693
    }
699
    }
694
 
700
 
695
    // Pad to 64-bit boundary.
701
    // Pad to 64-bit boundary.
696
    padBytes = (8-(bytes%8))%8;
702
    padBytes = (8-(bytes%8))%8;
697
    fwrite( &zero, 1, padBytes, fp );
703
    fwrite( &zero, 1, padBytes, fp );
698
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
704
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
699
 
705
 
700
    fclose(fp);
706
    fclose(fp);
701
    delete[] text;
707
    delete[] text;
702
    delete[] subsysOffset;
708
    delete[] subsysOffset;
703
    delete[] ver;
709
    delete[] ver;
704
}
710
}
705
 
711
 
706
 
712
 
707
 
713
 
708
 
714
 
709
 
715
 
710
}
716
}
711
 
717