Subversion Repositories seema-scanner

Rev

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

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