Subversion Repositories seema-scanner

Rev

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

Rev 139 Rev 141
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
#include <png.h>
-
 
10
#include <zlib.h>
-
 
11
 
9
namespace cvtools{
12
namespace cvtools{
10
 
13
 
-
 
14
//bool imwriteTiff(std::string filename, cv::Mat img){
-
 
15
 
-
 
16
//    int channels = img.channels();
-
 
17
//    int width = img.cols, height = img.rows;
-
 
18
//    int depth = img.depth();
-
 
19
 
-
 
20
//    int bitsPerChannel = -1;
-
 
21
//    switch (depth)
-
 
22
//    {
-
 
23
//        case CV_8U:
-
 
24
//        {
-
 
25
//            bitsPerChannel = 8;
-
 
26
//            break;
-
 
27
//        }
-
 
28
//        case CV_16U:
-
 
29
//        {
-
 
30
//            bitsPerChannel = 16;
-
 
31
//            break;
-
 
32
//        }
-
 
33
//        default:
-
 
34
//        {
-
 
35
//            return false;
-
 
36
//        }
-
 
37
//    }
-
 
38
 
-
 
39
//    const int bitsPerByte = 8;
-
 
40
//    size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
-
 
41
 
-
 
42
//    int rowsPerStrip = (int)((1 << 13)/fileStep);
-
 
43
//    readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);
-
 
44
 
-
 
45
//    if( rowsPerStrip < 1 )
-
 
46
//        rowsPerStrip = 1;
-
 
47
 
-
 
48
//    if( rowsPerStrip > height )
-
 
49
//        rowsPerStrip = height;
-
 
50
 
-
 
51
 
-
 
52
//    // do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
-
 
53
//    // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
-
 
54
//    TIFF* pTiffHandle = TIFFOpen(m_filename.c_str(), "w");
-
 
55
//    if (!pTiffHandle)
-
 
56
//    {
-
 
57
//        return false;
-
 
58
//    }
-
 
59
 
-
 
60
//    // defaults for now, maybe base them on params in the future
-
 
61
//    int   compression  = COMPRESSION_LZW;
-
 
62
//    int   predictor    = PREDICTOR_HORIZONTAL;
-
 
63
 
-
 
64
//    readParam(params, TIFFTAG_COMPRESSION, compression);
-
 
65
//    readParam(params, TIFFTAG_PREDICTOR, predictor);
-
 
66
 
-
 
67
//    int   colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
-
 
68
 
-
 
69
//    if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)
-
 
70
//      || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)
-
 
71
//      || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)
-
 
72
//      || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)
-
 
73
//      || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)
-
 
74
//      || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)
-
 
75
//      || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
-
 
76
//      || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)
-
 
77
//      || !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor)
-
 
78
//       )
-
 
79
//    {
-
 
80
//        TIFFClose(pTiffHandle);
-
 
81
//        return false;
-
 
82
//    }
-
 
83
 
-
 
84
//    // row buffer, because TIFFWriteScanline modifies the original data!
-
 
85
//    size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
-
 
86
//    AutoBuffer<uchar> _buffer(scanlineSize+32);
-
 
87
//    uchar* buffer = _buffer;
-
 
88
//    if (!buffer)
-
 
89
//    {
-
 
90
//        TIFFClose(pTiffHandle);
-
 
91
//        return false;
-
 
92
//    }
-
 
93
 
-
 
94
//    for (int y = 0; y < height; ++y)
-
 
95
//    {
-
 
96
//        switch(channels)
-
 
97
//        {
-
 
98
//            case 1:
-
 
99
//            {
-
 
100
//                memcpy(buffer, img.data + img.step * y, scanlineSize);
-
 
101
//                break;
-
 
102
//            }
-
 
103
 
-
 
104
//            case 3:
-
 
105
//            {
-
 
106
//                if (depth == CV_8U)
-
 
107
//                    icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
-
 
108
//                else
-
 
109
//                    icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
-
 
110
//                break;
-
 
111
//            }
-
 
112
 
-
 
113
//            case 4:
-
 
114
//            {
-
 
115
//                if (depth == CV_8U)
-
 
116
//                    icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
-
 
117
//                else
-
 
118
//                    icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
-
 
119
//                break;
-
 
120
//            }
-
 
121
 
-
 
122
//            default:
-
 
123
//            {
-
 
124
//                TIFFClose(pTiffHandle);
-
 
125
//                return false;
-
 
126
//            }
-
 
127
//        }
-
 
128
 
-
 
129
//        int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
-
 
130
//        if (writeResult != 1)
-
 
131
//        {
-
 
132
//            TIFFClose(pTiffHandle);
-
 
133
//            return false;
-
 
134
//        }
-
 
135
//    }
-
 
136
 
-
 
137
//    TIFFClose(pTiffHandle);
-
 
138
//    return true;
-
 
139
//}
-
 
140
 
-
 
141
 
-
 
142
// imwrite for png images, with little compression for good speed. Defaults to rgb, not bgr (as cv::imwrite).
-
 
143
bool imwritePNG(const std::string& filename, const cv::Mat img){
-
 
144
    png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
-
 
145
    png_infop info_ptr = 0;
-
 
146
    FILE* f = 0;
-
 
147
    int y, width = img.cols, height = img.rows;
-
 
148
    int depth = img.depth(), channels = img.channels();
-
 
149
    bool result = false;
-
 
150
    cv::AutoBuffer<uchar*> buffer;
-
 
151
 
-
 
152
    if( depth != CV_8U && depth != CV_16U )
-
 
153
        return false;
-
 
154
 
-
 
155
    if( png_ptr )
-
 
156
    {
-
 
157
        info_ptr = png_create_info_struct( png_ptr );
-
 
158
 
-
 
159
        if( info_ptr )
-
 
160
        {
-
 
161
            if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
-
 
162
            {
-
 
163
 
-
 
164
                f = fopen( filename.c_str(), "wb" );
-
 
165
                if(f)
-
 
166
                    png_init_io( png_ptr, f );
-
 
167
 
-
 
168
                png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);
-
 
169
                png_set_compression_level( png_ptr, Z_BEST_SPEED );
-
 
170
                png_set_compression_strategy(png_ptr, Z_FILTERED);
-
 
171
                //png_set_filter_heuristics(png_ptr, )
-
 
172
 
-
 
173
                bool isBilevel = (depth == CV_16UC3 || depth == CV_16UC1);
-
 
174
 
-
 
175
                png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16,
-
 
176
                    channels == 1 ? PNG_COLOR_TYPE_GRAY :
-
 
177
                    channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
-
 
178
                    PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
-
 
179
                    PNG_FILTER_TYPE_DEFAULT );
-
 
180
 
-
 
181
                png_write_info( png_ptr, info_ptr );
-
 
182
 
-
 
183
                if (isBilevel)
-
 
184
                    png_set_packing(png_ptr);
-
 
185
 
-
 
186
                png_set_bgr( png_ptr );
-
 
187
                bool isBigEndian = (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
-
 
188
                if( !isBigEndian )
-
 
189
                    png_set_swap( png_ptr );
-
 
190
 
-
 
191
                buffer.allocate(height);
-
 
192
                for( y = 0; y < height; y++ )
-
 
193
                    buffer[y] = img.data + y*img.step;
-
 
194
 
-
 
195
                png_write_image( png_ptr, buffer );
-
 
196
                png_write_end( png_ptr, info_ptr );
-
 
197
 
-
 
198
                result = true;
-
 
199
 
-
 
200
            }
-
 
201
        }
-
 
202
    }
-
 
203
 
-
 
204
    png_destroy_write_struct( &png_ptr, &info_ptr );
-
 
205
    if(f) fclose( f );
-
 
206
 
-
 
207
    return result;
-
 
208
}
-
 
209
 
-
 
210
 
11
// Convert an BGR 3-channel image back into a Bayered image
211
// Convert an BGR 3-channel image back into a Bayered image
12
void cvtColorBGRToBayerBG(const cv::Mat &imBGR, cv::Mat &imBayerBG){
212
void cvtColorBGRToBayerBG(const cv::Mat &imBGR, cv::Mat &imBayerBG){
13
 
213
 
14
    imBayerBG.create(imBGR.size(), CV_8UC1);
214
    imBayerBG.create(imBGR.size(), CV_8UC1);
15
 
215
 
16
 
216
 
17
    for(int r=0; r<imBGR.rows; r++){
217
    for(int r=0; r<imBGR.rows; r++){
18
        for(int c=0; c<imBGR.cols; c++){
218
        for(int c=0; c<imBGR.cols; c++){
19
 
219
 
20
            bool evenRow = r % 2;
220
            bool evenRow = r % 2;
21
            bool evenCol = c % 2;
221
            bool evenCol = c % 2;
22
 
222
 
23
            if(evenRow & evenCol)
223
            if(evenRow & evenCol)
24
                imBayerBG.at<uchar>(r,c) = imBGR.at<cv::Vec3b>(r,c)[0];
224
                imBayerBG.at<uchar>(r,c) = imBGR.at<cv::Vec3b>(r,c)[0];
25
            else if(!evenRow & !evenCol)
225
            else if(!evenRow & !evenCol)
26
                imBayerBG.at<uchar>(r,c) = imBGR.at<cv::Vec3b>(r,c)[2];
226
                imBayerBG.at<uchar>(r,c) = imBGR.at<cv::Vec3b>(r,c)[2];
27
            else
227
            else
28
                imBayerBG.at<uchar>(r,c) = imBGR.at<cv::Vec3b>(r,c)[1];
228
                imBayerBG.at<uchar>(r,c) = imBGR.at<cv::Vec3b>(r,c)[1];
29
 
229
 
30
        }
230
        }
31
 
231
 
32
    }
232
    }
33
 
233
 
34
 
234
 
35
}
235
}
36
 
236
 
37
 
237
 
38
// Removes matches not satisfying the epipolar constraint.
238
// Removes matches not satisfying the epipolar constraint.
39
// F is the fundamental matrix.
239
// F is the fundamental matrix.
40
// Works like cv::correctMatches(), except it removes matches with an error distance greater than maxD.
240
// Works like cv::correctMatches(), except it removes matches with an error distance greater than maxD.
41
void removeIncorrectMatches(const cv::Mat F, const std::vector<cv::Point2f> &q0, const std::vector<cv::Point2f> &q1, const float maxD,
241
void removeIncorrectMatches(const cv::Mat F, const std::vector<cv::Point2f> &q0, const std::vector<cv::Point2f> &q1, const float maxD,
42
                                std::vector<cv::Point2f> q0Correct, std::vector<cv::Point2f> q1Correct){
242
                                std::vector<cv::Point2f> q0Correct, std::vector<cv::Point2f> q1Correct){
43
 
243
 
44
    int n0 = (int)q0.size(), n1 = (int)q1.size();
244
    int n0 = (int)q0.size(), n1 = (int)q1.size();
45
    q0Correct.reserve(n0);
245
    q0Correct.reserve(n0);
46
    q1Correct.reserve(n1);
246
    q1Correct.reserve(n1);
47
 
247
 
48
    // Point to line distance
248
    // Point to line distance
49
//    for( int i = 0; i < n1; i++ ){
249
//    for( int i = 0; i < n1; i++ ){
50
//        cv::Vec3f p0 = cv::Vec3f(q0[i].x, q0[i].y, 1.0);
250
//        cv::Vec3f p0 = cv::Vec3f(q0[i].x, q0[i].y, 1.0);
51
//        // Epipolar line defined by p0
251
//        // Epipolar line defined by p0
52
//        cv::Vec3f l = F*p0;
252
//        cv::Vec3f l = F*p0;
53
//        l /= sqrt(l(0)*l(0) + l(1)*l(1));
253
//        l /= sqrt(l(0)*l(0) + l(1)*l(1));
54
//        for( int j = 0; j < n2; j++ ){
254
//        for( int j = 0; j < n2; j++ ){
55
//            cv::Vec3f p1 = cv::Vec3f(q1[i].x, q1[i].y, 1.0);
255
//            cv::Vec3f p1 = cv::Vec3f(q1[i].x, q1[i].y, 1.0);
56
//            // Signed distance to line
256
//            // Signed distance to line
57
//            float d = l.dot(p1);
257
//            float d = l.dot(p1);
58
//            if(d < maxD){
258
//            if(d < maxD){
59
//                q0Correct.push_back(q0[i]);
259
//                q0Correct.push_back(q0[i]);
60
//                q1Correct.push_back(q1[i]);
260
//                q1Correct.push_back(q1[i]);
61
//            }
261
//            }
62
//        }
262
//        }
63
//    }
263
//    }
64
 
264
 
65
    // Symmetric epipolar distance
265
    // Symmetric epipolar distance
66
    std::vector<cv::Point3f> l0, l1;
266
    std::vector<cv::Point3f> l0, l1;
67
    cv::computeCorrespondEpilines(q0, 1, F, l0);
267
    cv::computeCorrespondEpilines(q0, 1, F, l0);
68
    cv::computeCorrespondEpilines(q1, 2, F, l1);
268
    cv::computeCorrespondEpilines(q1, 2, F, l1);
69
 
269
 
70
    for(int i = 0; i < n0; i++){
270
    for(int i = 0; i < n0; i++){
71
        cv::Vec3f p0 = cv::Vec3f(q0[i].x, q0[i].y, 1.0);
271
        cv::Vec3f p0 = cv::Vec3f(q0[i].x, q0[i].y, 1.0);
72
        for(int j = 0; j < n1; j++){
272
        for(int j = 0; j < n1; j++){
73
            cv::Vec3f p1 = cv::Vec3f(q1[j].x, q1[j].y, 1.0);
273
            cv::Vec3f p1 = cv::Vec3f(q1[j].x, q1[j].y, 1.0);
74
            float d01 = l0[i].dot(p1);
274
            float d01 = l0[i].dot(p1);
75
            float d10 = l1[j].dot(p0);
275
            float d10 = l1[j].dot(p0);
76
            float d = d01*d01 + d10*d10;
276
            float d = d01*d01 + d10*d10;
77
            if(d < maxD){
277
            if(d < maxD){
78
                q0Correct.push_back(q0[i]);
278
                q0Correct.push_back(q0[i]);
79
                q1Correct.push_back(q1[i]);
279
                q1Correct.push_back(q1[i]);
80
            }
280
            }
81
        }
281
        }
82
    }
282
    }
83
 
283
 
84
//    // Sampson Error (H&Z, p. 287) (expensive...)
284
//    // Sampson Error (H&Z, p. 287) (expensive...)
85
//    std::vector<cv::Point3f> p0, p1;
285
//    std::vector<cv::Point3f> p0, p1;
86
//    cv::convertPointsToHomogeneous(q0, p0);
286
//    cv::convertPointsToHomogeneous(q0, p0);
87
//    cv::convertPointsToHomogeneous(q1, p1);
287
//    cv::convertPointsToHomogeneous(q1, p1);
88
//    cv::Mat Fp0Mat = cv::Mat(F)*cv::Mat(p0).reshape(1).t();
288
//    cv::Mat Fp0Mat = cv::Mat(F)*cv::Mat(p0).reshape(1).t();
89
//    cv::Mat FTp1Mat = cv::Mat(F.t())*cv::Mat(p1).reshape(1).t();
289
//    cv::Mat FTp1Mat = cv::Mat(F.t())*cv::Mat(p1).reshape(1).t();
90
//    for( int i = 0; i < n1; i++ ){
290
//    for( int i = 0; i < n1; i++ ){
91
//        cv::Vec3f Fp0 = Fp0Mat.col(i);
291
//        cv::Vec3f Fp0 = Fp0Mat.col(i);
92
//        for( int j = 0; j < n2; j++ ){
292
//        for( int j = 0; j < n2; j++ ){
93
//            cv::Vec3f FTp1 = FTp1Mat.col(j);
293
//            cv::Vec3f FTp1 = FTp1Mat.col(j);
94
//            cv::Matx<float,1,1> p1TFp0 = cv::Matx31f(p1[j]).t()*F*cv::Matx31f(p0[i]);
294
//            cv::Matx<float,1,1> p1TFp0 = cv::Matx31f(p1[j]).t()*F*cv::Matx31f(p0[i]);
95
//            float d = p1TFp0(0)*p1TFp0(0) / (Fp0(0)*Fp0(0) + Fp0(1)*Fp0(1) + FTp1(0)*FTp1(0) + FTp1(1)*FTp1(1));
295
//            float d = p1TFp0(0)*p1TFp0(0) / (Fp0(0)*Fp0(0) + Fp0(1)*Fp0(1) + FTp1(0)*FTp1(0) + FTp1(1)*FTp1(1));
96
//            if(d < maxD){
296
//            if(d < maxD){
97
//                q0Correct.push_back(q0[i]);
297
//                q0Correct.push_back(q0[i]);
98
//                q1Correct.push_back(q1[i]);
298
//                q1Correct.push_back(q1[i]);
99
//            }
299
//            }
100
//        }
300
//        }
101
//    }
301
//    }
102
 
302
 
103
    return;
303
    return;
104
}
304
}
105
 
305
 
106
// Lightly modified OpenCV function which accepts a line width argument
-
 
107
void drawChessboardCorners(cv::InputOutputArray _image, cv::Size patternSize, cv::InputArray _corners, bool patternWasFound, int line_width){
306
// Performs bitwise right-shift on every value of matrix I. This is done e.g. to remove the least significant bits in a 16 to 8-bit image conversion.
108
    cv::Mat corners = _corners.getMat();
-
 
109
    if( corners.empty() )
-
 
110
        return;
-
 
111
    cv::Mat image = _image.getMat(); CvMat c_image = _image.getMat();
-
 
112
    int nelems = corners.checkVector(2, CV_32F, true);
-
 
113
    CV_Assert(nelems >= 0);
-
 
114
    cvDrawChessboardCorners( &c_image, patternSize, (CvPoint2D32f*)corners.data,
-
 
115
                             nelems, patternWasFound, line_width);
-
 
116
}
-
 
117
 
-
 
118
void rshift(cv::Mat& I, unsigned int shift){
307
void rshift(cv::Mat& I, unsigned int shift){
119
 
308
 
120
    int nRows = I.rows;
309
    int nRows = I.rows;
121
    int nCols = I.cols;
310
    int nCols = I.cols;
122
 
311
 
123
    if (I.isContinuous()){
312
    if (I.isContinuous()){
124
        nCols *= nRows;
313
        nCols *= nRows;
125
        nRows = 1;
314
        nRows = 1;
126
    }
315
    }
127
 
316
 
128
    int i,j;
317
    int i,j;
129
    unsigned short* p;
318
    unsigned short* p;
130
    for( i = 0; i < nRows; ++i){
319
    for( i = 0; i < nRows; ++i){
131
        p = I.ptr<unsigned short>(i);
320
        p = I.ptr<unsigned short>(i);
132
        for ( j = 0; j < nCols; ++j){
321
        for ( j = 0; j < nCols; ++j){
133
            p[j] = p[j]>>shift;
322
            p[j] = p[j]>>shift;
134
        }
323
        }
135
    }
324
    }
136
}
325
}
137
 
326
 
-
 
327
 
-
 
328
// Lightly modified OpenCV function which accepts a line width argument
-
 
329
void drawChessboardCorners(cv::InputOutputArray _image, cv::Size patternSize, cv::InputArray _corners, bool patternWasFound, int line_width){
-
 
330
    cv::Mat corners = _corners.getMat();
-
 
331
    if( corners.empty() )
-
 
332
        return;
-
 
333
    cv::Mat image = _image.getMat(); CvMat c_image = _image.getMat();
-
 
334
    int nelems = corners.checkVector(2, CV_32F, true);
-
 
335
    CV_Assert(nelems >= 0);
-
 
336
    cvtools::cvDrawChessboardCorners( &c_image, patternSize, (CvPoint2D32f*)corners.data,
-
 
337
                             nelems, patternWasFound, line_width);
-
 
338
}
-
 
339
 
-
 
340
 
-
 
341
 
138
void cvDrawChessboardCorners(CvArr* _image, CvSize pattern_size, CvPoint2D32f* corners, int count, int found, int line_width){
342
void cvDrawChessboardCorners(CvArr* _image, CvSize pattern_size, CvPoint2D32f* corners, int count, int found, int line_width){
139
    const int shift = 0;
343
    const int shift = 0;
140
    const int radius = 12;
344
    const int radius = 12;
141
    const int r = radius*(1 << shift);
345
    const int r = radius*(1 << shift);
142
    int i;
346
    int i;
143
    CvMat stub, *image;
347
    CvMat stub, *image;
144
    double scale = 1;
348
    double scale = 1;
145
    int type, cn, line_type;
349
    int type, cn, line_type;
146
 
350
 
147
    image = cvGetMat( _image, &stub );
351
    image = cvGetMat( _image, &stub );
148
 
352
 
149
    type = CV_MAT_TYPE(image->type);
353
    type = CV_MAT_TYPE(image->type);
150
    cn = CV_MAT_CN(type);
354
    cn = CV_MAT_CN(type);
151
    if( cn != 1 && cn != 3 && cn != 4 )
355
    if( cn != 1 && cn != 3 && cn != 4 )
152
        CV_Error( CV_StsUnsupportedFormat, "Number of channels must be 1, 3 or 4" );
356
        CV_Error( CV_StsUnsupportedFormat, "Number of channels must be 1, 3 or 4" );
153
 
357
 
154
    switch( CV_MAT_DEPTH(image->type) )
358
    switch( CV_MAT_DEPTH(image->type) )
155
    {
359
    {
156
    case CV_8U:
360
    case CV_8U:
157
        scale = 1;
361
        scale = 1;
158
        break;
362
        break;
159
    case CV_16U:
363
    case CV_16U:
160
        scale = 256;
364
        scale = 256;
161
        break;
365
        break;
162
    case CV_32F:
366
    case CV_32F:
163
        scale = 1./255;
367
        scale = 1./255;
164
        break;
368
        break;
165
    default:
369
    default:
166
        CV_Error( CV_StsUnsupportedFormat,
370
        CV_Error( CV_StsUnsupportedFormat,
167
            "Only 8-bit, 16-bit or floating-point 32-bit images are supported" );
371
            "Only 8-bit, 16-bit or floating-point 32-bit images are supported" );
168
    }
372
    }
169
 
373
 
170
    line_type = type == CV_8UC1 || type == CV_8UC3 ? CV_AA : 8;
374
    line_type = type == CV_8UC1 || type == CV_8UC3 ? CV_AA : 8;
171
 
375
 
172
    if( !found )
376
    if( !found )
173
    {
377
    {
174
        CvScalar color = {{0,0,255}};
378
        CvScalar color = {{0,0,255}};
175
        if( cn == 1 )
379
        if( cn == 1 )
176
            color = cvScalarAll(200);
380
            color = cvScalarAll(200);
177
        color.val[0] *= scale;
381
        color.val[0] *= scale;
178
        color.val[1] *= scale;
382
        color.val[1] *= scale;
179
        color.val[2] *= scale;
383
        color.val[2] *= scale;
180
        color.val[3] *= scale;
384
        color.val[3] *= scale;
181
 
385
 
182
        for( i = 0; i < count; i++ )
386
        for( i = 0; i < count; i++ )
183
        {
387
        {
184
            CvPoint pt;
388
            CvPoint pt;
185
            pt.x = cvRound(corners[i].x*(1 << shift));
389
            pt.x = cvRound(corners[i].x*(1 << shift));
186
            pt.y = cvRound(corners[i].y*(1 << shift));
390
            pt.y = cvRound(corners[i].y*(1 << shift));
187
            cvLine( image, cvPoint( pt.x - r, pt.y - r ),
391
            cvLine( image, cvPoint( pt.x - r, pt.y - r ),
188
                    cvPoint( pt.x + r, pt.y + r ), color, line_width, line_type, shift );
392
                    cvPoint( pt.x + r, pt.y + r ), color, line_width, line_type, shift );
189
            cvLine( image, cvPoint( pt.x - r, pt.y + r),
393
            cvLine( image, cvPoint( pt.x - r, pt.y + r),
190
                    cvPoint( pt.x + r, pt.y - r), color, line_width, line_type, shift );
394
                    cvPoint( pt.x + r, pt.y - r), color, line_width, line_type, shift );
191
            cvCircle( image, pt, r+(1<<shift), color, line_width, line_type, shift );
395
            cvCircle( image, pt, r+(1<<shift), color, line_width, line_type, shift );
192
        }
396
        }
193
    }
397
    }
194
    else
398
    else
195
    {
399
    {
196
        int x, y;
400
        int x, y;
197
        CvPoint prev_pt = {0, 0};
401
        CvPoint prev_pt = {0, 0};
198
        const int line_max = 7;
402
        const int line_max = 7;
199
        static const CvScalar line_colors[line_max] =
403
        static const CvScalar line_colors[line_max] =
200
        {
404
        {
201
            {{0,0,255}},
405
            {{0,0,255}},
202
            {{0,128,255}},
406
            {{0,128,255}},
203
            {{0,200,200}},
407
            {{0,200,200}},
204
            {{0,255,0}},
408
            {{0,255,0}},
205
            {{200,200,0}},
409
            {{200,200,0}},
206
            {{255,0,0}},
410
            {{255,0,0}},
207
            {{255,0,255}}
411
            {{255,0,255}}
208
        };
412
        };
209
 
413
 
210
        for( y = 0, i = 0; y < pattern_size.height; y++ )
414
        for( y = 0, i = 0; y < pattern_size.height; y++ )
211
        {
415
        {
212
            CvScalar color = line_colors[y % line_max];
416
            CvScalar color = line_colors[y % line_max];
213
            if( cn == 1 )
417
            if( cn == 1 )
214
                color = cvScalarAll(200);
418
                color = cvScalarAll(200);
215
            color.val[0] *= scale;
419
            color.val[0] *= scale;
216
            color.val[1] *= scale;
420
            color.val[1] *= scale;
217
            color.val[2] *= scale;
421
            color.val[2] *= scale;
218
            color.val[3] *= scale;
422
            color.val[3] *= scale;
219
 
423
 
220
            for( x = 0; x < pattern_size.width; x++, i++ )
424
            for( x = 0; x < pattern_size.width; x++, i++ )
221
            {
425
            {
222
                CvPoint pt;
426
                CvPoint pt;
223
                pt.x = cvRound(corners[i].x*(1 << shift));
427
                pt.x = cvRound(corners[i].x*(1 << shift));
224
                pt.y = cvRound(corners[i].y*(1 << shift));
428
                pt.y = cvRound(corners[i].y*(1 << shift));
225
 
429
 
226
                if( i != 0 )
430
                if( i != 0 )
227
                    cvLine( image, prev_pt, pt, color, 1, line_type, shift );
431
                    cvLine( image, prev_pt, pt, color, 1, line_type, shift );
228
 
432
 
229
                cvLine( image, cvPoint(pt.x - r, pt.y - r),
433
                cvLine( image, cvPoint(pt.x - r, pt.y - r),
230
                        cvPoint(pt.x + r, pt.y + r), color, line_width, line_type, shift );
434
                        cvPoint(pt.x + r, pt.y + r), color, line_width, line_type, shift );
231
                cvLine( image, cvPoint(pt.x - r, pt.y + r),
435
                cvLine( image, cvPoint(pt.x - r, pt.y + r),
232
                        cvPoint(pt.x + r, pt.y - r), color, line_width, line_type, shift );
436
                        cvPoint(pt.x + r, pt.y - r), color, line_width, line_type, shift );
233
                cvCircle( image, pt, r+(1<<shift), color, line_width, line_type, shift );
437
                cvCircle( image, pt, r+(1<<shift), color, line_width, line_type, shift );
234
                prev_pt = pt;
438
                prev_pt = pt;
235
            }
439
            }
236
        }
440
        }
237
    }
441
    }
238
}
442
}
239
 
443
 
240
// Returns the result of mod(mat(x,y), moduli) for each matrix element
444
// Returns the result of mod(mat(x,y), moduli) for each matrix element
241
cv::Mat modulo(const cv::Mat &mat, float n){
445
cv::Mat modulo(const cv::Mat &mat, float n){
242
 
446
 
243
    cv::Mat ret(mat.rows, mat.cols, mat.type());
447
    cv::Mat ret(mat.rows, mat.cols, mat.type());
244
 
448
 
245
    for(int row=0; row<ret.rows; row++){
449
    for(int row=0; row<ret.rows; row++){
246
        for(int col=0; col<ret.cols; col++){
450
        for(int col=0; col<ret.cols; col++){
247
            float val = mat.at<float>(row, col);
451
            float val = mat.at<float>(row, col);
248
            // note: std::fmod calculates the remainder, not arithmetic modulo
452
            // note: std::fmod calculates the remainder, not arithmetic modulo
249
            ret.at<float>(row, col) = val - n * std::floor(val / n);
453
            ret.at<float>(row, col) = val - n * std::floor(val / n);
250
        }
454
        }
251
    }
455
    }
252
 
456
 
253
    return ret;
457
    return ret;
254
}
458
}
255
 
459
 
256
// Convert a 3xN matrix to a vector of Point3fs.
460
// Convert a 3xN matrix to a vector of Point3fs.
257
void matToPoints3f(const cv::Mat &mat, std::vector<cv::Point3f> &points){
461
void matToPoints3f(const cv::Mat &mat, std::vector<cv::Point3f> &points){
258
 
462
 
259
    unsigned int nPoints = mat.cols;
463
    unsigned int nPoints = mat.cols;
260
    points.resize(nPoints);
464
    points.resize(nPoints);
261
 
465
 
262
    for(unsigned int i=0; i<nPoints; i++)
466
    for(unsigned int i=0; i<nPoints; i++)
263
        points[i] = cv::Point3f(mat.at<float>(0, i), mat.at<float>(1, i), mat.at<float>(2, i));
467
        points[i] = cv::Point3f(mat.at<float>(0, i), mat.at<float>(1, i), mat.at<float>(2, i));
264
}
468
}
265
 
469
 
266
// Convert a (Dim+1)xN matrix of homogenous points to a DimxN matrix of points in non-homogenous coordinates.
470
// Convert a (Dim+1)xN matrix of homogenous points to a DimxN matrix of points in non-homogenous coordinates.
267
void convertMatFromHomogeneous(cv::Mat &src, cv::Mat &dst){
471
void convertMatFromHomogeneous(cv::Mat &src, cv::Mat &dst){
268
    unsigned int N = src.cols;
472
    unsigned int N = src.cols;
269
    unsigned int Dim = src.rows-1;
473
    unsigned int Dim = src.rows-1;
270
    dst.create(Dim, N, src.type());
474
    dst.create(Dim, N, src.type());
271
    for(unsigned int i=0; i<N; i++){
475
    for(unsigned int i=0; i<N; i++){
272
        for(unsigned int j=0; j<Dim; j++)
476
        for(unsigned int j=0; j<Dim; j++)
273
            dst.at<float>(j,i) = src.at<float>(j,i)/src.at<float>(Dim,i);
477
            dst.at<float>(j,i) = src.at<float>(j,i)/src.at<float>(Dim,i);
274
    }
478
    }
275
 
479
 
276
}
480
}
277
 
481
 
278
// Function to solve the hand-eye (or eye-in-hand) calibration problem.
482
// Function to solve the hand-eye (or eye-in-hand) calibration problem.
279
// Finds [Omega | tau], to minimize ||[R_mark | t_mark][Omega | tau] - [Omega | tau][R | t]||^2
483
// Finds [Omega | tau], to minimize ||[R_mark | t_mark][Omega | tau] - [Omega | tau][R | t]||^2
280
// Algorithm according to Tsai, Lenz, A new technique for fully autonomous and efficient 3d robotics hand-eye calibration
484
// Algorithm according to Tsai, Lenz, A new technique for fully autonomous and efficient 3d robotics hand-eye calibration
281
// DTU, 2014, Jakob Wilm
485
// DTU, 2014, Jakob Wilm
282
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){
486
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){
283
 
487
 
284
    int N = R.size();
488
    int N = R.size();
285
    assert(N == R_mark.size());
489
    assert(N == R_mark.size());
286
    assert(N == t.size());
490
    assert(N == t.size());
287
    assert(N == t_mark.size());
491
    assert(N == t_mark.size());
288
 
492
 
289
    // construct equations for rotation
493
    // construct equations for rotation
290
    cv::Mat A(3*N, 3, CV_32F);
494
    cv::Mat A(3*N, 3, CV_32F);
291
    cv::Mat b(3*N, 1, CV_32F);
495
    cv::Mat b(3*N, 1, CV_32F);
292
    for(int i=0; i<N; i++){
496
    for(int i=0; i<N; i++){
293
        // angle axis representations
497
        // angle axis representations
294
        cv::Vec3f rot;
498
        cv::Vec3f rot;
295
        cv::Vec3f rot_mark;
499
        cv::Vec3f rot_mark;
296
        cv::Rodrigues(R[i], rot);
500
        cv::Rodrigues(R[i], rot);
297
        cv::Rodrigues(R_mark[i], rot_mark);
501
        cv::Rodrigues(R_mark[i], rot_mark);
298
 
502
 
299
        cv::Vec3f P = 2.0*sin(cv::norm(rot)/2.0)*cv::normalize(rot);
503
        cv::Vec3f P = 2.0*sin(cv::norm(rot)/2.0)*cv::normalize(rot);
300
//std::cout << "P: " << std::endl << P << std::endl;
504
//std::cout << "P: " << std::endl << P << std::endl;
301
        cv::Vec3f P_mark = 2.0*sin(cv::norm(rot_mark)/2.0)*cv::normalize(rot_mark);
505
        cv::Vec3f P_mark = 2.0*sin(cv::norm(rot_mark)/2.0)*cv::normalize(rot_mark);
302
//std::cout << "P_mark: " << std::endl << P_mark << std::endl;
506
//std::cout << "P_mark: " << std::endl << P_mark << std::endl;
303
        cv::Vec3f sum = P+P_mark;
507
        cv::Vec3f sum = P+P_mark;
304
        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);
508
        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);
305
//std::cout << "crossProduct: " << std::endl << crossProduct << std::endl;
509
//std::cout << "crossProduct: " << std::endl << crossProduct << std::endl;
306
        crossProduct.copyTo(A.rowRange(i*3, i*3+3));
510
        crossProduct.copyTo(A.rowRange(i*3, i*3+3));
307
 
511
 
308
        cv::Mat(P-P_mark).copyTo(b.rowRange(i*3, i*3+3));
512
        cv::Mat(P-P_mark).copyTo(b.rowRange(i*3, i*3+3));
309
    }
513
    }
310
 
514
 
311
    // solve for rotation
515
    // solve for rotation
312
    cv::Vec3f P_prime;
516
    cv::Vec3f P_prime;
313
    cv::solve(A, b, P_prime, cv::DECOMP_SVD);
517
    cv::solve(A, b, P_prime, cv::DECOMP_SVD);
314
    cv::Vec3f P = 2.0*P_prime/(cv::sqrt(1.0 + cv::norm(P_prime)*cv::norm(P_prime)));
518
    cv::Vec3f P = 2.0*P_prime/(cv::sqrt(1.0 + cv::norm(P_prime)*cv::norm(P_prime)));
315
    float nP = cv::norm(P);
519
    float nP = cv::norm(P);
316
    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);
520
    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);
317
    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);
521
    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);
318
    Omega = cv::Matx33f(OmegaMat);
522
    Omega = cv::Matx33f(OmegaMat);
319
 
523
 
320
    // construct equations for translation
524
    // construct equations for translation
321
    A.setTo(0.0);
525
    A.setTo(0.0);
322
    b.setTo(0.0);
526
    b.setTo(0.0);
323
    for(int i=0; i<N; i++){
527
    for(int i=0; i<N; i++){
324
 
528
 
325
        cv::Mat diff = cv::Mat(R_mark[i]) - cv::Mat::eye(3, 3, CV_32F);
529
        cv::Mat diff = cv::Mat(R_mark[i]) - cv::Mat::eye(3, 3, CV_32F);
326
        diff.copyTo(A.rowRange(i*3, i*3+3));
530
        diff.copyTo(A.rowRange(i*3, i*3+3));
327
 
531
 
328
        cv::Mat diff_mark = cv::Mat(Omega*t[i] - t_mark[i]);
532
        cv::Mat diff_mark = cv::Mat(Omega*t[i] - t_mark[i]);
329
        diff_mark.copyTo(b.rowRange(i*3, i*3+3));
533
        diff_mark.copyTo(b.rowRange(i*3, i*3+3));
330
    }
534
    }
331
 
535
 
332
    // solve for translation
536
    // solve for translation
333
    cv::solve(A, b, tau, cv::DECOMP_SVD);
537
    cv::solve(A, b, tau, cv::DECOMP_SVD);
334
 
538
 
335
    cv::Mat err_tau = b - (A*cv::Mat(tau));
539
    cv::Mat err_tau = b - (A*cv::Mat(tau));
336
    std::cout << err_tau << std::endl;
540
    std::cout << err_tau << std::endl;
337
}
541
}
338
 
542
 
339
// Function to solve for the rotation axis from sets of 3D point coordinates of flat pattern feature points
543
// Function to solve for the rotation axis from sets of 3D point coordinates of flat pattern feature points
340
// Algorithm according to Chen et al., Rotation axis calibration of a turntable using constrained global optimization, Optik 2014
544
// Algorithm according to Chen et al., Rotation axis calibration of a turntable using constrained global optimization, Optik 2014
341
// DTU, 2014, Jakob Wilm
545
// DTU, 2014, Jakob Wilm
342
void rotationAxisCalibration(const std::vector< std::vector<cv::Point3f> > Qcam, const std::vector<cv::Point3f> Qobj, cv::Vec3f &axis, cv::Vec3f &point){
546
void rotationAxisCalibration(const std::vector< std::vector<cv::Point3f> > Qcam, const std::vector<cv::Point3f> Qobj, cv::Vec3f &axis, cv::Vec3f &point){
343
 
547
 
344
    // number of frames (points on each arch)
548
    // number of frames (points on each arch)
345
    int l = Qcam.size();
549
    int l = Qcam.size();
346
 
550
 
347
    // number of points in each frame
551
    // number of points in each frame
348
    int mn = Qobj.size();
552
    int mn = Qobj.size();
349
 
553
 
350
    assert(mn == Qcam[0].size());
554
    assert(mn == Qcam[0].size());
351
 
555
 
352
    // construct matrix for axis determination
556
    // construct matrix for axis determination
353
    cv::Mat M(6, 6, CV_32F, cv::Scalar(0));
557
    cv::Mat M(6, 6, CV_32F, cv::Scalar(0));
354
 
558
 
355
    for(int k=0; k<l; k++){
559
    for(int k=0; k<l; k++){
356
        for(int idx=0; idx<mn; idx++){
560
        for(int idx=0; idx<mn; idx++){
357
 
561
 
358
//            float i = Qobj[idx].x+4;
562
//            float i = Qobj[idx].x+4;
359
//            float j = Qobj[idx].y+4;
563
//            float j = Qobj[idx].y+4;
360
            float i = Qobj[idx].x;
564
            float i = Qobj[idx].x;
361
            float j = Qobj[idx].y;
565
            float j = Qobj[idx].y;
362
 
566
 
363
            float x = Qcam[k][idx].x;
567
            float x = Qcam[k][idx].x;
364
            float y = Qcam[k][idx].y;
568
            float y = Qcam[k][idx].y;
365
            float z = Qcam[k][idx].z;
569
            float z = Qcam[k][idx].z;
366
 
570
 
367
            M += (cv::Mat_<float>(6,6) << x*x, x*y, x*z, x, i*x, j*x,
571
            M += (cv::Mat_<float>(6,6) << x*x, x*y, x*z, x, i*x, j*x,
368
                                            0, y*y, y*z, y, i*y, j*y,
572
                                            0, y*y, y*z, y, i*y, j*y,
369
                                            0,   0, z*z, z, i*z, j*z,
573
                                            0,   0, z*z, z, i*z, j*z,
370
                                            0,   0,   0, 1,   i,   j,
574
                                            0,   0,   0, 1,   i,   j,
371
                                            0,   0,   0, 0, i*i, i*j,
575
                                            0,   0,   0, 0, i*i, i*j,
372
                                            0,   0,   0, 0,   0, j*j);
576
                                            0,   0,   0, 0,   0, j*j);
373
 
577
 
374
        }
578
        }
375
    }
579
    }
376
 
580
 
377
    cv::completeSymm(M, false);
581
    cv::completeSymm(M, false);
378
 
582
 
379
    // solve for axis
583
    // solve for axis
380
    std::vector<float> lambda;
584
    std::vector<float> lambda;
381
    cv::Mat u;
585
    cv::Mat u;
382
    cv::eigen(M, lambda, u);
586
    cv::eigen(M, lambda, u);
383
 
587
 
384
    float minLambda = abs(lambda[0]);
588
    float minLambda = abs(lambda[0]);
385
    int idx = 0;
589
    int idx = 0;
386
    for(int i=1; i<lambda.size(); i++){
590
    for(int i=1; i<lambda.size(); i++){
387
        if(abs(lambda[i]) < minLambda){
591
        if(abs(lambda[i]) < minLambda){
388
            minLambda = lambda[i];
592
            minLambda = lambda[i];
389
            idx = i;
593
            idx = i;
390
        }
594
        }
391
    }
595
    }
392
 
596
 
393
    axis = u.row(idx).colRange(0, 3);
597
    axis = u.row(idx).colRange(0, 3);
394
    axis = cv::normalize(axis);
598
    axis = cv::normalize(axis);
395
 
599
 
396
    float nx = u.at<float>(idx, 0);
600
    float nx = u.at<float>(idx, 0);
397
    float ny = u.at<float>(idx, 1);
601
    float ny = u.at<float>(idx, 1);
398
    float nz = u.at<float>(idx, 2);
602
    float nz = u.at<float>(idx, 2);
399
    float d  = u.at<float>(idx, 3);
603
    float d  = u.at<float>(idx, 3);
400
    float dh = u.at<float>(idx, 4);
604
    float dh = u.at<float>(idx, 4);
401
    float dv = u.at<float>(idx, 5);
605
    float dv = u.at<float>(idx, 5);
402
 
606
 
403
//    // Paper version: c is initially eliminated
607
//    // Paper version: c is initially eliminated
404
//    cv::Mat A(l*mn, mn+2, CV_32F, cv::Scalar(0.0));
608
//    cv::Mat A(l*mn, mn+2, CV_32F, cv::Scalar(0.0));
405
//    cv::Mat bb(l*mn, 1, CV_32F);
609
//    cv::Mat bb(l*mn, 1, CV_32F);
406
 
610
 
407
//    for(int k=0; k<l; k++){
611
//    for(int k=0; k<l; k++){
408
//        for(int idx=0; idx<mn; idx++){
612
//        for(int idx=0; idx<mn; idx++){
409
 
613
 
410
//            float i = Qobj[idx].x;
614
//            float i = Qobj[idx].x;
411
//            float j = Qobj[idx].y;
615
//            float j = Qobj[idx].y;
412
 
616
 
413
//            float x = Qcam[k][idx].x;
617
//            float x = Qcam[k][idx].x;
414
//            float y = Qcam[k][idx].y;
618
//            float y = Qcam[k][idx].y;
415
//            float z = Qcam[k][idx].z;
619
//            float z = Qcam[k][idx].z;
416
 
620
 
417
//            float f = x*x + y*y + z*z + (2*x*nx + 2*y*ny + 2*z*nz)*(i*dh + j*dv);
621
//            float f = x*x + y*y + z*z + (2*x*nx + 2*y*ny + 2*z*nz)*(i*dh + j*dv);
418
 
622
 
419
//            int row = k*mn+idx;
623
//            int row = k*mn+idx;
420
//            A.at<float>(row, 0) = 2*x - (2*z*nx)/nz;
624
//            A.at<float>(row, 0) = 2*x - (2*z*nx)/nz;
421
//            A.at<float>(row, 1) = 2*y - (2*z*ny)/nz;
625
//            A.at<float>(row, 1) = 2*y - (2*z*ny)/nz;
422
//            A.at<float>(row, idx+2) = 1.0;
626
//            A.at<float>(row, idx+2) = 1.0;
423
 
627
 
424
//            bb.at<float>(row, 0) = f + (2*z*d)/nz;
628
//            bb.at<float>(row, 0) = f + (2*z*d)/nz;
425
//        }
629
//        }
426
//    }
630
//    }
427
 
631
 
428
//    // solve for point
632
//    // solve for point
429
//    cv::Mat abe;
633
//    cv::Mat abe;
430
//    cv::solve(A, bb, abe, cv::DECOMP_SVD);
634
//    cv::solve(A, bb, abe, cv::DECOMP_SVD);
431
 
635
 
432
//    float a = abe.at<float>(0, 0);
636
//    float a = abe.at<float>(0, 0);
433
//    float b = abe.at<float>(1, 0);
637
//    float b = abe.at<float>(1, 0);
434
//    float c = -(nx*a+ny*b+d)/nz;
638
//    float c = -(nx*a+ny*b+d)/nz;
435
 
639
 
436
    // Our version: solve simultanously for a,b,c
640
    // Our version: solve simultanously for a,b,c
437
    cv::Mat A(l*mn, mn+3, CV_32F, cv::Scalar(0.0));
641
    cv::Mat A(l*mn, mn+3, CV_32F, cv::Scalar(0.0));
438
    cv::Mat bb(l*mn, 1, CV_32F);
642
    cv::Mat bb(l*mn, 1, CV_32F);
439
 
643
 
440
    for(int k=0; k<l; k++){
644
    for(int k=0; k<l; k++){
441
        for(int idx=0; idx<mn; idx++){
645
        for(int idx=0; idx<mn; idx++){
442
 
646
 
443
            float i = Qobj[idx].x;
647
            float i = Qobj[idx].x;
444
            float j = Qobj[idx].y;
648
            float j = Qobj[idx].y;
445
 
649
 
446
            float x = Qcam[k][idx].x;
650
            float x = Qcam[k][idx].x;
447
            float y = Qcam[k][idx].y;
651
            float y = Qcam[k][idx].y;
448
            float z = Qcam[k][idx].z;
652
            float z = Qcam[k][idx].z;
449
 
653
 
450
            float f = x*x + y*y + z*z + (2*x*nx + 2*y*ny + 2*z*nz)*(i*dh + j*dv);
654
            float f = x*x + y*y + z*z + (2*x*nx + 2*y*ny + 2*z*nz)*(i*dh + j*dv);
451
 
655
 
452
            int row = k*mn+idx;
656
            int row = k*mn+idx;
453
            A.at<float>(row, 0) = 2*x;
657
            A.at<float>(row, 0) = 2*x;
454
            A.at<float>(row, 1) = 2*y;
658
            A.at<float>(row, 1) = 2*y;
455
            A.at<float>(row, 2) = 2*z;
659
            A.at<float>(row, 2) = 2*z;
456
            A.at<float>(row, idx+3) = 1.0;
660
            A.at<float>(row, idx+3) = 1.0;
457
 
661
 
458
            bb.at<float>(row, 0) = f;
662
            bb.at<float>(row, 0) = f;
459
        }
663
        }
460
    }
664
    }
461
 
665
 
462
    // solve for point
666
    // solve for point
463
    cv::Mat abe;
667
    cv::Mat abe;
464
    cv::solve(A, bb, abe, cv::DECOMP_SVD);
668
    cv::solve(A, bb, abe, cv::DECOMP_SVD);
465
 
669
 
466
    float a = abe.at<float>(0, 0);
670
    float a = abe.at<float>(0, 0);
467
    float b = abe.at<float>(1, 0);
671
    float b = abe.at<float>(1, 0);
468
    float c = abe.at<float>(2, 0);
672
    float c = abe.at<float>(2, 0);
469
 
673
 
470
    point[0] = a;
674
    point[0] = a;
471
    point[1] = b;
675
    point[1] = b;
472
    point[2] = c;
676
    point[2] = c;
473
 
677
 
474
}
678
}
475
 
679
 
476
// Function to fit two sets of corresponding pose data.
680
// Function to fit two sets of corresponding pose data.
477
// Finds [Omega | tau], to minimize ||[R_mark | t_mark] - [Omega | tau][R | t]||^2
681
// Finds [Omega | tau], to minimize ||[R_mark | t_mark] - [Omega | tau][R | t]||^2
478
// Algorithm and notation according to Mili Shah, Comparing two sets of corresponding six degree of freedom data, CVIU 2011.
682
// Algorithm and notation according to Mili Shah, Comparing two sets of corresponding six degree of freedom data, CVIU 2011.
479
// DTU, 2013, Oline V. Olesen, Jakob Wilm
683
// DTU, 2013, Oline V. Olesen, Jakob Wilm
480
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){
684
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){
481
 
685
 
482
    int N = R.size();
686
    int N = R.size();
483
    assert(N == R_mark.size());
687
    assert(N == R_mark.size());
484
    assert(N == t.size());
688
    assert(N == t.size());
485
    assert(N == t_mark.size());
689
    assert(N == t_mark.size());
486
 
690
 
487
    // Mean translations
691
    // Mean translations
488
    cv::Vec3f t_mean;
692
    cv::Vec3f t_mean;
489
    cv::Vec3f t_mark_mean;
693
    cv::Vec3f t_mark_mean;
490
    for(int i=0; i<N; i++){
694
    for(int i=0; i<N; i++){
491
        t_mean += 1.0/N * t[i];
695
        t_mean += 1.0/N * t[i];
492
        t_mark_mean += 1.0/N * t_mark[i];
696
        t_mark_mean += 1.0/N * t_mark[i];
493
    }
697
    }
494
 
698
 
495
    // Data with mean adjusted translations
699
    // Data with mean adjusted translations
496
    cv::Mat X_bar(3, 4*N, CV_32F);
700
    cv::Mat X_bar(3, 4*N, CV_32F);
497
    cv::Mat X_mark_bar(3, 4*N, CV_32F);
701
    cv::Mat X_mark_bar(3, 4*N, CV_32F);
498
    for(int i=0; i<N; i++){
702
    for(int i=0; i<N; i++){
499
        cv::Mat(R[i]).copyTo(X_bar.colRange(i*4,i*4+3));
703
        cv::Mat(R[i]).copyTo(X_bar.colRange(i*4,i*4+3));
500
        cv::Mat(t[i] - t_mean).copyTo(X_bar.col(i*4+3));
704
        cv::Mat(t[i] - t_mean).copyTo(X_bar.col(i*4+3));
501
        cv::Mat(R_mark[i]).copyTo(X_mark_bar.colRange(i*4,i*4+3));
705
        cv::Mat(R_mark[i]).copyTo(X_mark_bar.colRange(i*4,i*4+3));
502
        cv::Mat(t_mark[i] - t_mark_mean).copyTo(X_mark_bar.col(i*4+3));
706
        cv::Mat(t_mark[i] - t_mark_mean).copyTo(X_mark_bar.col(i*4+3));
503
    }
707
    }
504
    //std::cout << X_bar << std::endl;
708
    //std::cout << X_bar << std::endl;
505
    // SVD
709
    // SVD
506
    cv::Mat W, U, VT;
710
    cv::Mat W, U, VT;
507
    cv::SVDecomp(X_bar*X_mark_bar.t(), W, U, VT);
711
    cv::SVDecomp(X_bar*X_mark_bar.t(), W, U, VT);
508
 
712
 
509
    cv::Matx33f D = cv::Matx33f::eye();
713
    cv::Matx33f D = cv::Matx33f::eye();
510
    if(cv::determinant(VT*U) < 0)
714
    if(cv::determinant(VT*U) < 0)
511
        D(3,3) = -1;
715
        D(3,3) = -1;
512
 
716
 
513
    // Best rotation
717
    // Best rotation
514
    Omega = cv::Matx33f(cv::Mat(VT.t()))*D*cv::Matx33f(cv::Mat(U.t()));
718
    Omega = cv::Matx33f(cv::Mat(VT.t()))*D*cv::Matx33f(cv::Mat(U.t()));
515
 
719
 
516
    // Best translation
720
    // Best translation
517
    tau = t_mark_mean - Omega*t_mean;
721
    tau = t_mark_mean - Omega*t_mean;
518
 
722
 
519
}
723
}
520
 
724
 
521
// Forward distortion of points. The inverse of the undistortion in cv::initUndistortRectifyMap().
725
// Forward distortion of points. The inverse of the undistortion in cv::initUndistortRectifyMap().
522
// Inspired by Pascal Thomet, http://code.opencv.org/issues/1387#note-11
726
// Inspired by Pascal Thomet, http://code.opencv.org/issues/1387#note-11
523
// Convention for distortion parameters: http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/parameters.html
727
// Convention for distortion parameters: http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/parameters.html
524
void initDistortMap(const cv::Matx33f cameraMatrix, const cv::Vec<float, 5> distCoeffs, const cv::Size size, cv::Mat &map1, cv::Mat &map2){
728
void initDistortMap(const cv::Matx33f cameraMatrix, const cv::Vec<float, 5> distCoeffs, const cv::Size size, cv::Mat &map1, cv::Mat &map2){
525
 
729
 
526
    float fx = cameraMatrix(0,0);
730
    float fx = cameraMatrix(0,0);
527
    float fy = cameraMatrix(1,1);
731
    float fy = cameraMatrix(1,1);
528
    float ux = cameraMatrix(0,2);
732
    float ux = cameraMatrix(0,2);
529
    float uy = cameraMatrix(1,2);
733
    float uy = cameraMatrix(1,2);
530
 
734
 
531
    float k1 = distCoeffs[0];
735
    float k1 = distCoeffs[0];
532
    float k2 = distCoeffs[1];
736
    float k2 = distCoeffs[1];
533
    float p1 = distCoeffs[2];
737
    float p1 = distCoeffs[2];
534
    float p2 = distCoeffs[3];
738
    float p2 = distCoeffs[3];
535
    float k3 = distCoeffs[4];
739
    float k3 = distCoeffs[4];
536
 
740
 
537
    map1.create(size, CV_32F);
741
    map1.create(size, CV_32F);
538
    map2.create(size, CV_32F);
742
    map2.create(size, CV_32F);
539
 
743
 
540
    for(int col = 0; col < size.width; col++){
744
    for(int col = 0; col < size.width; col++){
541
        for(int row = 0; row < size.height; row++){
745
        for(int row = 0; row < size.height; row++){
542
 
746
 
543
            // move origo to principal point and convert using focal length
747
            // move origo to principal point and convert using focal length
544
            float x = (col-ux)/fx;
748
            float x = (col-ux)/fx;
545
            float y = (row-uy)/fy;
749
            float y = (row-uy)/fy;
546
 
750
 
547
            float xCorrected, yCorrected;
751
            float xCorrected, yCorrected;
548
 
752
 
549
            //Step 1 : correct distortion
753
            //Step 1 : correct distortion
550
            float r2 = x*x + y*y;
754
            float r2 = x*x + y*y;
551
            //radial
755
            //radial
552
            xCorrected = x * (1. + k1*r2 + k2*r2*r2 + k3*r2*r2*r2);
756
            xCorrected = x * (1. + k1*r2 + k2*r2*r2 + k3*r2*r2*r2);
553
            yCorrected = y * (1. + k1*r2 + k2*r2*r2 + k3*r2*r2*r2);
757
            yCorrected = y * (1. + k1*r2 + k2*r2*r2 + k3*r2*r2*r2);
554
            //tangential
758
            //tangential
555
            xCorrected = xCorrected + (2.*p1*x*y + p2*(r2+2.*x*x));
759
            xCorrected = xCorrected + (2.*p1*x*y + p2*(r2+2.*x*x));
556
            yCorrected = yCorrected + (p1*(r2+2.*y*y) + 2.*p2*x*y);
760
            yCorrected = yCorrected + (p1*(r2+2.*y*y) + 2.*p2*x*y);
557
 
761
 
558
            //convert back to pixel coordinates
762
            //convert back to pixel coordinates
559
            float col_displaced = xCorrected * fx + ux;
763
            float col_displaced = xCorrected * fx + ux;
560
            float row_displaced = yCorrected * fy + uy;
764
            float row_displaced = yCorrected * fy + uy;
561
 
765
 
562
            // correct the vector in the opposite direction
766
            // correct the vector in the opposite direction
563
            map1.at<float>(row,col) = col+(col-col_displaced);
767
            map1.at<float>(row,col) = col+(col-col_displaced);
564
            map2.at<float>(row,col) = row +(row-row_displaced);
768
            map2.at<float>(row,col) = row +(row-row_displaced);
565
        }
769
        }
566
    }
770
    }
567
}
771
}
568
 
772
 
569
// Downsample a texture which was created in virtual column/row space for a diamond pixel array projector
773
// Downsample a texture which was created in virtual column/row space for a diamond pixel array projector
570
cv::Mat diamondDownsample(cv::Mat &pattern){
774
cv::Mat diamondDownsample(cv::Mat &pattern){
571
 
775
 
572
    cv::Mat pattern_diamond(pattern.rows,pattern.cols/2,CV_8UC3);
776
    cv::Mat pattern_diamond(pattern.rows,pattern.cols/2,CV_8UC3);
573
 
777
 
574
    for(unsigned int col = 0; col < pattern_diamond.cols; col++){
778
    for(unsigned int col = 0; col < pattern_diamond.cols; col++){
575
        for(unsigned int row = 0; row < pattern_diamond.rows; row++){
779
        for(unsigned int row = 0; row < pattern_diamond.rows; row++){
576
 
780
 
577
            pattern_diamond.at<cv::Vec3b>(row,col)=pattern.at<cv::Vec3b>(row,col*2+row%2);
781
            pattern_diamond.at<cv::Vec3b>(row,col)=pattern.at<cv::Vec3b>(row,col*2+row%2);
578
        }
782
        }
579
    }
783
    }
580
 
784
 
581
    return pattern_diamond;
785
    return pattern_diamond;
582
 
786
 
583
}
787
}
584
 
788
 
585
 
789
 
586
void mouseCallback(int evt, int x, int y, int flags, void* param){
790
void mouseCallback(int evt, int x, int y, int flags, void* param){
587
    cv::Mat *im = (cv::Mat*) param;
791
    cv::Mat *im = (cv::Mat*) param;
588
    if (evt == CV_EVENT_LBUTTONDOWN) {
792
    if (evt == CV_EVENT_LBUTTONDOWN) {
589
        if(im->type() == CV_8UC3){
793
        if(im->type() == CV_8UC3){
590
            printf("%d %d: %d, %d, %d\n",
794
            printf("%d %d: %d, %d, %d\n",
591
                   x, y,
795
                   x, y,
592
                   (int)(*im).at<cv::Vec3b>(y, x)[0],
796
                   (int)(*im).at<cv::Vec3b>(y, x)[0],
593
                    (int)(*im).at<cv::Vec3b>(y, x)[1],
797
                    (int)(*im).at<cv::Vec3b>(y, x)[1],
594
                    (int)(*im).at<cv::Vec3b>(y, x)[2]);
798
                    (int)(*im).at<cv::Vec3b>(y, x)[2]);
595
        } else if (im->type() == CV_32F) {
799
        } else if (im->type() == CV_32F) {
596
            printf("%d %d: %f\n",
800
            printf("%d %d: %f\n",
597
                   x, y,
801
                   x, y,
598
                   im->at<float>(y, x));
802
                   im->at<float>(y, x));
599
        }
803
        }
600
    }
804
    }
601
}
805
}
602
 
806
 
603
void imshow(const char *windowName, cv::Mat im, unsigned int x, unsigned int y){
807
void imshow(const char *windowName, cv::Mat im, unsigned int x, unsigned int y){
604
 
808
 
605
    // Imshow
809
    // Imshow
606
    if(!cvGetWindowHandle(windowName)){
810
    if(!cvGetWindowHandle(windowName)){
607
        int windowFlags = CV_GUI_EXPANDED | CV_WINDOW_KEEPRATIO;
811
        int windowFlags = CV_GUI_EXPANDED | CV_WINDOW_KEEPRATIO;
608
        cv::namedWindow(windowName, windowFlags);
812
        cv::namedWindow(windowName, windowFlags);
609
        cv::moveWindow(windowName, x, y);
813
        cv::moveWindow(windowName, x, y);
610
    }
814
    }
611
    cv::imshow(windowName, im);
815
    cv::imshow(windowName, im);
612
}
816
}
613
 
817
 
614
void imagesc(const char *windowName, cv::Mat im){
818
void imagesc(const char *windowName, cv::Mat im){
615
 
819
 
616
    // Imshow with scaled image
820
    // Imshow with scaled image
617
 
821
 
618
 
822
 
619
}
823
}
620
 
824
 
621
cv::Mat histimage(cv::Mat histogram){
825
cv::Mat histimage(cv::Mat histogram){
622
 
826
 
623
    cv::Mat histImage(512, 640, CV_8UC3, cv::Scalar(0));
827
    cv::Mat histImage(512, 640, CV_8UC3, cv::Scalar(0));
624
 
828
 
625
    // Normalize the result to [ 2, histImage.rows-2 ]
829
    // Normalize the result to [ 2, histImage.rows-2 ]
626
    cv::normalize(histogram, histogram, 2, histImage.rows-2, cv::NORM_MINMAX, -1, cv::Mat());
830
    cv::normalize(histogram, histogram, 2, histImage.rows-2, cv::NORM_MINMAX, -1, cv::Mat());
627
 
831
 
628
    float bin_w = (float)histImage.cols/(float)histogram.rows;
832
    float bin_w = (float)histImage.cols/(float)histogram.rows;
629
 
833
 
630
    // Draw main histogram
834
    // Draw main histogram
631
    for(int i = 1; i < histogram.rows-10; i++){
835
    for(int i = 1; i < histogram.rows-10; i++){
632
        cv::line(histImage, cv::Point( bin_w*(i-1), histImage.rows - cvRound(histogram.at<float>(i-1)) ),
836
        cv::line(histImage, cv::Point( bin_w*(i-1), histImage.rows - cvRound(histogram.at<float>(i-1)) ),
633
                 cv::Point( bin_w*(i), histImage.rows - cvRound(histogram.at<float>(i)) ),
837
                 cv::Point( bin_w*(i), histImage.rows - cvRound(histogram.at<float>(i)) ),
634
                 cv::Scalar(255, 255, 255), 2, 4);
838
                 cv::Scalar(255, 255, 255), 2, 4);
635
    }
839
    }
636
 
840
 
637
    // Draw red max
841
    // Draw red max
638
    for(int i = histogram.rows-10; i < histogram.rows; i++){
842
    for(int i = histogram.rows-10; i < histogram.rows; i++){
639
        cv::line(histImage, cv::Point( bin_w*(i-1), histImage.rows - cvRound(histogram.at<float>(i-1)) ),
843
        cv::line(histImage, cv::Point( bin_w*(i-1), histImage.rows - cvRound(histogram.at<float>(i-1)) ),
640
                 cv::Point( bin_w*(i), histImage.rows - cvRound(histogram.at<float>(i)) ),
844
                 cv::Point( bin_w*(i), histImage.rows - cvRound(histogram.at<float>(i)) ),
641
                 cv::Scalar(0, 0, 255), 2, 4);
845
                 cv::Scalar(0, 0, 255), 2, 4);
642
    }
846
    }
643
 
847
 
644
    return histImage;
848
    return histImage;
645
}
849
}
646
 
850
 
647
void hist(const char *windowName, cv::Mat histogram, unsigned int x, unsigned int y){
851
void hist(const char *windowName, cv::Mat histogram, unsigned int x, unsigned int y){
648
 
852
 
649
    // Display
853
    // Display
650
    imshow(windowName, histimage(histogram), x, y);
854
    imshow(windowName, histimage(histogram), x, y);
651
    cv::Point(1,2);
855
    cv::Point(1,2);
652
}
856
}
653
 
857
 
654
 
858
 
655
void writeMat(cv::Mat const& mat, const char* filename, const char* varName, bool bgr2rgb){
859
void writeMat(cv::Mat const& mat, const char* filename, const char* varName, bool bgr2rgb){
656
    /*!
860
    /*!
657
         *  \author Philip G. Lee <rocketman768@gmail.com>
861
         *  \author Philip G. Lee <rocketman768@gmail.com>
658
         *  Write \b mat into \b filename
862
         *  Write \b mat into \b filename
659
         *  in uncompressed .mat format (Level 5 MATLAB) for Matlab.
863
         *  in uncompressed .mat format (Level 5 MATLAB) for Matlab.
660
         *  The variable name in matlab will be \b varName. If
864
         *  The variable name in matlab will be \b varName. If
661
         *  \b bgr2rgb is true and there are 3 channels, swaps 1st and 3rd
865
         *  \b bgr2rgb is true and there are 3 channels, swaps 1st and 3rd
662
         *  channels in the output. This is needed because OpenCV matrices
866
         *  channels in the output. This is needed because OpenCV matrices
663
         *  are bgr, while Matlab is rgb. This has been tested to work with
867
         *  are bgr, while Matlab is rgb. This has been tested to work with
664
         *  3-channel single-precision floating point matrices, and I hope
868
         *  3-channel single-precision floating point matrices, and I hope
665
         *  it works on other types/channels, but not exactly sure.
869
         *  it works on other types/channels, but not exactly sure.
666
         *  Documentation at <http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf>
870
         *  Documentation at <http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf>
667
         */
871
         */
668
    int textLen = 116;
872
    int textLen = 116;
669
    char* text;
873
    char* text;
670
    int subsysOffsetLen = 8;
874
    int subsysOffsetLen = 8;
671
    char* subsysOffset;
875
    char* subsysOffset;
672
    int verLen = 2;
876
    int verLen = 2;
673
    char* ver;
877
    char* ver;
674
    char flags;
878
    char flags;
675
    int bytes;
879
    int bytes;
676
    int padBytes;
880
    int padBytes;
677
    int bytesPerElement;
881
    int bytesPerElement;
678
    int i,j,k,k2;
882
    int i,j,k,k2;
679
    bool doBgrSwap;
883
    bool doBgrSwap;
680
    char mxClass;
884
    char mxClass;
681
    int32_t miClass;
885
    int32_t miClass;
682
    uchar const* rowPtr;
886
    uchar const* rowPtr;
683
    uint32_t tmp32;
887
    uint32_t tmp32;
684
    float tmp;
888
    float tmp;
685
    FILE* fp;
889
    FILE* fp;
686
 
890
 
687
    // Matlab constants.
891
    // Matlab constants.
688
    const uint16_t MI = 0x4d49; // Contains "MI" in ascii.
892
    const uint16_t MI = 0x4d49; // Contains "MI" in ascii.
689
    const int32_t miINT8 = 1;
893
    const int32_t miINT8 = 1;
690
    const int32_t miUINT8 = 2;
894
    const int32_t miUINT8 = 2;
691
    const int32_t miINT16 = 3;
895
    const int32_t miINT16 = 3;
692
    const int32_t miUINT16 = 4;
896
    const int32_t miUINT16 = 4;
693
    const int32_t miINT32 = 5;
897
    const int32_t miINT32 = 5;
694
    const int32_t miUINT32 = 6;
898
    const int32_t miUINT32 = 6;
695
    const int32_t miSINGLE = 7;
899
    const int32_t miSINGLE = 7;
696
    const int32_t miDOUBLE = 9;
900
    const int32_t miDOUBLE = 9;
697
    const int32_t miMATRIX = 14;
901
    const int32_t miMATRIX = 14;
698
    const char mxDOUBLE_CLASS = 6;
902
    const char mxDOUBLE_CLASS = 6;
699
    const char mxSINGLE_CLASS = 7;
903
    const char mxSINGLE_CLASS = 7;
700
    const char mxINT8_CLASS = 8;
904
    const char mxINT8_CLASS = 8;
701
    const char mxUINT8_CLASS = 9;
905
    const char mxUINT8_CLASS = 9;
702
    const char mxINT16_CLASS = 10;
906
    const char mxINT16_CLASS = 10;
703
    const char mxUINT16_CLASS = 11;
907
    const char mxUINT16_CLASS = 11;
704
    const char mxINT32_CLASS = 12;
908
    const char mxINT32_CLASS = 12;
705
    const char mxUINT32_CLASS = 13;
909
    const char mxUINT32_CLASS = 13;
706
    const uint64_t zero = 0; // Used for padding.
910
    const uint64_t zero = 0; // Used for padding.
707
 
911
 
708
    fp = fopen( filename, "wb" );
912
    fp = fopen( filename, "wb" );
709
 
913
 
710
    if( fp == 0 )
914
    if( fp == 0 )
711
        return;
915
        return;
712
 
916
 
713
    const int rows = mat.rows;
917
    const int rows = mat.rows;
714
    const int cols = mat.cols;
918
    const int cols = mat.cols;
715
    const int chans = mat.channels();
919
    const int chans = mat.channels();
716
 
920
 
717
    doBgrSwap = (chans==3) && bgr2rgb;
921
    doBgrSwap = (chans==3) && bgr2rgb;
718
 
922
 
719
    // I hope this mapping is right :-/
923
    // I hope this mapping is right :-/
720
    switch( mat.depth() ){
924
    switch( mat.depth() ){
721
    case CV_8U:
925
    case CV_8U:
722
        mxClass = mxUINT8_CLASS;
926
        mxClass = mxUINT8_CLASS;
723
        miClass = miUINT8;
927
        miClass = miUINT8;
724
        bytesPerElement = 1;
928
        bytesPerElement = 1;
725
        break;
929
        break;
726
    case CV_8S:
930
    case CV_8S:
727
        mxClass = mxINT8_CLASS;
931
        mxClass = mxINT8_CLASS;
728
        miClass = miINT8;
932
        miClass = miINT8;
729
        bytesPerElement = 1;
933
        bytesPerElement = 1;
730
        break;
934
        break;
731
    case CV_16U:
935
    case CV_16U:
732
        mxClass = mxUINT16_CLASS;
936
        mxClass = mxUINT16_CLASS;
733
        miClass = miUINT16;
937
        miClass = miUINT16;
734
        bytesPerElement = 2;
938
        bytesPerElement = 2;
735
        break;
939
        break;
736
    case CV_16S:
940
    case CV_16S:
737
        mxClass = mxINT16_CLASS;
941
        mxClass = mxINT16_CLASS;
738
        miClass = miINT16;
942
        miClass = miINT16;
739
        bytesPerElement = 2;
943
        bytesPerElement = 2;
740
        break;
944
        break;
741
    case CV_32S:
945
    case CV_32S:
742
        mxClass = mxINT32_CLASS;
946
        mxClass = mxINT32_CLASS;
743
        miClass = miINT32;
947
        miClass = miINT32;
744
        bytesPerElement = 4;
948
        bytesPerElement = 4;
745
        break;
949
        break;
746
    case CV_32F:
950
    case CV_32F:
747
        mxClass = mxSINGLE_CLASS;
951
        mxClass = mxSINGLE_CLASS;
748
        miClass = miSINGLE;
952
        miClass = miSINGLE;
749
        bytesPerElement = 4;
953
        bytesPerElement = 4;
750
        break;
954
        break;
751
    case CV_64F:
955
    case CV_64F:
752
        mxClass = mxDOUBLE_CLASS;
956
        mxClass = mxDOUBLE_CLASS;
753
        miClass = miDOUBLE;
957
        miClass = miDOUBLE;
754
        bytesPerElement = 8;
958
        bytesPerElement = 8;
755
        break;
959
        break;
756
    default:
960
    default:
757
        return;
961
        return;
758
    }
962
    }
759
 
963
 
760
    //==================Mat-file header (128 bytes, page 1-5)==================
964
    //==================Mat-file header (128 bytes, page 1-5)==================
761
    text = new char[textLen]; // Human-readable text.
965
    text = new char[textLen]; // Human-readable text.
762
    memset( text, ' ', textLen );
966
    memset( text, ' ', textLen );
763
    text[textLen-1] = '\0';
967
    text[textLen-1] = '\0';
764
    const char* t = "MATLAB 5.0 MAT-file, Platform: PCWIN";
968
    const char* t = "MATLAB 5.0 MAT-file, Platform: PCWIN";
765
    memcpy( text, t, strlen(t) );
969
    memcpy( text, t, strlen(t) );
766
 
970
 
767
    subsysOffset = new char[subsysOffsetLen]; // Zeros for us.
971
    subsysOffset = new char[subsysOffsetLen]; // Zeros for us.
768
    memset( subsysOffset, 0x00, subsysOffsetLen );
972
    memset( subsysOffset, 0x00, subsysOffsetLen );
769
    ver = new char[verLen];
973
    ver = new char[verLen];
770
    ver[0] = 0x00;
974
    ver[0] = 0x00;
771
    ver[1] = 0x01;
975
    ver[1] = 0x01;
772
 
976
 
773
    fwrite( text, 1, textLen, fp );
977
    fwrite( text, 1, textLen, fp );
774
    fwrite( subsysOffset, 1, subsysOffsetLen, fp );
978
    fwrite( subsysOffset, 1, subsysOffsetLen, fp );
775
    fwrite( ver, 1, verLen, fp );
979
    fwrite( ver, 1, verLen, fp );
776
    // Endian indicator. MI will show up as "MI" on big-endian
980
    // Endian indicator. MI will show up as "MI" on big-endian
777
    // systems and "IM" on little-endian systems.
981
    // systems and "IM" on little-endian systems.
778
    fwrite( &MI, 2, 1, fp );
982
    fwrite( &MI, 2, 1, fp );
779
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
983
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
780
 
984
 
781
    //===================Data element tag (8 bytes, page 1-8)==================
985
    //===================Data element tag (8 bytes, page 1-8)==================
782
    bytes = 16 + 24 + (8 + strlen(varName) + (8-(strlen(varName)%8))%8)
986
    bytes = 16 + 24 + (8 + strlen(varName) + (8-(strlen(varName)%8))%8)
783
            + (8 + rows*cols*chans*bytesPerElement);
987
            + (8 + rows*cols*chans*bytesPerElement);
784
    fwrite( &miMATRIX, 4, 1, fp ); // Data type.
988
    fwrite( &miMATRIX, 4, 1, fp ); // Data type.
785
    fwrite( &bytes, 4, 1, fp); // Data size in bytes.
989
    fwrite( &bytes, 4, 1, fp); // Data size in bytes.
786
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
990
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
787
 
991
 
788
    //====================Array flags (16 bytes, page 1-15)====================
992
    //====================Array flags (16 bytes, page 1-15)====================
789
    bytes = 8;
993
    bytes = 8;
790
    fwrite( &miUINT32, 4, 1, fp );
994
    fwrite( &miUINT32, 4, 1, fp );
791
    fwrite( &bytes, 4, 1, fp );
995
    fwrite( &bytes, 4, 1, fp );
792
    flags = 0x00; // Complex, logical, and global flags all off.
996
    flags = 0x00; // Complex, logical, and global flags all off.
793
 
997
 
794
    tmp32 = 0;
998
    tmp32 = 0;
795
    tmp32 = (flags << 8 ) | (mxClass);
999
    tmp32 = (flags << 8 ) | (mxClass);
796
    fwrite( &tmp32, 4, 1, fp );
1000
    fwrite( &tmp32, 4, 1, fp );
797
 
1001
 
798
    fwrite( &zero, 4, 1, fp ); // Padding to 64-bit boundary.
1002
    fwrite( &zero, 4, 1, fp ); // Padding to 64-bit boundary.
799
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1003
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
800
 
1004
 
801
    //===============Dimensions subelement (24 bytes, page 1-17)===============
1005
    //===============Dimensions subelement (24 bytes, page 1-17)===============
802
    bytes = 12;
1006
    bytes = 12;
803
    fwrite( &miINT32, 4, 1, fp );
1007
    fwrite( &miINT32, 4, 1, fp );
804
    fwrite( &bytes, 4, 1, fp );
1008
    fwrite( &bytes, 4, 1, fp );
805
 
1009
 
806
    fwrite( &rows, 4, 1, fp );
1010
    fwrite( &rows, 4, 1, fp );
807
    fwrite( &cols, 4, 1, fp );
1011
    fwrite( &cols, 4, 1, fp );
808
    fwrite( &chans, 4, 1, fp );
1012
    fwrite( &chans, 4, 1, fp );
809
    fwrite( &zero, 4, 1, fp ); // Padding to 64-bit boundary.
1013
    fwrite( &zero, 4, 1, fp ); // Padding to 64-bit boundary.
810
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1014
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
811
 
1015
 
812
    //==Array name (8 + strlen(varName) + (8-(strlen(varName)%8))%8 bytes, page 1-17)==
1016
    //==Array name (8 + strlen(varName) + (8-(strlen(varName)%8))%8 bytes, page 1-17)==
813
    bytes = strlen(varName);
1017
    bytes = strlen(varName);
814
 
1018
 
815
    fwrite( &miINT8, 4, 1, fp );
1019
    fwrite( &miINT8, 4, 1, fp );
816
    fwrite( &bytes, 4, 1, fp );
1020
    fwrite( &bytes, 4, 1, fp );
817
    fwrite( varName, 1, bytes, fp );
1021
    fwrite( varName, 1, bytes, fp );
818
 
1022
 
819
    // Pad to nearest 64-bit boundary.
1023
    // Pad to nearest 64-bit boundary.
820
    padBytes = (8-(bytes%8))%8;
1024
    padBytes = (8-(bytes%8))%8;
821
    fwrite( &zero, 1, padBytes, fp );
1025
    fwrite( &zero, 1, padBytes, fp );
822
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1026
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
823
 
1027
 
824
    //====Matrix data (rows*cols*chans*bytesPerElement+8 bytes, page 1-20)=====
1028
    //====Matrix data (rows*cols*chans*bytesPerElement+8 bytes, page 1-20)=====
825
    bytes = rows*cols*chans*bytesPerElement;
1029
    bytes = rows*cols*chans*bytesPerElement;
826
    fwrite( &miClass, 4, 1, fp );
1030
    fwrite( &miClass, 4, 1, fp );
827
    fwrite( &bytes, 4, 1, fp );
1031
    fwrite( &bytes, 4, 1, fp );
828
 
1032
 
829
    for( k = 0; k < chans; ++k )
1033
    for( k = 0; k < chans; ++k )
830
    {
1034
    {
831
        if( doBgrSwap )
1035
        if( doBgrSwap )
832
        {
1036
        {
833
            k2 = (k==0)? 2 : ((k==2)? 0 : 1);
1037
            k2 = (k==0)? 2 : ((k==2)? 0 : 1);
834
        }
1038
        }
835
        else
1039
        else
836
            k2 = k;
1040
            k2 = k;
837
 
1041
 
838
        for( j = 0; j < cols; ++j )
1042
        for( j = 0; j < cols; ++j )
839
        {
1043
        {
840
            for( i = 0; i < rows; ++i )
1044
            for( i = 0; i < rows; ++i )
841
            {
1045
            {
842
                rowPtr = mat.data + mat.step*i;
1046
                rowPtr = mat.data + mat.step*i;
843
                fwrite( rowPtr + (chans*j + k2)*bytesPerElement, bytesPerElement, 1, fp );
1047
                fwrite( rowPtr + (chans*j + k2)*bytesPerElement, bytesPerElement, 1, fp );
844
            }
1048
            }
845
        }
1049
        }
846
    }
1050
    }
847
 
1051
 
848
    // Pad to 64-bit boundary.
1052
    // Pad to 64-bit boundary.
849
    padBytes = (8-(bytes%8))%8;
1053
    padBytes = (8-(bytes%8))%8;
850
    fwrite( &zero, 1, padBytes, fp );
1054
    fwrite( &zero, 1, padBytes, fp );
851
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1055
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
852
 
1056
 
853
    fclose(fp);
1057
    fclose(fp);
854
    delete[] text;
1058
    delete[] text;
855
    delete[] subsysOffset;
1059
    delete[] subsysOffset;
856
    delete[] ver;
1060
    delete[] ver;
857
}
1061
}
858
 
1062
 
859
 
1063
 
860
 
1064
 
861
 
1065
 
862
 
1066
 
863
}
1067
}
864
 
1068